Upgrade ofono to 1.2
[profile/ivi/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 "slc.h"
44
45 static const char *binp_prefix[] = { "+BINP:", NULL };
46 static const char *bvra_prefix[] = { "+BVRA:", NULL };
47
48 struct hf_data {
49         GAtChat *chat;
50         unsigned int ag_features;
51         int battchg_index;
52         guint register_source;
53 };
54
55 static void hf_generic_set_cb(gboolean ok, GAtResult *result,
56                                 gpointer user_data)
57 {
58         struct cb_data *cbd = user_data;
59         ofono_handsfree_cb_t cb = cbd->cb;
60         struct ofono_error error;
61
62         decode_at_error(&error, g_at_result_final_response(result));
63
64         cb(&error, cbd->data);
65 }
66
67 static void bsir_notify(GAtResult *result, gpointer user_data)
68 {
69         struct ofono_handsfree *hf = user_data;
70         GAtResultIter iter;
71         int value;
72
73         g_at_result_iter_init(&iter, result);
74
75         if (!g_at_result_iter_next(&iter, "+BSIR:"))
76                 return;
77
78         if (!g_at_result_iter_next_number(&iter, &value))
79                 return;
80
81         ofono_handsfree_set_inband_ringing(hf, (ofono_bool_t) value);
82 }
83
84 static void bvra_notify(GAtResult *result, gpointer user_data)
85 {
86         struct ofono_handsfree *hf = user_data;
87         GAtResultIter iter;
88         int value;
89
90         g_at_result_iter_init(&iter, result);
91
92         if (!g_at_result_iter_next(&iter, "+BVRA:"))
93                 return;
94
95         if (!g_at_result_iter_next_number(&iter, &value))
96                 return;
97
98         ofono_handsfree_voice_recognition_notify(hf, (ofono_bool_t) value);
99 }
100
101 static void ciev_notify(GAtResult *result, gpointer user_data)
102 {
103         struct ofono_handsfree *hf = user_data;
104         struct hf_data *hd = ofono_handsfree_get_data(hf);
105         int index;
106         int value;
107         GAtResultIter iter;
108
109         g_at_result_iter_init(&iter, result);
110
111         if (!g_at_result_iter_next(&iter, "+CIEV:"))
112                 return;
113
114         if (!g_at_result_iter_next_number(&iter, &index))
115                 return;
116
117         if (index != hd->battchg_index)
118                 return;
119
120         if (!g_at_result_iter_next_number(&iter, &value))
121                 return;
122
123         ofono_handsfree_battchg_notify(hf, value);
124 }
125
126 static gboolean hfp_handsfree_register(gpointer user_data)
127 {
128         struct ofono_handsfree *hf = user_data;
129         struct hf_data *hd = ofono_handsfree_get_data(hf);
130
131         hd->register_source = 0;
132
133         g_at_chat_register(hd->chat, "+BSIR:", bsir_notify, FALSE, hf, NULL);
134         g_at_chat_register(hd->chat, "+BVRA:", bvra_notify, FALSE, hf, NULL);
135         g_at_chat_register(hd->chat, "+CIEV:", ciev_notify, FALSE, hf, NULL);
136
137         if (hd->ag_features & HFP_AG_FEATURE_IN_BAND_RING_TONE)
138                 ofono_handsfree_set_inband_ringing(hf, TRUE);
139
140         ofono_handsfree_set_ag_features(hf, hd->ag_features);
141         ofono_handsfree_register(hf);
142
143         return FALSE;
144 }
145
146 static int hfp_handsfree_probe(struct ofono_handsfree *hf,
147                                 unsigned int vendor, void *data)
148 {
149         struct hfp_slc_info *info = data;
150         struct hf_data *hd;
151
152         DBG("");
153         hd = g_new0(struct hf_data, 1);
154         hd->chat = g_at_chat_clone(info->chat);
155         hd->ag_features = info->ag_features;
156
157         ofono_handsfree_set_data(hf, hd);
158
159         hd->battchg_index = info->cind_pos[HFP_INDICATOR_BATTCHG];
160         ofono_handsfree_battchg_notify(hf,
161                                         info->cind_val[HFP_INDICATOR_BATTCHG]);
162
163         hd->register_source = g_idle_add(hfp_handsfree_register, hf);
164
165         return 0;
166 }
167
168 static void hfp_handsfree_remove(struct ofono_handsfree *hf)
169 {
170         struct hf_data *hd = ofono_handsfree_get_data(hf);
171
172         if (hd->register_source != 0)
173                 g_source_remove(hd->register_source);
174
175         ofono_handsfree_set_data(hf, NULL);
176
177         g_at_chat_unref(hd->chat);
178         g_free(hd);
179 }
180
181 static void hfp_request_phone_number_cb(gboolean ok, GAtResult *result,
182                                         gpointer user_data)
183 {
184         struct cb_data *cbd = user_data;
185         ofono_handsfree_phone_cb_t cb = cbd->cb;
186         GAtResultIter iter;
187         struct ofono_error error;
188         const char *num;
189         int type;
190         struct ofono_phone_number phone_number;
191
192         decode_at_error(&error, g_at_result_final_response(result));
193
194         if (!ok) {
195                 cb(&error, NULL, cbd->data);
196                 return;
197         }
198
199         g_at_result_iter_init(&iter, result);
200
201         if (!g_at_result_iter_next(&iter, "+BINP:"))
202                 goto fail;
203
204         if (!g_at_result_iter_next_string(&iter, &num))
205                 goto fail;
206
207         if (!g_at_result_iter_next_number(&iter, &type))
208                 goto fail;
209
210         DBG("AT+BINP=1 response: %s %d", num, type);
211
212         strncpy(phone_number.number, num,
213                 OFONO_MAX_PHONE_NUMBER_LENGTH);
214         phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
215         phone_number.type = type;
216
217         cb(&error, &phone_number, cbd->data);
218         return;
219
220 fail:
221         CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
222 }
223
224 static void hfp_request_phone_number(struct ofono_handsfree *hf,
225                                         ofono_handsfree_phone_cb_t cb,
226                                         void *data)
227 {
228         struct hf_data *hd = ofono_handsfree_get_data(hf);
229         struct cb_data *cbd = cb_data_new(cb, data);
230
231         if (g_at_chat_send(hd->chat, "AT+BINP=1", binp_prefix,
232                                 hfp_request_phone_number_cb,
233                                 cbd, g_free) > 0)
234                 return;
235
236         g_free(cbd);
237
238         CALLBACK_WITH_FAILURE(cb, NULL, data);
239 }
240
241 static void hfp_voice_recognition(struct ofono_handsfree *hf,
242                                         ofono_bool_t enabled,
243                                         ofono_handsfree_cb_t cb, void *data)
244 {
245         struct hf_data *hd = ofono_handsfree_get_data(hf);
246         struct cb_data *cbd = cb_data_new(cb, data);
247         char buf[64];
248
249         snprintf(buf, sizeof(buf), "AT+BVRA=%d",
250                                 (int)(enabled));
251
252         if (g_at_chat_send(hd->chat, buf, bvra_prefix,
253                                 hf_generic_set_cb,
254                                 cbd, g_free) > 0)
255                 return;
256
257         g_free(cbd);
258
259         CALLBACK_WITH_FAILURE(cb, data);
260 }
261
262 static struct ofono_handsfree_driver driver = {
263         .name                   = "hfpmodem",
264         .probe                  = hfp_handsfree_probe,
265         .remove                 = hfp_handsfree_remove,
266         .request_phone_number   = hfp_request_phone_number,
267         .voice_recognition      = hfp_voice_recognition,
268 };
269
270 void hfp_handsfree_init(void)
271 {
272         ofono_handsfree_driver_register(&driver);
273 }
274
275 void hfp_handsfree_exit(void)
276 {
277         ofono_handsfree_driver_unregister(&driver);
278 }