blob: b18117ce41858073e1a9b75c8c334f0890f9f102 [file] [log] [blame]
Mingming Yinc09967e2012-04-27 15:09:43 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/err.h>
15#include <linux/module.h>
16#include <linux/time.h>
17#include <linux/wait.h>
18#include <linux/platform_device.h>
19#include <linux/slab.h>
20#include <linux/dma-mapping.h>
21#include <sound/core.h>
22#include <sound/soc.h>
23#include <sound/soc-dapm.h>
24#include <sound/pcm.h>
25#include <sound/initval.h>
26#include <sound/control.h>
27#include <asm/dma.h>
28
29#include "msm-pcm-q6.h"
30#include "msm-pcm-routing.h"
31#include "qdsp6/q6voice.h"
32
33#define VOIP_MAX_Q_LEN 10
Helen Zengb62d92a2011-08-23 17:51:17 -070034#define VOIP_MAX_VOC_PKT_SIZE 640
Panneer Arumugam418aa0a2011-10-11 18:44:16 -070035#define VOIP_MIN_VOC_PKT_SIZE 320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
Helen Zengb9d00ce2011-10-13 17:25:50 -070037/* Length of the DSP frame info header added to the voc packet. */
38#define DSP_FRAME_HDR_LEN 1
39
Laxminath Kasam481d4982012-04-04 20:54:30 +053040#define MODE_IS127 0x2
41#define MODE_4GV_NB 0x3
42#define MODE_4GV_WB 0x4
Helen Zengb9d00ce2011-10-13 17:25:50 -070043#define MODE_AMR 0x5
44#define MODE_AMR_WB 0xD
45#define MODE_PCM 0xC
46
47enum format {
48 FORMAT_S16_LE = 2,
49 FORMAT_SPECIAL = 31,
50};
51
52
53enum amr_rate_type {
54 AMR_RATE_4750, /* AMR 4.75 kbps */
55 AMR_RATE_5150, /* AMR 5.15 kbps */
56 AMR_RATE_5900, /* AMR 5.90 kbps */
57 AMR_RATE_6700, /* AMR 6.70 kbps */
58 AMR_RATE_7400, /* AMR 7.40 kbps */
59 AMR_RATE_7950, /* AMR 7.95 kbps */
60 AMR_RATE_10200, /* AMR 10.20 kbps */
61 AMR_RATE_12200, /* AMR 12.20 kbps */
62 AMR_RATE_6600, /* AMR-WB 6.60 kbps */
63 AMR_RATE_8850, /* AMR-WB 8.85 kbps */
64 AMR_RATE_12650, /* AMR-WB 12.65 kbps */
65 AMR_RATE_14250, /* AMR-WB 14.25 kbps */
66 AMR_RATE_15850, /* AMR-WB 15.85 kbps */
67 AMR_RATE_18250, /* AMR-WB 18.25 kbps */
68 AMR_RATE_19850, /* AMR-WB 19.85 kbps */
69 AMR_RATE_23050, /* AMR-WB 23.05 kbps */
70 AMR_RATE_23850, /* AMR-WB 23.85 kbps */
71 AMR_RATE_UNDEF
72};
73
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074enum voip_state {
75 VOIP_STOPPED,
76 VOIP_STARTED,
77};
78
79struct voip_frame {
Laxminath Kasam481d4982012-04-04 20:54:30 +053080 union {
Helen Zengb9d00ce2011-10-13 17:25:50 -070081 uint32_t frame_type;
Laxminath Kasam481d4982012-04-04 20:54:30 +053082 uint32_t packet_rate;
83 } header;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 uint32_t len;
85 uint8_t voc_pkt[VOIP_MAX_VOC_PKT_SIZE];
86};
87
88struct voip_buf_node {
89 struct list_head list;
90 struct voip_frame frame;
91};
92
93struct voip_drv_info {
94 enum voip_state state;
95
96 struct snd_pcm_substream *playback_substream;
97 struct snd_pcm_substream *capture_substream;
98
99 struct list_head in_queue;
100 struct list_head free_in_queue;
101
102 struct list_head out_queue;
103 struct list_head free_out_queue;
104
105 wait_queue_head_t out_wait;
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700106 wait_queue_head_t in_wait;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107
108 struct mutex lock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109
110 spinlock_t dsp_lock;
Helen Zeng6c7dc952012-06-04 17:44:28 -0700111 spinlock_t dsp_ul_lock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
Helen Zengb9d00ce2011-10-13 17:25:50 -0700113 uint32_t mode;
114 uint32_t rate_type;
115 uint32_t rate;
Helen Zengff97bec2012-02-20 14:30:50 -0800116 uint32_t dtx_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117
118 uint8_t capture_start;
119 uint8_t playback_start;
120
121 uint8_t playback_instance;
122 uint8_t capture_instance;
123
124 unsigned int play_samp_rate;
125 unsigned int cap_samp_rate;
126
127 unsigned int pcm_size;
128 unsigned int pcm_count;
129 unsigned int pcm_playback_irq_pos; /* IRQ position */
130 unsigned int pcm_playback_buf_pos; /* position in buffer */
131
132 unsigned int pcm_capture_size;
133 unsigned int pcm_capture_count;
134 unsigned int pcm_capture_irq_pos; /* IRQ position */
135 unsigned int pcm_capture_buf_pos; /* position in buffer */
136};
137
Helen Zengb9d00ce2011-10-13 17:25:50 -0700138static int voip_get_media_type(uint32_t mode,
139 unsigned int samp_rate);
140static int voip_get_rate_type(uint32_t mode,
141 uint32_t rate,
142 uint32_t *rate_type);
143static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
144 struct snd_ctl_elem_value *ucontrol);
145static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
146 struct snd_ctl_elem_value *ucontrol);
147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148static struct voip_drv_info voip_info;
149
150static struct snd_pcm_hardware msm_pcm_hardware = {
151 .info = (SNDRV_PCM_INFO_MMAP |
152 SNDRV_PCM_INFO_BLOCK_TRANSFER |
153 SNDRV_PCM_INFO_MMAP_VALID |
154 SNDRV_PCM_INFO_INTERLEAVED),
Helen Zengb9d00ce2011-10-13 17:25:50 -0700155 .formats = SNDRV_PCM_FMTBIT_S16_LE |
156 SNDRV_PCM_FMTBIT_SPECIAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
158 .rate_min = 8000,
159 .rate_max = 16000,
160 .channels_min = 1,
161 .channels_max = 1,
Helen Zengb9d00ce2011-10-13 17:25:50 -0700162 .buffer_bytes_max = sizeof(struct voip_buf_node) * VOIP_MAX_Q_LEN,
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700163 .period_bytes_min = VOIP_MIN_VOC_PKT_SIZE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164 .period_bytes_max = VOIP_MAX_VOC_PKT_SIZE,
165 .periods_min = VOIP_MAX_Q_LEN,
166 .periods_max = VOIP_MAX_Q_LEN,
167 .fifo_size = 0,
168};
169
170
Panneer Arumugambcac6862011-10-27 18:20:44 -0700171static int msm_voip_mute_put(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
173{
174 int mute = ucontrol->value.integer.value[0];
175
176 pr_debug("%s: mute=%d\n", __func__, mute);
177
178 voc_set_tx_mute(voc_get_session_id(VOIP_SESSION_NAME), TX_PATH, mute);
179
180 return 0;
181}
182
183static int msm_voip_mute_get(struct snd_kcontrol *kcontrol,
184 struct snd_ctl_elem_value *ucontrol)
185{
186 ucontrol->value.integer.value[0] = 0;
187 return 0;
188}
189
190static int msm_voip_volume_put(struct snd_kcontrol *kcontrol,
191 struct snd_ctl_elem_value *ucontrol)
192{
193 int volume = ucontrol->value.integer.value[0];
194
195 pr_debug("%s: volume: %d\n", __func__, volume);
196
197 voc_set_rx_vol_index(voc_get_session_id(VOIP_SESSION_NAME),
198 RX_PATH,
199 volume);
200 return 0;
201}
202static int msm_voip_volume_get(struct snd_kcontrol *kcontrol,
203 struct snd_ctl_elem_value *ucontrol)
204{
205 ucontrol->value.integer.value[0] = 0;
206 return 0;
207}
208
Helen Zengff97bec2012-02-20 14:30:50 -0800209static int msm_voip_dtx_mode_put(struct snd_kcontrol *kcontrol,
210 struct snd_ctl_elem_value *ucontrol)
211{
212 mutex_lock(&voip_info.lock);
213
214 voip_info.dtx_mode = ucontrol->value.integer.value[0];
215
216 pr_debug("%s: dtx: %d\n", __func__, voip_info.dtx_mode);
217
218 mutex_unlock(&voip_info.lock);
219
220 return 0;
221}
222static int msm_voip_dtx_mode_get(struct snd_kcontrol *kcontrol,
223 struct snd_ctl_elem_value *ucontrol)
224{
225 mutex_lock(&voip_info.lock);
226
227 ucontrol->value.integer.value[0] = voip_info.dtx_mode;
228
229 mutex_unlock(&voip_info.lock);
230
231 return 0;
232}
233
Panneer Arumugambcac6862011-10-27 18:20:44 -0700234static struct snd_kcontrol_new msm_voip_controls[] = {
235 SOC_SINGLE_EXT("Voip Tx Mute", SND_SOC_NOPM, 0, 1, 0,
236 msm_voip_mute_get, msm_voip_mute_put),
237 SOC_SINGLE_EXT("Voip Rx Volume", SND_SOC_NOPM, 0, 5, 0,
238 msm_voip_volume_get, msm_voip_volume_put),
Helen Zengb9d00ce2011-10-13 17:25:50 -0700239 SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
240 0, 2, msm_voip_mode_rate_config_get,
241 msm_voip_mode_rate_config_put),
Helen Zengff97bec2012-02-20 14:30:50 -0800242 SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
243 msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
Panneer Arumugambcac6862011-10-27 18:20:44 -0700244};
245
246static int msm_pcm_voip_probe(struct snd_soc_platform *platform)
247{
248 snd_soc_add_platform_controls(platform, msm_voip_controls,
249 ARRAY_SIZE(msm_voip_controls));
250
251 return 0;
252}
253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254/* sample rate supported */
255static unsigned int supported_sample_rates[] = {8000, 16000};
256
257/* capture path */
258static void voip_process_ul_pkt(uint8_t *voc_pkt,
259 uint32_t pkt_len,
260 void *private_data)
261{
262 struct voip_buf_node *buf_node = NULL;
263 struct voip_drv_info *prtd = private_data;
264 unsigned long dsp_flags;
265
266 if (prtd->capture_substream == NULL)
267 return;
268
269 /* Copy up-link packet into out_queue. */
Helen Zeng6c7dc952012-06-04 17:44:28 -0700270 spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271
272 /* discarding UL packets till start is received */
273 if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
274 buf_node = list_first_entry(&prtd->free_out_queue,
275 struct voip_buf_node, list);
276 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700277 switch (prtd->mode) {
278 case MODE_AMR_WB:
279 case MODE_AMR: {
280 /* Remove the DSP frame info header. Header format:
281 * Bits 0-3: Frame rate
282 * Bits 4-7: Frame type
283 */
Laxminath Kasam481d4982012-04-04 20:54:30 +0530284 buf_node->frame.header.frame_type =
285 ((*voc_pkt) & 0xF0) >> 4;
Helen Zengb9d00ce2011-10-13 17:25:50 -0700286 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
287 buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
288 memcpy(&buf_node->frame.voc_pkt[0],
289 voc_pkt,
290 buf_node->frame.len);
291 list_add_tail(&buf_node->list, &prtd->out_queue);
292 break;
293 }
Laxminath Kasam481d4982012-04-04 20:54:30 +0530294 case MODE_IS127:
295 case MODE_4GV_NB:
296 case MODE_4GV_WB: {
297 /* Remove the DSP frame info header.
298 * Header format:
299 * Bits 0-3: frame rate
300 */
301 buf_node->frame.header.packet_rate = (*voc_pkt) & 0x0F;
302 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
303 buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
304
305 memcpy(&buf_node->frame.voc_pkt[0],
306 voc_pkt,
307 buf_node->frame.len);
308
309 list_add_tail(&buf_node->list, &prtd->out_queue);
310 break;
311 }
Helen Zengb9d00ce2011-10-13 17:25:50 -0700312 default: {
313 buf_node->frame.len = pkt_len;
314 memcpy(&buf_node->frame.voc_pkt[0],
315 voc_pkt,
316 buf_node->frame.len);
317 list_add_tail(&buf_node->list, &prtd->out_queue);
318 }
319 }
320 pr_debug("ul_pkt: pkt_len =%d, frame.len=%d\n", pkt_len,
321 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
Helen Zeng6c7dc952012-06-04 17:44:28 -0700323 spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 snd_pcm_period_elapsed(prtd->capture_substream);
325 } else {
Helen Zeng6c7dc952012-06-04 17:44:28 -0700326 spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 pr_err("UL data dropped\n");
328 }
329
330 wake_up(&prtd->out_wait);
331}
332
333/* playback path */
334static void voip_process_dl_pkt(uint8_t *voc_pkt,
335 uint32_t *pkt_len,
336 void *private_data)
337{
338 struct voip_buf_node *buf_node = NULL;
339 struct voip_drv_info *prtd = private_data;
340 unsigned long dsp_flags;
341
342
343 if (prtd->playback_substream == NULL)
344 return;
345
346 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
347
348 if (!list_empty(&prtd->in_queue) && prtd->playback_start) {
349 buf_node = list_first_entry(&prtd->in_queue,
350 struct voip_buf_node, list);
351 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700352 switch (prtd->mode) {
353 case MODE_AMR:
354 case MODE_AMR_WB: {
355 /* Add the DSP frame info header. Header format:
356 * Bits 0-3: Frame rate
357 * Bits 4-7: Frame type
358 */
Laxminath Kasam481d4982012-04-04 20:54:30 +0530359 *voc_pkt = ((buf_node->frame.header.frame_type &
360 0x0F) << 4) | (prtd->rate_type & 0x0F);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700361 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
362 *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
363 memcpy(voc_pkt,
364 &buf_node->frame.voc_pkt[0],
365 buf_node->frame.len);
366 list_add_tail(&buf_node->list, &prtd->free_in_queue);
367 break;
368 }
Laxminath Kasam481d4982012-04-04 20:54:30 +0530369 case MODE_IS127:
370 case MODE_4GV_NB:
371 case MODE_4GV_WB: {
372 /* Add the DSP frame info header. Header format:
373 * Bits 0-3 : Frame rate
374 */
375 *voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
376 voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
377 *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
378
379 memcpy(voc_pkt,
380 &buf_node->frame.voc_pkt[0],
381 buf_node->frame.len);
382
383 list_add_tail(&buf_node->list, &prtd->free_in_queue);
384 break;
385 }
Helen Zengb9d00ce2011-10-13 17:25:50 -0700386 default: {
387 *pkt_len = buf_node->frame.len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388
Helen Zengb9d00ce2011-10-13 17:25:50 -0700389 memcpy(voc_pkt,
390 &buf_node->frame.voc_pkt[0],
391 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392
Helen Zengb9d00ce2011-10-13 17:25:50 -0700393 list_add_tail(&buf_node->list, &prtd->free_in_queue);
394 }
395 }
396 pr_debug("dl_pkt: pkt_len=%d, frame_len=%d\n", *pkt_len,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 buf_node->frame.len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 prtd->pcm_playback_irq_pos += prtd->pcm_count;
399 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
400 snd_pcm_period_elapsed(prtd->playback_substream);
401 } else {
402 *pkt_len = 0;
403 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
404 pr_err("DL data not available\n");
405 }
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700406 wake_up(&prtd->in_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407}
408
409static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
410 .count = ARRAY_SIZE(supported_sample_rates),
411 .list = supported_sample_rates,
412 .mask = 0,
413};
414
415static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
416{
417 struct snd_pcm_runtime *runtime = substream->runtime;
418 struct voip_drv_info *prtd = runtime->private_data;
419
420 prtd->play_samp_rate = runtime->rate;
421 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
422 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
423 prtd->pcm_playback_irq_pos = 0;
424 prtd->pcm_playback_buf_pos = 0;
425
426 return 0;
427}
428
429static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
430{
431 struct snd_pcm_runtime *runtime = substream->runtime;
432 struct voip_drv_info *prtd = runtime->private_data;
433 int ret = 0;
434
435 prtd->cap_samp_rate = runtime->rate;
436 prtd->pcm_capture_size = snd_pcm_lib_buffer_bytes(substream);
437 prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
438 prtd->pcm_capture_irq_pos = 0;
439 prtd->pcm_capture_buf_pos = 0;
440 return ret;
441}
442
443static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
444{
445 int ret = 0;
446 struct snd_pcm_runtime *runtime = substream->runtime;
447 struct voip_drv_info *prtd = runtime->private_data;
448
449 switch (cmd) {
450 case SNDRV_PCM_TRIGGER_START:
451 case SNDRV_PCM_TRIGGER_RESUME:
452 pr_debug("%s: Trigger start\n", __func__);
453 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
454 prtd->capture_start = 1;
455 else
456 prtd->playback_start = 1;
457 break;
458 case SNDRV_PCM_TRIGGER_STOP:
459 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
460 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
461 prtd->playback_start = 0;
462 else
463 prtd->capture_start = 0;
464 break;
465 default:
466 ret = -EINVAL;
467 break;
468 }
469
470 return ret;
471}
472
473static int msm_pcm_open(struct snd_pcm_substream *substream)
474{
475 struct snd_pcm_runtime *runtime = substream->runtime;
476 struct voip_drv_info *prtd = &voip_info;
477 int ret = 0;
478
479 pr_debug("%s, VoIP\n", __func__);
480 mutex_lock(&prtd->lock);
481
482 runtime->hw = msm_pcm_hardware;
483
484 ret = snd_pcm_hw_constraint_list(runtime, 0,
485 SNDRV_PCM_HW_PARAM_RATE,
486 &constraints_sample_rates);
487 if (ret < 0)
488 pr_debug("snd_pcm_hw_constraint_list failed\n");
489
490 ret = snd_pcm_hw_constraint_integer(runtime,
491 SNDRV_PCM_HW_PARAM_PERIODS);
492 if (ret < 0) {
493 pr_debug("snd_pcm_hw_constraint_integer failed\n");
494 goto err;
495 }
496
497 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
498 prtd->playback_substream = substream;
499 prtd->playback_instance++;
500 } else {
501 prtd->capture_substream = substream;
502 prtd->capture_instance++;
503 }
504 runtime->private_data = prtd;
505err:
506 mutex_unlock(&prtd->lock);
507
508 return ret;
509}
510
511static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
512 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
513{
514 int ret = 0;
515 struct voip_buf_node *buf_node = NULL;
516 struct snd_pcm_runtime *runtime = substream->runtime;
517 struct voip_drv_info *prtd = runtime->private_data;
Helen Zeng6c7dc952012-06-04 17:44:28 -0700518 unsigned long dsp_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519
520 int count = frames_to_bytes(runtime, frames);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700521 pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700523 ret = wait_event_interruptible_timeout(prtd->in_wait,
524 (!list_empty(&prtd->free_in_queue) ||
525 prtd->state == VOIP_STOPPED),
526 1 * HZ);
527 if (ret > 0) {
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700528 if (count <= VOIP_MAX_VOC_PKT_SIZE) {
Helen Zeng6c7dc952012-06-04 17:44:28 -0700529 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 buf_node =
531 list_first_entry(&prtd->free_in_queue,
532 struct voip_buf_node, list);
533 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700534 if (prtd->mode == MODE_PCM) {
535 ret = copy_from_user(&buf_node->frame.voc_pkt,
536 buf, count);
537 buf_node->frame.len = count;
538 } else
539 ret = copy_from_user(&buf_node->frame,
540 buf, count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 list_add_tail(&buf_node->list, &prtd->in_queue);
Helen Zeng6c7dc952012-06-04 17:44:28 -0700542 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700543 } else {
544 pr_err("%s: Write cnt %d is > VOIP_MAX_VOC_PKT_SIZE\n",
545 __func__, count);
546 ret = -ENOMEM;
547 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700549 } else if (ret == 0) {
550 pr_err("%s: No free DL buffs\n", __func__);
551 ret = -ETIMEDOUT;
552 } else {
553 pr_err("%s: playback copy was interrupted\n", __func__);
554 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555
556 return ret;
557}
558static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
559 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
560 snd_pcm_uframes_t frames)
561{
562 int ret = 0;
563 int count = 0;
564 struct voip_buf_node *buf_node = NULL;
565 struct snd_pcm_runtime *runtime = substream->runtime;
566 struct voip_drv_info *prtd = runtime->private_data;
Helen Zeng6c7dc952012-06-04 17:44:28 -0700567 unsigned long dsp_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568
569 count = frames_to_bytes(runtime, frames);
570
571 pr_debug("%s: count = %d\n", __func__, count);
572
573 ret = wait_event_interruptible_timeout(prtd->out_wait,
574 (!list_empty(&prtd->out_queue) ||
575 prtd->state == VOIP_STOPPED),
576 1 * HZ);
577
578 if (ret > 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700580 if (count <= VOIP_MAX_VOC_PKT_SIZE) {
Helen Zeng6c7dc952012-06-04 17:44:28 -0700581 spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 buf_node = list_first_entry(&prtd->out_queue,
583 struct voip_buf_node, list);
584 list_del(&buf_node->list);
Helen Zengb9d00ce2011-10-13 17:25:50 -0700585 if (prtd->mode == MODE_PCM)
586 ret = copy_to_user(buf,
587 &buf_node->frame.voc_pkt,
588 count);
589 else
590 ret = copy_to_user(buf,
591 &buf_node->frame,
592 count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 if (ret) {
594 pr_err("%s: Copy to user retuned %d\n",
595 __func__, ret);
596 ret = -EFAULT;
597 }
598 list_add_tail(&buf_node->list,
599 &prtd->free_out_queue);
Helen Zeng6c7dc952012-06-04 17:44:28 -0700600 spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602 } else {
Panneer Arumugam418aa0a2011-10-11 18:44:16 -0700603 pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
604 __func__, count);
605 ret = -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 }
607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608
609 } else if (ret == 0) {
610 pr_err("%s: No UL data available\n", __func__);
611 ret = -ETIMEDOUT;
612 } else {
613 pr_err("%s: Read was interrupted\n", __func__);
614 ret = -ERESTARTSYS;
615 }
616 return ret;
617}
618static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
619 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
620{
621 int ret = 0;
622
623 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
624 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
625 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
626 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
627
628 return ret;
629}
630
631static int msm_pcm_close(struct snd_pcm_substream *substream)
632{
633 int ret = 0;
634 struct list_head *ptr = NULL;
635 struct list_head *next = NULL;
636 struct voip_buf_node *buf_node = NULL;
637 struct snd_dma_buffer *p_dma_buf, *c_dma_buf;
638 struct snd_pcm_substream *p_substream, *c_substream;
639 struct snd_pcm_runtime *runtime;
640 struct voip_drv_info *prtd;
Helen Zeng6c7dc952012-06-04 17:44:28 -0700641 unsigned long dsp_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642
643 if (substream == NULL) {
644 pr_err("substream is NULL\n");
645 return -EINVAL;
646 }
647 runtime = substream->runtime;
648 prtd = runtime->private_data;
649
650 wake_up(&prtd->out_wait);
651
652 mutex_lock(&prtd->lock);
653
654 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
655 prtd->playback_instance--;
656 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
657 prtd->capture_instance--;
658
659 if (!prtd->playback_instance && !prtd->capture_instance) {
660 if (prtd->state == VOIP_STARTED) {
661 prtd->state = VOIP_STOPPED;
Neema Shetty2c07eb52011-08-21 20:33:52 -0700662 voc_end_voice_call(
663 voc_get_session_id(VOIP_SESSION_NAME));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 voc_register_mvs_cb(NULL, NULL, prtd);
665 }
666 /* release all buffer */
667 /* release in_queue and free_in_queue */
668 pr_debug("release all buffer\n");
669 p_substream = prtd->playback_substream;
670 if (p_substream == NULL) {
671 pr_debug("p_substream is NULL\n");
672 goto capt;
673 }
674 p_dma_buf = &p_substream->dma_buffer;
675 if (p_dma_buf == NULL) {
676 pr_debug("p_dma_buf is NULL\n");
677 goto capt;
678 }
679 if (p_dma_buf->area != NULL) {
Helen Zeng6c7dc952012-06-04 17:44:28 -0700680 spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 list_for_each_safe(ptr, next, &prtd->in_queue) {
682 buf_node = list_entry(ptr,
683 struct voip_buf_node, list);
684 list_del(&buf_node->list);
685 }
686 list_for_each_safe(ptr, next, &prtd->free_in_queue) {
687 buf_node = list_entry(ptr,
688 struct voip_buf_node, list);
689 list_del(&buf_node->list);
690 }
Helen Zeng6c7dc952012-06-04 17:44:28 -0700691 spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 dma_free_coherent(p_substream->pcm->card->dev,
693 runtime->hw.buffer_bytes_max, p_dma_buf->area,
694 p_dma_buf->addr);
695 p_dma_buf->area = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 }
697 /* release out_queue and free_out_queue */
698capt: c_substream = prtd->capture_substream;
699 if (c_substream == NULL) {
700 pr_debug("c_substream is NULL\n");
701 goto done;
702 }
703 c_dma_buf = &c_substream->dma_buffer;
704 if (c_substream == NULL) {
705 pr_debug("c_dma_buf is NULL.\n");
706 goto done;
707 }
708 if (c_dma_buf->area != NULL) {
Helen Zeng6c7dc952012-06-04 17:44:28 -0700709 spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 list_for_each_safe(ptr, next, &prtd->out_queue) {
711 buf_node = list_entry(ptr,
712 struct voip_buf_node, list);
713 list_del(&buf_node->list);
714 }
715 list_for_each_safe(ptr, next, &prtd->free_out_queue) {
716 buf_node = list_entry(ptr,
717 struct voip_buf_node, list);
718 list_del(&buf_node->list);
719 }
Helen Zeng6c7dc952012-06-04 17:44:28 -0700720 spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 dma_free_coherent(c_substream->pcm->card->dev,
722 runtime->hw.buffer_bytes_max, c_dma_buf->area,
723 c_dma_buf->addr);
724 c_dma_buf->area = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 }
726done:
727 prtd->capture_substream = NULL;
728 prtd->playback_substream = NULL;
729 }
730 mutex_unlock(&prtd->lock);
731
732 return ret;
733}
734static int msm_pcm_prepare(struct snd_pcm_substream *substream)
735{
736 int ret = 0;
737 struct snd_pcm_runtime *runtime = substream->runtime;
738 struct voip_drv_info *prtd = runtime->private_data;
Mingming Yinc09967e2012-04-27 15:09:43 -0700739 uint32_t media_type = 0;
Helen Zengb9d00ce2011-10-13 17:25:50 -0700740 uint32_t rate_type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741
742 mutex_lock(&prtd->lock);
743
744 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
745 ret = msm_pcm_playback_prepare(substream);
746 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
747 ret = msm_pcm_capture_prepare(substream);
748
Helen Zengb9d00ce2011-10-13 17:25:50 -0700749 if ((runtime->format != FORMAT_SPECIAL) &&
Laxminath Kasam481d4982012-04-04 20:54:30 +0530750 ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
751 (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
752 (prtd->mode == MODE_4GV_WB))) {
Helen Zengb9d00ce2011-10-13 17:25:50 -0700753 pr_err("mode:%d and format:%u are not mached\n",
754 prtd->mode, (uint32_t)runtime->format);
755 ret = -EINVAL;
756 goto done;
757 }
758
759 if ((runtime->format != FORMAT_S16_LE) &&
760 (prtd->mode == MODE_PCM)) {
761 pr_err("mode:%d and format:%u are not mached\n",
762 prtd->mode, (uint32_t)runtime->format);
763 ret = -EINVAL;
764 goto done;
765 }
766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 if (prtd->playback_instance && prtd->capture_instance
768 && (prtd->state != VOIP_STARTED)) {
769
Helen Zengb9d00ce2011-10-13 17:25:50 -0700770 ret = voip_get_rate_type(prtd->mode,
771 prtd->rate,
772 &rate_type);
773 if (ret < 0) {
774 pr_err("fail at getting rate_type\n");
775 ret = -EINVAL;
776 goto done;
777 }
778 prtd->rate_type = rate_type;
779 media_type = voip_get_media_type(prtd->mode,
780 prtd->play_samp_rate);
781 if (media_type < 0) {
782 pr_err("fail at getting media_type\n");
783 ret = -EINVAL;
784 goto done;
785 }
786 pr_debug(" media_type=%d, rate_type=%d\n", media_type,
787 rate_type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 if ((prtd->play_samp_rate == 8000) &&
789 (prtd->cap_samp_rate == 8000))
Helen Zengb9d00ce2011-10-13 17:25:50 -0700790 voc_config_vocoder(media_type, rate_type,
Helen Zengff97bec2012-02-20 14:30:50 -0800791 VSS_NETWORK_ID_VOIP_NB,
792 voip_info.dtx_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 else if ((prtd->play_samp_rate == 16000) &&
794 (prtd->cap_samp_rate == 16000))
Helen Zengb9d00ce2011-10-13 17:25:50 -0700795 voc_config_vocoder(media_type, rate_type,
Helen Zengff97bec2012-02-20 14:30:50 -0800796 VSS_NETWORK_ID_VOIP_WB,
797 voip_info.dtx_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798 else {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700799 pr_debug("%s: Invalid rate playback %d, capture %d\n",
800 __func__, prtd->play_samp_rate,
801 prtd->cap_samp_rate);
802 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 }
804 voc_register_mvs_cb(voip_process_ul_pkt,
805 voip_process_dl_pkt, prtd);
Neema Shetty2c07eb52011-08-21 20:33:52 -0700806 voc_start_voice_call(voc_get_session_id(VOIP_SESSION_NAME));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807
808 prtd->state = VOIP_STARTED;
809 }
Neema Shetty2c07eb52011-08-21 20:33:52 -0700810done:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811 mutex_unlock(&prtd->lock);
812
813 return ret;
814}
815
816static snd_pcm_uframes_t
817msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
818{
819 struct snd_pcm_runtime *runtime = substream->runtime;
820 struct voip_drv_info *prtd = runtime->private_data;
821
822 pr_debug("%s\n", __func__);
823 if (prtd->pcm_playback_irq_pos >= prtd->pcm_size)
824 prtd->pcm_playback_irq_pos = 0;
825 return bytes_to_frames(runtime, (prtd->pcm_playback_irq_pos));
826}
827
828static snd_pcm_uframes_t
829msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
830{
831 struct snd_pcm_runtime *runtime = substream->runtime;
832 struct voip_drv_info *prtd = runtime->private_data;
833
834 if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
835 prtd->pcm_capture_irq_pos = 0;
836 return bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
837}
838
839static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
840{
841 snd_pcm_uframes_t ret = 0;
842 pr_debug("%s\n", __func__);
843 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
844 ret = msm_pcm_playback_pointer(substream);
845 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
846 ret = msm_pcm_capture_pointer(substream);
847 return ret;
848}
849
850static int msm_pcm_mmap(struct snd_pcm_substream *substream,
851 struct vm_area_struct *vma)
852{
853 struct snd_pcm_runtime *runtime = substream->runtime;
854
855 pr_debug("%s\n", __func__);
856 dma_mmap_coherent(substream->pcm->card->dev, vma,
857 runtime->dma_area,
858 runtime->dma_addr,
859 runtime->dma_bytes);
860 return 0;
861}
862
863static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
864 struct snd_pcm_hw_params *params)
865{
866 struct snd_pcm_runtime *runtime = substream->runtime;
867 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
868 struct voip_buf_node *buf_node = NULL;
869 int i = 0, offset = 0;
870
871 pr_debug("%s: voip\n", __func__);
872
873 mutex_lock(&voip_info.lock);
874
875 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
876 dma_buf->dev.dev = substream->pcm->card->dev;
877 dma_buf->private_data = NULL;
878
879 dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
880 runtime->hw.buffer_bytes_max,
881 &dma_buf->addr, GFP_KERNEL);
882 if (!dma_buf->area) {
883 pr_err("%s:MSM VOIP dma_alloc failed\n", __func__);
884 return -ENOMEM;
885 }
886
887 dma_buf->bytes = runtime->hw.buffer_bytes_max;
888 memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
889
890 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
891 for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
892 buf_node = (void *)dma_buf->area + offset;
893
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 list_add_tail(&buf_node->list,
895 &voip_info.free_in_queue);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896 offset = offset + sizeof(struct voip_buf_node);
897 }
898 } else {
899 for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
900 buf_node = (void *) dma_buf->area + offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 list_add_tail(&buf_node->list,
902 &voip_info.free_out_queue);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 offset = offset + sizeof(struct voip_buf_node);
904 }
905 }
906
907 mutex_unlock(&voip_info.lock);
908
909 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
910
911 return 0;
912}
913
Helen Zengb9d00ce2011-10-13 17:25:50 -0700914static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
915 struct snd_ctl_elem_value *ucontrol)
916{
917 mutex_lock(&voip_info.lock);
918
919 ucontrol->value.integer.value[0] = voip_info.mode;
920 ucontrol->value.integer.value[1] = voip_info.rate;
921
922 mutex_unlock(&voip_info.lock);
923
924 return 0;
925}
926
927static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
928 struct snd_ctl_elem_value *ucontrol)
929{
930 mutex_lock(&voip_info.lock);
931
932 voip_info.mode = ucontrol->value.integer.value[0];
933 voip_info.rate = ucontrol->value.integer.value[1];
934
935 pr_debug("%s: mode=%d,rate=%d\n", __func__, voip_info.mode,
936 voip_info.rate);
937
938 mutex_unlock(&voip_info.lock);
939
940 return 0;
941}
942
943static int voip_get_rate_type(uint32_t mode, uint32_t rate,
944 uint32_t *rate_type)
945{
946 int ret = 0;
947
948 switch (mode) {
949 case MODE_AMR: {
950 switch (rate) {
951 case 4750:
952 *rate_type = AMR_RATE_4750;
953 break;
954 case 5150:
955 *rate_type = AMR_RATE_5150;
956 break;
957 case 5900:
958 *rate_type = AMR_RATE_5900;
959 break;
960 case 6700:
961 *rate_type = AMR_RATE_6700;
962 break;
963 case 7400:
964 *rate_type = AMR_RATE_7400;
965 break;
966 case 7950:
967 *rate_type = AMR_RATE_7950;
968 break;
969 case 10200:
970 *rate_type = AMR_RATE_10200;
971 break;
972 case 12200:
973 *rate_type = AMR_RATE_12200;
974 break;
975 default:
976 pr_err("wrong rate for AMR NB.\n");
977 ret = -EINVAL;
978 break;
979 }
980 break;
981 }
982 case MODE_AMR_WB: {
983 switch (rate) {
984 case 6600:
985 *rate_type = AMR_RATE_6600 - AMR_RATE_6600;
986 break;
987 case 8850:
988 *rate_type = AMR_RATE_8850 - AMR_RATE_6600;
989 break;
990 case 12650:
991 *rate_type = AMR_RATE_12650 - AMR_RATE_6600;
992 break;
993 case 14250:
994 *rate_type = AMR_RATE_14250 - AMR_RATE_6600;
995 break;
996 case 15850:
997 *rate_type = AMR_RATE_15850 - AMR_RATE_6600;
998 break;
999 case 18250:
1000 *rate_type = AMR_RATE_18250 - AMR_RATE_6600;
1001 break;
1002 case 19850:
1003 *rate_type = AMR_RATE_19850 - AMR_RATE_6600;
1004 break;
1005 case 23050:
1006 *rate_type = AMR_RATE_23050 - AMR_RATE_6600;
1007 break;
1008 case 23850:
1009 *rate_type = AMR_RATE_23850 - AMR_RATE_6600;
1010 break;
1011 default:
1012 pr_err("wrong rate for AMR_WB.\n");
1013 ret = -EINVAL;
1014 break;
1015 }
1016 break;
1017 }
1018 case MODE_PCM: {
1019 *rate_type = 0;
1020 break;
1021 }
Laxminath Kasam481d4982012-04-04 20:54:30 +05301022 case MODE_IS127:
1023 case MODE_4GV_NB:
1024 case MODE_4GV_WB: {
1025 switch (rate) {
1026 case VOC_0_RATE:
1027 case VOC_8_RATE:
1028 case VOC_4_RATE:
1029 case VOC_2_RATE:
1030 case VOC_1_RATE:
1031 *rate_type = rate;
1032 break;
1033 default:
1034 pr_err("wrong rate for IS127/4GV_NB/WB.\n");
1035 ret = -EINVAL;
1036 break;
1037 }
1038 break;
1039 }
Helen Zengb9d00ce2011-10-13 17:25:50 -07001040 default:
1041 pr_err("wrong mode type.\n");
1042 ret = -EINVAL;
1043 }
1044 pr_debug("%s, mode=%d, rate=%u, rate_type=%d\n",
1045 __func__, mode, rate, *rate_type);
1046 return ret;
1047}
1048
1049static int voip_get_media_type(uint32_t mode,
1050 unsigned int samp_rate)
1051{
Mingming Yinc09967e2012-04-27 15:09:43 -07001052 uint32_t media_type;
Helen Zengb9d00ce2011-10-13 17:25:50 -07001053
1054 pr_debug("%s: mode=%d, samp_rate=%d\n", __func__,
1055 mode, samp_rate);
1056 switch (mode) {
1057 case MODE_AMR:
1058 media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
1059 break;
1060 case MODE_AMR_WB:
1061 media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
1062 break;
1063 case MODE_PCM:
1064 if (samp_rate == 8000)
1065 media_type = VSS_MEDIA_ID_PCM_NB;
1066 else
1067 media_type = VSS_MEDIA_ID_PCM_WB;
1068 break;
Laxminath Kasam481d4982012-04-04 20:54:30 +05301069 case MODE_IS127: /* EVRC-A */
1070 media_type = VSS_MEDIA_ID_EVRC_MODEM;
1071 break;
1072 case MODE_4GV_NB: /* EVRC-B */
1073 media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
1074 break;
1075 case MODE_4GV_WB: /* EVRC-WB */
1076 media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
1077 break;
Helen Zengb9d00ce2011-10-13 17:25:50 -07001078 default:
1079 pr_debug(" input mode is not supported\n");
1080 media_type = -EINVAL;
1081 }
1082
1083 pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
1084
1085 return media_type;
1086}
1087
1088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089static struct snd_pcm_ops msm_pcm_ops = {
1090 .open = msm_pcm_open,
1091 .copy = msm_pcm_copy,
1092 .hw_params = msm_pcm_hw_params,
1093 .close = msm_pcm_close,
1094 .prepare = msm_pcm_prepare,
1095 .trigger = msm_pcm_trigger,
1096 .pointer = msm_pcm_pointer,
1097 .mmap = msm_pcm_mmap,
1098};
1099
1100static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
1101{
1102 struct snd_card *card = rtd->card->snd_card;
1103 int ret = 0;
1104
1105 pr_debug("msm_asoc_pcm_new\n");
1106 if (!card->dev->coherent_dma_mask)
1107 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1108 return ret;
1109}
1110
1111static struct snd_soc_platform_driver msm_soc_platform = {
1112 .ops = &msm_pcm_ops,
1113 .pcm_new = msm_asoc_pcm_new,
Panneer Arumugambcac6862011-10-27 18:20:44 -07001114 .probe = msm_pcm_voip_probe,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115};
1116
1117static __devinit int msm_pcm_probe(struct platform_device *pdev)
1118{
1119 pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
1120 return snd_soc_register_platform(&pdev->dev,
1121 &msm_soc_platform);
1122}
1123
1124static int msm_pcm_remove(struct platform_device *pdev)
1125{
1126 snd_soc_unregister_platform(&pdev->dev);
1127 return 0;
1128}
1129
1130static struct platform_driver msm_pcm_driver = {
1131 .driver = {
1132 .name = "msm-voip-dsp",
1133 .owner = THIS_MODULE,
1134 },
1135 .probe = msm_pcm_probe,
1136 .remove = __devexit_p(msm_pcm_remove),
1137};
1138
1139static int __init msm_soc_platform_init(void)
1140{
1141 memset(&voip_info, 0, sizeof(voip_info));
Helen Zengb9d00ce2011-10-13 17:25:50 -07001142 voip_info.mode = MODE_PCM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 mutex_init(&voip_info.lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144
1145 spin_lock_init(&voip_info.dsp_lock);
Helen Zeng6c7dc952012-06-04 17:44:28 -07001146 spin_lock_init(&voip_info.dsp_ul_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147
1148 init_waitqueue_head(&voip_info.out_wait);
Panneer Arumugam418aa0a2011-10-11 18:44:16 -07001149 init_waitqueue_head(&voip_info.in_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150
1151 INIT_LIST_HEAD(&voip_info.in_queue);
1152 INIT_LIST_HEAD(&voip_info.free_in_queue);
1153 INIT_LIST_HEAD(&voip_info.out_queue);
1154 INIT_LIST_HEAD(&voip_info.free_out_queue);
1155
1156 return platform_driver_register(&msm_pcm_driver);
1157}
1158module_init(msm_soc_platform_init);
1159
1160static void __exit msm_soc_platform_exit(void)
1161{
1162 platform_driver_unregister(&msm_pcm_driver);
1163}
1164module_exit(msm_soc_platform_exit);
1165
1166MODULE_DESCRIPTION("PCM module platform driver");
1167MODULE_LICENSE("GPL v2");