hfp: Fixup variable names
[platform/upstream/ofono.git] / drivers / hfpmodem / handsfree.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #define _GNU_SOURCE
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <unistd.h>
33
34 #include <glib.h>
35 #include <gatchat.h>
36 #include <gatresult.h>
37
38 #include <ofono/log.h>
39 #include <ofono/modem.h>
40 #include <ofono/handsfree.h>
41
42 #include "hfpmodem.h"
43 #include "hfp.h"
44 #include "slc.h"
45
46 static const char *binp_prefix[] = { "+BINP:", NULL };
47 static const char *bvra_prefix[] = { "+BVRA:", NULL };
48
49 struct hf_data {
50         GAtChat *chat;
51         unsigned int ag_features;
52         unsigned int ag_chld_features;
53         int battchg_index;
54         guint register_source;
55 };
56
57 static void hf_generic_set_cb(gboolean ok, GAtResult *result,
58                                 gpointer user_data)
59 {
60         struct cb_data *cbd = user_data;
61         ofono_handsfree_cb_t cb = cbd->cb;
62         struct ofono_error error;
63
64         decode_at_error(&error, g_at_result_final_response(result));
65
66         cb(&error, cbd->data);
67 }
68
69 static void bsir_notify(GAtResult *result, gpointer user_data)
70 {
71         struct ofono_handsfree *hf = user_data;
72         GAtResultIter iter;
73         int value;
74
75         g_at_result_iter_init(&iter, result);
76
77         if (!g_at_result_iter_next(&iter, "+BSIR:"))
78                 return;
79
80         if (!g_at_result_iter_next_number(&iter, &value))
81                 return;
82
83         ofono_handsfree_set_inband_ringing(hf, (ofono_bool_t) value);
84 }
85
86 static void bvra_notify(GAtResult *result, gpointer user_data)
87 {
88         struct ofono_handsfree *hf = user_data;
89         GAtResultIter iter;
90         int value;
91
92         g_at_result_iter_init(&iter, result);
93
94         if (!g_at_result_iter_next(&iter, "+BVRA:"))
95                 return;
96
97         if (!g_at_result_iter_next_number(&iter, &value))
98                 return;
99
100         ofono_handsfree_voice_recognition_notify(hf, (ofono_bool_t) value);
101 }
102
103 static void ciev_notify(GAtResult *result, gpointer user_data)
104 {
105         struct ofono_handsfree *hf = user_data;
106         struct hf_data *hd = ofono_handsfree_get_data(hf);
107         int index;
108         int value;
109         GAtResultIter iter;
110
111         g_at_result_iter_init(&iter, result);
112
113         if (!g_at_result_iter_next(&iter, "+CIEV:"))
114                 return;
115
116         if (!g_at_result_iter_next_number(&iter, &index))
117                 return;
118
119         if (index != hd->battchg_index)
120                 return;
121
122         if (!g_at_result_iter_next_number(&iter, &value))
123                 return;
124
125         ofono_handsfree_battchg_notify(hf, value);
126 }
127
128 static gboolean hfp_handsfree_register(gpointer user_data)
129 {
130         struct ofono_handsfree *hf = user_data;
131         struct hf_data *hd = ofono_handsfree_get_data(hf);
132
133         hd->register_source = 0;
134
135         g_at_chat_register(hd->chat, "+BSIR:", bsir_notify, FALSE, hf, NULL);
136         g_at_chat_register(hd->chat, "+BVRA:", bvra_notify, FALSE, hf, NULL);
137         g_at_chat_register(hd->chat, "+CIEV:", ciev_notify, FALSE, hf, NULL);
138
139         if (hd->ag_features & HFP_AG_FEATURE_IN_BAND_RING_TONE)
140                 ofono_handsfree_set_inband_ringing(hf, TRUE);
141
142         ofono_handsfree_set_ag_features(hf, hd->ag_features);
143         ofono_handsfree_set_ag_chld_features(hf, hd->ag_chld_features);
144         ofono_handsfree_register(hf);
145
146         return FALSE;
147 }
148
149 static int hfp_handsfree_probe(struct ofono_handsfree *hf,
150                                 unsigned int vendor, void *data)
151 {
152         struct hfp_slc_info *info = data;
153         struct hf_data *hd;
154
155         DBG("");
156         hd = g_new0(struct hf_data, 1);
157         hd->chat = g_at_chat_clone(info->chat);
158         hd->ag_features = info->ag_features;
159         hd->ag_chld_features = info->ag_mpty_features;
160
161         ofono_handsfree_set_data(hf, hd);
162
163         hd->battchg_index = info->cind_pos[HFP_INDICATOR_BATTCHG];
164         ofono_handsfree_battchg_notify(hf,
165                                         info->cind_val[HFP_INDICATOR_BATTCHG]);
166
167         hd->register_source = g_idle_add(hfp_handsfree_register, hf);
168
169         return 0;
170 }
171
172 static void hfp_handsfree_remove(struct ofono_handsfree *hf)
173 {
174         struct hf_data *hd = ofono_handsfree_get_data(hf);
175
176         if (hd->register_source != 0)
177                 g_source_remove(hd->register_source);
178
179         ofono_handsfree_set_data(hf, NULL);
180
181         g_at_chat_unref(hd->chat);
182         g_free(hd);
183 }
184
185 static void hfp_request_phone_number_cb(gboolean ok, GAtResult *result,
186                                         gpointer user_data)
187 {
188         struct cb_data *cbd = user_data;
189         ofono_handsfree_phone_cb_t cb = cbd->cb;
190         GAtResultIter iter;
191         struct ofono_error error;
192         const char *num;
193         int type;
194         struct ofono_phone_number phone_number;
195
196         decode_at_error(&error, g_at_result_final_response(result));
197
198         if (!ok) {
199                 cb(&error, NULL, cbd->data);
200                 return;
201         }
202
203         g_at_result_iter_init(&iter, result);
204
205         if (!g_at_result_iter_next(&iter, "+BINP:"))
206                 goto fail;
207
208         if (!g_at_result_iter_next_string(&iter, &num))
209                 goto fail;
210
211         if (!g_at_result_iter_next_number(&iter, &type))
212                 goto fail;
213
214         DBG("AT+BINP=1 response: %s %d", num, type);
215
216         strncpy(phone_number.number, num,
217                 OFONO_MAX_PHONE_NUMBER_LENGTH);
218         phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
219         phone_number.type = type;
220
221         cb(&error, &phone_number, cbd->data);
222         return;
223
224 fail:
225         CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
226 }
227
228 static void hfp_request_phone_number(struct ofono_handsfree *hf,
229                                         ofono_handsfree_phone_cb_t cb,
230                                         void *data)
231 {
232         struct hf_data *hd = ofono_handsfree_get_data(hf);
233         struct cb_data *cbd = cb_data_new(cb, data);
234
235         if (g_at_chat_send(hd->chat, "AT+BINP=1", binp_prefix,
236                                 hfp_request_phone_number_cb,
237                                 cbd, g_free) > 0)
238                 return;
239
240         g_free(cbd);
241
242         CALLBACK_WITH_FAILURE(cb, NULL, data);
243 }
244
245 static void hfp_voice_recognition(struct ofono_handsfree *hf,
246                                         ofono_bool_t enabled,
247                                         ofono_handsfree_cb_t cb, void *data)
248 {
249         struct hf_data *hd = ofono_handsfree_get_data(hf);
250         struct cb_data *cbd = cb_data_new(cb, data);
251         char buf[64];
252
253         snprintf(buf, sizeof(buf), "AT+BVRA=%d",
254                                 (int)(enabled));
255
256         if (g_at_chat_send(hd->chat, buf, bvra_prefix,
257                                 hf_generic_set_cb,
258                                 cbd, g_free) > 0)
259                 return;
260
261         g_free(cbd);
262
263         CALLBACK_WITH_FAILURE(cb, data);
264 }
265
266 static void hfp_disable_nrec(struct ofono_handsfree *hf,
267                                 ofono_handsfree_cb_t cb, void *data)
268 {
269         struct hf_data *hd = ofono_handsfree_get_data(hf);
270         struct cb_data *cbd = cb_data_new(cb, data);
271         const char *buf = "AT+NREC=0";
272
273         if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
274                                                         cbd, g_free) > 0)
275                 return;
276
277         g_free(cbd);
278
279         CALLBACK_WITH_FAILURE(cb, data);
280 }
281
282 static struct ofono_handsfree_driver driver = {
283         .name                   = "hfpmodem",
284         .probe                  = hfp_handsfree_probe,
285         .remove                 = hfp_handsfree_remove,
286         .request_phone_number   = hfp_request_phone_number,
287         .voice_recognition      = hfp_voice_recognition,
288         .disable_nrec           = hfp_disable_nrec,
289 };
290
291 void hfp_handsfree_init(void)
292 {
293         ofono_handsfree_driver_register(&driver);
294 }
295
296 void hfp_handsfree_exit(void)
297 {
298         ofono_handsfree_driver_unregister(&driver);
299 }