staging: r8712u: Fix regression caused by commit 8c213fa
[pandora-kernel.git] / drivers / staging / intel_sst / intel_sst_ipc.c
1 /*
2  *  intel_sst_ipc.c - Intel SST Driver for audio engine
3  *
4  *  Copyright (C) 2008-10 Intel Corporation
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 defines all ipc functions
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.h"
35 #include "intel_sst_ioctl.h"
36 #include "intel_sst_fw_ipc.h"
37 #include "intel_sst_common.h"
38
39 /*
40  * sst_send_sound_card_type - send sound card type
41  *
42  * this function sends the sound card type to sst dsp engine
43  */
44 static void sst_send_sound_card_type(void)
45 {
46         struct ipc_post *msg = NULL;
47
48         if (sst_create_short_msg(&msg))
49                 return;
50
51         sst_fill_header(&msg->header, IPC_IA_SET_PMIC_TYPE, 0, 0);
52         msg->header.part.data = sst_drv_ctx->pmic_vendor;
53         spin_lock(&sst_drv_ctx->list_spin_lock);
54         list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
55         spin_unlock(&sst_drv_ctx->list_spin_lock);
56         sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
57         return;
58 }
59
60 /**
61 * sst_post_message - Posts message to SST
62 *
63 * @work: Pointer to work structure
64 *
65 * This function is called by any component in driver which
66 * wants to send an IPC message. This will post message only if
67 * busy bit is free
68 */
69 void sst_post_message(struct work_struct *work)
70 {
71         struct ipc_post *msg;
72         union ipc_header header;
73         union  interrupt_reg imr;
74         int retval = 0;
75         imr.full = 0;
76
77         /*To check if LPE is in stalled state.*/
78         retval = sst_stalled();
79         if (retval < 0) {
80                 pr_err("in stalled state\n");
81                 return;
82         }
83         pr_debug("post message called\n");
84         spin_lock(&sst_drv_ctx->list_spin_lock);
85
86         /* check list */
87         if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
88                 /* list is empty, mask imr */
89                 pr_debug("Empty msg queue... masking\n");
90                 imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
91                 imr.part.done_interrupt = 1;
92                 /* dummy register for shim workaround */
93                 sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
94                 spin_unlock(&sst_drv_ctx->list_spin_lock);
95                 return;
96         }
97
98         /* check busy bit */
99         header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
100         if (header.part.busy) {
101                 /* busy, unmask */
102                 pr_debug("Busy not free... unmasking\n");
103                 imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
104                 imr.part.done_interrupt = 0;
105                 /* dummy register for shim workaround */
106                 sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
107                 spin_unlock(&sst_drv_ctx->list_spin_lock);
108                 return;
109         }
110         /* copy msg from list */
111         msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
112                         struct ipc_post, node);
113         list_del(&msg->node);
114         pr_debug("Post message: header = %x\n", msg->header.full);
115         pr_debug("size: = %x\n", msg->header.part.data);
116         if (msg->header.part.large)
117                 memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
118                         msg->mailbox_data, msg->header.part.data);
119         /* dummy register for shim workaround */
120
121         sst_shim_write(sst_drv_ctx->shim, SST_IPCX, msg->header.full);
122         spin_unlock(&sst_drv_ctx->list_spin_lock);
123
124         kfree(msg->mailbox_data);
125         kfree(msg);
126         return;
127 }
128
129 /*
130  * sst_clear_interrupt - clear the SST FW interrupt
131  *
132  * This function clears the interrupt register after the interrupt
133  * bottom half is complete allowing next interrupt to arrive
134  */
135 void sst_clear_interrupt(void)
136 {
137         union interrupt_reg isr;
138         union interrupt_reg imr;
139         union ipc_header clear_ipc;
140
141         imr.full = sst_shim_read(sst_drv_ctx->shim, SST_IMRX);
142         isr.full = sst_shim_read(sst_drv_ctx->shim, SST_ISRX);
143         /*  write 1 to clear  */;
144         isr.part.busy_interrupt = 1;
145         sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full);
146         /* Set IA done bit */
147         clear_ipc.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCD);
148         clear_ipc.part.busy = 0;
149         clear_ipc.part.done = 1;
150         clear_ipc.part.data = IPC_ACK_SUCCESS;
151         sst_shim_write(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full);
152         /* un mask busy interrupt */
153         imr.part.busy_interrupt = 0;
154         sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
155 }
156
157 void sst_restore_fw_context(void)
158 {
159         struct snd_sst_ctxt_params fw_context;
160         struct ipc_post *msg = NULL;
161
162         pr_debug("restore_fw_context\n");
163         /*check cpu type*/
164         if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
165                 return;
166                 /*not supported for rest*/
167         if (!sst_drv_ctx->fw_cntx_size)
168                 return;
169                 /*nothing to restore*/
170         pr_debug("restoring context......\n");
171         /*send msg to fw*/
172         if (sst_create_large_msg(&msg))
173                 return;
174
175         sst_fill_header(&msg->header, IPC_IA_SET_FW_CTXT, 1, 0);
176         msg->header.part.data = sizeof(fw_context) + sizeof(u32);
177         fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx);
178         fw_context.size = sst_drv_ctx->fw_cntx_size;
179         memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
180         memcpy(msg->mailbox_data + sizeof(u32),
181                                 &fw_context, sizeof(fw_context));
182         spin_lock(&sst_drv_ctx->list_spin_lock);
183         list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
184         spin_unlock(&sst_drv_ctx->list_spin_lock);
185         sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
186         return;
187 }
188 /*
189  * process_fw_init - process the FW init msg
190  *
191  * @msg: IPC message from FW
192  *
193  * This function processes the FW init msg from FW
194  * marks FW state and prints debug info of loaded FW
195  */
196 int process_fw_init(struct sst_ipc_msg_wq *msg)
197 {
198         struct ipc_header_fw_init *init =
199                 (struct ipc_header_fw_init *)msg->mailbox;
200         int retval = 0;
201
202         pr_debug("*** FW Init msg came***\n");
203         if (init->result) {
204                 mutex_lock(&sst_drv_ctx->sst_lock);
205                 sst_drv_ctx->sst_state = SST_ERROR;
206                 mutex_unlock(&sst_drv_ctx->sst_lock);
207                 pr_debug("FW Init failed, Error %x\n", init->result);
208                 pr_err("FW Init failed, Error %x\n", init->result);
209                 retval = -init->result;
210                 return retval;
211         }
212         if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
213                 sst_send_sound_card_type();
214         mutex_lock(&sst_drv_ctx->sst_lock);
215         sst_drv_ctx->sst_state = SST_FW_RUNNING;
216         sst_drv_ctx->lpe_stalled = 0;
217         mutex_unlock(&sst_drv_ctx->sst_lock);
218         pr_debug("FW Version %02x.%02x.%02x\n", init->fw_version.major,
219                         init->fw_version.minor, init->fw_version.build);
220         pr_debug("Build Type %x\n", init->fw_version.type);
221         pr_debug(" Build date %s Time %s\n",
222                         init->build_info.date, init->build_info.time);
223         sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
224         sst_restore_fw_context();
225         return retval;
226 }
227 /**
228 * sst_process_message - Processes message from SST
229 *
230 * @work:        Pointer to work structure
231 *
232 * This function is scheduled by ISR
233 * It take a msg from process_queue and does action based on msg
234 */
235 void sst_process_message(struct work_struct *work)
236 {
237         struct sst_ipc_msg_wq *msg =
238                         container_of(work, struct sst_ipc_msg_wq, wq);
239         int str_id = msg->header.part.str_id;
240
241         pr_debug("IPC process for %x\n", msg->header.full);
242
243         /* based on msg in list call respective handler */
244         switch (msg->header.part.msg_id) {
245         case IPC_SST_BUF_UNDER_RUN:
246         case IPC_SST_BUF_OVER_RUN:
247                 if (sst_validate_strid(str_id)) {
248                         pr_err("stream id %d invalid\n", str_id);
249                         break;
250                 }
251                 pr_err("Buffer under/overrun for %d\n",
252                                 msg->header.part.str_id);
253                 pr_err("Got Underrun & not to send data...ignore\n");
254                 break;
255
256         case IPC_SST_GET_PLAY_FRAMES:
257                 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
258                         struct stream_info *stream ;
259
260                         if (sst_validate_strid(str_id)) {
261                                 pr_err("strid %d invalid\n", str_id);
262                                 break;
263                         }
264                         /* call sst_play_frame */
265                         stream = &sst_drv_ctx->streams[str_id];
266                         pr_debug("sst_play_frames for %d\n",
267                                         msg->header.part.str_id);
268                         mutex_lock(&sst_drv_ctx->streams[str_id].lock);
269                         sst_play_frame(msg->header.part.str_id);
270                         mutex_unlock(&sst_drv_ctx->streams[str_id].lock);
271                         break;
272                 } else
273                         pr_err("sst_play_frames for Penwell!!\n");
274
275         case IPC_SST_GET_CAPT_FRAMES:
276                 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
277                         struct stream_info *stream;
278                         /* call sst_capture_frame */
279                         if (sst_validate_strid(str_id)) {
280                                 pr_err("str id %d invalid\n", str_id);
281                                 break;
282                         }
283                         stream = &sst_drv_ctx->streams[str_id];
284                         pr_debug("sst_capture_frames for %d\n",
285                                         msg->header.part.str_id);
286                         mutex_lock(&stream->lock);
287                         if (stream->mmapped == false &&
288                                         stream->src == SST_DRV) {
289                                 pr_debug("waking up block for copy.\n");
290                                 stream->data_blk.ret_code = 0;
291                                 stream->data_blk.condition = true;
292                                 stream->data_blk.on = false;
293                                 wake_up(&sst_drv_ctx->wait_queue);
294                         } else
295                                 sst_capture_frame(msg->header.part.str_id);
296                         mutex_unlock(&stream->lock);
297                 } else
298                         pr_err("sst_play_frames for Penwell!!\n");
299                 break;
300
301         case IPC_IA_PRINT_STRING:
302                 pr_debug("been asked to print something by fw\n");
303                 /* TBD */
304                 break;
305
306         case IPC_IA_FW_INIT_CMPLT: {
307                 /* send next data to FW */
308                 process_fw_init(msg);
309                 break;
310         }
311
312         case IPC_SST_STREAM_PROCESS_FATAL_ERR:
313                 if (sst_validate_strid(str_id)) {
314                         pr_err("stream id %d invalid\n", str_id);
315                         break;
316                 }
317                 pr_err("codec fatal error %x stream %d...\n",
318                                 msg->header.full, msg->header.part.str_id);
319                 pr_err("Dropping the stream\n");
320                 sst_drop_stream(msg->header.part.str_id);
321                 break;
322         case IPC_IA_LPE_GETTING_STALLED:
323                 sst_drv_ctx->lpe_stalled = 1;
324                 break;
325         case IPC_IA_LPE_UNSTALLED:
326                 sst_drv_ctx->lpe_stalled = 0;
327                 break;
328         default:
329                 /* Illegal case */
330                 pr_err("Unhandled msg %x header %x\n",
331                 msg->header.part.msg_id, msg->header.full);
332         }
333         sst_clear_interrupt();
334         return;
335 }
336
337 /**
338 * sst_process_reply - Processes reply message from SST
339 *
340 * @work:        Pointer to work structure
341 *
342 * This function is scheduled by ISR
343 * It take a reply msg from response_queue and
344 * does action based on msg
345 */
346 void sst_process_reply(struct work_struct *work)
347 {
348         struct sst_ipc_msg_wq *msg =
349                         container_of(work, struct sst_ipc_msg_wq, wq);
350
351         int str_id = msg->header.part.str_id;
352         struct stream_info *str_info;
353
354         switch (msg->header.part.msg_id) {
355         case IPC_IA_TARGET_DEV_SELECT:
356                 if (!msg->header.part.data) {
357                         sst_drv_ctx->tgt_dev_blk.ret_code = 0;
358                 } else {
359                         pr_err(" Msg %x reply error %x\n",
360                         msg->header.part.msg_id, msg->header.part.data);
361                         sst_drv_ctx->tgt_dev_blk.ret_code =
362                                         -msg->header.part.data;
363                 }
364
365                 if (sst_drv_ctx->tgt_dev_blk.on == true) {
366                                 sst_drv_ctx->tgt_dev_blk.condition = true;
367                                 wake_up(&sst_drv_ctx->wait_queue);
368                 }
369                 break;
370         case IPC_IA_ALG_PARAMS: {
371                 pr_debug("sst:IPC_ALG_PARAMS response %x\n", msg->header.full);
372                 pr_debug("sst: data value %x\n", msg->header.part.data);
373                 pr_debug("sst: large value %x\n", msg->header.part.large);
374
375                 if (!msg->header.part.large) {
376                         if (!msg->header.part.data) {
377                                 pr_debug("sst: alg set success\n");
378                                 sst_drv_ctx->ppp_params_blk.ret_code = 0;
379                         } else {
380                                 pr_debug("sst: alg set failed\n");
381                                 sst_drv_ctx->ppp_params_blk.ret_code =
382                                                         -msg->header.part.data;
383                         }
384
385                 } else if (msg->header.part.data) {
386                         struct snd_ppp_params *mailbox_params, *get_params;
387                         char *params;
388
389                         pr_debug("sst: alg get success\n");
390                         mailbox_params = (struct snd_ppp_params *)msg->mailbox;
391                         get_params = kzalloc(sizeof(*get_params), GFP_KERNEL);
392                         if (get_params == NULL) {
393                                 pr_err("sst: out of memory for ALG PARAMS");
394                                 break;
395                         }
396                         memcpy_fromio(get_params, mailbox_params,
397                                                         sizeof(*get_params));
398                         get_params->params = kzalloc(mailbox_params->size,
399                                                         GFP_KERNEL);
400                         if (get_params->params == NULL) {
401                                 kfree(get_params);
402                                 pr_err("sst: out of memory for ALG PARAMS block");
403                                 break;
404                         }
405                         params = msg->mailbox;
406                         params = params + sizeof(*mailbox_params) - sizeof(u32);
407                         memcpy_fromio(get_params->params, params,
408                                                         get_params->size);
409                         sst_drv_ctx->ppp_params_blk.ret_code = 0;
410                         sst_drv_ctx->ppp_params_blk.data = get_params;
411                 }
412
413                 if (sst_drv_ctx->ppp_params_blk.on == true) {
414                         sst_drv_ctx->ppp_params_blk.condition = true;
415                         wake_up(&sst_drv_ctx->wait_queue);
416                 }
417                 break;
418         }
419
420         case IPC_IA_TUNING_PARAMS: {
421                 pr_debug("sst:IPC_TUNING_PARAMS resp: %x\n", msg->header.full);
422                 pr_debug("data value %x\n", msg->header.part.data);
423                 if (msg->header.part.large) {
424                         pr_debug("alg set failed\n");
425                         sst_drv_ctx->ppp_params_blk.ret_code =
426                                                         -msg->header.part.data;
427                 } else {
428                         pr_debug("alg set success\n");
429                         sst_drv_ctx->ppp_params_blk.ret_code = 0;
430                 }
431                 if (sst_drv_ctx->ppp_params_blk.on == true) {
432                         sst_drv_ctx->ppp_params_blk.condition = true;
433                         wake_up(&sst_drv_ctx->wait_queue);
434                 }
435         }
436
437         case IPC_IA_GET_FW_INFO: {
438                 struct snd_sst_fw_info *fw_info =
439                         (struct snd_sst_fw_info *)msg->mailbox;
440                 if (msg->header.part.large) {
441                         int major = fw_info->fw_version.major;
442                         int minor = fw_info->fw_version.minor;
443                         int build = fw_info->fw_version.build;
444                         pr_debug("Msg succeeded %x\n",
445                                        msg->header.part.msg_id);
446                         pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n",
447                                         major, minor, build);
448                         memcpy_fromio(sst_drv_ctx->fw_info_blk.data,
449                                 ((struct snd_sst_fw_info *)(msg->mailbox)),
450                                 sizeof(struct snd_sst_fw_info));
451                         sst_drv_ctx->fw_info_blk.ret_code = 0;
452                 } else {
453                         pr_err(" Msg %x reply error %x\n",
454                         msg->header.part.msg_id, msg->header.part.data);
455                         sst_drv_ctx->fw_info_blk.ret_code =
456                                         -msg->header.part.data;
457                 }
458                 if (sst_drv_ctx->fw_info_blk.on == true) {
459                         pr_debug("Memcopy succeeded\n");
460                         sst_drv_ctx->fw_info_blk.on = false;
461                         sst_drv_ctx->fw_info_blk.condition = true;
462                         wake_up(&sst_drv_ctx->wait_queue);
463                 }
464                 break;
465         }
466         case IPC_IA_SET_STREAM_MUTE:
467                 if (!msg->header.part.data) {
468                         pr_debug("Msg succeeded %x\n",
469                                        msg->header.part.msg_id);
470                         sst_drv_ctx->mute_info_blk.ret_code = 0;
471                 } else {
472                         pr_err(" Msg %x reply error %x\n",
473                         msg->header.part.msg_id, msg->header.part.data);
474                         sst_drv_ctx->mute_info_blk.ret_code =
475                                         -msg->header.part.data;
476
477                 }
478                 if (sst_drv_ctx->mute_info_blk.on == true) {
479                         sst_drv_ctx->mute_info_blk.on = false;
480                         sst_drv_ctx->mute_info_blk.condition = true;
481                         wake_up(&sst_drv_ctx->wait_queue);
482                 }
483                 break;
484         case IPC_IA_SET_STREAM_VOL:
485                 if (!msg->header.part.data) {
486                         pr_debug("Msg succeeded %x\n",
487                                        msg->header.part.msg_id);
488                         sst_drv_ctx->vol_info_blk.ret_code = 0;
489                 } else {
490                         pr_err(" Msg %x reply error %x\n",
491                                         msg->header.part.msg_id,
492                         msg->header.part.data);
493                         sst_drv_ctx->vol_info_blk.ret_code =
494                                         -msg->header.part.data;
495
496                 }
497
498                 if (sst_drv_ctx->vol_info_blk.on == true) {
499                         sst_drv_ctx->vol_info_blk.on = false;
500                         sst_drv_ctx->vol_info_blk.condition = true;
501                         wake_up(&sst_drv_ctx->wait_queue);
502                 }
503                 break;
504         case IPC_IA_GET_STREAM_VOL:
505                 if (msg->header.part.large) {
506                         pr_debug("Large Msg Received Successfully\n");
507                         pr_debug("Msg succeeded %x\n",
508                                        msg->header.part.msg_id);
509                         memcpy_fromio(sst_drv_ctx->vol_info_blk.data,
510                                 (void *) msg->mailbox,
511                                 sizeof(struct snd_sst_vol));
512                         sst_drv_ctx->vol_info_blk.ret_code = 0;
513                 } else {
514                         pr_err("Msg %x reply error %x\n",
515                         msg->header.part.msg_id, msg->header.part.data);
516                         sst_drv_ctx->vol_info_blk.ret_code =
517                                         -msg->header.part.data;
518                 }
519                 if (sst_drv_ctx->vol_info_blk.on == true) {
520                         sst_drv_ctx->vol_info_blk.on = false;
521                         sst_drv_ctx->vol_info_blk.condition = true;
522                         wake_up(&sst_drv_ctx->wait_queue);
523                 }
524                 break;
525
526         case IPC_IA_GET_STREAM_PARAMS:
527                 if (sst_validate_strid(str_id)) {
528                         pr_err("stream id %d invalid\n", str_id);
529                         break;
530                 }
531                 str_info = &sst_drv_ctx->streams[str_id];
532                 if (msg->header.part.large) {
533                         pr_debug("Get stream large success\n");
534                         memcpy_fromio(str_info->ctrl_blk.data,
535                                 ((void *)(msg->mailbox)),
536                                 sizeof(struct snd_sst_fw_get_stream_params));
537                         str_info->ctrl_blk.ret_code = 0;
538                 } else {
539                         pr_err("Msg %x reply error %x\n",
540                                 msg->header.part.msg_id, msg->header.part.data);
541                         str_info->ctrl_blk.ret_code = -msg->header.part.data;
542                 }
543                 if (str_info->ctrl_blk.on == true) {
544                         str_info->ctrl_blk.on = false;
545                         str_info->ctrl_blk.condition = true;
546                         wake_up(&sst_drv_ctx->wait_queue);
547                 }
548                 break;
549         case IPC_IA_DECODE_FRAMES:
550                 if (sst_validate_strid(str_id)) {
551                         pr_err("stream id %d invalid\n", str_id);
552                         break;
553                 }
554                 str_info = &sst_drv_ctx->streams[str_id];
555                 if (msg->header.part.large) {
556                         pr_debug("Msg succeeded %x\n",
557                                        msg->header.part.msg_id);
558                         memcpy_fromio(str_info->data_blk.data,
559                                         ((void *)(msg->mailbox)),
560                                         sizeof(struct snd_sst_decode_info));
561                         str_info->data_blk.ret_code = 0;
562                 } else {
563                         pr_err("Msg %x reply error %x\n",
564                                 msg->header.part.msg_id, msg->header.part.data);
565                         str_info->data_blk.ret_code = -msg->header.part.data;
566                 }
567                 if (str_info->data_blk.on == true) {
568                         str_info->data_blk.on = false;
569                         str_info->data_blk.condition = true;
570                         wake_up(&sst_drv_ctx->wait_queue);
571                 }
572                 break;
573         case IPC_IA_DRAIN_STREAM:
574                 if (sst_validate_strid(str_id)) {
575                         pr_err("stream id %d invalid\n", str_id);
576                         break;
577                 }
578                 str_info = &sst_drv_ctx->streams[str_id];
579                 if (!msg->header.part.data) {
580                         pr_debug("Msg succeeded %x\n",
581                                         msg->header.part.msg_id);
582                         str_info->ctrl_blk.ret_code = 0;
583
584                 } else {
585                         pr_err(" Msg %x reply error %x\n",
586                                 msg->header.part.msg_id, msg->header.part.data);
587                         str_info->ctrl_blk.ret_code = -msg->header.part.data;
588
589                 }
590                 str_info = &sst_drv_ctx->streams[str_id];
591                 if (str_info->data_blk.on == true) {
592                         str_info->data_blk.on = false;
593                         str_info->data_blk.condition = true;
594                         wake_up(&sst_drv_ctx->wait_queue);
595                 }
596                 break;
597
598         case IPC_IA_DROP_STREAM:
599                 if (sst_validate_strid(str_id)) {
600                         pr_err("str id %d invalid\n", str_id);
601                         break;
602                 }
603                 str_info = &sst_drv_ctx->streams[str_id];
604                 if (msg->header.part.large) {
605                         struct snd_sst_drop_response *drop_resp =
606                                 (struct snd_sst_drop_response *)msg->mailbox;
607
608                         pr_debug("Drop ret bytes %x\n", drop_resp->bytes);
609
610                         str_info->curr_bytes = drop_resp->bytes;
611                         str_info->ctrl_blk.ret_code =  0;
612                 } else {
613                         pr_err(" Msg %x reply error %x\n",
614                                 msg->header.part.msg_id, msg->header.part.data);
615                         str_info->ctrl_blk.ret_code = -msg->header.part.data;
616                 }
617                 if (str_info->ctrl_blk.on == true) {
618                         str_info->ctrl_blk.on = false;
619                         str_info->ctrl_blk.condition = true;
620                         wake_up(&sst_drv_ctx->wait_queue);
621                 }
622                 break;
623         case IPC_IA_ENABLE_RX_TIME_SLOT:
624                 if (!msg->header.part.data) {
625                         pr_debug("RX_TIME_SLOT success\n");
626                         sst_drv_ctx->hs_info_blk.ret_code = 0;
627                 } else {
628                         pr_err(" Msg %x reply error %x\n",
629                                 msg->header.part.msg_id,
630                                 msg->header.part.data);
631                         sst_drv_ctx->hs_info_blk.ret_code =
632                                 -msg->header.part.data;
633                 }
634                 if (sst_drv_ctx->hs_info_blk.on == true) {
635                         sst_drv_ctx->hs_info_blk.on = false;
636                         sst_drv_ctx->hs_info_blk.condition = true;
637                         wake_up(&sst_drv_ctx->wait_queue);
638                 }
639                 break;
640         case IPC_IA_PAUSE_STREAM:
641         case IPC_IA_RESUME_STREAM:
642         case IPC_IA_SET_STREAM_PARAMS:
643                 str_info = &sst_drv_ctx->streams[str_id];
644                 if (!msg->header.part.data) {
645                         pr_debug("Msg succeeded %x\n",
646                                         msg->header.part.msg_id);
647                         str_info->ctrl_blk.ret_code = 0;
648                 } else {
649                         pr_err(" Msg %x reply error %x\n",
650                                         msg->header.part.msg_id,
651                                         msg->header.part.data);
652                         str_info->ctrl_blk.ret_code = -msg->header.part.data;
653                 }
654                 if (sst_validate_strid(str_id)) {
655                         pr_err(" stream id %d invalid\n", str_id);
656                         break;
657                 }
658
659                 if (str_info->ctrl_blk.on == true) {
660                         str_info->ctrl_blk.on = false;
661                         str_info->ctrl_blk.condition = true;
662                         wake_up(&sst_drv_ctx->wait_queue);
663                 }
664                 break;
665
666         case IPC_IA_FREE_STREAM:
667                 str_info = &sst_drv_ctx->streams[str_id];
668                 if (!msg->header.part.data) {
669                         pr_debug("Stream %d freed\n", str_id);
670                 } else {
671                         pr_err("Free for %d ret error %x\n",
672                                        str_id, msg->header.part.data);
673                 }
674                 if (str_info->ctrl_blk.on == true) {
675                         str_info->ctrl_blk.on = false;
676                         str_info->ctrl_blk.condition = true;
677                         wake_up(&sst_drv_ctx->wait_queue);
678                 }
679                 break;
680         case IPC_IA_ALLOC_STREAM: {
681                 /* map to stream, call play */
682                 struct snd_sst_alloc_response *resp =
683                                 (struct snd_sst_alloc_response *)msg->mailbox;
684                 if (resp->str_type.result)
685                         pr_err("error alloc stream = %x\n",
686                                        resp->str_type.result);
687                 sst_alloc_stream_response(str_id, resp);
688                 break;
689         }
690
691         case IPC_IA_PLAY_FRAMES:
692         case IPC_IA_CAPT_FRAMES:
693                 if (sst_validate_strid(str_id)) {
694                         pr_err("stream id %d invalid\n", str_id);
695                         break;
696                 }
697                 pr_debug("Ack for play/capt frames received\n");
698                 break;
699
700         case IPC_IA_PREP_LIB_DNLD: {
701                 struct snd_sst_str_type *str_type =
702                         (struct snd_sst_str_type *)msg->mailbox;
703                 pr_debug("Prep Lib download %x\n",
704                                 msg->header.part.msg_id);
705                 if (str_type->result)
706                         pr_err("Prep lib download %x\n", str_type->result);
707                 else
708                         pr_debug("Can download codec now...\n");
709                 sst_wake_up_alloc_block(sst_drv_ctx, str_id,
710                                 str_type->result, NULL);
711                 break;
712         }
713
714         case IPC_IA_LIB_DNLD_CMPLT: {
715                 struct snd_sst_lib_download_info *resp =
716                         (struct snd_sst_lib_download_info *)msg->mailbox;
717                 int retval = resp->result;
718
719                 pr_debug("Lib downloaded %x\n", msg->header.part.msg_id);
720                 if (resp->result) {
721                         pr_err("err in lib dload %x\n", resp->result);
722                 } else {
723                         pr_debug("Codec download complete...\n");
724                         pr_debug("codec Type %d Ver %d Built %s: %s\n",
725                                 resp->dload_lib.lib_info.lib_type,
726                                 resp->dload_lib.lib_info.lib_version,
727                                 resp->dload_lib.lib_info.b_date,
728                                 resp->dload_lib.lib_info.b_time);
729                 }
730                 sst_wake_up_alloc_block(sst_drv_ctx, str_id,
731                                                 retval, NULL);
732                 break;
733         }
734
735         case IPC_IA_GET_FW_VERSION: {
736                 struct ipc_header_fw_init *version =
737                                 (struct ipc_header_fw_init *)msg->mailbox;
738                 int major = version->fw_version.major;
739                 int minor = version->fw_version.minor;
740                 int build = version->fw_version.build;
741                 dev_info(&sst_drv_ctx->pci->dev,
742                         "INFO: ***LOADED SST FW VERSION*** = %02d.%02d.%02d\n",
743                 major, minor, build);
744                 break;
745         }
746         case IPC_IA_GET_FW_BUILD_INF: {
747                 struct sst_fw_build_info *build =
748                         (struct sst_fw_build_info *)msg->mailbox;
749                 pr_debug("Build date:%sTime:%s", build->date, build->time);
750                 break;
751         }
752         case IPC_IA_SET_PMIC_TYPE:
753                 break;
754         case IPC_IA_START_STREAM:
755                 pr_debug("reply for START STREAM %x\n", msg->header.full);
756                 break;
757
758         case IPC_IA_GET_FW_CTXT:
759                 pr_debug("reply for get fw ctxt  %x\n", msg->header.full);
760                 if (msg->header.part.data)
761                         sst_drv_ctx->fw_cntx_size = 0;
762                 else
763                         sst_drv_ctx->fw_cntx_size = *sst_drv_ctx->fw_cntx;
764                 pr_debug("fw copied data %x\n", sst_drv_ctx->fw_cntx_size);
765                 sst_wake_up_alloc_block(
766                         sst_drv_ctx, str_id, msg->header.part.data, NULL);
767                 break;
768         default:
769                 /* Illegal case */
770                 pr_err("process reply:default = %x\n", msg->header.full);
771         }
772         sst_clear_interrupt();
773         return;
774 }