3 * oFono - Open Source Telephony
5 * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
6 * Copyright (C) 2010 ST-Ericsson AB.
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.
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.
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
35 #include <ofono/log.h>
36 #include <ofono/modem.h>
37 #include <ofono/gprs.h>
40 #include "gatresult.h"
45 static const char *cgreg_prefix[] = { "+CGREG:", NULL };
46 static const char *cgdcont_prefix[] = { "+CGDCONT:", NULL };
47 static const char *none_prefix[] = { NULL };
54 static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
56 struct cb_data *cbd = user_data;
57 ofono_gprs_cb_t cb = cbd->cb;
58 struct ofono_error error;
60 decode_at_error(&error, g_at_result_final_response(result));
62 cb(&error, cbd->data);
65 static void at_gprs_set_attached(struct ofono_gprs *gprs, int attached,
66 ofono_gprs_cb_t cb, void *data)
68 struct gprs_data *gd = ofono_gprs_get_data(gprs);
69 struct cb_data *cbd = cb_data_new(cb, data);
72 snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
74 if (g_at_chat_send(gd->chat, buf, none_prefix,
75 at_cgatt_cb, cbd, g_free) > 0)
80 CALLBACK_WITH_FAILURE(cb, data);
83 static void at_cgreg_cb(gboolean ok, GAtResult *result, gpointer user_data)
85 struct cb_data *cbd = user_data;
86 ofono_gprs_status_cb_t cb = cbd->cb;
87 struct ofono_error error;
89 struct gprs_data *gd = cbd->user;
91 decode_at_error(&error, g_at_result_final_response(result));
94 cb(&error, -1, cbd->data);
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);
104 cb(&error, status, cbd->data);
107 static void at_gprs_registration_status(struct ofono_gprs *gprs,
108 ofono_gprs_status_cb_t cb,
111 struct gprs_data *gd = ofono_gprs_get_data(gprs);
112 struct cb_data *cbd = cb_data_new(cb, data);
116 switch (gd->vendor) {
117 case OFONO_VENDOR_GOBI:
119 * Send *CNTI=0 to find out the current tech, it will be
120 * intercepted in gobi_cnti_notify in network registration
122 g_at_chat_send(gd->chat, "AT*CNTI=0", none_prefix,
125 case OFONO_VENDOR_NOVATEL:
127 * Send $CNTI=0 to find out the current tech, it will be
128 * intercepted in nw_cnti_notify in network registration
130 g_at_chat_send(gd->chat, "AT$CNTI=0", none_prefix,
135 if (g_at_chat_send(gd->chat, "AT+CGREG?", cgreg_prefix,
136 at_cgreg_cb, cbd, g_free) > 0)
141 CALLBACK_WITH_FAILURE(cb, -1, data);
144 static void cgreg_notify(GAtResult *result, gpointer user_data)
146 struct ofono_gprs *gprs = user_data;
148 struct gprs_data *gd = ofono_gprs_get_data(gprs);
150 if (at_util_parse_reg_unsolicited(result, "+CGREG:", &status,
151 NULL, NULL, NULL, gd->vendor) == FALSE)
154 ofono_gprs_status_notify(gprs, status);
157 static void cgev_notify(GAtResult *result, gpointer user_data)
159 struct ofono_gprs *gprs = user_data;
163 g_at_result_iter_init(&iter, result);
165 if (!g_at_result_iter_next(&iter, "+CGEV:"))
168 if (!g_at_result_iter_next_unquoted_string(&iter, &event))
171 if (g_str_equal(event, "NW DETACH") ||
172 g_str_equal(event, "ME DETACH")) {
173 ofono_gprs_detached_notify(gprs);
178 static void xdatastat_notify(GAtResult *result, gpointer user_data)
180 struct ofono_gprs *gprs = user_data;
184 g_at_result_iter_init(&iter, result);
186 if (!g_at_result_iter_next(&iter, "+XDATASTAT:"))
189 if (!g_at_result_iter_next_number(&iter, &stat))
191 DBG("stat %d", stat);
195 ofono_gprs_suspend_notify(gprs, GPRS_SUSPENDED_UNKNOWN_CAUSE);
198 ofono_gprs_resume_notify(gprs);
203 static void huawei_mode_notify(GAtResult *result, gpointer user_data)
205 struct ofono_gprs *gprs = user_data;
210 g_at_result_iter_init(&iter, result);
212 if (!g_at_result_iter_next(&iter, "^MODE:"))
215 if (!g_at_result_iter_next_number(&iter, &mode))
218 if (!g_at_result_iter_next_number(&iter, &submode))
224 bearer = 1; /* GPRS */
227 bearer = 2; /* EDGE */
230 bearer = 3; /* UMTS */
233 bearer = 5; /* HSDPA */
236 bearer = 4; /* HSUPA */
240 bearer = 6; /* HSUPA + HSDPA */
247 ofono_gprs_bearer_notify(gprs, bearer);
250 static void telit_mode_notify(GAtResult *result, gpointer user_data)
252 struct ofono_gprs *gprs = user_data;
256 g_at_result_iter_init(&iter, result);
258 if (!g_at_result_iter_next(&iter, "#PSNT:"))
261 if (!g_at_result_iter_next_number(&iter,&nt))
266 bearer = 1; /* GPRS */
269 bearer = 2; /* EDGE */
272 bearer = 3; /* UMTS */
275 bearer = 5; /* HSDPA */
282 ofono_gprs_bearer_notify(gprs, bearer);
285 static void cpsb_notify(GAtResult *result, gpointer user_data)
287 struct ofono_gprs *gprs = user_data;
291 g_at_result_iter_init(&iter, result);
293 if (!g_at_result_iter_next(&iter, "+CPSB:"))
296 if (!g_at_result_iter_next_number(&iter, NULL))
299 if (!g_at_result_iter_next_number(&iter, &bearer))
302 ofono_gprs_bearer_notify(gprs, bearer);
305 static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
307 struct ofono_gprs *gprs = user_data;
308 struct gprs_data *gd = ofono_gprs_get_data(gprs);
310 g_at_chat_register(gd->chat, "+CGEV:", cgev_notify, FALSE, gprs, NULL);
311 g_at_chat_register(gd->chat, "+CGREG:", cgreg_notify,
314 switch (gd->vendor) {
315 case OFONO_VENDOR_HUAWEI:
316 g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
319 case OFONO_VENDOR_TELIT:
320 g_at_chat_register(gd->chat, "#PSNT:", telit_mode_notify,
322 g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
325 g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
327 g_at_chat_send(gd->chat, "AT+CPSB=1", none_prefix,
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,
337 g_at_chat_send(gd->chat, "AT+XDATASTAT=1", none_prefix,
342 ofono_gprs_register(gprs);
345 static void at_cgreg_test_cb(gboolean ok, GAtResult *result,
348 struct ofono_gprs *gprs = user_data;
349 struct gprs_data *gd = ofono_gprs_get_data(gprs);
359 g_at_result_iter_init(&iter, result);
362 if (!g_at_result_iter_next(&iter, "+CGREG:"))
365 if (!g_at_result_iter_open_list(&iter))
368 while (g_at_result_iter_next_range(&iter, &range[0], &range[1])) {
369 if (1 >= range[0] && 1 <= range[1])
371 if (2 >= range[0] && 2 <= range[1])
375 g_at_result_iter_close_list(&iter);
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);
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);
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);
399 g_at_chat_send(gd->chat, "AT+CGEREP=2,1", none_prefix,
400 gprs_initialized, gprs, NULL);
407 ofono_info("GPRS not supported on this device");
408 ofono_gprs_remove(gprs);
411 static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
414 struct ofono_gprs *gprs = user_data;
415 struct gprs_data *gd = ofono_gprs_get_data(gprs);
418 const char *pdp_type;
419 gboolean found = FALSE;
424 g_at_result_iter_init(&iter, result);
426 while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
427 gboolean in_list = FALSE;
429 if (!g_at_result_iter_open_list(&iter))
432 if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
435 if (!g_at_result_iter_close_list(&iter))
438 if (g_at_result_iter_open_list(&iter))
441 if (!g_at_result_iter_next_string(&iter, &pdp_type))
444 if (in_list && !g_at_result_iter_close_list(&iter))
447 /* We look for IP PDPs */
448 if (g_str_equal(pdp_type, "IP"))
455 ofono_gprs_set_cid_range(gprs, min, max);
457 g_at_chat_send(gd->chat, "AT+CGREG=?", cgreg_prefix,
458 at_cgreg_test_cb, gprs, NULL);
463 ofono_info("GPRS not supported on this device");
464 ofono_gprs_remove(gprs);
467 static int at_gprs_probe(struct ofono_gprs *gprs,
468 unsigned int vendor, void *data)
470 GAtChat *chat = data;
471 struct gprs_data *gd;
473 gd = g_try_new0(struct gprs_data, 1);
477 gd->chat = g_at_chat_clone(chat);
480 ofono_gprs_set_data(gprs, gd);
482 g_at_chat_send(gd->chat, "AT+CGDCONT=?", cgdcont_prefix,
483 at_cgdcont_test_cb, gprs, NULL);
488 static void at_gprs_remove(struct ofono_gprs *gprs)
490 struct gprs_data *gd = ofono_gprs_get_data(gprs);
492 ofono_gprs_set_data(gprs, NULL);
494 g_at_chat_unref(gd->chat);
498 static struct ofono_gprs_driver driver = {
500 .probe = at_gprs_probe,
501 .remove = at_gprs_remove,
502 .set_attached = at_gprs_set_attached,
503 .attached_status = at_gprs_registration_status,
506 void at_gprs_init(void)
508 ofono_gprs_driver_register(&driver);
511 void at_gprs_exit(void)
513 ofono_gprs_driver_unregister(&driver);