Merge branch 'for-2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc...
[deliverable/linux.git] / drivers / staging / intel_sst / intel_sst_pvt.c
CommitLineData
fffa1cca
VK
1/*
2 * intel_sst_pvt.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 driver exposes the audio engine functionalities to the ALSA
27 * and middleware.
28 *
29 * This file contains all private functions
30 */
31
32#include <linux/pci.h>
33#include <linux/fs.h>
34#include <linux/firmware.h>
35#include <linux/sched.h>
36#include "intel_sst.h"
37#include "intel_sst_ioctl.h"
38#include "intel_sst_fw_ipc.h"
39#include "intel_sst_common.h"
40
41/*
42 * sst_get_block_stream - get a new block stream
43 *
44 * @sst_drv_ctx: Driver context structure
45 *
46 * This function assigns a block for the calls that dont have stream context yet
47 * the blocks are used for waiting on Firmware's response for any operation
48 * Should be called with stream lock held
49 */
50int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
51{
52 int i;
53
54 for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
55 if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) {
56 sst_drv_ctx->alloc_block[i].ops_block.condition = false;
57 sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0;
58 sst_drv_ctx->alloc_block[i].sst_id = 0;
59 break;
60 }
61 }
62 if (i == MAX_ACTIVE_STREAM) {
63 pr_err("sst: max alloc_stream reached");
64 i = -EBUSY; /* active stream limit reached */
65 }
66 return i;
67}
68
69/*
70 * sst_wait_interruptible - wait on event
71 *
72 * @sst_drv_ctx: Driver context
73 * @block: Driver block to wait on
74 *
75 * This function waits without a timeout (and is interruptable) for a
76 * given block event
77 */
78int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
79 struct sst_block *block)
80{
81 int retval = 0;
82
83 if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
84 block->condition)) {
85 /* event wake */
86 if (block->ret_code < 0) {
87 pr_err("sst: stream failed %d\n", block->ret_code);
88 retval = -EBUSY;
89 } else {
90 pr_debug("sst: event up\n");
91 retval = 0;
92 }
93 } else {
94 pr_err("sst: signal interrupted\n");
95 retval = -EINTR;
96 }
97 return retval;
98
99}
100
101
102/*
103 * sst_wait_interruptible_timeout - wait on event interruptable
104 *
105 * @sst_drv_ctx: Driver context
106 * @block: Driver block to wait on
107 * @timeout: time for wait on
108 *
109 * This function waits with a timeout value (and is interruptible) on a
110 * given block event
111 */
112int sst_wait_interruptible_timeout(
113 struct intel_sst_drv *sst_drv_ctx,
114 struct sst_block *block, int timeout)
115{
116 int retval = 0;
117
118 pr_debug("sst: sst_wait_interruptible_timeout - waiting....\n");
119 if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
120 block->condition,
121 msecs_to_jiffies(timeout))) {
122 if (block->ret_code < 0)
123 pr_err("sst: stream failed %d\n", block->ret_code);
124 else
125 pr_debug("sst: event up\n");
126 retval = block->ret_code;
127 } else {
128 block->on = false;
129 pr_err("sst: timeout occured...\n");
130 /*setting firmware state as uninit so that the
131 firmware will get re-downloaded on next request
132 this is because firmare not responding for 5 sec
133 is equalant to some unrecoverable error of FW
134 sst_drv_ctx->sst_state = SST_UN_INIT;*/
135 retval = -EBUSY;
136 }
137 return retval;
138
139}
140
141
142/*
143 * sst_wait_timeout - wait on event for timeout
144 *
145 * @sst_drv_ctx: Driver context
146 * @block: Driver block to wait on
147 *
148 * This function waits with a timeout value (and is not interruptible) on a
149 * given block event
150 */
151int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
152 struct stream_alloc_block *block)
153{
154 int retval = 0;
155
156 /* NOTE:
157 Observed that FW processes the alloc msg and replies even
158 before the alloc thread has finished execution */
159 pr_debug("sst: waiting for %x, condition %x\n",
160 block->sst_id, block->ops_block.condition);
161 if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
162 block->ops_block.condition,
163 msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
164 /* event wake */
165 pr_debug("sst: Event wake %x\n", block->ops_block.condition);
166 pr_debug("sst: message ret: %d\n", block->ops_block.ret_code);
167 retval = block->ops_block.ret_code;
168 } else {
169 block->ops_block.on = false;
170 pr_err("sst: Wait timed-out %x\n", block->ops_block.condition);
171 /* settign firmware state as uninit so that the
172 firmware will get redownloaded on next request
173 this is because firmare not responding for 5 sec
174 is equalant to some unrecoverable error of FW
175 sst_drv_ctx->sst_state = SST_UN_INIT;*/
176 retval = -EBUSY;
177 }
178 return retval;
179
180}
181
182/*
183 * sst_create_large_msg - create a large IPC message
184 *
185 * @arg: ipc message
186 *
187 * this function allocates structures to send a large message to the firmware
188 */
189int sst_create_large_msg(struct ipc_post **arg)
190{
191 struct ipc_post *msg;
192
193 msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
194 if (!msg) {
195 pr_err("sst: kzalloc msg failed\n");
196 return -ENOMEM;
197 }
198
199 msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
200 if (!msg->mailbox_data) {
201 kfree(msg);
202 pr_err("sst: kzalloc mailbox_data failed");
203 return -ENOMEM;
204 };
205 *arg = msg;
206 return 0;
207}
208
209/*
210 * sst_create_short_msg - create a short IPC message
211 *
212 * @arg: ipc message
213 *
214 * this function allocates structures to send a short message to the firmware
215 */
216int sst_create_short_msg(struct ipc_post **arg)
217{
218 struct ipc_post *msg;
219
220 msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
221 if (!msg) {
222 pr_err("sst: kzalloc msg failed\n");
223 return -ENOMEM;
224 }
225 msg->mailbox_data = NULL;
226 *arg = msg;
227 return 0;
228}
229
230/*
231 * sst_clean_stream - clean the stream context
232 *
233 * @stream: stream structure
234 *
235 * this function resets the stream contexts
236 * should be called in free
237 */
238void sst_clean_stream(struct stream_info *stream)
239{
240 struct sst_stream_bufs *bufs = NULL, *_bufs;
241 stream->status = STREAM_UN_INIT;
242 stream->prev = STREAM_UN_INIT;
243 mutex_lock(&stream->lock);
244 list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) {
245 list_del(&bufs->node);
246 kfree(bufs);
247 }
248 mutex_unlock(&stream->lock);
249
250 if (stream->ops != STREAM_OPS_PLAYBACK_DRM)
251 kfree(stream->decode_ibuf);
252}
253
254/*
255 * sst_wake_up_alloc_block - wake up waiting block
256 *
257 * @sst_drv_ctx: Driver context
258 * @sst_id: stream id
259 * @status: status of wakeup
260 * @data: data pointer of wakeup
261 *
262 * This function wakes up a sleeping block event based on the response
263 */
264void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
265 u8 sst_id, int status, void *data)
266{
267 int i;
268
269 /* Unblock with retval code */
270 for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
271 if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) {
272 sst_drv_ctx->alloc_block[i].ops_block.condition = true;
273 sst_drv_ctx->alloc_block[i].ops_block.ret_code = status;
274 sst_drv_ctx->alloc_block[i].ops_block.data = data;
275 wake_up(&sst_drv_ctx->wait_queue);
276 break;
277 }
278 }
279}
280
281/*
282 * sst_enable_rx_timeslot - Send msg to query for stream parameters
283 * @status: rx timeslot to be enabled
284 *
285 * This function is called when the RX timeslot is required to be enabled
286 */
287int sst_enable_rx_timeslot(int status)
288{
289 int retval = 0;
290 struct ipc_post *msg = NULL;
291
292 if (sst_create_short_msg(&msg)) {
293 pr_err("sst: mem allocation failed\n");
294 return -ENOMEM;
295 }
296 pr_debug("sst: ipc message sending: ENABLE_RX_TIME_SLOT\n");
297 sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0);
298 msg->header.part.data = status;
299 sst_drv_ctx->hs_info_blk.condition = false;
300 sst_drv_ctx->hs_info_blk.ret_code = 0;
301 sst_drv_ctx->hs_info_blk.on = true;
302 spin_lock(&sst_drv_ctx->list_spin_lock);
303 list_add_tail(&msg->node,
304 &sst_drv_ctx->ipc_dispatch_list);
305 spin_unlock(&sst_drv_ctx->list_spin_lock);
306 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
307 retval = sst_wait_interruptible_timeout(sst_drv_ctx,
308 &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT);
309 return retval;
310}
311
This page took 0.048272 seconds and 5 git commands to generate.