From a7989b7cbb76c528b9390c40ff6487ac9618a188 Mon Sep 17 00:00:00 2001 From: Aki Niemi Date: Fri, 5 Feb 2010 12:22:44 +0200 Subject: [PATCH] Add isimodem gprs driver --- Makefile.am | 1 + drivers/isimodem/gprs.c | 315 ++++++++++++++++++++++++++++++++++++ drivers/isimodem/isimodem.c | 4 + drivers/isimodem/isimodem.h | 3 + 4 files changed, 323 insertions(+) create mode 100644 drivers/isimodem/gprs.c diff --git a/Makefile.am b/Makefile.am index 2aaff05e..20afadf1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -112,6 +112,7 @@ builtin_sources += $(gisi_sources) \ drivers/isimodem/ss.h \ drivers/isimodem/radio-settings.c \ drivers/isimodem/gss.h \ + drivers/isimodem/gprs.c \ drivers/isimodem/gpds.h endif diff --git a/drivers/isimodem/gprs.c b/drivers/isimodem/gprs.c new file mode 100644 index 00000000..623ba3c3 --- /dev/null +++ b/drivers/isimodem/gprs.c @@ -0,0 +1,315 @@ +/* + * This file is part of oFono - Open Source Telephony + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidary(-ies). + * + * 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 +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "isimodem.h" +#include "isiutil.h" +#include "gpds.h" +#include "debug.h" + +struct gprs_data { + GIsiClient *client; +}; + +static void detach_ind_cb(GIsiClient *client, const void *restrict data, + size_t len, uint16_t object, void *opaque) +{ + /*struct ofono_gprs *gprs = opaque;*/ + const unsigned char *msg = data; + + if (!msg || len < 3 || msg[0] != GPDS_DETACH_IND) + return; + + DBG("detached: %s (0x%02"PRIx8")", + gpds_isi_cause_name(msg[1]), msg[1]); + + /* TODO: Don't report this to core, it won't ever reattach */ + /*ofono_gprs_detached_notify(gprs);*/ +} + +static gboolean isi_gprs_register(gpointer user) +{ + struct ofono_gprs *gprs = user; + struct gprs_data *gd = ofono_gprs_get_data(gprs); + + const char *debug = getenv("OFONO_ISI_DEBUG"); + + if (debug && (strcmp(debug, "all") == 0 || strcmp(debug, "gpds") == 0)) + g_isi_client_set_debug(gd->client, gpds_debug, NULL); + + g_isi_subscribe(gd->client, GPDS_DETACH_IND, detach_ind_cb, gprs); + + ofono_gprs_register(user); + + return FALSE; +} + +static void gpds_reachable_cb(GIsiClient *client, bool alive, uint16_t object, + void *opaque) +{ + struct ofono_gprs *gprs = opaque; + + if (!alive) { + DBG("unable to bootsrap gprs driver"); + return; + } + + DBG("%s (v%03d.%03d)", + pn_resource_name(g_isi_client_resource(client)), + g_isi_version_major(client), + g_isi_version_minor(client)); + + g_idle_add(isi_gprs_register, gprs); +} + +static int isi_gprs_probe(struct ofono_gprs *gprs, + unsigned int vendor, void *user) +{ + GIsiModem *idx = user; + struct gprs_data *gd = g_try_new0(struct gprs_data, 1); + + if (!gd) + return -ENOMEM; + + gd->client = g_isi_client_create(idx, PN_GPDS); + if (!gd->client) { + g_free(gd); + return -ENOMEM; + } + + ofono_gprs_set_data(gprs, gd); + + ofono_gprs_set_cid_range(gprs, 1, GPDS_MAX_CONTEXT_COUNT + 1); + + g_isi_verify(gd->client, gpds_reachable_cb, gprs); + + return 0; +} + +static void isi_gprs_remove(struct ofono_gprs *gprs) +{ + struct gprs_data *gd = ofono_gprs_get_data(gprs); + + ofono_gprs_set_data(gprs, NULL); + + if (gd->client) + g_isi_client_destroy(gd->client); + + g_free(gd); +} + +static bool attach_resp_cb(GIsiClient *client, const void *restrict data, + size_t len, uint16_t object, void *opaque) +{ + const unsigned char *msg = data; + struct isi_cb_data *cbd = opaque; + ofono_gprs_cb_t cb = cbd->cb; + + if(!msg) { + DBG("ISI client error: %d", g_isi_client_error(client)); + goto error; + } + + if (len != 4 || msg[0] != GPDS_ATTACH_RESP) + return false; + + if (msg[1] != GPDS_OK) { + DBG("attach failed: %s", gpds_status_name(msg[1])); + goto error; + } + + CALLBACK_WITH_SUCCESS(cb, cbd->data); + goto out; + +error: + CALLBACK_WITH_FAILURE(cb, cbd->data); + +out: + g_free(cbd); + return true; +} + +static bool detach_resp_cb(GIsiClient *client, const void *restrict data, + size_t len, uint16_t object, void *opaque) +{ + const unsigned char *msg = data; + struct isi_cb_data *cbd = opaque; + ofono_gprs_cb_t cb = cbd->cb; + + if(!msg) { + DBG("ISI client error: %d", g_isi_client_error(client)); + goto error; + } + + if (len != 3 || msg[0] != GPDS_DETACH_RESP) + return false; + + if (msg[1] != GPDS_OK) { + DBG("detach failed: %s", gpds_status_name(msg[1])); + goto error; + } + + CALLBACK_WITH_SUCCESS(cb, cbd->data); + goto out; + +error: + CALLBACK_WITH_FAILURE(cb, cbd->data); + +out: + g_free(cbd); + return true; +} + +static GIsiRequest *attach_request_make(GIsiClient *client, void *data) +{ + const unsigned char msg[] = { + GPDS_ATTACH_REQ, + GPDS_FOLLOW_OFF + }; + + return g_isi_request_make(client, msg, sizeof(msg), GPDS_TIMEOUT, + attach_resp_cb, data); +} + +static GIsiRequest *detach_request_make(GIsiClient *client, void *data) +{ + const unsigned char msg[] = { + GPDS_DETACH_REQ, + 0x00, /* filler */ + 0x00 /* sub-blocks */ + }; + + return g_isi_request_make(client, msg, sizeof(msg), GPDS_TIMEOUT, + detach_resp_cb, data); +} + +static void isi_gprs_set_attached(struct ofono_gprs *gprs, int attached, + ofono_gprs_cb_t cb, void *data) +{ + struct gprs_data *gd = ofono_gprs_get_data(gprs); + struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, data); + + GIsiRequest *req; + + if (!cbd) + goto error; + + if (attached) + req = attach_request_make(gd->client, cbd); + else + req = detach_request_make(gd->client, cbd); + + if (req) + return; + +error: + CALLBACK_WITH_FAILURE(cb, data); + g_free(cbd); +} + +static bool status_resp_cb(GIsiClient *client, const void *restrict data, + size_t len, uint16_t object, void *opaque) +{ + const unsigned char *msg = data; + struct isi_cb_data *cbd = opaque; + ofono_gprs_status_cb_t cb = cbd->cb; + + if(!msg) { + DBG("ISI client error: %d", g_isi_client_error(client)); + goto error; + } + + if (len < 2 || msg[0] != GPDS_STATUS_RESP) + return false; + + /* FIXME: the core still expects reg status, and not a boolean + * attached status here.*/ + + /* CALLBACK_WITH_SUCCESS(cb, msg[1] == GPDS_ATTACHED, cbd->data); */ + CALLBACK_WITH_SUCCESS(cb, 1, cbd->data); + + goto out; + +error: + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + +out: + g_free(cbd); + return true; +} + +static void isi_gprs_attached_status(struct ofono_gprs *gprs, + ofono_gprs_status_cb_t cb, + void *data) +{ + struct gprs_data *gd = ofono_gprs_get_data(gprs); + struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, data); + + const unsigned char msg[] = { + GPDS_STATUS_REQ, + }; + + if (!cbd) + goto error; + + if (g_isi_request_make(gd->client, msg, sizeof(msg), GPDS_TIMEOUT, + status_resp_cb, cbd)) + return; + +error: + CALLBACK_WITH_FAILURE(cb, -1, data); + g_free(cbd); + +} + +static struct ofono_gprs_driver driver = { + .name = "isimodem", + .probe = isi_gprs_probe, + .remove = isi_gprs_remove, + .set_attached = isi_gprs_set_attached, + .attached_status = isi_gprs_attached_status, +}; + +void isi_gprs_init(void) +{ + ofono_gprs_driver_register(&driver); +} + +void isi_gprs_exit(void) +{ + ofono_gprs_driver_unregister(&driver); +} diff --git a/drivers/isimodem/isimodem.c b/drivers/isimodem/isimodem.c index bef80a00..cec1dfff 100644 --- a/drivers/isimodem/isimodem.c +++ b/drivers/isimodem/isimodem.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "isimodem.h" #include "isiutil.h" @@ -312,6 +313,7 @@ static void isi_modem_post_sim(struct ofono_modem *modem) ofono_call_barring_create(isi->modem, 0, "isimodem", isi->idx); ofono_call_meter_create(isi->modem, 0, "isimodem", isi->idx); ofono_radio_settings_create(isi->modem, 0, "isimodem", isi->idx); + ofono_gprs_create(isi->modem, 0, "isimodem", isi->idx); } static struct ofono_modem_driver driver = { @@ -342,6 +344,7 @@ static int isimodem_init(void) isi_call_barring_init(); isi_call_meter_init(); isi_radio_settings_init(); + isi_gprs_init(); ofono_modem_driver_register(&driver); @@ -383,6 +386,7 @@ static void isimodem_exit(void) isi_call_barring_exit(); isi_call_meter_exit(); isi_radio_settings_exit(); + isi_gprs_exit(); } OFONO_PLUGIN_DEFINE(isimodem, "PhoNet / ISI modem driver", VERSION, diff --git a/drivers/isimodem/isimodem.h b/drivers/isimodem/isimodem.h index a363dc64..b57ca4e0 100644 --- a/drivers/isimodem/isimodem.h +++ b/drivers/isimodem/isimodem.h @@ -60,3 +60,6 @@ extern void isi_call_meter_exit(); extern void isi_radio_settings_init(); extern void isi_radio_settings_exit(); + +extern void isi_gprs_init(); +extern void isi_gprs_exit();