3 * oFono - Open Source Telephony
5 * Copyright (C) 2008-2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #define OFONO_API_SUBJECT_TO_CHANGE
32 #include <ofono/plugin.h>
33 #include <ofono/modem.h>
34 #include <ofono/devinfo.h>
35 #include <ofono/netreg.h>
36 #include <ofono/phonebook.h>
37 #include <ofono/voicecall.h>
38 #include <ofono/sim.h>
39 #include <ofono/stk.h>
40 #include <ofono/sms.h>
41 #include <ofono/ussd.h>
42 #include <ofono/gprs.h>
43 #include <ofono/gprs-context.h>
44 #include <ofono/radio-settings.h>
45 #include <ofono/location-reporting.h>
46 #include <ofono/log.h>
48 #include <drivers/qmimodem/qmi.h>
49 #include <drivers/qmimodem/dms.h>
50 #include <drivers/qmimodem/util.h>
52 #define GOBI_DMS (1 << 0)
53 #define GOBI_NAS (1 << 1)
54 #define GOBI_WMS (1 << 2)
55 #define GOBI_WDS (1 << 3)
56 #define GOBI_PDS (1 << 4)
57 #define GOBI_PBM (1 << 5)
58 #define GOBI_UIM (1 << 6)
59 #define GOBI_CAT (1 << 7)
60 #define GOBI_CAT_OLD (1 << 8)
61 #define GOBI_VOICE (1 << 9)
64 struct qmi_device *device;
65 struct qmi_service *dms;
66 unsigned long features;
67 unsigned int discover_attempts;
71 static void gobi_debug(const char *str, void *user_data)
73 const char *prefix = user_data;
75 ofono_info("%s%s", prefix, str);
78 static int gobi_probe(struct ofono_modem *modem)
80 struct gobi_data *data;
84 data = g_try_new0(struct gobi_data, 1);
88 ofono_modem_set_data(modem, data);
93 static void gobi_remove(struct ofono_modem *modem)
95 struct gobi_data *data = ofono_modem_get_data(modem);
99 ofono_modem_set_data(modem, NULL);
101 qmi_service_unref(data->dms);
103 qmi_device_unref(data->device);
108 static void shutdown_cb(void *user_data)
110 struct ofono_modem *modem = user_data;
111 struct gobi_data *data = ofono_modem_get_data(modem);
115 data->discover_attempts = 0;
117 qmi_device_unref(data->device);
120 ofono_modem_set_powered(modem, FALSE);
123 static void shutdown_device(struct ofono_modem *modem)
125 struct gobi_data *data = ofono_modem_get_data(modem);
129 qmi_service_unref(data->dms);
132 qmi_device_shutdown(data->device, shutdown_cb, modem, NULL);
135 static void power_reset_cb(struct qmi_result *result, void *user_data)
137 struct ofono_modem *modem = user_data;
141 if (qmi_result_set_error(result, NULL)) {
142 shutdown_device(modem);
146 ofono_modem_set_powered(modem, TRUE);
149 static void get_oper_mode_cb(struct qmi_result *result, void *user_data)
151 struct ofono_modem *modem = user_data;
152 struct gobi_data *data = ofono_modem_get_data(modem);
153 struct qmi_param *param;
158 if (qmi_result_set_error(result, NULL)) {
159 shutdown_device(modem);
163 if (!qmi_result_get_uint8(result, QMI_DMS_RESULT_OPER_MODE, &mode)) {
164 shutdown_device(modem);
168 data->oper_mode = mode;
170 switch (data->oper_mode) {
171 case QMI_DMS_OPER_MODE_ONLINE:
172 param = qmi_param_new_uint8(QMI_DMS_PARAM_OPER_MODE,
173 QMI_DMS_OPER_MODE_PERSIST_LOW_POWER);
175 shutdown_device(modem);
179 if (qmi_service_send(data->dms, QMI_DMS_SET_OPER_MODE, param,
180 power_reset_cb, modem, NULL) > 0)
183 shutdown_device(modem);
186 ofono_modem_set_powered(modem, TRUE);
191 static void get_caps_cb(struct qmi_result *result, void *user_data)
193 struct ofono_modem *modem = user_data;
194 struct gobi_data *data = ofono_modem_get_data(modem);
195 const struct qmi_dms_device_caps *caps;
201 if (qmi_result_set_error(result, NULL))
204 caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
208 DBG("service capabilities %d", caps->data_capa);
209 DBG("sim supported %d", caps->sim_supported);
211 for (i = 0; i < caps->radio_if_count; i++)
212 DBG("radio = %d", caps->radio_if[i]);
214 if (qmi_service_send(data->dms, QMI_DMS_GET_OPER_MODE, NULL,
215 get_oper_mode_cb, modem, NULL) > 0)
219 shutdown_device(modem);
222 static void create_dms_cb(struct qmi_service *service, void *user_data)
224 struct ofono_modem *modem = user_data;
225 struct gobi_data *data = ofono_modem_get_data(modem);
232 data->dms = qmi_service_ref(service);
234 if (qmi_service_send(data->dms, QMI_DMS_GET_CAPS, NULL,
235 get_caps_cb, modem, NULL) > 0)
239 shutdown_device(modem);
242 static void discover_cb(uint8_t count, const struct qmi_version *list,
245 struct ofono_modem *modem = user_data;
246 struct gobi_data *data = ofono_modem_get_data(modem);
251 for (i = 0; i < count; i++) {
252 DBG("%s %d.%d", list[i].name, list[i].major, list[i].minor);
254 switch (list[i].type) {
255 case QMI_SERVICE_DMS:
256 data->features |= GOBI_DMS;
258 case QMI_SERVICE_NAS:
259 data->features |= GOBI_NAS;
261 case QMI_SERVICE_WMS:
262 data->features |= GOBI_WMS;
264 case QMI_SERVICE_WDS:
265 data->features |= GOBI_WDS;
267 case QMI_SERVICE_PDS:
268 data->features |= GOBI_PDS;
270 case QMI_SERVICE_PBM:
271 data->features |= GOBI_PBM;
273 case QMI_SERVICE_CAT:
274 data->features |= GOBI_CAT;
276 case QMI_SERVICE_CAT_OLD:
277 if (list[i].major > 0)
278 data->features |= GOBI_CAT_OLD;
280 case QMI_SERVICE_VOICE:
281 data->features |= GOBI_VOICE;
286 if (!(data->features & GOBI_DMS)) {
287 if (++data->discover_attempts < 3) {
288 qmi_device_discover(data->device, discover_cb,
293 shutdown_device(modem);
297 qmi_service_create_shared(data->device, QMI_SERVICE_DMS,
298 create_dms_cb, modem, NULL);
301 static int gobi_enable(struct ofono_modem *modem)
303 struct gobi_data *data = ofono_modem_get_data(modem);
309 device = ofono_modem_get_string(modem, "Device");
313 fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
317 data->device = qmi_device_new(fd);
323 if (getenv("OFONO_QMI_DEBUG"))
324 qmi_device_set_debug(data->device, gobi_debug, "QMI: ");
326 qmi_device_set_close_on_unref(data->device, true);
328 qmi_device_discover(data->device, discover_cb, modem, NULL);
333 static void power_disable_cb(struct qmi_result *result, void *user_data)
335 struct ofono_modem *modem = user_data;
339 shutdown_device(modem);
342 static int gobi_disable(struct ofono_modem *modem)
344 struct gobi_data *data = ofono_modem_get_data(modem);
345 struct qmi_param *param;
349 qmi_service_cancel_all(data->dms);
350 qmi_service_unregister_all(data->dms);
352 param = qmi_param_new_uint8(QMI_DMS_PARAM_OPER_MODE,
353 QMI_DMS_OPER_MODE_PERSIST_LOW_POWER);
357 if (qmi_service_send(data->dms, QMI_DMS_SET_OPER_MODE, param,
358 power_disable_cb, modem, NULL) > 0)
361 shutdown_device(modem);
366 static void set_online_cb(struct qmi_result *result, void *user_data)
368 struct cb_data *cbd = user_data;
369 ofono_modem_online_cb_t cb = cbd->cb;
373 if (qmi_result_set_error(result, NULL))
374 CALLBACK_WITH_FAILURE(cb, cbd->data);
376 CALLBACK_WITH_SUCCESS(cb, cbd->data);
379 static void gobi_set_online(struct ofono_modem *modem, ofono_bool_t online,
380 ofono_modem_online_cb_t cb, void *user_data)
382 struct gobi_data *data = ofono_modem_get_data(modem);
383 struct cb_data *cbd = cb_data_new(cb, user_data);
384 struct qmi_param *param;
387 DBG("%p %s", modem, online ? "online" : "offline");
390 mode = QMI_DMS_OPER_MODE_ONLINE;
392 mode = QMI_DMS_OPER_MODE_LOW_POWER;
394 param = qmi_param_new_uint8(QMI_DMS_PARAM_OPER_MODE, mode);
398 if (qmi_service_send(data->dms, QMI_DMS_SET_OPER_MODE, param,
399 set_online_cb, cbd, g_free) > 0)
402 qmi_param_free(param);
405 CALLBACK_WITH_FAILURE(cb, cbd->data);
410 static void gobi_pre_sim(struct ofono_modem *modem)
412 struct gobi_data *data = ofono_modem_get_data(modem);
416 ofono_devinfo_create(modem, 0, "qmimodem", data->device);
418 if (data->features & GOBI_UIM)
419 ofono_sim_create(modem, 0, "qmimodem", data->device);
420 else if (data->features & GOBI_DMS)
421 ofono_sim_create(modem, 0, "qmimodem-legacy", data->device);
423 if (data->features & GOBI_VOICE)
424 ofono_voicecall_create(modem, 0, "qmimodem", data->device);
426 if (data->features & GOBI_PDS)
427 ofono_location_reporting_create(modem, 0, "qmimodem",
431 static void gobi_post_sim(struct ofono_modem *modem)
433 struct gobi_data *data = ofono_modem_get_data(modem);
437 if (data->features & GOBI_CAT)
438 ofono_stk_create(modem, 0, "qmimodem", data->device);
439 else if (data->features & GOBI_CAT_OLD)
440 ofono_stk_create(modem, 1, "qmimodem", data->device);
442 if (data->features & GOBI_PBM)
443 ofono_phonebook_create(modem, 0, "qmimodem", data->device);
445 if (data->features & GOBI_NAS)
446 ofono_radio_settings_create(modem, 0, "qmimodem", data->device);
448 if (data->features & GOBI_WMS)
449 ofono_sms_create(modem, 0, "qmimodem", data->device);
452 static void gobi_post_online(struct ofono_modem *modem)
454 struct gobi_data *data = ofono_modem_get_data(modem);
455 struct ofono_gprs *gprs;
456 struct ofono_gprs_context *gc;
460 if (data->features & GOBI_NAS)
461 ofono_netreg_create(modem, 0, "qmimodem", data->device);
463 if (data->features & GOBI_VOICE)
464 ofono_ussd_create(modem, 0, "qmimodem", data->device);
466 if (data->features & GOBI_WDS) {
467 gprs = ofono_gprs_create(modem, 0, "qmimodem", data->device);
468 gc = ofono_gprs_context_create(modem, 0, "qmimodem",
472 ofono_gprs_add_context(gprs, gc);
476 static struct ofono_modem_driver gobi_driver = {
479 .remove = gobi_remove,
480 .enable = gobi_enable,
481 .disable = gobi_disable,
482 .set_online = gobi_set_online,
483 .pre_sim = gobi_pre_sim,
484 .post_sim = gobi_post_sim,
485 .post_online = gobi_post_online,
488 static int gobi_init(void)
490 return ofono_modem_driver_register(&gobi_driver);
493 static void gobi_exit(void)
495 ofono_modem_driver_unregister(&gobi_driver);
498 OFONO_PLUGIN_DEFINE(gobi, "Qualcomm Gobi modem driver", VERSION,
499 OFONO_PLUGIN_PRIORITY_DEFAULT, gobi_init, gobi_exit)