diff --git a/include/Makefile.am b/include/Makefile.am index 22244228..c256346d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,7 +4,7 @@ includedir = @includedir@/ofono 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 + ssn.h ussd.h nodist_include_HEADERS = version.h diff --git a/include/ussd.h b/include/ussd.h new file mode 100644 index 00000000..dd961b8a --- /dev/null +++ b/include/ussd.h @@ -0,0 +1,63 @@ +/* + * + * 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_USSD_H +#define __OFONO_USSD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct ofono_ussd; + +typedef void (*ofono_ussd_cb_t)(const struct ofono_error *error, void *data); + +struct ofono_ussd_driver { + const char *name; + int (*probe)(struct ofono_ussd *ussd); + int (*remove)(struct ofono_ussd *ussd); + void (*request)(struct ofono_ussd *ussd, const char *str, + ofono_ussd_cb_t, void *data); + void (*cancel)(struct ofono_ussd *ussd, + ofono_ussd_cb_t cb, void *data); +}; + +void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str); + +int ofono_ussd_driver_register(const struct ofono_ussd_driver *d); +void ofono_ussd_driver_unregister(const struct ofono_ussd_driver *d); + +struct ofono_ussd *ofono_ussd_create(struct ofono_modem *modem, + const char *driver, void *data); + +void ofono_ussd_register(struct ofono_ussd *ussd); +void ofono_ussd_remove(struct ofono_ussd *ussd); + +void ofono_ussd_set_data(struct ofono_ussd *ussd, void *data); +void *ofono_ussd_get_data(struct ofono_ussd *ussd); + +#ifdef __cplusplus +} +#endif + +#endif /* __OFONO_USSD_H */ diff --git a/src/driver.h b/src/driver.h index 81db1da3..f62d2f34 100644 --- a/src/driver.h +++ b/src/driver.h @@ -212,17 +212,6 @@ void ofono_voicecall_disconnected(struct ofono_modem *modem, int id, int ofono_voicecall_register(struct ofono_modem *modem, struct ofono_voicecall_ops *ops); void ofono_voicecall_unregister(struct ofono_modem *modem); -struct ofono_ussd_ops { - void (*request)(struct ofono_modem *modem, const char *str, - ofono_generic_cb_t cb, void *data); - void (*cancel)(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); -}; - -void ofono_ussd_notify(struct ofono_modem *modem, int status, const char *str); -int ofono_ussd_register(struct ofono_modem *modem, struct ofono_ussd_ops *ops); -void ofono_ussd_unregister(struct ofono_modem *modem); - struct ofono_sim_ops { void (*read_file_info)(struct ofono_modem *modem, int fileid, ofono_sim_file_info_cb_t cb, void *data); diff --git a/src/ofono.h b/src/ofono.h index 10d94434..ae223f9a 100644 --- a/src/ofono.h +++ b/src/ofono.h @@ -78,7 +78,6 @@ struct ofono_modem { struct network_registration_data *network_registration; struct voicecalls_data *voicecalls; struct ofono_call_forwarding *call_forwarding; - struct ussd_data *ussd; struct ofono_call_settings *call_settings; struct ofono_call_barring *call_barring; struct cssn_data *cssn; @@ -170,6 +169,8 @@ unsigned int __ofono_ssn_mt_watch_add(struct ofono_ssn *ssn, int code2, ofono_destroy_func destroy); gboolean __ofono_ssn_mt_watch_remove(struct ofono_ssn *ssn, int id); +#include + #include void __ofono_history_probe_drivers(struct ofono_modem *modem); diff --git a/src/ussd.c b/src/ussd.c index 27c389c9..4a0a3e81 100644 --- a/src/ussd.c +++ b/src/ussd.c @@ -26,13 +26,13 @@ #define _GNU_SOURCE #include #include +#include #include #include #include "ofono.h" -#include "driver.h" #include "common.h" #include "ussd.h" @@ -40,36 +40,23 @@ #define USSD_FLAG_PENDING 0x1 +static GSList *g_drivers = NULL; + enum ussd_state { USSD_STATE_IDLE = 0, USSD_STATE_ACTIVE = 1, USSD_STATE_USER_ACTION = 2 }; -struct ussd_data { - struct ofono_ussd_ops *ops; +struct ofono_ussd { int state; DBusMessage *pending; int flags; + const struct ofono_ussd_driver *driver; + void *driver_data; + struct ofono_atom *atom; }; -static struct ussd_data *ussd_create() -{ - struct ussd_data *r; - - r = g_try_new0(struct ussd_data, 1); - - return r; -} - -static void ussd_destroy(gpointer data) -{ - struct ofono_modem *modem = data; - struct ussd_data *ussd = modem->ussd; - - g_free(ussd); -} - struct ss_control_entry { char *service; ss_control_cb_t cb; @@ -355,9 +342,8 @@ out: return ret; } -void ofono_ussd_notify(struct ofono_modem *modem, int status, const char *str) +void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str) { - struct ussd_data *ussd = modem->ussd; DBusConnection *conn = ofono_dbus_get_connection(); const char *ussdstr = "USSD"; const char sig[] = { DBUS_TYPE_STRING, 0 }; @@ -416,7 +402,7 @@ out: static void ussd_callback(const struct ofono_error *error, void *data) { - struct ussd_data *ussd = data; + struct ofono_ussd *ussd = data; DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *reply; @@ -445,8 +431,8 @@ static void ussd_callback(const struct ofono_error *error, void *data) static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct ussd_data *ussd = modem->ussd; + struct ofono_ussd *ussd = data; + struct ofono_modem *modem = __ofono_atom_get_modem(ussd->atom); const char *str; if (ussd->flags & USSD_FLAG_PENDING) @@ -472,20 +458,20 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg, ofono_debug("OK, running USSD request"); - if (!ussd->ops->request) + if (!ussd->driver->request) return __ofono_error_not_implemented(msg); ussd->flags |= USSD_FLAG_PENDING; ussd->pending = dbus_message_ref(msg); - ussd->ops->request(modem, str, ussd_callback, ussd); + ussd->driver->request(ussd, str, ussd_callback, ussd); return NULL; } static void ussd_cancel_callback(const struct ofono_error *error, void *data) { - struct ussd_data *ussd = data; + struct ofono_ussd *ussd = data; DBusMessage *reply; if (error->type != OFONO_ERROR_TYPE_NO_ERROR) @@ -510,8 +496,7 @@ static void ussd_cancel_callback(const struct ofono_error *error, void *data) static DBusMessage *ussd_cancel(DBusConnection *conn, DBusMessage *msg, void *data) { - struct ofono_modem *modem = data; - struct ussd_data *ussd = modem->ussd; + struct ofono_ussd *ussd = data; if (ussd->flags & USSD_FLAG_PENDING) return __ofono_error_busy(msg); @@ -519,13 +504,13 @@ static DBusMessage *ussd_cancel(DBusConnection *conn, DBusMessage *msg, if (ussd->state == USSD_STATE_IDLE) return __ofono_error_not_active(msg); - if (!ussd->ops->cancel) + if (!ussd->driver->cancel) return __ofono_error_not_implemented(msg); ussd->flags |= USSD_FLAG_PENDING; ussd->pending = dbus_message_ref(msg); - ussd->ops->cancel(modem, ussd_cancel_callback, ussd); + ussd->driver->cancel(ussd, ussd_cancel_callback, ussd); return NULL; } @@ -542,48 +527,119 @@ static GDBusSignalTable ussd_signals[] = { { } }; -int ofono_ussd_register(struct ofono_modem *modem, struct ofono_ussd_ops *ops) +int ofono_ussd_driver_register(const struct ofono_ussd_driver *d) { - DBusConnection *conn = ofono_dbus_get_connection(); + DBG("driver: %p, name: %s", d, d->name); - if (modem == NULL) - return -1; + if (d->probe == NULL) + return -EINVAL; - if (ops == NULL) - return -1; - - modem->ussd = ussd_create(); - - if (modem->ussd == NULL) - return -1; - - modem->ussd->ops = ops; - - if (!g_dbus_register_interface(conn, modem->path, - SUPPLEMENTARY_SERVICES_INTERFACE, - ussd_methods, ussd_signals, NULL, - modem, ussd_destroy)) { - ofono_error("Could not create %s interface", - SUPPLEMENTARY_SERVICES_INTERFACE); - - ussd_destroy(modem->ussd); - - return -1; - } - - ofono_modem_add_interface(modem, SUPPLEMENTARY_SERVICES_INTERFACE); + g_drivers = g_slist_prepend(g_drivers, (void *)d); return 0; } -void ofono_ussd_unregister(struct ofono_modem *modem) +void ofono_ussd_driver_unregister(const struct ofono_ussd_driver *d) { - DBusConnection *conn = ofono_dbus_get_connection(); + DBG("driver: %p, name: %s", d, d->name); - if (modem->ussd == NULL) - return; + g_drivers = g_slist_remove(g_drivers, (void *)d); +} + +static void ussd_unregister(struct ofono_atom *atom) +{ + struct ofono_ussd *ussd = __ofono_atom_get_data(atom); + DBusConnection *conn = ofono_dbus_get_connection(); + struct ofono_modem *modem = __ofono_atom_get_modem(atom); + const char *path = __ofono_atom_get_path(atom); ofono_modem_remove_interface(modem, SUPPLEMENTARY_SERVICES_INTERFACE); - g_dbus_unregister_interface(conn, modem->path, + g_dbus_unregister_interface(conn, path, SUPPLEMENTARY_SERVICES_INTERFACE); } + +static void ussd_remove(struct ofono_atom *atom) +{ + struct ofono_ussd *ussd = __ofono_atom_get_data(atom); + + DBG("atom: %p", atom); + + if (ussd == NULL) + return; + + if (ussd->driver && ussd->driver->remove) + ussd->driver->remove(ussd); + + g_free(ussd); +} + +struct ofono_ussd *ofono_ussd_create(struct ofono_modem *modem, + const char *driver, + void *data) +{ + struct ofono_ussd *ussd; + GSList *l; + + if (driver == NULL) + return NULL; + + ussd = g_try_new0(struct ofono_ussd, 1); + + if (ussd == NULL) + return NULL; + + ussd->driver_data = data; + ussd->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_USSD, + ussd_remove, ussd); + + for (l = g_drivers; l; l = l->next) { + const struct ofono_ussd_driver *drv = l->data; + + if (g_strcmp0(drv->name, driver)) + continue; + + if (drv->probe(ussd) < 0) + continue; + + ussd->driver = drv; + break; + } + + return ussd; +} + +void ofono_ussd_register(struct ofono_ussd *ussd) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + struct ofono_modem *modem = __ofono_atom_get_modem(ussd->atom); + const char *path = __ofono_atom_get_path(ussd->atom); + + if (!g_dbus_register_interface(conn, path, + SUPPLEMENTARY_SERVICES_INTERFACE, + ussd_methods, ussd_signals, NULL, + ussd, NULL)) { + ofono_error("Could not create %s interface", + OFONO_CALL_BARRING_INTERFACE); + + return; + } + + ofono_modem_add_interface(modem, SUPPLEMENTARY_SERVICES_INTERFACE); + + __ofono_atom_register(ussd->atom, ussd_unregister); +} + +void ofono_ussd_remove(struct ofono_ussd *ussd) +{ + __ofono_atom_free(ussd->atom); +} + +void ofono_ussd_set_data(struct ofono_ussd *ussd, void *data) +{ + ussd->driver_data = data; +} + +void *ofono_ussd_get_data(struct ofono_ussd *ussd) +{ + return ussd->driver_data; +}