From 04c12038baedf21e8615a45907164648c83032f7 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 19 Aug 2009 17:22:02 -0500 Subject: [PATCH] Evolve the voicecall driver --- include/Makefile.am | 2 +- include/types.h | 16 + include/voicecall.h | 108 ++++++ src/driver.h | 80 ---- src/ofono.h | 2 +- src/voicecall.c | 899 +++++++++++++++++++++++--------------------- 6 files changed, 586 insertions(+), 521 deletions(-) create mode 100644 include/voicecall.h diff --git a/include/Makefile.am b/include/Makefile.am index 705b9b00..8992cee4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -5,7 +5,7 @@ include_HEADERS = log.h plugin.h history.h dbus.h modem.h \ types.h call-barring.h call-forwarding.h \ call-meter.h call-settings.h phonebook.h \ ssn.h ussd.h sms.h sim.h message-waiting.h \ - netreg.h + netreg.h voicecall.h nodist_include_HEADERS = version.h diff --git a/include/types.h b/include/types.h index 54cb3f40..7f99f80c 100644 --- a/include/types.h +++ b/include/types.h @@ -53,6 +53,13 @@ enum ofono_error_type { OFONO_ERROR_TYPE_FAILURE }; +enum ofono_disconnect_reason { + OFONO_DISCONNECT_REASON_UNKNOWN = 0, + OFONO_DISCONNECT_REASON_LOCAL_HANGUP, + OFONO_DISCONNECT_REASON_REMOTE_HANGUP, + OFONO_DISCONNECT_REASON_ERROR, +}; + struct ofono_error { enum ofono_error_type type; int error; @@ -65,6 +72,15 @@ struct ofono_phone_number { int type; }; +struct ofono_call { + unsigned id; + int type; + int direction; + int status; + struct ofono_phone_number phone_number; + int clip_validity; +}; + #ifdef __cplusplus } #endif diff --git a/include/voicecall.h b/include/voicecall.h new file mode 100644 index 00000000..2ccc5548 --- /dev/null +++ b/include/voicecall.h @@ -0,0 +1,108 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2009 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 + * + */ + +#ifndef __OFONO_VOICECALL_H +#define __OFONO_VOICECALL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct ofono_voicecall; + +typedef void (*ofono_voicecall_cb_t)(const struct ofono_error *error, + void *data); + +typedef void (*ofono_call_list_cb_t)(const struct ofono_error *error, + int numcalls, + const struct ofono_call *call_list, + void *data); + +/* Voice call related functionality, including ATD, ATA, +CHLD, CTFR, CLCC + * and VTS. + * + * It is up to the plugin to implement polling of CLCC if the modem does + * not support vendor extensions for call progress indication. + */ +struct ofono_voicecall_driver { + const char *name; + int (*probe)(struct ofono_voicecall *vc); + int (*remove)(struct ofono_voicecall *vc); + void (*dial)(struct ofono_voicecall *vc, + const struct ofono_phone_number *number, + enum ofono_clir_option clir, enum ofono_cug_option cug, + ofono_voicecall_cb_t cb, void *data); + void (*answer)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*hangup)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*list_calls)(struct ofono_voicecall *vc, + ofono_call_list_cb_t cb, void *data); + void (*hold_all_active)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*release_all_held)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*set_udub)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*release_all_active)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*release_specific)(struct ofono_voicecall *vc, int id, + ofono_voicecall_cb_t cb, void *data); + void (*private_chat)(struct ofono_voicecall *vc, int id, + ofono_voicecall_cb_t cb, void *data); + void (*create_multiparty)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*transfer)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*deflect)(struct ofono_voicecall *vc, + const struct ofono_phone_number *ph, + ofono_voicecall_cb_t cb, void *data); + void (*swap_without_accept)(struct ofono_voicecall *vc, + ofono_voicecall_cb_t cb, void *data); + void (*send_tones)(struct ofono_voicecall *vc, const char *tones, + ofono_voicecall_cb_t cb, void *data); +}; + +void ofono_voicecall_notify(struct ofono_voicecall *vc, + const struct ofono_call *call); +void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id, + enum ofono_disconnect_reason reason, + const struct ofono_error *error); + +int ofono_voicecall_driver_register(const struct ofono_voicecall_driver *d); +void ofono_voicecall_driver_unregister(const struct ofono_voicecall_driver *d); + +struct ofono_voicecall *ofono_voicecall_create(struct ofono_modem *modem, + const char *driver, void *data); + +void ofono_voicecall_register(struct ofono_voicecall *vc); +void ofono_voicecall_remove(struct ofono_voicecall *vc); + +void ofono_voicecall_set_data(struct ofono_voicecall *vc, void *data); +void *ofono_voicecall_get_data(struct ofono_voicecall *vc); + +#ifdef __cplusplus +} +#endif + +#endif /* __OFONO_VOICECALL_H */ diff --git a/src/driver.h b/src/driver.h index 1224be68..2635a510 100644 --- a/src/driver.h +++ b/src/driver.h @@ -23,36 +23,6 @@ struct ofono_modem; -enum ofono_disconnect_reason { - OFONO_DISCONNECT_REASON_UNKNOWN = 0, - OFONO_DISCONNECT_REASON_LOCAL_HANGUP, - OFONO_DISCONNECT_REASON_REMOTE_HANGUP, - OFONO_DISCONNECT_REASON_ERROR, -}; - -struct ofono_call { - unsigned id; - int type; - int direction; - int status; - struct ofono_phone_number phone_number; - int clip_validity; -}; - -/* Notification functions, the integer values here should map to - * values obtained from the modem. The enumerations are the same - * as the values for the fields found in 3GPP TS 27.007 - * - * Pass in the integer value -1 if the value is not known - * Pass in NULL string value if the value is not known - */ -typedef void (*ofono_generic_cb_t)(const struct ofono_error *error, - void *data); - -typedef void (*ofono_call_list_cb_t)(const struct ofono_error *error, - int numcalls, - const struct ofono_call *call_list, - void *data); typedef void (*ofono_modem_attribute_query_cb_t)(const struct ofono_error *error, const char *attribute, void *data); @@ -71,53 +41,3 @@ struct ofono_modem_attribute_ops { struct ofono_modem *ofono_modem_register(struct ofono_modem_attribute_ops *ops); int ofono_modem_unregister(struct ofono_modem *modem); -/* Voice call related functionality, including ATD, ATA, +CHLD, CTFR, CLCC - * and VTS. - * - * It is up to the plugin to implement polling of CLCC if the modem does - * not support vendor extensions for call progress indication. - */ -struct ofono_voicecall_ops { - void (*dial)(struct ofono_modem *modem, - const struct ofono_phone_number *number, - enum ofono_clir_option clir, enum ofono_cug_option cug, - ofono_generic_cb_t cb, void *data); - void (*answer)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*hangup)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*list_calls)(struct ofono_modem *modem, - ofono_call_list_cb_t cb, void *data); - void (*hold_all_active)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*release_all_held)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*set_udub)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*release_all_active)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*release_specific)(struct ofono_modem *modem, int id, - ofono_generic_cb_t cb, void *data); - void (*private_chat)(struct ofono_modem *modem, int id, - ofono_generic_cb_t cb, void *data); - void (*create_multiparty)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*transfer)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*deflect)(struct ofono_modem *modem, - const struct ofono_phone_number *ph, - ofono_generic_cb_t cb, void *data); - void (*swap_without_accept)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); - void (*send_tones)(struct ofono_modem *modem, const char *tones, - ofono_generic_cb_t cb, void *data); -}; - -void ofono_voicecall_notify(struct ofono_modem *modem, const struct ofono_call *call); -void ofono_voicecall_disconnected(struct ofono_modem *modem, int id, - enum ofono_disconnect_reason reason, - const struct ofono_error *error); - -int ofono_voicecall_register(struct ofono_modem *modem, struct ofono_voicecall_ops *ops); -void ofono_voicecall_unregister(struct ofono_modem *modem); - diff --git a/src/ofono.h b/src/ofono.h index 1b56380b..a19dc5f9 100644 --- a/src/ofono.h +++ b/src/ofono.h @@ -143,8 +143,8 @@ void __ofono_atom_free(struct ofono_atom *atom); #include #include #include - #include +#include #include diff --git a/src/voicecall.c b/src/voicecall.c index 32b8a10b..47e293b5 100644 --- a/src/voicecall.c +++ b/src/voicecall.c @@ -26,13 +26,13 @@ #include #include #include +#include #include #include #include "ofono.h" -#include "driver.h" #include "common.h" #include "simutil.h" @@ -44,23 +44,27 @@ #define MAX_VOICE_CALLS 16 -struct voicecalls_data { +GSList *g_drivers = NULL; + +struct ofono_voicecall { GSList *call_list; GSList *release_list; GSList *multiparty_list; GSList *en_list; /* emergency number list */ GSList *new_en_list; /* Emergency numbers being read from SIM */ - struct ofono_voicecall_ops *ops; int flags; DBusMessage *pending; gint emit_calls_source; gint emit_multi_source; unsigned int sim_watch; + const struct ofono_voicecall_driver *driver; + void *driver_data; + struct ofono_atom *atom; }; struct voicecall { struct ofono_call *call; - struct ofono_modem *modem; + struct ofono_voicecall *vc; time_t start_time; time_t detect_time; }; @@ -202,24 +206,23 @@ static DBusMessage *voicecall_busy(DBusConnection *conn, DBusMessage *msg, void *data) { struct voicecall *v = data; - struct ofono_modem *modem = v->modem; - struct voicecalls_data *voicecalls = modem->voicecalls; + struct ofono_voicecall *vc = v->vc; struct ofono_call *call = v->call; if (call->status != CALL_STATUS_INCOMING && call->status != CALL_STATUS_WAITING) return __ofono_error_failed(msg); - if (!voicecalls->ops->set_udub) + if (!vc->driver->set_udub) return __ofono_error_not_implemented(msg); - if (voicecalls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - voicecalls->flags |= VOICECALLS_FLAG_PENDING; - voicecalls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - voicecalls->ops->set_udub(modem, generic_callback, voicecalls); + vc->driver->set_udub(vc, generic_callback, vc); return NULL; } @@ -228,8 +231,7 @@ static DBusMessage *voicecall_deflect(DBusConnection *conn, DBusMessage *msg, void *data) { struct voicecall *v = data; - struct ofono_modem *modem = v->modem; - struct voicecalls_data *voicecalls = modem->voicecalls; + struct ofono_voicecall *vc = v->vc; struct ofono_call *call = v->call; struct ofono_phone_number ph; @@ -239,10 +241,10 @@ static DBusMessage *voicecall_deflect(DBusConnection *conn, call->status != CALL_STATUS_WAITING) return __ofono_error_failed(msg); - if (!voicecalls->ops->deflect) + if (!vc->driver->deflect) return __ofono_error_not_implemented(msg); - if (voicecalls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, @@ -252,12 +254,12 @@ static DBusMessage *voicecall_deflect(DBusConnection *conn, if (!valid_phone_number_format(number)) return __ofono_error_invalid_format(msg); - voicecalls->flags |= VOICECALLS_FLAG_PENDING; - voicecalls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); string_to_phone_number(number, &ph); - voicecalls->ops->deflect(modem, &ph, generic_callback, voicecalls); + vc->driver->deflect(vc, &ph, generic_callback, vc); return NULL; } @@ -266,24 +268,23 @@ static DBusMessage *voicecall_hangup(DBusConnection *conn, DBusMessage *msg, void *data) { struct voicecall *v = data; - struct ofono_modem *modem = v->modem; - struct voicecalls_data *voicecalls = modem->voicecalls; + struct ofono_voicecall *vc = v->vc; struct ofono_call *call = v->call; if (call->status == CALL_STATUS_DISCONNECTED) return __ofono_error_failed(msg); - if (!voicecalls->ops->release_specific) + if (!vc->driver->release_specific) return __ofono_error_not_implemented(msg); - if (voicecalls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - voicecalls->flags |= VOICECALLS_FLAG_PENDING; - voicecalls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - voicecalls->ops->release_specific(modem, call->id, - generic_callback, voicecalls); + vc->driver->release_specific(vc, call->id, + generic_callback, vc); return NULL; } @@ -292,23 +293,22 @@ static DBusMessage *voicecall_answer(DBusConnection *conn, DBusMessage *msg, void *data) { struct voicecall *v = data; - struct ofono_modem *modem = v->modem; - struct voicecalls_data *voicecalls = modem->voicecalls; + struct ofono_voicecall *vc = v->vc; struct ofono_call *call = v->call; if (call->status != CALL_STATUS_INCOMING) return __ofono_error_failed(msg); - if (!voicecalls->ops->answer) + if (!vc->driver->answer) return __ofono_error_not_implemented(msg); - if (voicecalls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - voicecalls->flags |= VOICECALLS_FLAG_PENDING; - voicecalls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - voicecalls->ops->answer(modem, generic_callback, voicecalls); + vc->driver->answer(vc, generic_callback, vc); return NULL; } @@ -332,7 +332,7 @@ static GDBusSignalTable voicecall_signals[] = { { } }; -static struct voicecall *voicecall_create(struct ofono_modem *modem, +static struct voicecall *voicecall_create(struct ofono_voicecall *vc, struct ofono_call *call) { struct voicecall *v; @@ -343,7 +343,7 @@ static struct voicecall *voicecall_create(struct ofono_modem *modem, return NULL; v->call = call; - v->modem = modem; + v->vc = vc; return v; } @@ -357,19 +357,18 @@ static void voicecall_destroy(gpointer userdata) g_free(voicecall); } -static const char *voicecall_build_path(struct ofono_modem *modem, +static const char *voicecall_build_path(struct ofono_voicecall *vc, const struct ofono_call *call) { static char path[256]; snprintf(path, sizeof(path), "%s/voicecall%02d", - modem->path, call->id); + __ofono_atom_get_path(vc->atom), call->id); return path; } -static void voicecall_set_call_status(struct ofono_modem *modem, - struct voicecall *call, +static void voicecall_set_call_status(struct voicecall *call, int status) { DBusConnection *conn = ofono_dbus_get_connection(); @@ -385,7 +384,7 @@ static void voicecall_set_call_status(struct ofono_modem *modem, call->call->status = status; status_str = call_status_to_string(status); - path = voicecall_build_path(modem, call->call); + path = voicecall_build_path(call->vc, call->call); ofono_dbus_signal_property_changed(conn, path, VOICECALL_INTERFACE, "State", DBUS_TYPE_STRING, @@ -409,8 +408,7 @@ static void voicecall_set_call_status(struct ofono_modem *modem, } } -static void voicecall_set_call_lineid(struct ofono_modem *modem, - struct voicecall *v, +static void voicecall_set_call_lineid(struct voicecall *v, const struct ofono_phone_number *ph, int clip_validity) { @@ -438,7 +436,7 @@ static void voicecall_set_call_lineid(struct ofono_modem *modem, call->clip_validity = clip_validity; call->phone_number.type = ph->type; - path = voicecall_build_path(modem, call); + path = voicecall_build_path(v->vc, call); if (call->direction == CALL_DIRECTION_MOBILE_TERMINATED) lineid_str = phone_and_clip_to_string(ph, clip_validity); @@ -450,23 +448,22 @@ static void voicecall_set_call_lineid(struct ofono_modem *modem, DBUS_TYPE_STRING, &lineid_str); } -static gboolean voicecall_dbus_register(struct voicecall *voicecall) +static gboolean voicecall_dbus_register(struct voicecall *v) { DBusConnection *conn = ofono_dbus_get_connection(); const char *path; - if (!voicecall) + if (!v) return FALSE; - path = voicecall_build_path(voicecall->modem, voicecall->call); + path = voicecall_build_path(v->vc, v->call); if (!g_dbus_register_interface(conn, path, VOICECALL_INTERFACE, voicecall_methods, voicecall_signals, - NULL, voicecall, - voicecall_destroy)) { + NULL, v, voicecall_destroy)) { ofono_error("Could not register VoiceCall %s", path); - voicecall_destroy(voicecall); + voicecall_destroy(v); return FALSE; } @@ -474,69 +471,18 @@ static gboolean voicecall_dbus_register(struct voicecall *voicecall) return TRUE; } -static gboolean voicecall_dbus_unregister(struct ofono_modem *modem, - struct voicecall *call) +static gboolean voicecall_dbus_unregister(struct ofono_voicecall *vc, + struct voicecall *v) { DBusConnection *conn = ofono_dbus_get_connection(); - const char *path = voicecall_build_path(modem, call->call); + const char *path = voicecall_build_path(vc, v->call); return g_dbus_unregister_interface(conn, path, VOICECALL_INTERFACE); } -static struct voicecalls_data *voicecalls_create() -{ - struct voicecalls_data *calls; - calls = g_try_new0(struct voicecalls_data, 1); - - return calls; -} - -static void voicecalls_destroy(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct voicecalls_data *calls = modem->voicecalls; - GSList *l; - - if (calls->sim_watch) { - __ofono_modem_remove_atom_watch(modem, calls->sim_watch); - calls->sim_watch = 0; - } - - if (calls->emit_calls_source) { - g_source_remove(calls->emit_calls_source); - calls->emit_calls_source = 0; - } - - if (calls->emit_multi_source) { - g_source_remove(calls->emit_multi_source); - calls->emit_multi_source = 0; - } - - if (calls->en_list) { - g_slist_foreach(calls->en_list, (GFunc)g_free, NULL); - g_slist_free(calls->en_list); - calls->en_list = NULL; - } - - if (calls->new_en_list) { - g_slist_foreach(calls->new_en_list, (GFunc)g_free, NULL); - g_slist_free(calls->new_en_list); - calls->new_en_list = NULL; - } - - for (l = calls->call_list; l; l = l->next) - voicecall_dbus_unregister(modem, l->data); - - g_slist_free(calls->call_list); - - g_free(calls); - - modem->voicecalls = 0; -} - -static int voicecalls_path_list(struct ofono_modem *modem, GSList *call_list, +static int voicecalls_path_list(struct ofono_voicecall *vc, GSList *call_list, char ***objlist) { GSList *l; @@ -550,18 +496,18 @@ static int voicecalls_path_list(struct ofono_modem *modem, GSList *call_list, for (i = 0, l = call_list; l; l = l->next, i++) { v = l->data; - (*objlist)[i] = g_strdup(voicecall_build_path(modem, v->call)); + (*objlist)[i] = g_strdup(voicecall_build_path(vc, v->call)); } return 0; } -static gboolean voicecalls_have_active(struct voicecalls_data *calls) +static gboolean voicecalls_have_active(struct ofono_voicecall *vc) { GSList *l; struct voicecall *v; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == CALL_STATUS_ACTIVE || @@ -574,12 +520,12 @@ static gboolean voicecalls_have_active(struct voicecalls_data *calls) return FALSE; } -static gboolean voicecalls_have_connected(struct voicecalls_data *calls) +static gboolean voicecalls_have_connected(struct ofono_voicecall *vc) { GSList *l; struct voicecall *v; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == CALL_STATUS_ACTIVE) @@ -589,12 +535,12 @@ static gboolean voicecalls_have_connected(struct voicecalls_data *calls) return FALSE; } -static gboolean voicecalls_have_held(struct voicecalls_data *calls) +static gboolean voicecalls_have_held(struct ofono_voicecall *vc) { GSList *l; struct voicecall *v; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == CALL_STATUS_HELD) @@ -604,14 +550,14 @@ static gboolean voicecalls_have_held(struct voicecalls_data *calls) return FALSE; } -static int voicecalls_num_with_status(struct voicecalls_data *calls, +static int voicecalls_num_with_status(struct ofono_voicecall *vc, int status) { GSList *l; struct voicecall *v; int num = 0; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == status) @@ -621,33 +567,33 @@ static int voicecalls_num_with_status(struct voicecalls_data *calls, return num; } -static int voicecalls_num_active(struct voicecalls_data *calls) +static int voicecalls_num_active(struct ofono_voicecall *vc) { - return voicecalls_num_with_status(calls, CALL_STATUS_ACTIVE); + return voicecalls_num_with_status(vc, CALL_STATUS_ACTIVE); } -static int voicecalls_num_held(struct voicecalls_data *calls) +static int voicecalls_num_held(struct ofono_voicecall *vc) { - return voicecalls_num_with_status(calls, CALL_STATUS_HELD); + return voicecalls_num_with_status(vc, CALL_STATUS_HELD); } -static int voicecalls_num_connecting(struct voicecalls_data *calls) +static int voicecalls_num_connecting(struct ofono_voicecall *vc) { int r = 0; - r += voicecalls_num_with_status(calls, CALL_STATUS_DIALING); - r += voicecalls_num_with_status(calls, CALL_STATUS_ALERTING); + r += voicecalls_num_with_status(vc, CALL_STATUS_DIALING); + r += voicecalls_num_with_status(vc, CALL_STATUS_ALERTING); return r; } -static GSList *voicecalls_held_list(struct voicecalls_data *calls) +static GSList *voicecalls_held_list(struct ofono_voicecall *vc) { GSList *l; GSList *r = NULL; struct voicecall *v; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == CALL_STATUS_HELD) @@ -662,13 +608,13 @@ static GSList *voicecalls_held_list(struct voicecalls_data *calls) /* Intended to be used for multiparty, which cannot be incoming, * alerting or dialing */ -static GSList *voicecalls_active_list(struct voicecalls_data *calls) +static GSList *voicecalls_active_list(struct ofono_voicecall *vc) { GSList *l; GSList *r = NULL; struct voicecall *v; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == CALL_STATUS_ACTIVE) @@ -681,12 +627,12 @@ static GSList *voicecalls_active_list(struct voicecalls_data *calls) return r; } -static gboolean voicecalls_have_waiting(struct voicecalls_data *calls) +static gboolean voicecalls_have_waiting(struct ofono_voicecall *vc) { GSList *l; struct voicecall *v; - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { v = l->data; if (v->call->status == CALL_STATUS_WAITING) @@ -696,42 +642,36 @@ static gboolean voicecalls_have_waiting(struct voicecalls_data *calls) return FALSE; } -static void voicecalls_release_queue(struct ofono_modem *modem, GSList *calls) +static void voicecalls_release_queue(struct ofono_voicecall *vc, GSList *calls) { - struct voicecalls_data *voicecalls = modem->voicecalls; GSList *l; - g_slist_free(voicecalls->release_list); - voicecalls->release_list = NULL; + g_slist_free(vc->release_list); + vc->release_list = NULL; - for (l = calls; l; l = l->next) { - voicecalls->release_list = - g_slist_prepend(voicecalls->release_list, l->data); - } + for (l = calls; l; l = l->next) + vc->release_list = g_slist_prepend(vc->release_list, l->data); } -static void voicecalls_release_next(struct ofono_modem *modem) +static void voicecalls_release_next(struct ofono_voicecall *vc) { - struct voicecalls_data *voicecalls = modem->voicecalls; struct voicecall *call; - if (!voicecalls->release_list) + if (!vc->release_list) return; - call = voicecalls->release_list->data; + call = vc->release_list->data; - voicecalls->release_list = g_slist_remove(voicecalls->release_list, - call); + vc->release_list = g_slist_remove(vc->release_list, call); - voicecalls->ops->release_specific(modem, call->call->id, - multirelease_callback, modem); + vc->driver->release_specific(vc, call->call->id, + multirelease_callback, vc); } static DBusMessage *manager_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; @@ -751,14 +691,14 @@ static DBusMessage *manager_get_properties(DBusConnection *conn, OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict); - voicecalls_path_list(modem, calls->call_list, &callobj_list); + voicecalls_path_list(vc, vc->call_list, &callobj_list); ofono_dbus_dict_append_array(&dict, "Calls", DBUS_TYPE_OBJECT_PATH, &callobj_list); g_strfreev(callobj_list); - voicecalls_path_list(modem, calls->multiparty_list, &callobj_list); + voicecalls_path_list(vc, vc->multiparty_list, &callobj_list); ofono_dbus_dict_append_array(&dict, "MultipartyCalls", DBUS_TYPE_OBJECT_PATH, &callobj_list); @@ -766,9 +706,11 @@ static DBusMessage *manager_get_properties(DBusConnection *conn, g_strfreev(callobj_list); /* property EmergencyNumbers */ - list = g_new0(char *, g_slist_length(calls->en_list) + 1); - for (i = 0, l = calls->en_list; l; l = l->next, i++) + list = g_new0(char *, g_slist_length(vc->en_list) + 1); + + for (i = 0, l = vc->en_list; l; l = l->next, i++) list[i] = g_strdup(l->data); + ofono_dbus_dict_append_array(&dict, "EmergencyNumbers", DBUS_TYPE_STRING, &list); g_strfreev(list); @@ -781,17 +723,16 @@ static DBusMessage *manager_get_properties(DBusConnection *conn, static DBusMessage *manager_dial(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; const char *number; struct ofono_phone_number ph; const char *clirstr; enum ofono_clir_option clir; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (g_slist_length(calls->call_list) >= MAX_VOICE_CALLS) + if (g_slist_length(vc->call_list) >= MAX_VOICE_CALLS) return __ofono_error_failed(msg); if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, @@ -811,20 +752,20 @@ static DBusMessage *manager_dial(DBusConnection *conn, else return __ofono_error_invalid_format(msg); - if (!calls->ops->dial) + if (!vc->driver->dial) return __ofono_error_not_implemented(msg); - if (voicecalls_have_active(calls) && - voicecalls_have_held(calls)) + if (voicecalls_have_active(vc) && + voicecalls_have_held(vc)) return __ofono_error_failed(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); string_to_phone_number(number, &ph); - calls->ops->dial(modem, &ph, clir, OFONO_CUG_OPTION_DEFAULT, - dial_callback, modem); + vc->driver->dial(vc, &ph, clir, OFONO_CUG_OPTION_DEFAULT, + dial_callback, vc); return NULL; } @@ -832,34 +773,33 @@ static DBusMessage *manager_dial(DBusConnection *conn, static DBusMessage *manager_transfer(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; int numactive; int numheld; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - numactive = voicecalls_num_active(calls); + numactive = voicecalls_num_active(vc); /* According to 22.091 section 5.8, the network has the option of * implementing the call transfer operation for a call that is * still dialing/alerting. */ - numactive += voicecalls_num_connecting(calls); + numactive += voicecalls_num_connecting(vc); - numheld = voicecalls_num_held(calls); + numheld = voicecalls_num_held(vc); if ((numactive != 1) && (numheld != 1)) return __ofono_error_failed(msg); - if (!calls->ops->transfer) + if (!vc->driver->transfer) return __ofono_error_not_implemented(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->transfer(modem, generic_callback, calls); + vc->driver->transfer(vc, generic_callback, vc); return NULL; } @@ -867,22 +807,21 @@ static DBusMessage *manager_transfer(DBusConnection *conn, static DBusMessage *manager_swap_calls(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (voicecalls_have_waiting(calls)) + if (voicecalls_have_waiting(vc)) return __ofono_error_failed(msg); - if (!calls->ops->hold_all_active) + if (!vc->driver->hold_all_active) return __ofono_error_not_implemented(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->hold_all_active(modem, generic_callback, calls); + vc->driver->hold_all_active(vc, generic_callback, vc); return NULL; } @@ -890,22 +829,21 @@ static DBusMessage *manager_swap_calls(DBusConnection *conn, static DBusMessage *manager_release_and_answer(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (!voicecalls_have_active(calls) || !voicecalls_have_waiting(calls)) + if (!voicecalls_have_active(vc) || !voicecalls_have_waiting(vc)) return __ofono_error_failed(msg); - if (!calls->ops->release_all_active) + if (!vc->driver->release_all_active) return __ofono_error_not_implemented(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->release_all_active(modem, generic_callback, calls); + vc->driver->release_all_active(vc, generic_callback, vc); return NULL; } @@ -913,23 +851,22 @@ static DBusMessage *manager_release_and_answer(DBusConnection *conn, static DBusMessage *manager_hold_and_answer(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (voicecalls_have_active(calls) && voicecalls_have_held(calls) && - voicecalls_have_waiting(calls)) + if (voicecalls_have_active(vc) && voicecalls_have_held(vc) && + voicecalls_have_waiting(vc)) return __ofono_error_failed(msg); - if (!calls->ops->hold_all_active) + if (!vc->driver->hold_all_active) return __ofono_error_not_implemented(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->hold_all_active(modem, generic_callback, calls); + vc->driver->hold_all_active(vc, generic_callback, vc); return NULL; } @@ -937,27 +874,26 @@ static DBusMessage *manager_hold_and_answer(DBusConnection *conn, static DBusMessage *manager_hangup_all(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (!calls->ops->release_specific) + if (!vc->driver->release_specific) return __ofono_error_not_implemented(msg); - if (calls->call_list == NULL) { + if (vc->call_list == NULL) { DBusMessage *reply = dbus_message_new_method_return(msg); return reply; } - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->flags |= VOICECALLS_FLAG_MULTI_RELEASE; + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->flags |= VOICECALLS_FLAG_MULTI_RELEASE; - calls->pending = dbus_message_ref(msg); + vc->pending = dbus_message_ref(msg); - voicecalls_release_queue(modem, calls->call_list); - voicecalls_release_next(modem); + voicecalls_release_queue(vc, vc->call_list); + voicecalls_release_next(vc); return NULL; } @@ -965,14 +901,14 @@ static DBusMessage *manager_hangup_all(DBusConnection *conn, static DBusMessage *multiparty_private_chat(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; + const char *path = __ofono_atom_get_path(vc->atom); const char *callpath; const char *c; unsigned int id; GSList *l; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &callpath, @@ -984,13 +920,13 @@ static DBusMessage *multiparty_private_chat(DBusConnection *conn, c = strrchr(callpath, '/'); - if (!c || strncmp(modem->path, callpath, c-callpath)) + if (!c || strncmp(path, callpath, c-callpath)) return __ofono_error_not_found(msg); if (!sscanf(c, "/voicecall%2u", &id)) return __ofono_error_not_found(msg); - for (l = calls->multiparty_list; l; l = l->next) { + for (l = vc->multiparty_list; l; l = l->next) { struct voicecall *v = l->data; if (v->call->id == id) break; @@ -1003,16 +939,16 @@ static DBusMessage *multiparty_private_chat(DBusConnection *conn, * the multiparty call exists. Only thing to check is whether we have * held calls */ - if (voicecalls_have_held(calls)) + if (voicecalls_have_held(vc)) return __ofono_error_failed(msg); - if (!calls->ops->private_chat) + if (!vc->driver->private_chat) return __ofono_error_not_implemented(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->private_chat(modem, id, private_chat_callback, modem); + vc->driver->private_chat(vc, id, private_chat_callback, vc); return NULL; } @@ -1020,22 +956,21 @@ static DBusMessage *multiparty_private_chat(DBusConnection *conn, static DBusMessage *multiparty_create(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (!voicecalls_have_held(calls) || !voicecalls_have_active(calls)) + if (!voicecalls_have_held(vc) || !voicecalls_have_active(vc)) return __ofono_error_failed(msg); - if (!calls->ops->create_multiparty) + if (!vc->driver->create_multiparty) return __ofono_error_not_implemented(msg); - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->create_multiparty(modem, multiparty_create_callback, modem); + vc->driver->create_multiparty(vc, multiparty_create_callback, vc); return NULL; } @@ -1043,36 +978,35 @@ static DBusMessage *multiparty_create(DBusConnection *conn, static DBusMessage *multiparty_hangup(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (!calls->ops->release_specific) + if (!vc->driver->release_specific) return __ofono_error_not_implemented(msg); - if (!calls->ops->release_all_held) + if (!vc->driver->release_all_held) return __ofono_error_not_implemented(msg); - if (!calls->ops->release_all_active) + if (!vc->driver->release_all_active) return __ofono_error_not_implemented(msg); - if (calls->multiparty_list == NULL) { + if (vc->multiparty_list == NULL) { DBusMessage *reply = dbus_message_new_method_return(msg); return reply; } - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); /* We don't have waiting calls, as we can't use +CHLD to release */ - if (!voicecalls_have_waiting(calls)) { - struct voicecall *v = calls->multiparty_list->data; + if (!voicecalls_have_waiting(vc)) { + struct voicecall *v = vc->multiparty_list->data; if (v->call->status == CALL_STATUS_HELD) { - calls->ops->release_all_held(modem, generic_callback, - calls); + vc->driver->release_all_held(vc, generic_callback, + vc); goto out; } @@ -1080,17 +1014,17 @@ static DBusMessage *multiparty_hangup(DBusConnection *conn, * we shouldn't use release_all_active here since this also * has the side-effect of activating held calls */ - if (!voicecalls_have_held(calls)) { - calls->ops->release_all_active(modem, generic_callback, - calls); + if (!voicecalls_have_held(vc)) { + vc->driver->release_all_active(vc, generic_callback, + vc); goto out; } } /* Fall back to the old-fashioned way */ - calls->flags |= VOICECALLS_FLAG_MULTI_RELEASE; - voicecalls_release_queue(modem, calls->multiparty_list); - voicecalls_release_next(modem); + vc->flags |= VOICECALLS_FLAG_MULTI_RELEASE; + voicecalls_release_queue(vc, vc->multiparty_list); + voicecalls_release_next(vc); out: return NULL; @@ -1099,20 +1033,19 @@ out: static DBusMessage *manager_tone(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; const char *in_tones; char *tones; int i, len; - if (calls->flags & VOICECALLS_FLAG_PENDING) + if (vc->flags & VOICECALLS_FLAG_PENDING) return __ofono_error_busy(msg); - if (!calls->ops->send_tones) + if (!vc->driver->send_tones) return __ofono_error_not_implemented(msg); /* Send DTMFs only if we have at least one connected call */ - if (!voicecalls_have_connected(calls)) + if (!voicecalls_have_connected(vc)) return __ofono_error_failed(msg); if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &in_tones, @@ -1137,10 +1070,10 @@ static DBusMessage *manager_tone(DBusConnection *conn, return __ofono_error_invalid_format(msg); } - calls->flags |= VOICECALLS_FLAG_PENDING; - calls->pending = dbus_message_ref(msg); + vc->flags |= VOICECALLS_FLAG_PENDING; + vc->pending = dbus_message_ref(msg); - calls->ops->send_tones(modem, tones, generic_callback, calls); + vc->driver->send_tones(vc, tones, generic_callback, vc); g_free(tones); @@ -1179,14 +1112,14 @@ static GDBusSignalTable manager_signals[] = { static gboolean real_emit_call_list_changed(void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *voicecalls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(vc->atom); char **objpath_list; - voicecalls_path_list(modem, voicecalls->call_list, &objpath_list); + voicecalls_path_list(vc, vc->call_list, &objpath_list); - ofono_dbus_signal_array_property_changed(conn, modem->path, + ofono_dbus_signal_array_property_changed(conn, path, VOICECALL_MANAGER_INTERFACE, "Calls", DBUS_TYPE_OBJECT_PATH, @@ -1194,72 +1127,68 @@ static gboolean real_emit_call_list_changed(void *data) g_strfreev(objpath_list); - voicecalls->emit_calls_source = 0; + vc->emit_calls_source = 0; return FALSE; } -static void emit_call_list_changed(struct ofono_modem *modem) +static void emit_call_list_changed(struct ofono_voicecall *vc) { #ifdef DELAY_EMIT - struct voicecalls_data *calls = modem->voicecalls; - - if (calls->emit_calls_source == 0) - calls->emit_calls_source = - g_timeout_add(0, real_emit_call_list_changed, modem); + if (vc->emit_calls_source == 0) + vc->emit_calls_source = + g_timeout_add(0, real_emit_call_list_changed, vc); #else - real_emit_call_list_changed(modem); + real_emit_call_list_changed(vc); #endif } static gboolean real_emit_multiparty_call_list_changed(void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *voicecalls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(vc->atom); char **objpath_list; - voicecalls_path_list(modem, voicecalls->multiparty_list, &objpath_list); + voicecalls_path_list(vc, vc->multiparty_list, &objpath_list); - ofono_dbus_signal_array_property_changed(conn, modem->path, + ofono_dbus_signal_array_property_changed(conn, path, VOICECALL_MANAGER_INTERFACE, "MultipartyCalls", DBUS_TYPE_OBJECT_PATH, &objpath_list); g_strfreev(objpath_list); - voicecalls->emit_multi_source = 0; + vc->emit_multi_source = 0; return FALSE; } -static void emit_multiparty_call_list_changed(struct ofono_modem *modem) +static void emit_multiparty_call_list_changed(struct ofono_voicecall *vc) { #ifdef DELAY_EMIT - struct voicecalls_data *calls = modem->voicecalls; - - if (calls->emit_multi_source == 0) - calls->emit_multi_source = g_timeout_add(0, - real_emit_multiparty_call_list_changed, modem); + if (vc->emit_multi_source == 0) + vc->emit_multi_source = g_timeout_add(0, + real_emit_multiparty_call_list_changed, vc); } #else - real_emit_multiparty_call_list_changed(modem); + real_emit_multiparty_call_list_changed(vc); #endif } -void ofono_voicecall_disconnected(struct ofono_modem *modem, int id, +void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id, enum ofono_disconnect_reason reason, const struct ofono_error *error) { + struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); GSList *l; - struct voicecalls_data *calls = modem->voicecalls; struct voicecall *call; time_t ts; enum call_status prev_status; ofono_debug("Got disconnection event for id: %d, reason: %d", id, reason); - l = g_slist_find_custom(calls->call_list, GINT_TO_POINTER(id), + l = g_slist_find_custom(vc->call_list, GINT_TO_POINTER(id), call_compare_by_id); if (!l) { @@ -1273,27 +1202,27 @@ void ofono_voicecall_disconnected(struct ofono_modem *modem, int id, ts = time(NULL); prev_status = call->call->status; - l = g_slist_find_custom(calls->multiparty_list, GINT_TO_POINTER(id), + l = g_slist_find_custom(vc->multiparty_list, GINT_TO_POINTER(id), call_compare_by_id); if (l) { - calls->multiparty_list = - g_slist_remove(calls->multiparty_list, call); + vc->multiparty_list = + g_slist_remove(vc->multiparty_list, call); - if (calls->multiparty_list->next == NULL) { /* Size == 1 */ - g_slist_free(calls->multiparty_list); - calls->multiparty_list = 0; + if (vc->multiparty_list->next == NULL) { /* Size == 1 */ + g_slist_free(vc->multiparty_list); + vc->multiparty_list = 0; } - emit_multiparty_call_list_changed(modem); + emit_multiparty_call_list_changed(vc); } - calls->release_list = g_slist_remove(calls->release_list, call); + vc->release_list = g_slist_remove(vc->release_list, call); __ofono_modem_release_callid(modem, id); /* TODO: Emit disconnect reason */ - voicecall_set_call_status(modem, call, CALL_STATUS_DISCONNECTED); + voicecall_set_call_status(call, CALL_STATUS_DISCONNECTED); if (prev_status == CALL_STATUS_INCOMING) __ofono_history_call_missed(modem, call->call, ts); @@ -1301,30 +1230,31 @@ void ofono_voicecall_disconnected(struct ofono_modem *modem, int id, __ofono_history_call_ended(modem, call->call, call->detect_time, ts); - voicecall_dbus_unregister(modem, call); + voicecall_dbus_unregister(vc, call); - calls->call_list = g_slist_remove(calls->call_list, call); + vc->call_list = g_slist_remove(vc->call_list, call); - emit_call_list_changed(modem); + emit_call_list_changed(vc); } -void ofono_voicecall_notify(struct ofono_modem *modem, const struct ofono_call *call) +void ofono_voicecall_notify(struct ofono_voicecall *vc, + const struct ofono_call *call) { + struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); GSList *l; - struct voicecalls_data *calls = modem->voicecalls; struct voicecall *v = NULL; struct ofono_call *newcall = NULL; ofono_debug("Got a voicecall event, status: %d, id: %u, number: %s", call->status, call->id, call->phone_number.number); - l = g_slist_find_custom(calls->call_list, GINT_TO_POINTER(call->id), + l = g_slist_find_custom(vc->call_list, GINT_TO_POINTER(call->id), call_compare_by_id); if (l) { ofono_debug("Found call with id: %d\n", call->id); - voicecall_set_call_status(modem, l->data, call->status); - voicecall_set_call_lineid(modem, l->data, &call->phone_number, + voicecall_set_call_status(l->data, call->status); + voicecall_set_call_lineid(l->data, &call->phone_number, call->clip_validity); return; @@ -1347,7 +1277,7 @@ void ofono_voicecall_notify(struct ofono_modem *modem, const struct ofono_call * goto err; } - v = voicecall_create(modem, newcall); + v = voicecall_create(vc, newcall); if (!v) { ofono_error("Unable to allocate voicecall_data"); @@ -1361,10 +1291,9 @@ void ofono_voicecall_notify(struct ofono_modem *modem, const struct ofono_call * goto err; } - calls->call_list = g_slist_insert_sorted(calls->call_list, v, - call_compare); + vc->call_list = g_slist_insert_sorted(vc->call_list, v, call_compare); - emit_call_list_changed(modem); + emit_call_list_changed(vc); return; @@ -1378,7 +1307,7 @@ err: static void generic_callback(const struct ofono_error *error, void *data) { - struct voicecalls_data *calls = data; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *reply; @@ -1386,51 +1315,51 @@ static void generic_callback(const struct ofono_error *error, void *data) ofono_debug("command failed with error: %s", telephony_error_to_str(error)); - calls->flags &= ~VOICECALLS_FLAG_PENDING; + vc->flags &= ~VOICECALLS_FLAG_PENDING; - if (!calls->pending) + if (!vc->pending) return; if (error->type == OFONO_ERROR_TYPE_NO_ERROR) - reply = dbus_message_new_method_return(calls->pending); + reply = dbus_message_new_method_return(vc->pending); else - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); g_dbus_send_message(conn, reply); - dbus_message_unref(calls->pending); - calls->pending = NULL; + dbus_message_unref(vc->pending); + vc->pending = NULL; } static void multirelease_callback(const struct ofono_error *error, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *reply; - if (calls->release_list != NULL) { - voicecalls_release_next(modem); + if (vc->release_list != NULL) { + voicecalls_release_next(vc); return; } - calls->flags &= ~VOICECALLS_FLAG_MULTI_RELEASE; - calls->flags &= ~VOICECALLS_FLAG_PENDING; + vc->flags &= ~VOICECALLS_FLAG_MULTI_RELEASE; + vc->flags &= ~VOICECALLS_FLAG_PENDING; - if (!calls->pending) + if (!vc->pending) return; - reply = dbus_message_new_method_return(calls->pending); + reply = dbus_message_new_method_return(vc->pending); g_dbus_send_message(conn, reply); - dbus_message_unref(calls->pending); - calls->pending = NULL; + dbus_message_unref(vc->pending); + vc->pending = NULL; } -static struct ofono_call *synthesize_outgoing_call(struct ofono_modem *modem, +static struct ofono_call *synthesize_outgoing_call(struct ofono_voicecall *vc, DBusMessage *msg) { + struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); const char *number; struct ofono_call *call; @@ -1462,8 +1391,7 @@ static struct ofono_call *synthesize_outgoing_call(struct ofono_modem *modem, static void dial_callback(const struct ofono_error *error, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *reply; GSList *l; @@ -1475,25 +1403,25 @@ static void dial_callback(const struct ofono_error *error, void *data) ofono_debug("Dial callback returned error: %s", telephony_error_to_str(error)); - calls->flags &= ~VOICECALLS_FLAG_PENDING; + vc->flags &= ~VOICECALLS_FLAG_PENDING; - if (!calls->pending) + if (!vc->pending) return; if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); g_dbus_send_message(conn, reply); goto out; } - reply = dbus_message_new_method_return(calls->pending); + reply = dbus_message_new_method_return(vc->pending); if (!reply) goto out; /* Two things can happen, the call notification arrived before dial * callback or dial callback was first. Handle here */ - for (l = calls->call_list; l; l = l->next) { + for (l = vc->call_list; l; l = l->next) { struct voicecall *v = l->data; if (v->call->status == CALL_STATUS_DIALING || @@ -1503,19 +1431,19 @@ static void dial_callback(const struct ofono_error *error, void *data) if (!l) { struct voicecall *v; - call = synthesize_outgoing_call(modem, calls->pending); + call = synthesize_outgoing_call(vc, vc->pending); if (!call) { - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); g_dbus_send_message(conn, reply); goto out; } - v = voicecall_create(modem, call); + v = voicecall_create(vc, call); if (!v) { - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); g_dbus_send_message(conn, reply); goto out; @@ -1526,7 +1454,7 @@ static void dial_callback(const struct ofono_error *error, void *data) ofono_debug("Registering new call: %d", call->id); voicecall_dbus_register(v); - calls->call_list = g_slist_insert_sorted(calls->call_list, v, + vc->call_list = g_slist_insert_sorted(vc->call_list, v, call_compare); need_to_emit = TRUE; @@ -1536,7 +1464,7 @@ static void dial_callback(const struct ofono_error *error, void *data) call = v->call; } - path = voicecall_build_path(modem, call); + path = voicecall_build_path(vc, call); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); @@ -1544,24 +1472,22 @@ static void dial_callback(const struct ofono_error *error, void *data) g_dbus_send_message(conn, reply); if (need_to_emit) - emit_call_list_changed(modem); + emit_call_list_changed(vc); out: - dbus_message_unref(calls->pending); - calls->pending = NULL; + dbus_message_unref(vc->pending); + vc->pending = NULL; } - -static void multiparty_callback_common(struct ofono_modem *modem, +static void multiparty_callback_common(struct ofono_voicecall *vc, DBusMessage *reply) { - struct voicecalls_data *voicecalls = modem->voicecalls; DBusMessageIter iter; DBusMessageIter array_iter; char **objpath_list; int i; - voicecalls_path_list(modem, voicecalls->multiparty_list, &objpath_list); + voicecalls_path_list(vc, vc->multiparty_list, &objpath_list); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, @@ -1576,8 +1502,7 @@ static void multiparty_callback_common(struct ofono_modem *modem, static void multiparty_create_callback(const struct ofono_error *error, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *reply; gboolean need_to_emit = FALSE; @@ -1586,42 +1511,42 @@ static void multiparty_create_callback(const struct ofono_error *error, void *da ofono_debug("command failed with error: %s", telephony_error_to_str(error)); - calls->flags &= ~VOICECALLS_FLAG_PENDING; + vc->flags &= ~VOICECALLS_FLAG_PENDING; - if (!calls->pending) + if (!vc->pending) return; if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); goto out; } /* We just created a multiparty call, gather all held * active calls and add them to the multiparty list */ - if (calls->multiparty_list) { - g_slist_free(calls->multiparty_list); - calls->multiparty_list = 0; + if (vc->multiparty_list) { + g_slist_free(vc->multiparty_list); + vc->multiparty_list = 0; } - calls->multiparty_list = g_slist_concat(calls->multiparty_list, - voicecalls_held_list(calls)); + vc->multiparty_list = g_slist_concat(vc->multiparty_list, + voicecalls_held_list(vc)); - calls->multiparty_list = g_slist_concat(calls->multiparty_list, - voicecalls_active_list(calls)); + vc->multiparty_list = g_slist_concat(vc->multiparty_list, + voicecalls_active_list(vc)); - calls->multiparty_list = g_slist_sort(calls->multiparty_list, + vc->multiparty_list = g_slist_sort(vc->multiparty_list, call_compare); - if (g_slist_length(calls->multiparty_list) < 2) { + if (g_slist_length(vc->multiparty_list) < 2) { ofono_error("Created multiparty call, but size is less than 2" " panic!"); - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); } else { - reply = dbus_message_new_method_return(calls->pending); + reply = dbus_message_new_method_return(vc->pending); - multiparty_callback_common(modem, reply); + multiparty_callback_common(vc, reply); need_to_emit = TRUE; } @@ -1629,16 +1554,15 @@ out: g_dbus_send_message(conn, reply); if (need_to_emit) - emit_multiparty_call_list_changed(modem); + emit_multiparty_call_list_changed(vc); - dbus_message_unref(calls->pending); - calls->pending = NULL; + dbus_message_unref(vc->pending); + vc->pending = NULL; } static void private_chat_callback(const struct ofono_error *error, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *reply; gboolean need_to_emit = FALSE; @@ -1651,49 +1575,49 @@ static void private_chat_callback(const struct ofono_error *error, void *data) ofono_debug("command failed with error: %s", telephony_error_to_str(error)); - calls->flags &= ~VOICECALLS_FLAG_PENDING; + vc->flags &= ~VOICECALLS_FLAG_PENDING; - if (!calls->pending) + if (!vc->pending) return; if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { - reply = __ofono_error_failed(calls->pending); + reply = __ofono_error_failed(vc->pending); goto out; } - dbus_message_get_args(calls->pending, NULL, + dbus_message_get_args(vc->pending, NULL, DBUS_TYPE_OBJECT_PATH, &callpath, DBUS_TYPE_INVALID); c = strrchr(callpath, '/'); sscanf(c, "/voicecall%2u", &id); - l = g_slist_find_custom(calls->multiparty_list, GINT_TO_POINTER(id), + l = g_slist_find_custom(vc->multiparty_list, GINT_TO_POINTER(id), call_compare_by_id); if (l) { - calls->multiparty_list = - g_slist_remove(calls->multiparty_list, l->data); + vc->multiparty_list = + g_slist_remove(vc->multiparty_list, l->data); - if (g_slist_length(calls->multiparty_list) < 2) { - g_slist_free(calls->multiparty_list); - calls->multiparty_list = 0; + if (g_slist_length(vc->multiparty_list) < 2) { + g_slist_free(vc->multiparty_list); + vc->multiparty_list = 0; } } - reply = dbus_message_new_method_return(calls->pending); + reply = dbus_message_new_method_return(vc->pending); - multiparty_callback_common(modem, reply); + multiparty_callback_common(vc, reply); need_to_emit = TRUE; out: g_dbus_send_message(conn, reply); if (need_to_emit) - emit_multiparty_call_list_changed(modem); + emit_multiparty_call_list_changed(vc); - dbus_message_unref(calls->pending); - calls->pending = NULL; + dbus_message_unref(vc->pending); + vc->pending = NULL; } static gboolean in_default_en_list(const char *en) @@ -1706,18 +1630,19 @@ static gboolean in_default_en_list(const char *en) return FALSE; } -static void emit_en_list_changed(struct ofono_modem *modem) +static void emit_en_list_changed(struct ofono_voicecall *vc) { - struct voicecalls_data *calls = modem->voicecalls; DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(vc->atom); char **list; GSList *l; int i; - list = g_new0(char *, g_slist_length(calls->en_list) + 1); - for (i = 0, l = calls->en_list; l; l = l->next, i++) + list = g_new0(char *, g_slist_length(vc->en_list) + 1); + for (i = 0, l = vc->en_list; l; l = l->next, i++) list[i] = g_strdup(l->data); - ofono_dbus_signal_array_property_changed(conn, modem->path, + + ofono_dbus_signal_array_property_changed(conn, path, VOICECALL_MANAGER_INTERFACE, "EmergencyNumbers", DBUS_TYPE_STRING, @@ -1726,44 +1651,41 @@ static void emit_en_list_changed(struct ofono_modem *modem) g_strfreev(list); } -static void set_new_ecc(struct ofono_modem *modem) +static void set_new_ecc(struct ofono_voicecall *vc) { - struct voicecalls_data *calls = modem->voicecalls; GSList *l; int i = 0; - g_slist_foreach(calls->en_list, (GFunc)g_free, NULL); - g_slist_free(calls->en_list); - calls->en_list = NULL; + g_slist_foreach(vc->en_list, (GFunc)g_free, NULL); + g_slist_free(vc->en_list); + vc->en_list = NULL; - calls->en_list = calls->new_en_list; - calls->new_en_list = NULL; + vc->en_list = vc->new_en_list; + vc->new_en_list = NULL; while (default_en_list[i]) { GSList *l; - for (l = calls->en_list; l; l = l->next) + for (l = vc->en_list; l; l = l->next) if (!strcmp(l->data, default_en_list[i])) break; if (l == NULL) - calls->en_list = g_slist_prepend(calls->en_list, + vc->en_list = g_slist_prepend(vc->en_list, g_strdup(default_en_list[i])); i++; } - calls->en_list = g_slist_reverse(calls->en_list); - emit_en_list_changed(modem); + vc->en_list = g_slist_reverse(vc->en_list); + emit_en_list_changed(vc); } -static void ecc_read_cb(int ok, - enum ofono_sim_file_structure structure, int total_length, - int record, const unsigned char *data, int record_length, - void *userdata) +static void ecc_read_cb(int ok, enum ofono_sim_file_structure structure, + int total_length, int record, const unsigned char *data, + int record_length, void *userdata) { - struct ofono_modem *modem = userdata; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = userdata; int total; char en[7]; @@ -1781,60 +1703,160 @@ static void ecc_read_cb(int ok, total = total_length / record_length; extract_bcd_number(data, 3, en); - calls->new_en_list = g_slist_prepend(calls->new_en_list, g_strdup(en)); + vc->new_en_list = g_slist_prepend(vc->new_en_list, g_strdup(en)); if (record != total) return; check: - if (calls->new_en_list == NULL) + if (vc->new_en_list == NULL) return; - set_new_ecc(modem); + set_new_ecc(vc); +} + +int ofono_voicecall_driver_register(const struct ofono_voicecall_driver *d) +{ + DBG("driver: %p, name: %s", d, d->name); + + if (d->probe == NULL) + return -EINVAL; + + g_drivers = g_slist_prepend(g_drivers, (void *)d); + + return 0; +} + +void ofono_voicecall_driver_unregister(const struct ofono_voicecall_driver *d) +{ + DBG("driver: %p, name: %s", d, d->name); + + g_drivers = g_slist_remove(g_drivers, (void *)d); +} + +static void voicecall_unregister(struct ofono_atom *atom) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + struct ofono_voicecall *vc = __ofono_atom_get_data(atom); + struct ofono_modem *modem = __ofono_atom_get_modem(atom); + const char *path = __ofono_atom_get_path(atom); + GSList *l; + + if (vc->sim_watch) { + __ofono_modem_remove_atom_watch(modem, vc->sim_watch); + vc->sim_watch = 0; + } + + if (vc->emit_calls_source) { + g_source_remove(vc->emit_calls_source); + vc->emit_calls_source = 0; + } + + if (vc->emit_multi_source) { + g_source_remove(vc->emit_multi_source); + vc->emit_multi_source = 0; + } + + for (l = vc->call_list; l; l = l->next) + voicecall_dbus_unregister(vc, l->data); + + g_slist_free(vc->call_list); + + ofono_modem_remove_interface(modem, VOICECALL_MANAGER_INTERFACE); + g_dbus_unregister_interface(conn, modem->path, + VOICECALL_MANAGER_INTERFACE); +} + +static void voicecall_remove(struct ofono_atom *atom) +{ + struct ofono_voicecall *vc = __ofono_atom_get_data(atom); + + DBG("atom: %p", atom); + + if (vc == NULL) + return; + + if (vc->driver && vc->driver->remove) + vc->driver->remove(vc); + + if (vc->en_list) { + g_slist_foreach(vc->en_list, (GFunc)g_free, NULL); + g_slist_free(vc->en_list); + vc->en_list = NULL; + } + + if (vc->new_en_list) { + g_slist_foreach(vc->new_en_list, (GFunc)g_free, NULL); + g_slist_free(vc->new_en_list); + vc->new_en_list = NULL; + } + + g_free(vc); +} + +struct ofono_voicecall *ofono_voicecall_create(struct ofono_modem *modem, + const char *driver, + void *data) +{ + struct ofono_voicecall *vc; + GSList *l; + + if (driver == NULL) + return NULL; + + vc = g_try_new0(struct ofono_voicecall, 1); + + if (vc == NULL) + return NULL; + + vc->driver_data = data; + vc->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_VOICECALL, + voicecall_remove, vc); + + for (l = g_drivers; l; l = l->next) { + const struct ofono_voicecall_driver *drv = l->data; + + if (g_strcmp0(drv->name, driver)) + continue; + + if (drv->probe(vc) < 0) + continue; + + vc->driver = drv; + break; + } + + return vc; } static void sim_watch(struct ofono_atom *atom, enum ofono_atom_watch_condition cond, void *data) { - struct ofono_modem *modem = data; - struct voicecalls_data *calls = modem->voicecalls; + struct ofono_voicecall *vc = data; struct ofono_sim *sim = __ofono_atom_get_data(atom); if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) { return; } - ofono_sim_read(sim, SIM_EFECC_FILEID, ecc_read_cb, modem); + ofono_sim_read(sim, SIM_EFECC_FILEID, ecc_read_cb, vc); } -int ofono_voicecall_register(struct ofono_modem *modem, struct ofono_voicecall_ops *ops) +void ofono_voicecall_register(struct ofono_voicecall *vc) { DBusConnection *conn = ofono_dbus_get_connection(); + struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); + const char *path = __ofono_atom_get_path(vc->atom); struct ofono_atom *sim_atom; - if (modem == NULL) - return -1; - - if (ops == NULL) - return -1; - - modem->voicecalls = voicecalls_create(); - - if (modem->voicecalls == NULL) - return -1; - - modem->voicecalls->ops = ops; - - if (!g_dbus_register_interface(conn, modem->path, + if (!g_dbus_register_interface(conn, path, VOICECALL_MANAGER_INTERFACE, manager_methods, manager_signals, NULL, - modem, voicecalls_destroy)) { + vc, NULL)) { ofono_error("Could not create %s interface", VOICECALL_MANAGER_INTERFACE); - voicecalls_destroy(modem->voicecalls); - - return -1; + return; } ofono_modem_add_interface(modem, VOICECALL_MANAGER_INTERFACE); @@ -1842,33 +1864,32 @@ int ofono_voicecall_register(struct ofono_modem *modem, struct ofono_voicecall_o /* Start out with the 22.101 mandated numbers, if we have a SIM and * the SIM contains EFecc, then we update the list once we've read them */ - add_to_en_list(&modem->voicecalls->en_list, default_en_list_no_sim); - add_to_en_list(&modem->voicecalls->en_list, default_en_list); + add_to_en_list(&vc->en_list, default_en_list_no_sim); + add_to_en_list(&vc->en_list, default_en_list); - modem->voicecalls->sim_watch = __ofono_modem_add_atom_watch(modem, - OFONO_ATOM_TYPE_SIM, - sim_watch, modem, NULL); + vc->sim_watch = __ofono_modem_add_atom_watch(modem, + OFONO_ATOM_TYPE_SIM, + sim_watch, vc, NULL); sim_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_SIM); if (sim_atom && __ofono_atom_get_registered(sim_atom)) - sim_watch(sim_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED, - modem); + sim_watch(sim_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED, vc); - return 0; + __ofono_atom_register(vc->atom, voicecall_unregister); } -void ofono_voicecall_unregister(struct ofono_modem *modem) +void ofono_voicecall_remove(struct ofono_voicecall *vc) { - DBusConnection *conn = ofono_dbus_get_connection(); - GSList *l; - - if (!modem->voicecalls) - return; - - ofono_modem_remove_interface(modem, VOICECALL_MANAGER_INTERFACE); - g_dbus_unregister_interface(conn, modem->path, - VOICECALL_MANAGER_INTERFACE); - - modem->voicecalls = NULL; + __ofono_atom_free(vc->atom); +} + +void ofono_voicecall_set_data(struct ofono_voicecall *vc, void *data) +{ + vc->driver_data = data; +} + +void *ofono_voicecall_get_data(struct ofono_voicecall *vc) +{ + return vc->driver_data; }