Upgrade ofono to 1.11 and merge to 2.0alpha
[profile/ivi/ofono.git] / drivers / atmodem / gprs.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2010  ST-Ericsson AB.
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
33 #include <glib.h>
34
35 #include <ofono/log.h>
36 #include <ofono/modem.h>
37 #include <ofono/gprs.h>
38
39 #include "gatchat.h"
40 #include "gatresult.h"
41
42 #include "atmodem.h"
43 #include "vendor.h"
44
45 static const char *cgreg_prefix[] = { "+CGREG:", NULL };
46 static const char *cgdcont_prefix[] = { "+CGDCONT:", NULL };
47 static const char *none_prefix[] = { NULL };
48
49 struct gprs_data {
50         GAtChat *chat;
51         unsigned int vendor;
52 };
53
54 static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
55 {
56         struct cb_data *cbd = user_data;
57         ofono_gprs_cb_t cb = cbd->cb;
58         struct ofono_error error;
59
60         decode_at_error(&error, g_at_result_final_response(result));
61
62         cb(&error, cbd->data);
63 }
64
65 static void at_gprs_set_attached(struct ofono_gprs *gprs, int attached,
66                                         ofono_gprs_cb_t cb, void *data)
67 {
68         struct gprs_data *gd = ofono_gprs_get_data(gprs);
69         struct cb_data *cbd = cb_data_new(cb, data);
70         char buf[64];
71
72         snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
73
74         if (g_at_chat_send(gd->chat, buf, none_prefix,
75                                 at_cgatt_cb, cbd, g_free) > 0)
76                 return;
77
78         g_free(cbd);
79
80         CALLBACK_WITH_FAILURE(cb, data);
81 }
82
83 static void at_cgreg_cb(gboolean ok, GAtResult *result, gpointer user_data)
84 {
85         struct cb_data *cbd = user_data;
86         ofono_gprs_status_cb_t cb = cbd->cb;
87         struct ofono_error error;
88         int status;
89         struct gprs_data *gd = cbd->user;
90
91         decode_at_error(&error, g_at_result_final_response(result));
92
93         if (!ok) {
94                 cb(&error, -1, cbd->data);
95                 return;
96         }
97
98         if (at_util_parse_reg(result, "+CGREG:", NULL, &status,
99                                 NULL, NULL, NULL, gd->vendor) == FALSE) {
100                 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
101                 return;
102         }
103
104         cb(&error, status, cbd->data);
105 }
106
107 static void at_gprs_registration_status(struct ofono_gprs *gprs,
108                                         ofono_gprs_status_cb_t cb,
109                                         void *data)
110 {
111         struct gprs_data *gd = ofono_gprs_get_data(gprs);
112         struct cb_data *cbd = cb_data_new(cb, data);
113
114         cbd->user = gd;
115
116         switch (gd->vendor) {
117         case OFONO_VENDOR_GOBI:
118                 /*
119                  * Send *CNTI=0 to find out the current tech, it will be
120                  * intercepted in gobi_cnti_notify in network registration
121                  */
122                 g_at_chat_send(gd->chat, "AT*CNTI=0", none_prefix,
123                                 NULL, NULL, NULL);
124                 break;
125         case OFONO_VENDOR_NOVATEL:
126                 /*
127                  * Send $CNTI=0 to find out the current tech, it will be
128                  * intercepted in nw_cnti_notify in network registration
129                  */
130                 g_at_chat_send(gd->chat, "AT$CNTI=0", none_prefix,
131                                 NULL, NULL, NULL);
132                 break;
133         }
134
135         if (g_at_chat_send(gd->chat, "AT+CGREG?", cgreg_prefix,
136                                 at_cgreg_cb, cbd, g_free) > 0)
137                 return;
138
139         g_free(cbd);
140
141         CALLBACK_WITH_FAILURE(cb, -1, data);
142 }
143
144 static void cgreg_notify(GAtResult *result, gpointer user_data)
145 {
146         struct ofono_gprs *gprs = user_data;
147         int status;
148         struct gprs_data *gd = ofono_gprs_get_data(gprs);
149
150         if (at_util_parse_reg_unsolicited(result, "+CGREG:", &status,
151                                 NULL, NULL, NULL, gd->vendor) == FALSE)
152                 return;
153
154         ofono_gprs_status_notify(gprs, status);
155 }
156
157 static void cgev_notify(GAtResult *result, gpointer user_data)
158 {
159         struct ofono_gprs *gprs = user_data;
160         GAtResultIter iter;
161         const char *event;
162
163         g_at_result_iter_init(&iter, result);
164
165         if (!g_at_result_iter_next(&iter, "+CGEV:"))
166                 return;
167
168         if (!g_at_result_iter_next_unquoted_string(&iter, &event))
169                 return;
170
171         if (g_str_equal(event, "NW DETACH") ||
172                         g_str_equal(event, "ME DETACH")) {
173                 ofono_gprs_detached_notify(gprs);
174                 return;
175         }
176 }
177
178 static void xdatastat_notify(GAtResult *result, gpointer user_data)
179 {
180         struct ofono_gprs *gprs = user_data;
181         GAtResultIter iter;
182         int stat;
183
184         g_at_result_iter_init(&iter, result);
185
186         if (!g_at_result_iter_next(&iter, "+XDATASTAT:"))
187                 return;
188
189         if (!g_at_result_iter_next_number(&iter, &stat))
190
191         DBG("stat %d", stat);
192
193         switch (stat) {
194         case 0:
195                 ofono_gprs_suspend_notify(gprs, GPRS_SUSPENDED_UNKNOWN_CAUSE);
196                 break;
197         case 1:
198                 ofono_gprs_resume_notify(gprs);
199                 break;
200         }
201 }
202
203 static void huawei_mode_notify(GAtResult *result, gpointer user_data)
204 {
205         struct ofono_gprs *gprs = user_data;
206         GAtResultIter iter;
207         int mode, submode;
208         gint bearer;
209
210         g_at_result_iter_init(&iter, result);
211
212         if (!g_at_result_iter_next(&iter, "^MODE:"))
213                 return;
214
215         if (!g_at_result_iter_next_number(&iter, &mode))
216                 return;
217
218         if (!g_at_result_iter_next_number(&iter, &submode))
219                 return;
220
221         switch (submode) {
222         case 1:
223         case 2:
224                 bearer = 1;     /* GPRS */
225                 break;
226         case 3:
227                 bearer = 2;     /* EDGE */
228                 break;
229         case 4:
230                 bearer = 3;     /* UMTS */
231                 break;
232         case 5:
233                 bearer = 5;     /* HSDPA */
234                 break;
235         case 6:
236                 bearer = 4;     /* HSUPA */
237                 break;
238         case 7:
239         case 9:
240                 bearer = 6;     /* HSUPA + HSDPA */
241                 break;
242         default:
243                 bearer = 0;
244                 break;
245         }
246
247         ofono_gprs_bearer_notify(gprs, bearer);
248 }
249
250 static void telit_mode_notify(GAtResult *result, gpointer user_data)
251 {
252         struct ofono_gprs *gprs = user_data;
253         GAtResultIter iter;
254         gint nt, bearer;
255
256         g_at_result_iter_init(&iter, result);
257
258         if (!g_at_result_iter_next(&iter, "#PSNT:"))
259                 return;
260
261         if (!g_at_result_iter_next_number(&iter,&nt))
262                 return;
263
264         switch (nt) {
265         case 0:
266                 bearer = 1;    /* GPRS */
267                 break;
268         case 1:
269                 bearer = 2;    /* EDGE */
270                 break;
271         case 2:
272                 bearer = 3;    /* UMTS */
273                 break;
274         case 3:
275                 bearer = 5;    /* HSDPA */
276                 break;
277         default:
278                 bearer = 0;
279                 break;
280         }
281
282         ofono_gprs_bearer_notify(gprs, bearer);
283 }
284
285 static void cpsb_notify(GAtResult *result, gpointer user_data)
286 {
287         struct ofono_gprs *gprs = user_data;
288         GAtResultIter iter;
289         gint bearer;
290
291         g_at_result_iter_init(&iter, result);
292
293         if (!g_at_result_iter_next(&iter, "+CPSB:"))
294                 return;
295
296         if (!g_at_result_iter_next_number(&iter, NULL))
297                 return;
298
299         if (!g_at_result_iter_next_number(&iter, &bearer))
300                 return;
301
302         ofono_gprs_bearer_notify(gprs, bearer);
303 }
304
305 static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
306 {
307         struct ofono_gprs *gprs = user_data;
308         struct gprs_data *gd = ofono_gprs_get_data(gprs);
309
310         g_at_chat_register(gd->chat, "+CGEV:", cgev_notify, FALSE, gprs, NULL);
311         g_at_chat_register(gd->chat, "+CGREG:", cgreg_notify,
312                                                 FALSE, gprs, NULL);
313
314         switch (gd->vendor) {
315         case OFONO_VENDOR_HUAWEI:
316                 g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
317                                                 FALSE, gprs, NULL);
318                 break;
319         case OFONO_VENDOR_TELIT:
320                 g_at_chat_register(gd->chat, "#PSNT:", telit_mode_notify,
321                                                 FALSE, gprs, NULL);
322                 g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
323                                                 NULL, NULL, NULL);
324         default:
325                 g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
326                                                 FALSE, gprs, NULL);
327                 g_at_chat_send(gd->chat, "AT+CPSB=1", none_prefix,
328                                                 NULL, NULL, NULL);
329                 break;
330         }
331
332         switch (gd->vendor) {
333         case OFONO_VENDOR_IFX:
334                 /* Register for GPRS suspend notifications */
335                 g_at_chat_register(gd->chat, "+XDATASTAT:", xdatastat_notify,
336                                                 FALSE, gprs, NULL);
337                 g_at_chat_send(gd->chat, "AT+XDATASTAT=1", none_prefix,
338                                                 NULL, NULL, NULL);
339                 break;
340         }
341
342         ofono_gprs_register(gprs);
343 }
344
345 static void at_cgreg_test_cb(gboolean ok, GAtResult *result,
346                                 gpointer user_data)
347 {
348         struct ofono_gprs *gprs = user_data;
349         struct gprs_data *gd = ofono_gprs_get_data(gprs);
350         gint range[2];
351         GAtResultIter iter;
352         int cgreg1 = 0;
353         int cgreg2 = 0;
354         const char *cmd;
355
356         if (!ok)
357                 goto error;
358
359         g_at_result_iter_init(&iter, result);
360
361 retry:
362         if (!g_at_result_iter_next(&iter, "+CGREG:"))
363                 goto error;
364
365         if (!g_at_result_iter_open_list(&iter))
366                 goto retry;
367
368         while (g_at_result_iter_next_range(&iter, &range[0], &range[1])) {
369                 if (1 >= range[0] && 1 <= range[1])
370                         cgreg1 = 1;
371                 if (2 >= range[0] && 2 <= range[1])
372                         cgreg2 = 1;
373         }
374
375         g_at_result_iter_close_list(&iter);
376
377         if (cgreg2)
378                 cmd = "AT+CGREG=2";
379         else if (cgreg1)
380                 cmd = "AT+CGREG=1";
381         else
382                 goto error;
383
384         g_at_chat_send(gd->chat, cmd, none_prefix, NULL, NULL, NULL);
385         g_at_chat_send(gd->chat, "AT+CGAUTO=0", none_prefix, NULL, NULL, NULL);
386
387         switch (gd->vendor) {
388         case OFONO_VENDOR_MBM:
389                 /* Ericsson MBM and ST-E modems don't support AT+CGEREP=2,1 */
390                 g_at_chat_send(gd->chat, "AT+CGEREP=1,0", none_prefix,
391                         gprs_initialized, gprs, NULL);
392                 break;
393         case OFONO_VENDOR_NOKIA:
394                 /* Nokia data cards don't support AT+CGEREP=1,0 either */
395                 g_at_chat_send(gd->chat, "AT+CGEREP=1", none_prefix,
396                         gprs_initialized, gprs, NULL);
397                 break;
398         default:
399                 g_at_chat_send(gd->chat, "AT+CGEREP=2,1", none_prefix,
400                         gprs_initialized, gprs, NULL);
401                 break;
402         }
403
404         return;
405
406 error:
407         ofono_info("GPRS not supported on this device");
408         ofono_gprs_remove(gprs);
409 }
410
411 static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
412                                 gpointer user_data)
413 {
414         struct ofono_gprs *gprs = user_data;
415         struct gprs_data *gd = ofono_gprs_get_data(gprs);
416         GAtResultIter iter;
417         int min, max;
418         const char *pdp_type;
419         gboolean found = FALSE;
420
421         if (!ok)
422                 goto error;
423
424         g_at_result_iter_init(&iter, result);
425
426         while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
427                 gboolean in_list = FALSE;
428
429                 if (!g_at_result_iter_open_list(&iter))
430                         continue;
431
432                 if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
433                         continue;
434
435                 if (!g_at_result_iter_close_list(&iter))
436                         continue;
437
438                 if (g_at_result_iter_open_list(&iter))
439                         in_list = TRUE;
440
441                 if (!g_at_result_iter_next_string(&iter, &pdp_type))
442                         continue;
443
444                 if (in_list && !g_at_result_iter_close_list(&iter))
445                         continue;
446
447                 /* We look for IP PDPs */
448                 if (g_str_equal(pdp_type, "IP"))
449                         found = TRUE;
450         }
451
452         if (found == FALSE)
453                 goto error;
454
455         ofono_gprs_set_cid_range(gprs, min, max);
456
457         g_at_chat_send(gd->chat, "AT+CGREG=?", cgreg_prefix,
458                         at_cgreg_test_cb, gprs, NULL);
459
460         return;
461
462 error:
463         ofono_info("GPRS not supported on this device");
464         ofono_gprs_remove(gprs);
465 }
466
467 static int at_gprs_probe(struct ofono_gprs *gprs,
468                                         unsigned int vendor, void *data)
469 {
470         GAtChat *chat = data;
471         struct gprs_data *gd;
472
473         gd = g_try_new0(struct gprs_data, 1);
474         if (gd == NULL)
475                 return -ENOMEM;
476
477         gd->chat = g_at_chat_clone(chat);
478         gd->vendor = vendor;
479
480         ofono_gprs_set_data(gprs, gd);
481
482         g_at_chat_send(gd->chat, "AT+CGDCONT=?", cgdcont_prefix,
483                         at_cgdcont_test_cb, gprs, NULL);
484
485         return 0;
486 }
487
488 static void at_gprs_remove(struct ofono_gprs *gprs)
489 {
490         struct gprs_data *gd = ofono_gprs_get_data(gprs);
491
492         ofono_gprs_set_data(gprs, NULL);
493
494         g_at_chat_unref(gd->chat);
495         g_free(gd);
496 }
497
498 static struct ofono_gprs_driver driver = {
499         .name                   = "atmodem",
500         .probe                  = at_gprs_probe,
501         .remove                 = at_gprs_remove,
502         .set_attached           = at_gprs_set_attached,
503         .attached_status        = at_gprs_registration_status,
504 };
505
506 void at_gprs_init(void)
507 {
508         ofono_gprs_driver_register(&driver);
509 }
510
511 void at_gprs_exit(void)
512 {
513         ofono_gprs_driver_unregister(&driver);
514 }