blob: 226146683db5c7a38d8a807c5aaaa76c25b29ac5 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
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/module.h>
14#include <linux/fs.h>
15#include <linux/miscdevice.h>
16#include <linux/msm_audio.h>
17#include <linux/slab.h>
18#include <linux/wait.h>
19#include <linux/sched.h>
20#include <asm/uaccess.h>
21#include <asm/atomic.h>
22#include <mach/qdsp6v2/audio_dev_ctl.h>
23#include <mach/debug_mm.h>
24#include <mach/qdsp6v2/q6voice.h>
25#include <mach/qdsp6v2/rtac.h>
26#include <sound/apr_audio.h>
27#include <sound/q6adm.h>
28
29#ifndef MAX
30#define MAX(x, y) (((x) > (y)) ? (x) : (y))
31#endif
32
33
34static DEFINE_MUTEX(session_lock);
35
36struct audio_dev_ctrl_state {
37 struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
38 u32 num_dev;
39 atomic_t opened;
40 struct msm_snddev_info *voice_rx_dev;
41 struct msm_snddev_info *voice_tx_dev;
42 wait_queue_head_t wait;
43};
44
45static struct audio_dev_ctrl_state audio_dev_ctrl;
46struct event_listner event;
47
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048#define MAX_COPP_DEVICES 4
49
50struct session_freq {
51 int freq;
52 int evt;
53};
54
55struct audio_routing_info {
56 unsigned short mixer_mask[MAX_SESSIONS];
57 unsigned short audrec_mixer_mask[MAX_SESSIONS];
58 struct session_freq dec_freq[MAX_SESSIONS];
59 struct session_freq enc_freq[MAX_SESSIONS];
60 unsigned int copp_list[MAX_SESSIONS][AFE_MAX_PORTS];
61 int voice_tx_dev_id;
62 int voice_rx_dev_id;
63 int voice_tx_sample_rate;
64 int voice_rx_sample_rate;
65 signed int voice_tx_vol;
66 signed int voice_rx_vol;
67 int tx_mute;
68 int rx_mute;
69 int voice_state;
70 struct mutex copp_list_mutex;
71 struct mutex adm_mutex;
72};
73
74static struct audio_routing_info routing_info;
75
76struct audio_copp_topology {
77 struct mutex lock;
78 int session_cnt;
79 int session_id[MAX_SESSIONS];
80 int topolog_id[MAX_SESSIONS];
81};
82static struct audio_copp_topology adm_tx_topology_tbl;
83
84int msm_reset_all_device(void)
85{
86 int rc = 0;
87 int dev_id = 0;
88 struct msm_snddev_info *dev_info = NULL;
89
90 for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
91 dev_info = audio_dev_ctrl_find_dev(dev_id);
92 if (IS_ERR(dev_info)) {
93 pr_err("%s:pass invalid dev_id\n", __func__);
94 rc = PTR_ERR(dev_info);
95 return rc;
96 }
97 if (!dev_info->opened)
98 continue;
99 pr_debug("%s:Resetting device %d active on COPP %d"
100 "with %lld as routing\n", __func__,
101 dev_id, dev_info->copp_id, dev_info->sessions);
102 broadcast_event(AUDDEV_EVT_REL_PENDING,
103 dev_id,
104 SESSION_IGNORE);
105 rc = dev_info->dev_ops.close(dev_info);
106 if (rc < 0) {
107 pr_err("%s:Snd device failed close!\n", __func__);
108 return rc;
109 } else {
110 dev_info->opened = 0;
111 broadcast_event(AUDDEV_EVT_DEV_RLS,
112 dev_id,
113 SESSION_IGNORE);
114
115 if (dev_info->copp_id == VOICE_PLAYBACK_TX)
116 voice_start_playback(0);
117 }
118 dev_info->sessions = 0;
119 }
120 msm_clear_all_session();
121 return 0;
122}
123EXPORT_SYMBOL(msm_reset_all_device);
124
125int msm_set_copp_id(int session_id, int copp_id)
126{
127 int rc = 0;
128 int index;
129
130 if (session_id < 1 || session_id > 8)
131 return -EINVAL;
132 if (afe_validate_port(copp_id) < 0)
133 return -EINVAL;
134
135 index = afe_get_port_index(copp_id);
136 if (index < 0 || index > AFE_MAX_PORTS)
137 return -EINVAL;
138 pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
139 session_id, copp_id, index);
140 mutex_lock(&routing_info.copp_list_mutex);
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700141 if (routing_info.copp_list[session_id][index] == COPP_IGNORE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 routing_info.copp_list[session_id][index] = copp_id;
143 mutex_unlock(&routing_info.copp_list_mutex);
144
145 return rc;
146}
147EXPORT_SYMBOL(msm_set_copp_id);
148
149int msm_clear_copp_id(int session_id, int copp_id)
150{
151 int rc = 0;
152 int index = afe_get_port_index(copp_id);
153
154 if (session_id < 1 || session_id > 8)
155 return -EINVAL;
156 pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
157 session_id, copp_id, index);
158 mutex_lock(&routing_info.copp_list_mutex);
159 if (routing_info.copp_list[session_id][index] == copp_id)
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700160 routing_info.copp_list[session_id][index] = COPP_IGNORE;
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700161#ifdef CONFIG_MSM8X60_RTAC
162 rtac_remove_adm_device(copp_id, session_id);
163#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164 mutex_unlock(&routing_info.copp_list_mutex);
165
166 return rc;
167}
168EXPORT_SYMBOL(msm_clear_copp_id);
169
170int msm_clear_session_id(int session_id)
171{
172 int rc = 0;
173 int i = 0;
174 if (session_id < 1 || session_id > 8)
175 return -EINVAL;
176 pr_debug("%s: session[%d]\n", __func__, session_id);
177 mutex_lock(&routing_info.adm_mutex);
178 mutex_lock(&routing_info.copp_list_mutex);
179 for (i = 0; i < AFE_MAX_PORTS; i++) {
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700180 if (routing_info.copp_list[session_id][i] != COPP_IGNORE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181 rc = adm_close(routing_info.copp_list[session_id][i]);
182 if (rc < 0) {
183 pr_err("%s: adm close fail port[%d] rc[%d]\n",
184 __func__,
185 routing_info.copp_list[session_id][i],
186 rc);
187 continue;
188 }
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700189#ifdef CONFIG_MSM8X60_RTAC
190 rtac_remove_adm_device(
191 routing_info.copp_list[session_id][i], session_id);
192#endif
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700193 routing_info.copp_list[session_id][i] = COPP_IGNORE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 rc = 0;
195 }
196 }
197 mutex_unlock(&routing_info.copp_list_mutex);
198 mutex_unlock(&routing_info.adm_mutex);
199
200 return rc;
201}
202EXPORT_SYMBOL(msm_clear_session_id);
203
204int msm_clear_all_session()
205{
206 int rc = 0;
207 int i = 0, j = 0;
208 pr_info("%s:\n", __func__);
209 mutex_lock(&routing_info.adm_mutex);
210 mutex_lock(&routing_info.copp_list_mutex);
211 for (j = 1; j < MAX_SESSIONS; j++) {
212 for (i = 0; i < AFE_MAX_PORTS; i++) {
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700213 if (routing_info.copp_list[j][i] != COPP_IGNORE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214 rc = adm_close(
215 routing_info.copp_list[j][i]);
216 if (rc < 0) {
217 pr_err("%s: adm close fail copp[%d]"
218 "session[%d] rc[%d]\n",
219 __func__,
220 routing_info.copp_list[j][i],
221 j, rc);
222 continue;
223 }
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700224 routing_info.copp_list[j][i] = COPP_IGNORE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 rc = 0;
226 }
227 }
228 }
229 mutex_unlock(&routing_info.copp_list_mutex);
230 mutex_unlock(&routing_info.adm_mutex);
231 return rc;
232}
233EXPORT_SYMBOL(msm_clear_all_session);
234
235int msm_get_voice_state(void)
236{
237 pr_debug("voice state %d\n", routing_info.voice_state);
238 return routing_info.voice_state;
239}
240EXPORT_SYMBOL(msm_get_voice_state);
241
242int msm_set_voice_mute(int dir, int mute)
243{
244 pr_debug("dir %x mute %x\n", dir, mute);
245 if (dir == DIR_TX) {
246 routing_info.tx_mute = mute;
247 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
248 routing_info.voice_tx_dev_id, SESSION_IGNORE);
249 } else
250 return -EPERM;
251 return 0;
252}
253EXPORT_SYMBOL(msm_set_voice_mute);
254
255int msm_set_voice_vol(int dir, s32 volume)
256{
257 if (dir == DIR_TX) {
258 routing_info.voice_tx_vol = volume;
259 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
260 routing_info.voice_tx_dev_id,
261 SESSION_IGNORE);
262 } else if (dir == DIR_RX) {
263 routing_info.voice_rx_vol = volume;
264 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
265 routing_info.voice_rx_dev_id,
266 SESSION_IGNORE);
267 } else
268 return -EINVAL;
269 return 0;
270}
271EXPORT_SYMBOL(msm_set_voice_vol);
272
273void msm_snddev_register(struct msm_snddev_info *dev_info)
274{
275 mutex_lock(&session_lock);
276 if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
277 audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
278 /* roughly 0 DB for digital gain
279 * If default gain is not desirable, it is expected that
280 * application sets desired gain before activating sound
281 * device
282 */
283 dev_info->dev_volume = 75;
284 dev_info->sessions = 0x0;
285 dev_info->usage_count = 0;
286 audio_dev_ctrl.num_dev++;
287 } else
288 pr_err("%s: device registry max out\n", __func__);
289 mutex_unlock(&session_lock);
290}
291EXPORT_SYMBOL(msm_snddev_register);
292
293int msm_snddev_devcount(void)
294{
295 return audio_dev_ctrl.num_dev;
296}
297EXPORT_SYMBOL(msm_snddev_devcount);
298
299int msm_snddev_query(int dev_id)
300{
301 if (dev_id <= audio_dev_ctrl.num_dev)
302 return 0;
303 return -ENODEV;
304}
305EXPORT_SYMBOL(msm_snddev_query);
306
307int msm_snddev_is_set(int popp_id, int copp_id)
308{
309 return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
310}
311EXPORT_SYMBOL(msm_snddev_is_set);
312
313unsigned short msm_snddev_route_enc(int enc_id)
314{
315 if (enc_id >= MAX_SESSIONS)
316 return -EINVAL;
317 return routing_info.audrec_mixer_mask[enc_id];
318}
319EXPORT_SYMBOL(msm_snddev_route_enc);
320
321unsigned short msm_snddev_route_dec(int popp_id)
322{
323 if (popp_id >= MAX_SESSIONS)
324 return -EINVAL;
325 return routing_info.mixer_mask[popp_id];
326}
327EXPORT_SYMBOL(msm_snddev_route_dec);
328
329/*To check one->many case*/
330int msm_check_multicopp_per_stream(int session_id,
331 struct route_payload *payload)
332{
333 int i = 0;
334 int flag = 0;
335 pr_debug("%s: session_id=%d\n", __func__, session_id);
336 mutex_lock(&routing_info.copp_list_mutex);
337 for (i = 0; i < AFE_MAX_PORTS; i++) {
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700338 if (routing_info.copp_list[session_id][i] == COPP_IGNORE)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339 continue;
340 else {
341 pr_debug("Device enabled\n");
342 payload->copp_ids[flag++] =
343 routing_info.copp_list[session_id][i];
344 }
345 }
346 mutex_unlock(&routing_info.copp_list_mutex);
347 if (flag > 1) {
348 pr_debug("Multiple copp per stream case num_copps=%d\n", flag);
349 } else {
350 pr_debug("Stream routed to single copp\n");
351 }
352 payload->num_copps = flag;
353 return flag;
354}
355
356int msm_snddev_set_dec(int popp_id, int copp_id, int set,
357 int rate, int mode)
358{
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700359 int rc = 0, i = 0, num_copps;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 struct route_payload payload;
361
362 if ((popp_id >= MAX_SESSIONS) || (popp_id <= 0)) {
363 pr_err("%s: Invalid session id %d\n", __func__, popp_id);
364 return 0;
365 }
366
367 mutex_lock(&routing_info.adm_mutex);
368 if (set) {
369 rc = adm_open(copp_id, PLAYBACK, rate, mode,
370 DEFAULT_COPP_TOPOLOGY);
371 if (rc < 0) {
372 pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
373 rc = -EINVAL;
374 mutex_unlock(&routing_info.adm_mutex);
375 return rc;
376 }
377 msm_set_copp_id(popp_id, copp_id);
378 pr_debug("%s:Session id=%d copp_id=%d\n",
379 __func__, popp_id, copp_id);
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -0700380 memset(payload.copp_ids, COPP_IGNORE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 (sizeof(unsigned int) * AFE_MAX_PORTS));
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700382 num_copps = msm_check_multicopp_per_stream(popp_id, &payload);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 /* Multiple streams per copp is handled, one stream at a time */
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700384 rc = adm_matrix_map(popp_id, PLAYBACK, num_copps,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 payload.copp_ids, copp_id);
386 if (rc < 0) {
387 pr_err("%s: matrix map failed rc[%d]\n",
388 __func__, rc);
389 adm_close(copp_id);
390 rc = -EINVAL;
391 mutex_unlock(&routing_info.adm_mutex);
392 return rc;
393 }
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700394#ifdef CONFIG_MSM8X60_RTAC
395 for (i = 0; i < num_copps; i++)
396 rtac_add_adm_device(payload.copp_ids[i], popp_id);
397#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 } else {
399 for (i = 0; i < AFE_MAX_PORTS; i++) {
400 if (routing_info.copp_list[popp_id][i] == copp_id) {
401 rc = adm_close(copp_id);
402 if (rc < 0) {
403 pr_err("%s: adm close fail copp[%d]"
404 "rc[%d]\n",
405 __func__, copp_id, rc);
406 rc = -EINVAL;
407 mutex_unlock(&routing_info.adm_mutex);
408 return rc;
409 }
410 msm_clear_copp_id(popp_id, copp_id);
411 break;
412 }
413 }
414 }
415
416 if (copp_id == VOICE_PLAYBACK_TX) {
417 /* Signal uplink playback. */
418 rc = voice_start_playback(set);
419 }
420 mutex_unlock(&routing_info.adm_mutex);
421 return rc;
422}
423EXPORT_SYMBOL(msm_snddev_set_dec);
424
425
426static int check_tx_copp_topology(int session_id)
427{
428 int cnt;
429 int ret_val = -ENOENT;
430
431 cnt = adm_tx_topology_tbl.session_cnt;
432 if (cnt) {
433 do {
434 if (adm_tx_topology_tbl.session_id[cnt-1]
435 == session_id)
436 ret_val = cnt-1;
437 } while (--cnt);
438 }
439
440 return ret_val;
441}
442
443static int add_to_tx_topology_lists(int session_id, int topology)
444{
445 int idx = 0, tbl_idx;
446 int ret_val = -ENOSPC;
447
448 mutex_lock(&adm_tx_topology_tbl.lock);
449
450 tbl_idx = check_tx_copp_topology(session_id);
451 if (tbl_idx == -ENOENT) {
452 while (adm_tx_topology_tbl.session_id[idx++])
453 ;
454 tbl_idx = idx-1;
455 }
456
457 if (tbl_idx < MAX_SESSIONS) {
458 adm_tx_topology_tbl.session_id[tbl_idx] = session_id;
459 adm_tx_topology_tbl.topolog_id[tbl_idx] = topology;
460 adm_tx_topology_tbl.session_cnt++;
461
462 ret_val = 0;
463 }
464 mutex_unlock(&adm_tx_topology_tbl.lock);
465 return ret_val;
466}
467
468static void remove_from_tx_topology_lists(int session_id)
469{
470 int tbl_idx;
471
472 mutex_lock(&adm_tx_topology_tbl.lock);
473 tbl_idx = check_tx_copp_topology(session_id);
474 if (tbl_idx != -ENOENT) {
475
476 adm_tx_topology_tbl.session_cnt--;
477 adm_tx_topology_tbl.session_id[tbl_idx] = 0;
478 adm_tx_topology_tbl.topolog_id[tbl_idx] = 0;
479 }
480 mutex_unlock(&adm_tx_topology_tbl.lock);
481}
482
483int auddev_cfg_tx_copp_topology(int session_id, int cfg)
484{
485 int ret = 0;
486
487 if (cfg == DEFAULT_COPP_TOPOLOGY)
488 remove_from_tx_topology_lists(session_id);
489 else {
490 switch (cfg) {
491 case VPM_TX_SM_ECNS_COPP_TOPOLOGY:
492 case VPM_TX_DM_FLUENCE_COPP_TOPOLOGY:
493 ret = add_to_tx_topology_lists(session_id, cfg);
494 break;
495
496 default:
497 ret = -ENODEV;
498 break;
499 }
500 }
501 return ret;
502}
503
504int msm_snddev_set_enc(int popp_id, int copp_id, int set,
505 int rate, int mode)
506{
507 int topology;
508 int tbl_idx;
509 int rc = 0, i = 0;
510 mutex_lock(&routing_info.adm_mutex);
511 if (set) {
512 mutex_lock(&adm_tx_topology_tbl.lock);
513 tbl_idx = check_tx_copp_topology(popp_id);
514 if (tbl_idx == -ENOENT)
515 topology = DEFAULT_COPP_TOPOLOGY;
516 else {
517 topology = adm_tx_topology_tbl.topolog_id[tbl_idx];
518 rate = 16000;
519 }
520 mutex_unlock(&adm_tx_topology_tbl.lock);
521 rc = adm_open(copp_id, LIVE_RECORDING, rate, mode, topology);
522 if (rc < 0) {
523 pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
524 rc = -EINVAL;
525 goto fail_cmd;
526 }
527
528 rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
529 (unsigned int *)&copp_id, copp_id);
530 if (rc < 0) {
531 pr_err("%s: matrix map failed rc[%d]\n", __func__, rc);
532 adm_close(copp_id);
533 rc = -EINVAL;
534 goto fail_cmd;
535 }
536 msm_set_copp_id(popp_id, copp_id);
Swaminathan Sathappan88163a72011-08-01 16:01:14 -0700537#ifdef CONFIG_MSM8X60_RTAC
538 rtac_add_adm_device(copp_id, popp_id);
539#endif
540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 } else {
542 for (i = 0; i < AFE_MAX_PORTS; i++) {
543 if (routing_info.copp_list[popp_id][i] == copp_id) {
544 rc = adm_close(copp_id);
545 if (rc < 0) {
546 pr_err("%s: adm close fail copp[%d]"
547 "rc[%d]\n",
548 __func__, copp_id, rc);
549 rc = -EINVAL;
550 goto fail_cmd;
551 }
552 msm_clear_copp_id(popp_id, copp_id);
553 break;
554 }
555 }
556 }
557fail_cmd:
558 mutex_unlock(&routing_info.adm_mutex);
559 return rc;
560}
561EXPORT_SYMBOL(msm_snddev_set_enc);
562
563int msm_device_is_voice(int dev_id)
564{
565 if ((dev_id == routing_info.voice_rx_dev_id)
566 || (dev_id == routing_info.voice_tx_dev_id))
567 return 0;
568 else
569 return -EINVAL;
570}
571EXPORT_SYMBOL(msm_device_is_voice);
572
573int msm_set_voc_route(struct msm_snddev_info *dev_info,
574 int stream_type, int dev_id)
575{
576 int rc = 0;
577 u64 session_mask = 0;
578
579 mutex_lock(&session_lock);
580 switch (stream_type) {
581 case AUDIO_ROUTE_STREAM_VOICE_RX:
582 if (audio_dev_ctrl.voice_rx_dev)
583 audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFFFF;
584
585 if (!(dev_info->capability & SNDDEV_CAP_RX) |
586 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
587 rc = -EINVAL;
588 break;
589 }
590 audio_dev_ctrl.voice_rx_dev = dev_info;
591 if (audio_dev_ctrl.voice_rx_dev) {
592 session_mask =
593 ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
594 ((int)AUDDEV_CLNT_VOC-1));
595 audio_dev_ctrl.voice_rx_dev->sessions |=
596 session_mask;
597 }
598 routing_info.voice_rx_dev_id = dev_id;
599 break;
600 case AUDIO_ROUTE_STREAM_VOICE_TX:
601 if (audio_dev_ctrl.voice_tx_dev)
602 audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFFFF;
603
604 if (!(dev_info->capability & SNDDEV_CAP_TX) |
605 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
606 rc = -EINVAL;
607 break;
608 }
609
610 audio_dev_ctrl.voice_tx_dev = dev_info;
611 if (audio_dev_ctrl.voice_rx_dev) {
612 session_mask =
613 ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
614 ((int)AUDDEV_CLNT_VOC-1));
615 audio_dev_ctrl.voice_tx_dev->sessions |=
616 session_mask;
617 }
618 routing_info.voice_tx_dev_id = dev_id;
619 break;
620 default:
621 rc = -EINVAL;
622 }
623 mutex_unlock(&session_lock);
624 return rc;
625}
626EXPORT_SYMBOL(msm_set_voc_route);
627
628void msm_release_voc_thread(void)
629{
630 wake_up(&audio_dev_ctrl.wait);
631}
632EXPORT_SYMBOL(msm_release_voc_thread);
633
634int msm_snddev_get_enc_freq(session_id)
635{
636 return routing_info.enc_freq[session_id].freq;
637}
638EXPORT_SYMBOL(msm_snddev_get_enc_freq);
639
640int msm_get_voc_freq(int *tx_freq, int *rx_freq)
641{
642 *tx_freq = routing_info.voice_tx_sample_rate;
643 *rx_freq = routing_info.voice_rx_sample_rate;
644 return 0;
645}
646EXPORT_SYMBOL(msm_get_voc_freq);
647
648int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
649{
650 int rc = 0;
651
652 if (!rx_id || !tx_id)
653 return -EINVAL;
654
655 mutex_lock(&session_lock);
656 if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
657 rc = -ENODEV;
658 mutex_unlock(&session_lock);
659 return rc;
660 }
661
662 *rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
663 *tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
664
665 mutex_unlock(&session_lock);
666
667 return rc;
668}
669EXPORT_SYMBOL(msm_get_voc_route);
670
671struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
672{
673 struct msm_snddev_info *info;
674
675 if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
676 info = ERR_PTR(-ENODEV);
677 goto error;
678 }
679
680 info = audio_dev_ctrl.devs[dev_id];
681error:
682 return info;
683
684}
685EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
686
687int snddev_voice_set_volume(int vol, int path)
688{
689 if (audio_dev_ctrl.voice_rx_dev
690 && audio_dev_ctrl.voice_tx_dev) {
691 if (path)
692 audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
693 else
694 audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
695 } else
696 return -ENODEV;
697 return 0;
698}
699EXPORT_SYMBOL(snddev_voice_set_volume);
700
701static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
702 void __user *arg)
703{
704 int rc = 0;
705 u32 index;
706 struct msm_snd_device_list work_list;
707 struct msm_snd_device_info *work_tbl;
708
709 if (copy_from_user(&work_list, arg, sizeof(work_list))) {
710 rc = -EFAULT;
711 goto error;
712 }
713
714 if (work_list.num_dev > dev_ctrl->num_dev) {
715 rc = -EINVAL;
716 goto error;
717 }
718
719 work_tbl = kmalloc(work_list.num_dev *
720 sizeof(struct msm_snd_device_info), GFP_KERNEL);
721 if (!work_tbl) {
722 rc = -ENOMEM;
723 goto error;
724 }
725
726 for (index = 0; index < dev_ctrl->num_dev; index++) {
727 work_tbl[index].dev_id = index;
728 work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
729 strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
730 64);
731 }
732
733 if (copy_to_user((void *) (work_list.list), work_tbl,
734 work_list.num_dev * sizeof(struct msm_snd_device_info)))
735 rc = -EFAULT;
736 kfree(work_tbl);
737error:
738 return rc;
739}
740
741
742int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
743 void (*listner)(u32 evt_id,
744 union auddev_evt_data *evt_payload,
745 void *private_data),
746 void *private_data)
747{
748 int rc;
749 struct msm_snd_evt_listner *callback = NULL;
750 struct msm_snd_evt_listner *new_cb;
751
752 new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
753 if (!new_cb) {
754 pr_err("No memory to add new listener node\n");
755 return -ENOMEM;
756 }
757
758 mutex_lock(&session_lock);
759 new_cb->cb_next = NULL;
760 new_cb->auddev_evt_listener = listner;
761 new_cb->evt_id = evt_id;
762 new_cb->clnt_type = clnt_type;
763 new_cb->clnt_id = clnt_id;
764 new_cb->private_data = private_data;
765 if (event.cb == NULL) {
766 event.cb = new_cb;
767 new_cb->cb_prev = NULL;
768 } else {
769 callback = event.cb;
770 for (; ;) {
771 if (callback->cb_next == NULL)
772 break;
773 else {
774 callback = callback->cb_next;
775 continue;
776 }
777 }
778 callback->cb_next = new_cb;
779 new_cb->cb_prev = callback;
780 }
781 event.num_listner++;
782 mutex_unlock(&session_lock);
783 rc = 0;
784 return rc;
785}
786EXPORT_SYMBOL(auddev_register_evt_listner);
787
788int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
789{
790 struct msm_snd_evt_listner *callback = event.cb;
791 struct msm_snddev_info *info;
792 u64 session_mask = 0;
793 int i = 0;
794
795 mutex_lock(&session_lock);
796 while (callback != NULL) {
797 if ((callback->clnt_type == clnt_type)
798 && (callback->clnt_id == clnt_id))
799 break;
800 callback = callback->cb_next;
801 }
802 if (callback == NULL) {
803 mutex_unlock(&session_lock);
804 return -EINVAL;
805 }
806
807 if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
808 event.cb = NULL;
809 else if (callback->cb_next == NULL)
810 callback->cb_prev->cb_next = NULL;
811 else if (callback->cb_prev == NULL) {
812 callback->cb_next->cb_prev = NULL;
813 event.cb = callback->cb_next;
814 } else {
815 callback->cb_prev->cb_next = callback->cb_next;
816 callback->cb_next->cb_prev = callback->cb_prev;
817 }
818 kfree(callback);
819
820 session_mask = (((u64)0x1) << clnt_id) << (MAX_BIT_PER_CLIENT * \
821 ((int)clnt_type-1));
822 for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
823 info = audio_dev_ctrl.devs[i];
824 info->sessions &= ~session_mask;
825 }
826 mutex_unlock(&session_lock);
827 return 0;
828}
829EXPORT_SYMBOL(auddev_unregister_evt_listner);
830
831int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
832{
833 int i = 0;
834 struct msm_snddev_info *info;
835 u64 session_mask = 0;
836
837 if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
838 return -EINVAL;
839 if ((clnt_type == AUDDEV_CLNT_DEC)
840 && (session_id >= MAX_SESSIONS))
841 return -EINVAL;
842 if ((clnt_type == AUDDEV_CLNT_ENC)
843 && (session_id >= MAX_SESSIONS))
844 return -EINVAL;
845
846 session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
847 ((int)clnt_type-1));
848
849 for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
850 info = audio_dev_ctrl.devs[i];
851 if ((info->sessions & session_mask)
852 && (info->capability & capability)) {
853 if (!(info->sessions & ~(session_mask)))
854 info->set_sample_rate = 0;
855 }
856 }
857 if (clnt_type == AUDDEV_CLNT_DEC)
858 routing_info.dec_freq[session_id].freq
859 = 0;
860 else if (clnt_type == AUDDEV_CLNT_ENC)
861 routing_info.enc_freq[session_id].freq
862 = 0;
863 else if (capability == SNDDEV_CAP_TX)
864 routing_info.voice_tx_sample_rate = 0;
865 else
866 routing_info.voice_rx_sample_rate = 48000;
867 return 0;
868}
869
870int msm_snddev_request_freq(int *freq, u32 session_id,
871 u32 capability, u32 clnt_type)
872{
873 int i = 0;
874 int rc = 0;
875 struct msm_snddev_info *info;
876 u32 set_freq;
877 u64 session_mask = 0;
878 u64 clnt_type_mask = 0;
879
880 pr_debug(": clnt_type 0x%08x\n", clnt_type);
881
882 if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
883 return -EINVAL;
884 if ((clnt_type == AUDDEV_CLNT_DEC)
885 && (session_id >= MAX_SESSIONS))
886 return -EINVAL;
887 if ((clnt_type == AUDDEV_CLNT_ENC)
888 && (session_id >= MAX_SESSIONS))
889 return -EINVAL;
890 session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
891 ((int)clnt_type-1));
892 clnt_type_mask = (0xFFFF << (MAX_BIT_PER_CLIENT * (clnt_type-1)));
893 if (!(*freq == 8000) && !(*freq == 11025) &&
894 !(*freq == 12000) && !(*freq == 16000) &&
895 !(*freq == 22050) && !(*freq == 24000) &&
896 !(*freq == 32000) && !(*freq == 44100) &&
897 !(*freq == 48000))
898 return -EINVAL;
899
900 for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
901 info = audio_dev_ctrl.devs[i];
902 if ((info->sessions & session_mask)
903 && (info->capability & capability)) {
904 rc = 0;
905 if ((info->sessions & ~clnt_type_mask)
906 && ((*freq != 8000) && (*freq != 16000)
907 && (*freq != 48000))) {
908 if (clnt_type == AUDDEV_CLNT_ENC) {
909 routing_info.enc_freq[session_id].freq
910 = 0;
911 return -EPERM;
912 } else if (clnt_type == AUDDEV_CLNT_DEC) {
913 routing_info.dec_freq[session_id].freq
914 = 0;
915 return -EPERM;
916 }
917 }
918 if (*freq == info->set_sample_rate) {
919 rc = info->set_sample_rate;
920 continue;
921 }
922 set_freq = MAX(*freq, info->set_sample_rate);
923
924
925 if (clnt_type == AUDDEV_CLNT_DEC) {
926 routing_info.dec_freq[session_id].evt = 1;
927 routing_info.dec_freq[session_id].freq
928 = set_freq;
929 } else if (clnt_type == AUDDEV_CLNT_ENC) {
930 routing_info.enc_freq[session_id].evt = 1;
931 routing_info.enc_freq[session_id].freq
932 = set_freq;
933 } else if (capability == SNDDEV_CAP_TX)
934 routing_info.voice_tx_sample_rate = set_freq;
935
936 rc = set_freq;
937 info->set_sample_rate = set_freq;
938 *freq = info->set_sample_rate;
939
940 if (info->opened) {
941 broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
942 SESSION_IGNORE);
943 set_freq = info->dev_ops.set_freq(info,
944 set_freq);
945 broadcast_event(AUDDEV_EVT_DEV_RDY, i,
946 SESSION_IGNORE);
947 }
948 }
949 pr_debug("info->set_sample_rate = %d\n", info->set_sample_rate);
950 pr_debug("routing_info.enc_freq.freq = %d\n",
951 routing_info.enc_freq[session_id].freq);
952 }
953 return rc;
954}
955EXPORT_SYMBOL(msm_snddev_request_freq);
956
957int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain)
958{
959 int rc;
960 struct msm_snddev_info *dev_info;
961
962 pr_debug("dev_id %d enable %d\n", dev_id, enable);
963
964 dev_info = audio_dev_ctrl_find_dev(dev_id);
965
966 if (IS_ERR(dev_info)) {
967 pr_err("bad dev_id %d\n", dev_id);
968 rc = -EINVAL;
969 } else if (!dev_info->dev_ops.enable_sidetone) {
970 pr_debug("dev %d no sidetone support\n", dev_id);
971 rc = -EPERM;
972 } else
973 rc = dev_info->dev_ops.enable_sidetone(dev_info, enable, gain);
974
975 return rc;
976}
977EXPORT_SYMBOL(msm_snddev_enable_sidetone);
978
979int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
980 int channel_mode)
981{
982 int rc = 0;
983 unsigned int port_id[2];
984 port_id[0] = VOICE_RECORD_TX;
985 port_id[1] = VOICE_RECORD_RX;
986
987 pr_debug("%s: popp_id %d, rec_mode %d, rate %d, channel_mode %d\n",
988 __func__, popp_id, rec_mode, rate, channel_mode);
989
990 mutex_lock(&routing_info.adm_mutex);
991
992 if (rec_mode == VOC_REC_UPLINK) {
993 rc = afe_start_pseudo_port(port_id[0]);
994 if (rc < 0) {
995 pr_err("%s: Error %d in Tx pseudo port start\n",
996 __func__, rc);
997
998 goto fail_cmd;
999 }
1000
1001 rc = adm_open(port_id[0], LIVE_RECORDING, rate, channel_mode,
1002 DEFAULT_COPP_TOPOLOGY);
1003 if (rc < 0) {
1004 pr_err("%s: Error %d in ADM open %d\n",
1005 __func__, rc, port_id[0]);
1006
1007 goto fail_cmd;
1008 }
1009
1010 rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
1011 &port_id[0], port_id[0]);
1012 if (rc < 0) {
1013 pr_err("%s: Error %d in ADM matrix map %d\n",
1014 __func__, rc, port_id[0]);
1015
1016 goto fail_cmd;
1017 }
1018
1019 msm_set_copp_id(popp_id, port_id[0]);
1020
1021 } else if (rec_mode == VOC_REC_DOWNLINK) {
1022 rc = afe_start_pseudo_port(port_id[1]);
1023 if (rc < 0) {
1024 pr_err("%s: Error %d in Rx pseudo port start\n",
1025 __func__, rc);
1026
1027 goto fail_cmd;
1028 }
1029
1030 rc = adm_open(port_id[1], LIVE_RECORDING, rate, channel_mode,
1031 DEFAULT_COPP_TOPOLOGY);
1032 if (rc < 0) {
1033 pr_err("%s: Error %d in ADM open %d\n",
1034 __func__, rc, port_id[1]);
1035
1036 goto fail_cmd;
1037 }
1038
1039 rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
1040 &port_id[1], port_id[1]);
1041 if (rc < 0) {
1042 pr_err("%s: Error %d in ADM matrix map %d\n",
1043 __func__, rc, port_id[1]);
1044
1045 goto fail_cmd;
1046 }
1047
1048 msm_set_copp_id(popp_id, port_id[1]);
1049
1050 } else if (rec_mode == VOC_REC_BOTH) {
1051 rc = afe_start_pseudo_port(port_id[0]);
1052 if (rc < 0) {
1053 pr_err("%s: Error %d in Tx pseudo port start\n",
1054 __func__, rc);
1055
1056 goto fail_cmd;
1057 }
1058
1059 rc = adm_open(port_id[0], LIVE_RECORDING, rate, channel_mode,
1060 DEFAULT_COPP_TOPOLOGY);
1061 if (rc < 0) {
1062 pr_err("%s: Error %d in ADM open %d\n",
1063 __func__, rc, port_id[0]);
1064
1065 goto fail_cmd;
1066 }
1067
1068 msm_set_copp_id(popp_id, port_id[0]);
1069
1070 rc = afe_start_pseudo_port(port_id[1]);
1071 if (rc < 0) {
1072 pr_err("%s: Error %d in Rx pseudo port start\n",
1073 __func__, rc);
1074
1075 goto fail_cmd;
1076 }
1077
1078 rc = adm_open(port_id[1], LIVE_RECORDING, rate, channel_mode,
1079 DEFAULT_COPP_TOPOLOGY);
1080 if (rc < 0) {
1081 pr_err("%s: Error %d in ADM open %d\n",
1082 __func__, rc, port_id[0]);
1083
1084 goto fail_cmd;
1085 }
1086
1087 rc = adm_matrix_map(popp_id, LIVE_RECORDING, 2,
1088 &port_id[0], port_id[1]);
1089 if (rc < 0) {
1090 pr_err("%s: Error %d in ADM matrix map\n",
1091 __func__, rc);
1092
1093 goto fail_cmd;
1094 }
1095
1096 msm_set_copp_id(popp_id, port_id[1]);
1097 } else {
1098 pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
1099
1100 goto fail_cmd;
1101 }
1102
1103 rc = voice_start_record(rec_mode, 1);
1104
1105fail_cmd:
1106 mutex_unlock(&routing_info.adm_mutex);
1107 return rc;
1108}
1109
1110int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode)
1111{
1112 int rc = 0;
1113 uint32_t port_id[2];
1114 port_id[0] = VOICE_RECORD_TX;
1115 port_id[1] = VOICE_RECORD_RX;
1116
1117 pr_debug("%s: popp_id %d, rec_mode %d\n", __func__, popp_id, rec_mode);
1118
1119 mutex_lock(&routing_info.adm_mutex);
1120
1121 rc = voice_start_record(rec_mode, 0);
1122 if (rc < 0) {
1123 pr_err("%s: Error %d stopping record\n", __func__, rc);
1124
1125 goto fail_cmd;
1126 }
1127
1128 if (rec_mode == VOC_REC_UPLINK) {
1129 rc = adm_close(port_id[0]);
1130 if (rc < 0) {
1131 pr_err("%s: Error %d in ADM close %d\n",
1132 __func__, rc, port_id[0]);
1133
1134 goto fail_cmd;
1135 }
1136
1137 msm_clear_copp_id(popp_id, port_id[0]);
1138
1139 rc = afe_stop_pseudo_port(port_id[0]);
1140 if (rc < 0) {
1141 pr_err("%s: Error %d in Tx pseudo port stop\n",
1142 __func__, rc);
1143 goto fail_cmd;
1144 }
1145
1146 } else if (rec_mode == VOC_REC_DOWNLINK) {
1147 rc = adm_close(port_id[1]);
1148 if (rc < 0) {
1149 pr_err("%s: Error %d in ADM close %d\n",
1150 __func__, rc, port_id[1]);
1151
1152 goto fail_cmd;
1153 }
1154
1155 msm_clear_copp_id(popp_id, port_id[1]);
1156
1157 rc = afe_stop_pseudo_port(port_id[1]);
1158 if (rc < 0) {
1159 pr_err("%s: Error %d in Rx pseudo port stop\n",
1160 __func__, rc);
1161 goto fail_cmd;
1162 }
1163 } else if (rec_mode == VOC_REC_BOTH) {
1164 rc = adm_close(port_id[0]);
1165 if (rc < 0) {
1166 pr_err("%s: Error %d in ADM close %d\n",
1167 __func__, rc, port_id[0]);
1168
1169 goto fail_cmd;
1170 }
1171
1172 msm_clear_copp_id(popp_id, port_id[0]);
1173
1174 rc = afe_stop_pseudo_port(port_id[0]);
1175 if (rc < 0) {
1176 pr_err("%s: Error %d in Tx pseudo port stop\n",
1177 __func__, rc);
1178 goto fail_cmd;
1179 }
1180
1181 rc = adm_close(port_id[1]);
1182 if (rc < 0) {
1183 pr_err("%s: Error %d in ADM close %d\n",
1184 __func__, rc, port_id[1]);
1185
1186 goto fail_cmd;
1187 }
1188
1189 msm_clear_copp_id(popp_id, port_id[1]);
1190
1191 rc = afe_stop_pseudo_port(port_id[1]);
1192 if (rc < 0) {
1193 pr_err("%s: Error %d in Rx pseudo port stop\n",
1194 __func__, rc);
1195 goto fail_cmd;
1196 }
1197 } else {
1198 pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
1199
1200 goto fail_cmd;
1201 }
1202
1203fail_cmd:
1204 mutex_unlock(&routing_info.adm_mutex);
1205 return rc;
1206}
1207
1208static long audio_dev_ctrl_ioctl(struct file *file,
1209 unsigned int cmd, unsigned long arg)
1210{
1211 int rc = 0;
1212 struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
1213
1214 mutex_lock(&session_lock);
1215 switch (cmd) {
1216 case AUDIO_GET_NUM_SND_DEVICE:
1217 rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
1218 break;
1219 case AUDIO_GET_SND_DEVICES:
1220 rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
1221 break;
1222 case AUDIO_ENABLE_SND_DEVICE: {
1223 struct msm_snddev_info *dev_info;
1224 u32 dev_id;
1225
1226 if (get_user(dev_id, (u32 __user *) arg)) {
1227 rc = -EFAULT;
1228 break;
1229 }
1230 dev_info = audio_dev_ctrl_find_dev(dev_id);
1231 if (IS_ERR(dev_info))
1232 rc = PTR_ERR(dev_info);
1233 else {
1234 rc = dev_info->dev_ops.open(dev_info);
1235 if (!rc)
1236 dev_info->opened = 1;
1237 wake_up(&audio_dev_ctrl.wait);
1238 }
1239 break;
1240
1241 }
1242
1243 case AUDIO_DISABLE_SND_DEVICE: {
1244 struct msm_snddev_info *dev_info;
1245 u32 dev_id;
1246
1247 if (get_user(dev_id, (u32 __user *) arg)) {
1248 rc = -EFAULT;
1249 break;
1250 }
1251 dev_info = audio_dev_ctrl_find_dev(dev_id);
1252 if (IS_ERR(dev_info))
1253 rc = PTR_ERR(dev_info);
1254 else {
1255 rc = dev_info->dev_ops.close(dev_info);
1256 dev_info->opened = 0;
1257 }
1258 break;
1259 }
1260
1261 case AUDIO_ROUTE_STREAM: {
1262 struct msm_audio_route_config route_cfg;
1263 struct msm_snddev_info *dev_info;
1264
1265 if (copy_from_user(&route_cfg, (void __user *) arg,
1266 sizeof(struct msm_audio_route_config))) {
1267 rc = -EFAULT;
1268 break;
1269 }
1270 pr_debug("%s: route cfg %d %d type\n", __func__,
1271 route_cfg.dev_id, route_cfg.stream_type);
1272 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
1273 if (IS_ERR(dev_info)) {
1274 pr_err("%s: pass invalid dev_id\n", __func__);
1275 rc = PTR_ERR(dev_info);
1276 break;
1277 }
1278
1279 switch (route_cfg.stream_type) {
1280
1281 case AUDIO_ROUTE_STREAM_VOICE_RX:
1282 if (!(dev_info->capability & SNDDEV_CAP_RX) |
1283 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
1284 rc = -EINVAL;
1285 break;
1286 }
1287 dev_ctrl->voice_rx_dev = dev_info;
1288 break;
1289 case AUDIO_ROUTE_STREAM_VOICE_TX:
1290 if (!(dev_info->capability & SNDDEV_CAP_TX) |
1291 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
1292 rc = -EINVAL;
1293 break;
1294 }
1295 dev_ctrl->voice_tx_dev = dev_info;
1296 break;
1297 }
1298 break;
1299 }
1300
1301 default:
1302 rc = -EINVAL;
1303 }
1304 mutex_unlock(&session_lock);
1305 return rc;
1306}
1307
1308static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
1309{
1310 pr_debug("open audio_dev_ctrl\n");
1311 atomic_inc(&audio_dev_ctrl.opened);
1312 file->private_data = &audio_dev_ctrl;
1313 return 0;
1314}
1315
1316static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
1317{
1318 pr_debug("release audio_dev_ctrl\n");
1319 atomic_dec(&audio_dev_ctrl.opened);
1320 return 0;
1321}
1322
1323static const struct file_operations audio_dev_ctrl_fops = {
1324 .owner = THIS_MODULE,
1325 .open = audio_dev_ctrl_open,
1326 .release = audio_dev_ctrl_release,
1327 .unlocked_ioctl = audio_dev_ctrl_ioctl,
1328};
1329
1330
1331struct miscdevice audio_dev_ctrl_misc = {
1332 .minor = MISC_DYNAMIC_MINOR,
1333 .name = "msm_audio_dev_ctrl",
1334 .fops = &audio_dev_ctrl_fops,
1335};
1336
1337/* session id is 64 bit routing mask per device
1338 * 0-15 for voice clients
1339 * 16-31 for Decoder clients
1340 * 32-47 for Encoder clients
1341 * 48-63 Do not care
1342 */
1343void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id)
1344{
1345 int clnt_id = 0, i;
1346 union auddev_evt_data *evt_payload;
1347 struct msm_snd_evt_listner *callback;
1348 struct msm_snddev_info *dev_info = NULL;
1349 u64 session_mask = 0;
1350 static int pending_sent;
1351
1352 pr_debug(": evt_id = %d\n", evt_id);
1353
1354 if ((evt_id != AUDDEV_EVT_START_VOICE)
1355 && (evt_id != AUDDEV_EVT_END_VOICE)
1356 && (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
1357 && (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
1358 dev_info = audio_dev_ctrl_find_dev(dev_id);
1359 if (IS_ERR(dev_info)) {
1360 pr_err("%s: pass invalid dev_id(%d)\n",
1361 __func__, dev_id);
1362 return;
1363 }
1364 }
1365
1366#ifdef CONFIG_MSM8X60_RTAC
1367 update_rtac(evt_id, dev_id, dev_info);
1368#endif
1369
1370 if (event.cb != NULL)
1371 callback = event.cb;
1372 else
1373 return;
1374 mutex_lock(&session_lock);
1375
1376 if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1377 routing_info.voice_state = dev_id;
1378
1379 evt_payload = kzalloc(sizeof(union auddev_evt_data),
1380 GFP_KERNEL);
1381
1382 if (evt_payload == NULL) {
1383 pr_err("broadcast_event: cannot allocate memory\n");
1384 mutex_unlock(&session_lock);
1385 return;
1386 }
1387 for (; ;) {
1388 if (!(evt_id & callback->evt_id)) {
1389 if (callback->cb_next == NULL)
1390 break;
1391 else {
1392 callback = callback->cb_next;
1393 continue;
1394 }
1395 }
1396 clnt_id = callback->clnt_id;
1397 memset(evt_payload, 0, sizeof(union auddev_evt_data));
1398
1399 if ((evt_id == AUDDEV_EVT_START_VOICE)
1400 || (evt_id == AUDDEV_EVT_END_VOICE))
1401 goto skip_check;
1402 if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
1403 goto aud_cal;
1404
1405 session_mask = (((u64)0x1) << clnt_id)
1406 << (MAX_BIT_PER_CLIENT * \
1407 ((int)callback->clnt_type-1));
1408
1409 if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
1410 (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
1411 pr_debug("AUDDEV_EVT_STREAM_VOL_CHG or\
1412 AUDDEV_EVT_VOICE_STATE_CHG\n");
1413 goto volume_strm;
1414 }
1415
1416 pr_debug("dev_info->sessions = %llu\n", dev_info->sessions);
1417
1418 if ((!session_id && !(dev_info->sessions & session_mask)) ||
1419 (session_id && ((dev_info->sessions & session_mask) !=
1420 session_id))) {
1421 if (callback->cb_next == NULL)
1422 break;
1423 else {
1424 callback = callback->cb_next;
1425 continue;
1426 }
1427 }
1428 if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
1429 goto voc_events;
1430
1431volume_strm:
1432 if (callback->clnt_type == AUDDEV_CLNT_DEC) {
1433 pr_debug("AUDDEV_CLNT_DEC\n");
1434 if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
1435 pr_debug("clnt_id = %d, session_id = %llu\n",
1436 clnt_id, session_id);
1437 if (session_mask != session_id)
1438 goto sent_dec;
1439 else
1440 evt_payload->session_vol =
1441 msm_vol_ctl.volume;
1442 } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
1443 if (routing_info.dec_freq[clnt_id].evt) {
1444 routing_info.dec_freq[clnt_id].evt
1445 = 0;
1446 goto sent_dec;
1447 } else if (routing_info.dec_freq[clnt_id].freq
1448 == dev_info->set_sample_rate)
1449 goto sent_dec;
1450 else {
1451 evt_payload->freq_info.sample_rate
1452 = dev_info->set_sample_rate;
1453 evt_payload->freq_info.dev_type
1454 = dev_info->capability;
1455 evt_payload->freq_info.acdb_dev_id
1456 = dev_info->acdb_id;
1457 }
1458 } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1459 evt_payload->voice_state =
1460 routing_info.voice_state;
1461 else
1462 evt_payload->routing_id = dev_info->copp_id;
1463 callback->auddev_evt_listener(
1464 evt_id,
1465 evt_payload,
1466 callback->private_data);
1467sent_dec:
1468 if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
1469 (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
1470 routing_info.dec_freq[clnt_id].freq
1471 = dev_info->set_sample_rate;
1472
1473 if (callback->cb_next == NULL)
1474 break;
1475 else {
1476 callback = callback->cb_next;
1477 continue;
1478 }
1479 }
1480 if (callback->clnt_type == AUDDEV_CLNT_ENC) {
1481 pr_debug("AUDDEV_CLNT_ENC\n");
1482 if (evt_id == AUDDEV_EVT_FREQ_CHG) {
1483 if (routing_info.enc_freq[clnt_id].evt) {
1484 routing_info.enc_freq[clnt_id].evt
1485 = 0;
1486 goto sent_enc;
1487 } else {
1488 evt_payload->freq_info.sample_rate
1489 = dev_info->set_sample_rate;
1490 evt_payload->freq_info.dev_type
1491 = dev_info->capability;
1492 evt_payload->freq_info.acdb_dev_id
1493 = dev_info->acdb_id;
1494 }
1495 } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1496 evt_payload->voice_state =
1497 routing_info.voice_state;
1498 else
1499 evt_payload->routing_id = dev_info->copp_id;
1500 callback->auddev_evt_listener(
1501 evt_id,
1502 evt_payload,
1503 callback->private_data);
1504sent_enc:
1505 if (callback->cb_next == NULL)
1506 break;
1507 else {
1508 callback = callback->cb_next;
1509 continue;
1510 }
1511 }
1512aud_cal:
1513 if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
1514 pr_debug("AUDDEV_CLNT_AUDIOCAL\n");
1515 if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1516 evt_payload->voice_state =
1517 routing_info.voice_state;
1518 else if (!dev_info->sessions)
1519 goto sent_aud_cal;
1520 else {
1521 evt_payload->audcal_info.dev_id =
1522 dev_info->copp_id;
1523 evt_payload->audcal_info.acdb_id =
1524 dev_info->acdb_id;
1525 evt_payload->audcal_info.dev_type =
1526 (dev_info->capability & SNDDEV_CAP_TX) ?
1527 SNDDEV_CAP_TX : SNDDEV_CAP_RX;
1528 evt_payload->audcal_info.sample_rate =
1529 dev_info->set_sample_rate ?
1530 dev_info->set_sample_rate :
1531 dev_info->sample_rate;
1532 }
1533 callback->auddev_evt_listener(
1534 evt_id,
1535 evt_payload,
1536 callback->private_data);
1537
1538sent_aud_cal:
1539 if (callback->cb_next == NULL)
1540 break;
1541 else {
1542 callback = callback->cb_next;
1543 continue;
1544 }
1545 }
1546skip_check:
1547voc_events:
1548 if (callback->clnt_type == AUDDEV_CLNT_VOC) {
1549 pr_debug("AUDDEV_CLNT_VOC\n");
1550 if (evt_id == AUDDEV_EVT_DEV_RLS) {
1551 if (!pending_sent)
1552 goto sent_voc;
1553 else
1554 pending_sent = 0;
1555 }
1556 if (evt_id == AUDDEV_EVT_REL_PENDING)
1557 pending_sent = 1;
1558
1559 if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
1560 if (dev_info->capability & SNDDEV_CAP_TX) {
1561 evt_payload->voc_vm_info.dev_type =
1562 SNDDEV_CAP_TX;
1563 evt_payload->voc_vm_info.acdb_dev_id =
1564 dev_info->acdb_id;
1565 evt_payload->
1566 voc_vm_info.dev_vm_val.mute =
1567 routing_info.tx_mute;
1568 } else {
1569 evt_payload->voc_vm_info.dev_type =
1570 SNDDEV_CAP_RX;
1571 evt_payload->voc_vm_info.acdb_dev_id =
1572 dev_info->acdb_id;
1573 evt_payload->
1574 voc_vm_info.dev_vm_val.vol =
1575 routing_info.voice_rx_vol;
1576 }
1577 } else if ((evt_id == AUDDEV_EVT_START_VOICE)
1578 || (evt_id == AUDDEV_EVT_END_VOICE))
1579 memset(evt_payload, 0,
1580 sizeof(union auddev_evt_data));
1581 else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
1582 if (routing_info.voice_tx_sample_rate
1583 != dev_info->set_sample_rate) {
1584 routing_info.voice_tx_sample_rate
1585 = dev_info->set_sample_rate;
1586 evt_payload->freq_info.sample_rate
1587 = dev_info->set_sample_rate;
1588 evt_payload->freq_info.dev_type
1589 = dev_info->capability;
1590 evt_payload->freq_info.acdb_dev_id
1591 = dev_info->acdb_id;
1592 } else
1593 goto sent_voc;
1594 } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1595 evt_payload->voice_state =
1596 routing_info.voice_state;
1597 else {
1598 evt_payload->voc_devinfo.dev_type =
1599 (dev_info->capability & SNDDEV_CAP_TX) ?
1600 SNDDEV_CAP_TX : SNDDEV_CAP_RX;
1601 evt_payload->voc_devinfo.acdb_dev_id =
1602 dev_info->acdb_id;
1603 evt_payload->voc_devinfo.dev_port_id =
1604 dev_info->copp_id;
1605 evt_payload->voc_devinfo.dev_sample =
1606 dev_info->set_sample_rate ?
1607 dev_info->set_sample_rate :
1608 dev_info->sample_rate;
1609 evt_payload->voc_devinfo.dev_id = dev_id;
1610 if (dev_info->capability & SNDDEV_CAP_RX) {
1611 for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
1612 i++) {
1613 evt_payload->
1614 voc_devinfo.max_rx_vol[i] =
1615 dev_info->max_voc_rx_vol[i];
1616 evt_payload
1617 ->voc_devinfo.min_rx_vol[i] =
1618 dev_info->min_voc_rx_vol[i];
1619 }
1620 }
1621 }
1622 callback->auddev_evt_listener(
1623 evt_id,
1624 evt_payload,
1625 callback->private_data);
1626 if (evt_id == AUDDEV_EVT_DEV_RLS)
1627 dev_info->sessions &= ~(0xFFFF);
1628sent_voc:
1629 if (callback->cb_next == NULL)
1630 break;
1631 else {
1632 callback = callback->cb_next;
1633 continue;
1634 }
1635 }
1636 }
1637 kfree(evt_payload);
1638 mutex_unlock(&session_lock);
1639}
1640EXPORT_SYMBOL(broadcast_event);
1641
1642
1643void mixer_post_event(u32 evt_id, u32 id)
1644{
1645
1646 pr_debug("evt_id = %d\n", evt_id);
1647 switch (evt_id) {
1648 case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
1649 broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
1650 break;
1651 case AUDDEV_EVT_DEV_RDY:
1652 broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
1653 break;
1654 case AUDDEV_EVT_DEV_RLS:
1655 broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
1656 break;
1657 case AUDDEV_EVT_REL_PENDING:
1658 broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
1659 break;
1660 case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
1661 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
1662 SESSION_IGNORE);
1663 break;
1664 case AUDDEV_EVT_STREAM_VOL_CHG:
1665 broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
1666 SESSION_IGNORE);
1667 break;
1668 case AUDDEV_EVT_START_VOICE:
1669 broadcast_event(AUDDEV_EVT_START_VOICE,
1670 id, SESSION_IGNORE);
1671 break;
1672 case AUDDEV_EVT_END_VOICE:
1673 broadcast_event(AUDDEV_EVT_END_VOICE,
1674 id, SESSION_IGNORE);
1675 break;
1676 case AUDDEV_EVT_FREQ_CHG:
1677 broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
1678 break;
1679 default:
1680 break;
1681 }
1682}
1683EXPORT_SYMBOL(mixer_post_event);
1684
1685static int __init audio_dev_ctrl_init(void)
1686{
1687 init_waitqueue_head(&audio_dev_ctrl.wait);
1688
1689 event.cb = NULL;
1690
1691 atomic_set(&audio_dev_ctrl.opened, 0);
1692 audio_dev_ctrl.num_dev = 0;
1693 audio_dev_ctrl.voice_tx_dev = NULL;
1694 audio_dev_ctrl.voice_rx_dev = NULL;
1695 routing_info.voice_state = VOICE_STATE_INVALID;
1696
1697 mutex_init(&adm_tx_topology_tbl.lock);
1698 mutex_init(&routing_info.copp_list_mutex);
1699 mutex_init(&routing_info.adm_mutex);
1700
Bharath Ramachandramurthyb85333e2011-07-29 12:33:37 -07001701 memset(routing_info.copp_list, COPP_IGNORE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 (sizeof(unsigned int) * MAX_SESSIONS * AFE_MAX_PORTS));
1703 return misc_register(&audio_dev_ctrl_misc);
1704}
1705
1706static void __exit audio_dev_ctrl_exit(void)
1707{
1708}
1709module_init(audio_dev_ctrl_init);
1710module_exit(audio_dev_ctrl_exit);
1711
1712MODULE_DESCRIPTION("MSM 8K Audio Device Control driver");
1713MODULE_LICENSE("GPL v2");