blob: ccb2bad4c051cab3e71cdd40e5aa61790528ad92 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010, The Linux Foundation. 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
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/miscdevice.h>
17#include <linux/uaccess.h>
18#include <linux/fs.h>
19#include <linux/mutex.h>
20#include <linux/sched.h>
21#include <linux/kthread.h>
22#include <linux/completion.h>
23#include <linux/wait.h>
24#include <mach/msm_qdsp6_audiov2.h>
25#include "../dal.h"
26#include "dal_voice.h"
27#include <mach/debug_mm.h>
28
29struct voice_struct {
30 struct dal_client *cvd;
31 struct apr_command_pkt apr_pkt;
32 struct completion compl;
33};
34
35static struct voice_struct voice;
36
37static int cvd_send_response(void)
38{
39 struct apr_command_pkt *pkt;
40 uint16_t src_addr;
41 uint16_t src_token;
42 uint16_t dst_token;
43 uint16_t dst_addr;
44
45 pkt = &voice.apr_pkt;
46 src_addr = pkt->dst_addr;
47 dst_addr = pkt->src_addr;
48 src_token = pkt->dst_token;
49 dst_token = pkt->src_token;
50
51 pkt->header &= ~APR_PKTV1_TYPE_MASK;
52 pkt->header |= APR_SET_FIELD(APR_PKTV1_TYPE, APR_PKTV1_TYPE_EVENT_V);
53 pkt->src_addr = src_addr;
54 pkt->dst_addr = dst_addr;
55 pkt->src_token = src_token;
56 pkt->dst_token = dst_token;
57 pkt->opcode = APR_IBASIC_RSP_RESULT;
58
59 dal_call(voice.cvd, VOICE_OP_CONTROL, 5, pkt,
60 sizeof(struct apr_command_pkt),
61 pkt, sizeof(u32));
62 return 0;
63}
64
65static int cvd_process_voice_setup(void)
66{
67 q6voice_setup();
68 cvd_send_response();
69 return 0;
70}
71
72static int cvd_process_voice_teardown(void)
73{
74 q6voice_teardown();
75 cvd_send_response();
76 return 0;
77}
78
79static int cvd_process_set_network(void)
80{
81 cvd_send_response();
82 return 0;
83}
84
85static int voice_thread(void *data)
86{
87 while (!kthread_should_stop()) {
88 wait_for_completion(&voice.compl);
89 init_completion(&voice.compl);
90
91 switch (voice.apr_pkt.opcode) {
92
93 case APR_OP_CMD_CREATE:
94 cvd_send_response();
95 break;
96 case VOICE_OP_CMD_BRINGUP:
97 cvd_process_voice_setup();
98 break;
99 case APR_OP_CMD_DESTROY:
100 cvd_send_response();
101 break;
102 case VOICE_OP_CMD_TEARDOWN:
103 cvd_process_voice_teardown();
104 break;
105 case VOICE_OP_CMD_SET_NETWORK:
106 cvd_process_set_network();
107 break;
108 default:
109 pr_err("[%s:%s] Undefined event\n", __MM_FILE__,
110 __func__);
111
112 }
113 }
114 return 0;
115}
116
117static void remote_cb_function(void *data, int len, void *cookie)
118{
119 struct apr_command_pkt *apr = data + 2*sizeof(uint32_t);
120
121 memcpy(&voice.apr_pkt, apr, sizeof(struct apr_command_pkt));
122
123 if (len <= 0) {
124 pr_err("[%s:%s] unexpected event with length %d\n",
125 __MM_FILE__, __func__, len);
126 return;
127 }
128
129 pr_debug("[%s:%s] APR = %x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", __MM_FILE__,
130 __func__,
131 apr->header,
132 apr->reserved1,
133 apr->src_addr,
134 apr->dst_addr,
135 apr->ret_addr,
136 apr->src_token,
137 apr->dst_token,
138 apr->ret_token,
139 apr->context,
140 apr->opcode);
141
142 complete(&voice.compl);
143}
144
145static int __init voice_init(void)
146{
147 int res = 0;
148 struct task_struct *task;
149 u32 tmp[2];
150
151 tmp[0] = sizeof(u32);
152 tmp[1] = 0;
153
154 voice.cvd = dal_attach(VOICE_DAL_DEVICE, VOICE_DAL_PORT, 0,
155 remote_cb_function, 0);
156
157 if (!voice.cvd) {
158 pr_err("[%s:%s] audio_init: cannot attach to cvd\n",
159 __MM_FILE__, __func__);
160 res = -ENODEV;
161 goto done;
162 }
163
164 if (check_version(voice.cvd, VOICE_DAL_VERSION) != 0) {
165 pr_err("[%s:%s] Incompatible cvd version\n",
166 __MM_FILE__, __func__);
167 res = -ENODEV;
168 goto done;
169 }
170 dal_call(voice.cvd, VOICE_OP_INIT, 5, tmp, sizeof(tmp),
171 tmp, sizeof(u32));
172
173 init_completion(&voice.compl);
174 task = kthread_run(voice_thread, &voice, "voice_thread");
175
176 if (IS_ERR(task)) {
177 pr_err("[%s:%s] Cannot start the voice thread\n", __MM_FILE__,
178 __func__);
179 res = PTR_ERR(task);
180 task = NULL;
181 } else
182 goto done;
183
184done:
185 return res;
186}
187
188late_initcall(voice_init);