[PATCH 1/2] lte.h: added ofono_lte_get_modem global function
by Giacinto Cifelli
this function can be used in the drivers to query the functions
ofono_modem_get_* to retrieve modem-specific properties
---
include/lte.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/lte.h b/include/lte.h
index ef84ab99..0f2501c0 100644
--- a/include/lte.h
+++ b/include/lte.h
@@ -61,6 +61,8 @@ void ofono_lte_set_data(struct ofono_lte *lte, void *data);
void *ofono_lte_get_data(const struct ofono_lte *lte);
+struct ofono_modem *ofono_lte_get_modem(const struct ofono_lte *lte);
+
#ifdef __cplusplus
}
#endif
--
2.17.1
2 years, 4 months
[PATCH] mbim driver: call the release function in case MBIM OPEN fails
by Giacinto Cifelli
---
drivers/mbimmodem/mbim.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mbimmodem/mbim.c b/drivers/mbimmodem/mbim.c
index 9fcf44b..f4132d0 100644
--- a/drivers/mbimmodem/mbim.c
+++ b/drivers/mbimmodem/mbim.c
@@ -781,6 +781,9 @@ static bool open_read_handler(struct l_io *io, void *user_data)
/* Grab OPEN_DONE Status field */
if (l_get_le32(buf) != 0) {
close(fd);
+ if (device->disconnect_handler)
+ device->disconnect_handler(device->ready_data);
+ device->is_ready = false;
return false;
}
--
1.9.1
2 years, 4 months
[PATCH 1/4] gprs: added two authentication methods: NONE and ANY
by Giacinto Cifelli
OFONO_GPRS_AUTH_METHOD_NONE disables the authentication
OFONO_GPRS_AUTH_METHOD_ANY tries first CHAP then PAP,
but only applies to supporting drivers and modules
---
include/gprs-context.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/gprs-context.h b/include/gprs-context.h
index 20ca9ef..7e1dfcc 100644
--- a/include/gprs-context.h
+++ b/include/gprs-context.h
@@ -55,7 +55,9 @@ enum ofono_gprs_context_type {
};
enum ofono_gprs_auth_method {
- OFONO_GPRS_AUTH_METHOD_CHAP = 0,
+ OFONO_GPRS_AUTH_METHOD_ANY = 0,
+ OFONO_GPRS_AUTH_METHOD_NONE,
+ OFONO_GPRS_AUTH_METHOD_CHAP,
OFONO_GPRS_AUTH_METHOD_PAP,
};
--
1.9.1
2 years, 4 months
[PATCH 1/2] gemaltomodem: added voicecall atom
by Giacinto Cifelli
---
drivers/gemaltomodem/gemaltomodem.c | 3 +-
drivers/gemaltomodem/gemaltomodem.h | 3 +
drivers/gemaltomodem/voicecall.c | 965 ++++++++++++++++++++++++++++++++++++
3 files changed, 970 insertions(+), 1 deletion(-)
create mode 100644 drivers/gemaltomodem/voicecall.c
diff --git a/drivers/gemaltomodem/gemaltomodem.c b/drivers/gemaltomodem/gemaltomodem.c
index 91cf238..614ca81 100644
--- a/drivers/gemaltomodem/gemaltomodem.c
+++ b/drivers/gemaltomodem/gemaltomodem.c
@@ -35,13 +35,14 @@
static int gemaltomodem_init(void)
{
gemalto_location_reporting_init();
-
+ gemalto_voicecall_init();
return 0;
}
static void gemaltomodem_exit(void)
{
gemalto_location_reporting_exit();
+ gemalto_voicecall_exit();
}
OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
diff --git a/drivers/gemaltomodem/gemaltomodem.h b/drivers/gemaltomodem/gemaltomodem.h
index 7ea1e8f..4e6ed16 100644
--- a/drivers/gemaltomodem/gemaltomodem.h
+++ b/drivers/gemaltomodem/gemaltomodem.h
@@ -23,3 +23,6 @@
extern void gemalto_location_reporting_init();
extern void gemalto_location_reporting_exit();
+
+extern void gemalto_voicecall_init();
+extern void gemalto_voicecall_exit();
diff --git a/drivers/gemaltomodem/voicecall.c b/drivers/gemaltomodem/voicecall.c
new file mode 100644
index 0000000..2a2af0d
--- /dev/null
+++ b/drivers/gemaltomodem/voicecall.c
@@ -0,0 +1,965 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/voicecall.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "common.h"
+
+#include "gemaltomodem.h"
+
+static const char *clcc_prefix[] = { "+CLCC:", NULL };
+static const char *none_prefix[] = { NULL };
+
+/* According to 27.007 COLP is an intermediate status for ATD */
+static const char *atd_prefix[] = { "+COLP:", NULL };
+
+#define FLAG_NEED_CLIP 1
+
+struct voicecall_data {
+ GAtChat *chat;
+ GSList *calls;
+ unsigned int local_release;
+ unsigned int vendor;
+ unsigned char flags;
+};
+
+struct release_id_req {
+ struct ofono_voicecall *vc;
+ ofono_voicecall_cb_t cb;
+ void *data;
+ int id;
+};
+
+struct change_state_req {
+ struct ofono_voicecall *vc;
+ ofono_voicecall_cb_t cb;
+ void *data;
+ int affected_types;
+};
+
+static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct change_state_req *req = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(req->vc);
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (ok && req->affected_types) {
+ GSList *l;
+ struct ofono_call *call;
+
+ for (l = vd->calls; l; l = l->next) {
+ call = l->data;
+
+ if (req->affected_types & (1 << call->status))
+ vd->local_release |= (1 << call->id);
+ }
+ }
+
+ req->cb(&error, req->data);
+}
+
+static void gemalto_template(const char *cmd, struct ofono_voicecall *vc,
+ GAtResultFunc result_cb, unsigned int affected_types,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ struct change_state_req *req = g_try_new0(struct change_state_req, 1);
+
+ if (req == NULL)
+ goto error;
+
+ req->vc = vc;
+ req->cb = cb;
+ req->data = data;
+ req->affected_types = affected_types;
+
+ if (g_at_chat_send(vd->chat, cmd, none_prefix,
+ result_cb, req, g_free) > 0)
+ return;
+
+error:
+ g_free(req);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void gemalto_answer(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ gemalto_template("ATA", vc, generic_cb, 0, cb, data);
+}
+
+static void gemalto_hangup_all(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ unsigned int affected = (1 << CALL_STATUS_INCOMING) |
+ (1 << CALL_STATUS_DIALING) |
+ (1 << CALL_STATUS_ALERTING) |
+ (1 << CALL_STATUS_WAITING) |
+ (1 << CALL_STATUS_HELD) |
+ (1 << CALL_STATUS_ACTIVE);
+
+ /* Hangup all calls */
+ gemalto_template("AT+CHUP", vc, generic_cb, affected, cb, data);
+}
+
+static void gemalto_hangup(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ unsigned int affected = (1 << CALL_STATUS_ACTIVE);
+
+ /* Hangup current active call */
+ gemalto_template("AT+CHLD=1", vc, generic_cb, affected, cb, data);
+}
+
+static void gemalto_hold_all_active(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ unsigned int affected = (1 << CALL_STATUS_ACTIVE);
+ gemalto_template("AT+CHLD=2", vc, generic_cb, affected, cb, data);
+}
+
+static void gemalto_release_all_held(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ unsigned int affected = (1 << CALL_STATUS_INCOMING) |
+ (1 << CALL_STATUS_WAITING);
+
+ gemalto_template("AT+CHLD=0", vc, generic_cb, affected, cb, data);
+}
+
+static void gemalto_set_udub(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ unsigned int affected = (1 << CALL_STATUS_INCOMING) |
+ (1 << CALL_STATUS_WAITING);
+
+ gemalto_template("AT+CHLD=0", vc, generic_cb, affected, cb, data);
+}
+
+static void gemalto_release_all_active(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ unsigned int affected = (1 << CALL_STATUS_ACTIVE);
+
+ gemalto_template("AT+CHLD=1", vc, generic_cb, affected, cb, data);
+}
+
+static void release_id_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct release_id_req *req = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(req->vc);
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (ok)
+ vd->local_release = 1 << req->id;
+
+ req->cb(&error, req->data);
+}
+
+static void gemalto_release_specific(struct ofono_voicecall *vc, int id,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ struct release_id_req *req = g_try_new0(struct release_id_req, 1);
+ char buf[32];
+
+ if (req == NULL)
+ goto error;
+
+ req->vc = vc;
+ req->cb = cb;
+ req->data = data;
+ req->id = id;
+
+ snprintf(buf, sizeof(buf), "AT+CHLD=1%d", id);
+
+ if (g_at_chat_send(vd->chat, buf, none_prefix,
+ release_id_cb, req, g_free) > 0)
+ return;
+
+error:
+ g_free(req);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void gemalto_private_chat(struct ofono_voicecall *vc, int id,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "AT+CHLD=2%d", id);
+ gemalto_template(buf, vc, generic_cb, 0, cb, data);
+}
+
+static void gemalto_create_multiparty(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ gemalto_template("AT+CHLD=3", vc, generic_cb, 0, cb, data);
+}
+
+static void gemalto_transfer(struct ofono_voicecall *vc,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ /* Held & Active */
+ unsigned int affected = (1 << CALL_STATUS_ACTIVE) |
+ (1 << CALL_STATUS_HELD);
+
+ /* Transfer can puts held & active calls together and disconnects
+ * from both. However, some networks support transferring of
+ * dialing/ringing calls as well.
+ */
+ affected |= (1 << CALL_STATUS_DIALING) |
+ (1 << CALL_STATUS_ALERTING);
+
+ gemalto_template("AT+CHLD=4", vc, generic_cb, affected, cb, data);
+}
+
+static void gemalto_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
+ ofono_voicecall_cb_t cb, void *data)
+{
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ int len = strlen(dtmf);
+ int s;
+ int i;
+ char *buf;
+ struct ofono_modem *modem = ofono_voicecall_get_modem(vc);
+ int use_quotes = ofono_modem_get_integer(modem, "Gemalto_VTS_quotes");
+
+ /* strlen("+VTS=\"T\";") = 9 + initial AT + null */
+ buf = g_try_new(char, len * 9 + 3);
+
+ if (buf == NULL) {
+ CALLBACK_WITH_FAILURE(cb, data);
+ return;
+ }
+
+ if (use_quotes)
+ s = sprintf(buf, "AT+VTS=\"%c\"", dtmf[0]);
+ else
+ s = sprintf(buf, "AT+VTS=%c", dtmf[0]);
+
+ for (i = 1; i < len; i++) {
+
+ if (use_quotes)
+ s += sprintf(buf + s, ";+VTS=\"%c\"", dtmf[i]);
+ else
+ s += sprintf(buf + s, ";+VTS=%c", dtmf[i]);
+ }
+
+ g_at_chat_send(vd->chat, buf, NULL, NULL, NULL, NULL);
+ g_free(buf);
+}
+
+static struct ofono_call *create_call(struct ofono_voicecall *vc, int type,
+ int direction, int status,
+ const char *num, int num_type, int clip)
+{
+ struct voicecall_data *d = ofono_voicecall_get_data(vc);
+ struct ofono_call *call;
+
+ /* Generate a call structure for the waiting call */
+ call = g_try_new(struct ofono_call, 1);
+ if (call == NULL)
+ return NULL;
+
+ ofono_call_init(call);
+
+ call->id = ofono_voicecall_get_next_callid(vc);
+ call->type = type;
+ call->direction = direction;
+ call->status = status;
+
+ if (clip != 2) {
+ strncpy(call->phone_number.number, num,
+ OFONO_MAX_PHONE_NUMBER_LENGTH);
+ call->phone_number.type = num_type;
+ }
+
+ call->clip_validity = clip;
+ call->cnap_validity = CNAP_VALIDITY_NOT_AVAILABLE;
+
+ d->calls = g_slist_insert_sorted(d->calls, call, at_util_call_compare);
+
+ return call;
+}
+
+static void atd_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ struct ofono_voicecall *vc = cbd->user;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ ofono_voicecall_cb_t cb = cbd->cb;
+ GAtResultIter iter;
+ const char *num;
+ int type = 128;
+ int validity = 2;
+ struct ofono_error error;
+ struct ofono_call *call;
+ GSList *l;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok)
+ goto out;
+
+ /* On a success, make sure to put all active calls on hold */
+ for (l = vd->calls; l; l = l->next) {
+ call = l->data;
+
+ if (call->status != CALL_STATUS_ACTIVE)
+ continue;
+
+ call->status = CALL_STATUS_HELD;
+ ofono_voicecall_notify(vc, call);
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ if (g_at_result_iter_next(&iter, "+COLP:")) {
+ g_at_result_iter_next_string(&iter, &num);
+ g_at_result_iter_next_number(&iter, &type);
+
+ if (strlen(num) > 0)
+ validity = 0;
+ else
+ validity = 2;
+
+ DBG("colp_notify: %s %d %d", num, type, validity);
+ }
+
+ /* Generate a voice call that was just dialed, we guess the ID */
+ call = create_call(vc, 0, 0, CALL_STATUS_DIALING, num, type, validity);
+ if (call == NULL) {
+ ofono_error("Unable to malloc, call tracking will fail!");
+ return;
+ }
+
+ /* oFono core will generate a call with the dialed number
+ * inside its dial callback. Unless we got COLP information
+ * we do not need to communicate that a call is being
+ * dialed
+ */
+ if (validity != 2)
+ ofono_voicecall_notify(vc, call);
+
+out:
+ cb(&error, cbd->data);
+}
+
+static void gemalto_dial(struct ofono_voicecall *vc,
+ const struct ofono_phone_number *ph,
+ enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
+ void *data)
+{
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ char buf[256];
+
+ cbd->user = vc;
+
+ if (ph->type == 145)
+ snprintf(buf, sizeof(buf), "ATD+%s", ph->number);
+ else
+ snprintf(buf, sizeof(buf), "ATD%s", ph->number);
+
+ switch (clir) {
+ case OFONO_CLIR_OPTION_INVOCATION:
+ strcat(buf, "I");
+ break;
+ case OFONO_CLIR_OPTION_SUPPRESSION:
+ strcat(buf, "i");
+ break;
+ default:
+ break;
+ }
+
+ strcat(buf, ";");
+
+ if (g_at_chat_send(vd->chat, buf, atd_prefix,
+ atd_cb, cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static GSList *gemalto_parse_slcc(GAtResult *result, unsigned int *ret_mpty_ids)
+{
+ GAtResultIter iter;
+ GSList *l = NULL;
+ int id, dir, status, type;
+ ofono_bool_t mpty;
+ struct ofono_call *call;
+ unsigned int mpty_ids = 0;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, "+CLCC:")) {
+ const char *str = "";
+ int number_type = 129;
+
+ if (!g_at_result_iter_next_number(&iter, &id))
+ continue;
+
+ if (id == 0)
+ continue;
+
+ if (!g_at_result_iter_next_number(&iter, &dir))
+ continue;
+
+ if (!g_at_result_iter_next_number(&iter, &status))
+ continue;
+
+ if (status > 5)
+ continue;
+
+ if (!g_at_result_iter_next_number(&iter, &type))
+ continue;
+
+ if (!g_at_result_iter_next_number(&iter, &mpty))
+ continue;
+
+ /* skip 'Reserved=0' parameter, only difference from CLCC */
+ if (!g_at_result_iter_skip_next(&iter))
+ continue;
+
+ if (g_at_result_iter_next_string(&iter, &str))
+ g_at_result_iter_next_number(&iter, &number_type);
+
+ call = g_try_new(struct ofono_call, 1);
+ if (call == NULL)
+ break;
+
+ ofono_call_init(call);
+
+ call->id = id;
+ call->direction = dir;
+ call->status = status;
+ call->type = type;
+ strncpy(call->phone_number.number, str,
+ OFONO_MAX_PHONE_NUMBER_LENGTH);
+ call->phone_number.type = number_type;
+
+ if (strlen(call->phone_number.number) > 0)
+ call->clip_validity = 0;
+ else
+ call->clip_validity = 2;
+
+ l = g_slist_insert_sorted(l, call, at_util_call_compare);
+
+ if (mpty)
+ mpty_ids |= 1 << id;
+ }
+
+ if (ret_mpty_ids)
+ *ret_mpty_ids = mpty_ids;
+
+ return l;
+}
+
+static void clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ GSList *l;
+
+ if (!ok)
+ return;
+
+ vd->calls = at_util_parse_clcc(result, NULL);
+
+ for (l = vd->calls; l; l = l->next)
+ ofono_voicecall_notify(vc, l->data);
+}
+
+static void slcc_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ GSList *calls;
+ GSList *n, *o;
+ struct ofono_call *nc, *oc;
+
+ calls = gemalto_parse_slcc(result, NULL);
+
+ n = calls;
+ o = vd->calls;
+
+ while (n || o) {
+ nc = n ? n->data : NULL;
+ oc = o ? o->data : NULL;
+
+ if (oc && (nc == NULL || (nc->id > oc->id))) {
+ enum ofono_disconnect_reason reason;
+
+ if (vd->local_release & (1 << oc->id))
+ reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
+ else
+ reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
+
+ if (!oc->type)
+ ofono_voicecall_disconnected(vc, oc->id,
+ reason, NULL);
+
+ o = o->next;
+ } else if (nc && (oc == NULL || (nc->id < oc->id))) {
+
+ if (nc->type == 0) /* new call, signal it */
+ ofono_voicecall_notify(vc, nc);
+
+ n = n->next;
+ } else {
+ /*
+ * Always use the clip_validity from old call
+ * the only place this is truly told to us is
+ * in the CLIP notify, the rest are fudged
+ * anyway. Useful when RING, CLIP is used,
+ * and we're forced to use CLCC/SLCC and clip_validity
+ * is 1
+ */
+ if (oc->clip_validity == 1)
+ nc->clip_validity = oc->clip_validity;
+
+ /*
+ * CNAP doesn't arrive as part of CLCC, always
+ * re-use from the old call
+ */
+ strncpy(nc->name, oc->name,
+ OFONO_MAX_CALLER_NAME_LENGTH);
+ nc->name[OFONO_MAX_CALLER_NAME_LENGTH] = '\0';
+ nc->cnap_validity = oc->cnap_validity;
+
+ /*
+ * CDIP doesn't arrive as part of CLCC, always
+ * re-use from the old call
+ */
+ memcpy(&nc->called_number, &oc->called_number,
+ sizeof(oc->called_number));
+
+ /*
+ * If the CLIP is not provided and the CLIP never
+ * arrives, or RING is used, then signal the call
+ * here
+ */
+ if (nc->status == CALL_STATUS_INCOMING &&
+ (vd->flags & FLAG_NEED_CLIP)) {
+ if (nc->type == 0)
+ ofono_voicecall_notify(vc, nc);
+
+ vd->flags &= ~FLAG_NEED_CLIP;
+ } else if (memcmp(nc, oc, sizeof(*nc)) && nc->type == 0)
+ ofono_voicecall_notify(vc, nc);
+
+ n = n->next;
+ o = o->next;
+ }
+ }
+
+ g_slist_free_full(vd->calls, g_free);
+
+ vd->calls = calls;
+
+ vd->local_release = 0;
+}
+
+static void ring_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ struct ofono_call *call;
+
+ /* See comment in CRING */
+ if (g_slist_find_custom(vd->calls,
+ GINT_TO_POINTER(CALL_STATUS_WAITING),
+ at_util_call_compare_by_status))
+ return;
+
+ /* RING can repeat, ignore if we already have an incoming call */
+ if (g_slist_find_custom(vd->calls,
+ GINT_TO_POINTER(CALL_STATUS_INCOMING),
+ at_util_call_compare_by_status))
+ return;
+
+ /* Generate an incoming call of unknown type */
+ call = create_call(vc, 9, 1, CALL_STATUS_INCOMING, NULL, 128, 2);
+ if (call == NULL) {
+ ofono_error("Couldn't create call!");
+ return;
+ }
+
+ /* We don't know the call type, we must wait for the SLCC URC */
+ vd->flags = FLAG_NEED_CLIP;
+}
+
+static void cring_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ GAtResultIter iter;
+ const char *line;
+ int type;
+
+ /* Handle the following situation:
+ * Active Call + Waiting Call. Active Call is Released. The Waiting
+ * call becomes Incoming and RING/CRING indications are signaled.
+ * Sometimes these arrive before we get the SLCC URC to find about
+ * the stage change. If this happens, simply ignore the RING/CRING
+ * when a waiting call exists (cannot have waiting + incoming in GSM)
+ */
+ if (g_slist_find_custom(vd->calls,
+ GINT_TO_POINTER(CALL_STATUS_WAITING),
+ at_util_call_compare_by_status))
+ return;
+
+ /* CRING can repeat, ignore if we already have an incoming call */
+ if (g_slist_find_custom(vd->calls,
+ GINT_TO_POINTER(CALL_STATUS_INCOMING),
+ at_util_call_compare_by_status))
+ return;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CRING:"))
+ return;
+
+ line = g_at_result_iter_raw_line(&iter);
+ if (line == NULL)
+ return;
+
+ /* Ignore everything that is not voice for now */
+ if (!strcasecmp(line, "VOICE"))
+ type = 0;
+ else
+ type = 9;
+
+ /* Generate an incoming call */
+ create_call(vc, type, 1, CALL_STATUS_INCOMING, NULL, 128, 2);
+
+ /* We have a call, and call type but don't know the number and
+ * must wait for the CLIP to arrive before announcing the call.
+ * And we wait also for SLCC. If the CLIP arrives
+ * earlier, we announce the call there
+ */
+ vd->flags = FLAG_NEED_CLIP;
+
+ DBG("");
+}
+
+static void clip_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ GAtResultIter iter;
+ const char *num;
+ int type, validity;
+ GSList *l;
+ struct ofono_call *call;
+
+ l = g_slist_find_custom(vd->calls,
+ GINT_TO_POINTER(CALL_STATUS_INCOMING),
+ at_util_call_compare_by_status);
+ if (l == NULL) {
+ ofono_error("CLIP for unknown call");
+ return;
+ }
+
+ /* We have already saw a CLIP for this call, no need to parse again */
+ if ((vd->flags & FLAG_NEED_CLIP) == 0)
+ return;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CLIP:"))
+ return;
+
+ if (!g_at_result_iter_next_string(&iter, &num))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &type))
+ return;
+
+ if (strlen(num) > 0)
+ validity = CLIP_VALIDITY_VALID;
+ else
+ validity = CLIP_VALIDITY_NOT_AVAILABLE;
+
+ /* Skip subaddr, satype and alpha */
+ g_at_result_iter_skip_next(&iter);
+ g_at_result_iter_skip_next(&iter);
+ g_at_result_iter_skip_next(&iter);
+
+ /* If we have CLI validity field, override our guessed value */
+ g_at_result_iter_next_number(&iter, &validity);
+
+ DBG("%s %d %d", num, type, validity);
+
+ call = l->data;
+
+ strncpy(call->phone_number.number, num,
+ OFONO_MAX_PHONE_NUMBER_LENGTH);
+ call->phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+ call->phone_number.type = type;
+ call->clip_validity = validity;
+
+ if (call->type == 0)
+ ofono_voicecall_notify(vc, call);
+
+ vd->flags &= ~FLAG_NEED_CLIP;
+}
+
+static int class_to_call_type(int cls)
+{
+ switch (cls) {
+ case 1:
+ return 0;
+ case 4:
+ return 2;
+ case 8:
+ return 9;
+ default:
+ return 1;
+ }
+}
+
+static void ccwa_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+ GAtResultIter iter;
+ const char *num;
+ int num_type, validity, cls;
+ struct ofono_call *call;
+
+ /* if CCWA is resent, ignore it the second time around */
+ if (g_slist_find_custom(vd->calls,
+ GINT_TO_POINTER(CALL_STATUS_WAITING),
+ at_util_call_compare_by_status))
+ return;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CCWA:"))
+ return;
+
+ if (!g_at_result_iter_next_string(&iter, &num))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &num_type))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &cls))
+ return;
+
+ /* Skip alpha field */
+ g_at_result_iter_skip_next(&iter);
+
+ if (strlen(num) > 0)
+ validity = 0;
+ else
+ validity = 2;
+
+ /* If we have CLI validity field, override our guessed value */
+ g_at_result_iter_next_number(&iter, &validity);
+
+ DBG("%s %d %d %d", num, num_type, cls, validity);
+
+ call = create_call(vc, class_to_call_type(cls), 1, CALL_STATUS_WAITING,
+ num, num_type, validity);
+ if (call == NULL) {
+ ofono_error("Unable to malloc. Call management is fubar");
+ return;
+ }
+
+ if (call->type == 0) /* Only notify voice calls */
+ ofono_voicecall_notify(vc, call);
+}
+
+static void cssi_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ GAtResultIter iter;
+ int code, index;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CSSI:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &code))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &index))
+ index = 0;
+
+ ofono_voicecall_ssn_mo_notify(vc, 0, code, index);
+}
+
+static void cssu_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ GAtResultIter iter;
+ int code;
+ int index;
+ const char *num;
+ struct ofono_phone_number ph;
+
+ ph.number[0] = '\0';
+ ph.type = 129;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CSSU:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &code))
+ return;
+
+ if (!g_at_result_iter_next_number_default(&iter, -1, &index))
+ goto out;
+
+ if (!g_at_result_iter_next_string(&iter, &num))
+ goto out;
+
+ strncpy(ph.number, num, OFONO_MAX_PHONE_NUMBER_LENGTH);
+
+ if (!g_at_result_iter_next_number(&iter, &ph.type))
+ return;
+
+out:
+ ofono_voicecall_ssn_mt_notify(vc, 0, code, index, &ph);
+}
+
+static void gemalto_voicecall_initialized(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_voicecall *vc = user_data;
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+ DBG("voicecall_init: registering to notifications");
+
+ /* NO CARRIER, NO ANSWER, BUSY, NO DIALTONE are handled through SLCC */
+ g_at_chat_register(vd->chat, "^SLCC:", slcc_notify, FALSE, vc, NULL);
+ g_at_chat_register(vd->chat, "RING", ring_notify, FALSE, vc, NULL);
+ g_at_chat_register(vd->chat, "+CRING:", cring_notify, FALSE, vc, NULL);
+ g_at_chat_register(vd->chat, "+CLIP:", clip_notify, FALSE, vc, NULL);
+ g_at_chat_register(vd->chat, "+CCWA:", ccwa_notify, FALSE, vc, NULL);
+ g_at_chat_register(vd->chat, "+CSSI:", cssi_notify, FALSE, vc, NULL);
+ g_at_chat_register(vd->chat, "+CSSU:", cssu_notify, FALSE, vc, NULL);
+
+ ofono_voicecall_register(vc);
+
+ /* Populate the call list */
+ g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix, clcc_cb, vc, NULL);
+}
+
+static int gemalto_voicecall_probe(struct ofono_voicecall *vc,
+ unsigned int vendor, void *data)
+{
+ GAtChat *chat = data;
+ struct voicecall_data *vd;
+
+ vd = g_try_new0(struct voicecall_data, 1);
+
+ if (vd == NULL)
+ return -ENOMEM;
+
+ vd->chat = g_at_chat_clone(chat);
+ vd->vendor = vendor;
+ ofono_voicecall_set_data(vc, vd);
+
+ // TODO: move to a config atom
+ g_at_chat_send(vd->chat, "AT^SNFS=5", NULL, NULL, NULL, NULL);
+
+ g_at_chat_send(vd->chat, "AT+CRC=1", NULL, NULL, NULL, NULL);
+ g_at_chat_send(vd->chat, "AT+COLP=1", NULL, NULL, NULL, NULL);
+ g_at_chat_send(vd->chat, "AT+CLIP=1", NULL, NULL, NULL, NULL);
+ g_at_chat_send(vd->chat, "AT+CCWA=1", NULL, NULL, NULL, NULL);
+ g_at_chat_send(vd->chat, "AT+CSSN=1,1", NULL, NULL, NULL, NULL);
+ g_at_chat_send(vd->chat, "AT^SLCC=1", NULL,
+ gemalto_voicecall_initialized, vc, NULL);
+ return 0;
+}
+
+static void gemalto_voicecall_remove(struct ofono_voicecall *vc)
+{
+ struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+ ofono_voicecall_set_data(vc, NULL);
+
+ g_at_chat_unref(vd->chat);
+ g_free(vd);
+}
+
+static struct ofono_voicecall_driver driver = {
+ .name = "gemaltomodem",
+ .probe = gemalto_voicecall_probe,
+ .remove = gemalto_voicecall_remove,
+ .dial = gemalto_dial,
+ .answer = gemalto_answer,
+ .hangup_all = gemalto_hangup_all,
+ .hangup_active = gemalto_hangup,
+ .hold_all_active = gemalto_hold_all_active,
+ .release_all_held = gemalto_release_all_held,
+ .set_udub = gemalto_set_udub,
+ .release_all_active = gemalto_release_all_active,
+ .release_specific = gemalto_release_specific,
+ .private_chat = gemalto_private_chat,
+ .create_multiparty = gemalto_create_multiparty,
+ .transfer = gemalto_transfer,
+ .deflect = NULL,
+ .swap_without_accept = NULL,
+ .send_tones = gemalto_send_dtmf
+};
+
+void gemalto_voicecall_init(void)
+{
+ ofono_voicecall_driver_register(&driver);
+}
+
+void gemalto_voicecall_exit(void)
+{
+ ofono_voicecall_driver_unregister(&driver);
+}
--
1.9.1
2 years, 4 months
[PATCH 1/3] sim800: adding support for Simcom SIM800 modem
by ClémentViel
From: clem <vielclement(a)gmail.com>
---
Makefile.am | 4 +
plugins/sim800.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 428 insertions(+)
create mode 100644 plugins/sim800.c
diff --git a/Makefile.am b/Makefile.am
index 6dee4ce..f4d03b6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -496,6 +496,10 @@ builtin_sources += plugins/speedupcdma.c
builtin_modules += samsung
builtin_sources += plugins/samsung.c
+builtin_modules += sim800
+builtin_sources += plugins/sim800.c
+
+
builtin_modules += sim900
builtin_sources += plugins/sim900.c
diff --git a/plugins/sim800.c b/plugins/sim800.c
new file mode 100644
index 0000000..a69fe6d
--- /dev/null
+++ b/plugins/sim800.c
@@ -0,0 +1,424 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+#include <gatchat.h>
+#include <gattty.h>
+#include <gatmux.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/netreg.h>
+#include <ofono/sim.h>
+#include <ofono/sms.h>
+#include <ofono/ussd.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/phonebook.h>
+#include <ofono/history.h>
+#include <ofono/log.h>
+#include <ofono/voicecall.h>
+#include <ofono/call-volume.h>
+#include <drivers/atmodem/vendor.h>
+
+#define NUM_DLC 5
+
+#define VOICE_DLC 0
+#define NETREG_DLC 1
+#define SMS_DLC 2
+#define GPRS_DLC 3
+#define SETUP_DLC 4
+
+static char *dlc_prefixes[NUM_DLC] = { "Voice: ", "Net: ", "SMS: ",
+ "GPRS: " , "Setup: "};
+
+static const char *none_prefix[] = { NULL };
+
+struct sim800_data {
+ GIOChannel *device;
+ GAtMux *mux;
+ GAtChat * dlcs[NUM_DLC];
+ guint frame_size;
+};
+
+static int sim800_probe(struct ofono_modem *modem)
+{
+ struct sim800_data *data;
+
+ DBG("%p", modem);
+
+ data = g_try_new0(struct sim800_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ofono_modem_set_data(modem, data);
+
+ return 0;
+}
+
+static void sim800_remove(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ ofono_modem_set_data(modem, NULL);
+
+ g_free(data);
+}
+
+static void sim800_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ ofono_info("%s%s", prefix, str);
+}
+
+static GAtChat *open_device(struct ofono_modem *modem,
+ const char *key, char *debug)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+ const char *device;
+ GAtSyntax *syntax;
+ GIOChannel *channel;
+ GAtChat *chat;
+ GHashTable *options;
+
+ device = ofono_modem_get_string(modem, key);
+ if (device == NULL) {
+ DBG("couldn't get string %s",key);
+ return NULL;
+ }
+
+ DBG("%s %s", key, device);
+
+ options = g_hash_table_new(g_str_hash, g_str_equal);
+ if (options == NULL) {
+ DBG("options is null");
+ return NULL;
+ }
+
+ g_hash_table_insert(options, "Baud", "115200");
+ g_hash_table_insert(options, "Parity", "none");
+ g_hash_table_insert(options, "StopBits", "1");
+ g_hash_table_insert(options, "DataBits", "8");
+ g_hash_table_insert(options, "XonXoff", "off");
+ g_hash_table_insert(options, "Local", "off");
+ g_hash_table_insert(options, "RtsCts", "off");
+ g_hash_table_insert(options, "Read", "on");
+
+ channel = g_at_tty_open(device, options);
+ g_hash_table_destroy(options);
+
+ if (channel == NULL){
+ DBG("serial channel couldn't be opened");
+ return NULL;
+ }
+
+ data->device = channel;
+ syntax = g_at_syntax_new_gsm_permissive();
+ chat = g_at_chat_new(channel, syntax);
+ g_at_syntax_unref(syntax);
+
+ if (chat == NULL) {
+ g_io_channel_unref(data->device);
+ data->device = NULL;
+ DBG("at channel couldn't be opened");
+
+ return NULL;
+ }
+
+ if (getenv("OFONO_AT_DEBUG"))
+ g_at_chat_set_debug(chat, sim800_debug, debug);
+
+ return chat;
+}
+
+static GAtChat *create_chat(GIOChannel *channel, struct ofono_modem *modem,
+ char *debug)
+{
+ GAtSyntax *syntax;
+ GAtChat *chat;
+
+ if (channel == NULL)
+ return NULL;
+
+ syntax = g_at_syntax_new_gsmv1();
+ chat = g_at_chat_new(channel, syntax);
+ g_at_syntax_unref(syntax);
+ g_io_channel_unref(channel);
+
+ if (chat == NULL)
+ return NULL;
+
+ if (getenv("OFONO_AT_DEBUG")) {
+ DBG("AT DEBUG enabled");
+ g_at_chat_set_debug(chat, sim800_debug, debug);
+ }
+
+ return chat;
+}
+
+static void shutdown_device(struct sim800_data *data)
+{
+ int i;
+
+ DBG("");
+
+ for (i = 0; i < NUM_DLC; i++) {
+ if (data->dlcs[i] == NULL)
+ continue;
+
+ g_at_chat_unref(data->dlcs[i]);
+ data->dlcs[i] = NULL;
+ }
+
+ if (data->mux) {
+ g_at_mux_shutdown(data->mux);
+ g_at_mux_unref(data->mux);
+ data->mux = NULL;
+ }
+
+ g_io_channel_unref(data->device);
+ data->device = NULL;
+}
+
+static void setup_internal_mux(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+ int i;
+
+ DBG("");
+
+ data->frame_size = 128;
+
+ data->mux = g_at_mux_new_gsm0710_basic(data->device,
+ data->frame_size);
+ if (data->mux == NULL)
+ goto error;
+
+ if (getenv("OFONO_MUX_DEBUG"))
+ g_at_mux_set_debug(data->mux, sim800_debug, "MUX: ");
+
+ if (!g_at_mux_start(data->mux)) {
+ g_at_mux_shutdown(data->mux);
+ g_at_mux_unref(data->mux);
+ goto error;
+ }
+
+ for (i = 0; i < NUM_DLC; i++) {
+ GIOChannel *channel = g_at_mux_create_channel(data->mux);
+
+ data->dlcs[i] = create_chat(channel, modem, dlc_prefixes[i]);
+ if (data->dlcs[i] == NULL) {
+ ofono_error("Failed to create channel");
+ goto error;
+ }
+ }
+
+ ofono_modem_set_powered(modem, TRUE);
+ return;
+
+error:
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static void mux_setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ g_at_chat_unref(data->dlcs[SETUP_DLC]);
+ data->dlcs[SETUP_DLC] = NULL;
+
+ if (!ok)
+ goto error;
+
+ setup_internal_mux(modem);
+ return;
+
+error:
+ DBG("If you are on a SIM800H modem with firmware version lower \
+ than ... CMUX command is not supported thus \
+ preventing GPRS, Voice and SMS managers to be executed simultaneously.");
+
+ shutdown_device(data);
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ if (!ok) {
+ g_at_chat_unref(data->dlcs[SETUP_DLC]);
+ data->dlcs[SETUP_DLC] = NULL;
+ ofono_modem_set_powered(modem, FALSE);
+ return;
+ }
+ DBG("sending CMUX");
+ g_at_chat_send(data->dlcs[SETUP_DLC],"AT+CMUX=0,0,5,128,10,3,30,10,2", NULL,mux_setup_cb, modem, NULL);
+
+}
+
+static int sim800_enable(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ data->dlcs[SETUP_DLC] = open_device(modem, "Device", "Setup: ");
+ if (data->dlcs[SETUP_DLC] == NULL){
+ DBG("couldn't open device");
+ return -EINVAL;
+ }
+
+ g_at_chat_send(data->dlcs[SETUP_DLC], "ATE0", NULL, NULL, NULL, NULL);
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=1", none_prefix,
+ cfun_enable, modem, NULL);
+
+ return -EINPROGRESS;
+}
+
+static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ shutdown_device(data);
+
+ if (ok)
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static int sim800_disable(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=4", none_prefix,
+ cfun_disable, modem, NULL);
+
+ return -EINPROGRESS;
+}
+
+static void sim800_pre_sim(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+ struct ofono_sim *sim;
+
+ DBG("%p %x", modem, data);
+
+ ofono_devinfo_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ DBG("devinfo created");
+ sim = ofono_sim_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
+ data->dlcs[VOICE_DLC]);
+ DBG("sim created created");
+
+ if (sim)
+ ofono_sim_inserted_notify(sim, TRUE);
+
+ DBG("pre sim finished");
+}
+
+static void sim800_post_sim(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+ struct ofono_gprs *gprs;
+ struct ofono_gprs_context *gc;
+
+ DBG("%p", modem);
+
+ /* Dirty Hack : give some time to sim800 for multiplexing
+ * to be effective and avoid VOICE_DLC to be
+ * flooded thus leading to a "famine" situation
+ */
+
+ sleep(2);
+ ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem",
+ data->dlcs[SMS_DLC]);
+
+
+ gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]);
+ if (gprs == NULL)
+ return;
+
+ gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM,
+ "atmodem", data->dlcs[GPRS_DLC]);
+ if (gc)
+ ofono_gprs_add_context(gprs, gc);
+}
+
+static void sim800_post_online(struct ofono_modem *modem)
+{
+ struct sim800_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ ofono_phonebook_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_netreg_create(modem, OFONO_VENDOR_SIMCOM,
+ "atmodem", data->dlcs[NETREG_DLC]);
+ ofono_ussd_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_voicecall_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+ ofono_call_volume_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]);
+}
+
+static struct ofono_modem_driver sim800_driver = {
+ .name = "sim800",
+ .probe = sim800_probe,
+ .remove = sim800_remove,
+ .enable = sim800_enable,
+ .disable = sim800_disable,
+ .pre_sim = sim800_pre_sim,
+ .post_sim = sim800_post_sim,
+ .post_online = sim800_post_online,
+};
+
+static int sim800_init(void)
+{
+ return ofono_modem_driver_register(&sim800_driver);
+}
+
+static void sim800_exit(void)
+{
+ ofono_modem_driver_unregister(&sim800_driver);
+}
+
+OFONO_PLUGIN_DEFINE(sim800, "SIM800 modem driver", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, sim800_init, sim800_exit)
--
2.7.4
2 years, 4 months
[PATCH 1/7] extended support for LTE and NR. Some minor fixes. part 1 of 7
by Giacinto Cifelli
---
include/gprs-context.h | 1 +
include/lte.h | 11 +++++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/include/gprs-context.h b/include/gprs-context.h
index 20ca9ef..8869c12 100644
--- a/include/gprs-context.h
+++ b/include/gprs-context.h
@@ -57,6 +57,7 @@ enum ofono_gprs_context_type {
enum ofono_gprs_auth_method {
OFONO_GPRS_AUTH_METHOD_CHAP = 0,
OFONO_GPRS_AUTH_METHOD_PAP,
+ OFONO_GPRS_AUTH_METHOD_NONE,
};
struct ofono_gprs_primary_context {
diff --git a/include/lte.h b/include/lte.h
index ef84ab9..38587c3 100644
--- a/include/lte.h
+++ b/include/lte.h
@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2016 Endocode AG. All rights reserved.
+ * Copyright (C) 2018 Gemalto M2M
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -28,14 +29,18 @@ extern "C" {
#include <ofono/types.h>
-struct ofono_lte;
-
struct ofono_lte_default_attach_info {
char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
+ enum ofono_gprs_proto proto;
+ enum ofono_gprs_auth_method auth_method;
+ char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
+ char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
};
typedef void (*ofono_lte_cb_t)(const struct ofono_error *error, void *data);
+struct ofono_lte;
+
struct ofono_lte_driver {
const char *name;
int (*probe)(struct ofono_lte *lte, unsigned int vendor, void *data);
@@ -61,6 +66,8 @@ void ofono_lte_set_data(struct ofono_lte *lte, void *data);
void *ofono_lte_get_data(const struct ofono_lte *lte);
+struct ofono_modem *ofono_lte_get_modem(const struct ofono_lte *lte);
+
#ifdef __cplusplus
}
#endif
--
1.9.1
2 years, 4 months
[PATCH] src/gprs.c: make sure that the context is properly released
by Giacinto Cifelli
---
src/gprs.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/gprs.c b/src/gprs.c
index 8f5d195..40f43e3 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -1642,6 +1642,9 @@ static void release_active_contexts(struct ofono_gprs *gprs)
if (gc->driver->detach_shutdown != NULL)
gc->driver->detach_shutdown(gc, ctx->context.cid);
+
+ /* Make sure the context is properly cleared */
+ release_context(ctx);
}
}
@@ -2241,6 +2244,7 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
}
DBG("Unregistering context: %s", ctx->path);
+ release_context(ctx);
context_dbus_unregister(ctx);
gprs->contexts = g_slist_remove(gprs->contexts, ctx);
--
1.9.1
2 years, 4 months
[PATCH] atmodem/sms: added missing return in at_cmt_notify before error processing
by Giacinto Cifelli
---
drivers/atmodem/sms.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index 7e78fcf..fb4d67a 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -455,6 +455,7 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
if (data->vendor != OFONO_VENDOR_SIMCOM)
at_ack_delivery(sms);
+ return;
err:
ofono_error("Unable to parse CMT notification");
--
1.9.1
2 years, 4 months
[PATCH] mbim driver: fixed the initialization function
by Giacinto Cifelli
---
drivers/mbimmodem/mbimmodem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mbimmodem/mbimmodem.c b/drivers/mbimmodem/mbimmodem.c
index a4c9daa..2a01dd6 100644
--- a/drivers/mbimmodem/mbimmodem.c
+++ b/drivers/mbimmodem/mbimmodem.c
@@ -33,7 +33,7 @@ static int mbimmodem_init(void)
mbim_devinfo_init();
mbim_sim_init();
mbim_netreg_init();
- mbim_sms_exit();
+ mbim_sms_init();
mbim_gprs_init();
mbim_gprs_context_init();
return 0;
--
1.9.1
2 years, 4 months
[PATCH 1/2] src/main.c: removed call to g_thread_init
by Giacinto Cifelli
according to g_thread documentation, this call is no longer needed,
and starting from g_thread version 2.32 it must not be used
---
src/main.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/main.c b/src/main.c
index 2d359dd..d8a06ba 100644
--- a/src/main.c
+++ b/src/main.c
@@ -211,11 +211,6 @@ int main(int argc, char **argv)
struct ell_event_source *source;
#endif
-#ifdef NEED_THREADS
- if (g_thread_supported() == FALSE)
- g_thread_init(NULL);
-#endif
-
context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, options, NULL);
--
1.9.1
2 years, 4 months