All of lore.kernel.org
 help / color / mirror / Atom feed
* Infineon modem API to support aGPS
@ 2010-10-30  3:43 Benis, Robertino
  2010-10-30 10:58 ` Marcel Holtmann
  0 siblings, 1 reply; 2+ messages in thread
From: Benis, Robertino @ 2010-10-30  3:43 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 34400 bytes --]

Hi

This is the first attempt to add aGPS support for Infineon modem. Patch
contains modem API per Waldo's RFC and suggestions.

DBUS API in ofono core are just place holders (not implemented), in this patch.

Thanks
-- r.

From fab1feadc9c9cf384aa42404bfba307c86f598db Mon Sep 17 00:00:00 2001
From: Robertino Benis <robertino.benis@intel.com>
Date: Fri, 29 Oct 2010 20:10:06 -0700
Subject: [CHANGE] Added aGPS Modem API implementation for Infineon modem
Organization: Intel
Cc: robertino.benis(a)intel.com

---
 Makefile.am                 |    7 +-
 drivers/ifxmodem/agps.c     |  418 +++++++++++++++++++++++++++++++++++++++++++
 drivers/ifxmodem/ifxmodem.c |    2 +
 drivers/ifxmodem/ifxmodem.h |    3 +
 include/agps.h              |  159 ++++++++++++++++
 include/dbus.h              |    1 +
 plugins/ifx.c               |   12 +-
 src/agps.c                  |  229 +++++++++++++++++++++++
 src/ofono.h                 |    2 +
 9 files changed, 827 insertions(+), 6 deletions(-)
 create mode 100644 drivers/ifxmodem/agps.c
 create mode 100644 include/agps.h
 create mode 100644 src/agps.c

diff --git a/Makefile.am b/Makefile.am
index 2562160..6ec4761 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ include_HEADERS = include/log.h include/plugin.h include/history.h \
                        include/cbs.h include/call-volume.h \
                        include/gprs.h include/gprs-context.h \
                        include/radio-settings.h include/stk.h \
-                       include/audio-settings.h include/nettime.h
+                       include/audio-settings.h include/nettime.h include/agps.h

 nodist_include_HEADERS = include/version.h

@@ -218,7 +218,8 @@ builtin_sources += drivers/atmodem/atutil.h \
                        drivers/ifxmodem/audio-settings.c \
                        drivers/ifxmodem/radio-settings.c \
                        drivers/ifxmodem/gprs-context.c \
-                       drivers/ifxmodem/stk.c
+                       drivers/ifxmodem/stk.c \
+                       drivers/ifxmodem/agps.c

 builtin_modules += stemodem
 builtin_sources += drivers/atmodem/atutil.h \
@@ -315,7 +316,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \
                        src/gprs.c src/idmap.h src/idmap.c \
                        src/radio-settings.c src/stkutil.h src/stkutil.c \
                        src/nettime.c src/stkagent.c src/stkagent.h \
-                       src/simfs.c src/simfs.h src/audio-settings.c
+                       src/simfs.c src/simfs.h src/audio-settings.c src/agps.c

 src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl

diff --git a/drivers/ifxmodem/agps.c b/drivers/ifxmodem/agps.c
new file mode 100644
index 0000000..202795e
--- /dev/null
+++ b/drivers/ifxmodem/agps.c
@@ -0,0 +1,418 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  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 <gisi/client.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/agps.h>
+
+#include "util.h"
+#include "ifxmodem.h"
+
+struct agps_data {
+       GAtChat *chat;
+       unsigned int vendor;
+       enum ofono_access_technology rad_acc_tech;
+};
+
+struct ofono_agps;
+static const char *none_prefix[] = { NULL };
+
+#define FRAME_LEN 128
+
+static void pos_request_notify(GAtResult *result, gpointer user_data)
+{
+       struct ofono_agps *agps = user_data;
+       int framelen;
+       int frametype;
+       GAtResultIter iter;
+       struct ofono_lcs_frame lcsframe;
+       const char *messageframe;
+       unsigned char frame[FRAME_LEN]; /* TODO - Length TBD */
+       long hexframelen;
+
+       /* Assuming Pos Req format: %XPOSR: <frametype>,<framelen>,<frame> */
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "%%XPOSR:"))
+               return;
+
+       if (!g_at_result_iter_next_number(&iter, &frametype))
+               return;
+
+       if (!g_at_result_iter_next_number(&iter, &framelen))
+               return;
+
+       if (framelen > FRAME_LEN) {
+               ofono_error("Got POS request message more than maximum buffer size!");
+               return;
+       }
+
+       messageframe = g_at_result_pdu(result);
+
+       if (strlen(messageframe) > sizeof(frame) * 2) { /* Hex, 2 chars / byte */
+               ofono_error("Message frame too long!");
+                return;
+       }
+
+       if (decode_hex_own_buf(messageframe, -1, &hexframelen, 0,
+                               frame) == NULL) {
+               ofono_error("Unable to hex-decode the AGPS frame");
+               return;
+       }
+
+       DBG("Got POS request data: %s, %ld", frame, hexframelen);
+
+       if (hexframelen != framelen) {
+               ofono_error("hexframelen not equal to reported framelen");
+               return;
+       }
+
+       lcsframe.lcs_frame_type = frametype;
+       lcsframe.frame_length = framelen;
+       lcsframe.raw_frame = (unsigned char *)frame;
+
+       ofono_agps_lcs_frame_notify(agps, lcsframe);
+}
+
+static int ifx_agps_probe(struct ofono_agps *agps,
+                                       unsigned int vendor, void *data)
+{
+       GAtChat *chat = data;
+       struct agps_data *agd = ofono_agps_get_data(agps);
+
+       agd = g_try_new0(struct agps_data, 1);
+       if (!agd)
+               return -ENOMEM;
+
+       agd->chat = g_at_chat_clone(chat);
+       agd->vendor = vendor;
+
+       ofono_agps_set_data(agps, agd);
+
+       g_at_chat_register(agd->chat, "%%XPOSR:", pos_request_notify, TRUE,
+                               agps, NULL);
+
+       ofono_agps_register(agps);
+
+       return 0;
+}
+
+static void ifx_agps_remove(struct ofono_agps *agps)
+{
+       struct agps_data *agd = ofono_agps_get_data(agps);
+
+       ofono_agps_set_data(agps, NULL);
+       g_at_chat_unref(agd->chat);
+       g_free(agd);
+}
+
+
+static void ifx_agps_receive_lcs_frame_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_agps_receive_lcs_frame_cb_t cb = cbd->cb;
+       struct ofono_error error;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+       cb(&error, cbd->data);
+}
+
+   /*
+       * The GPS manager can enable or disable AGPS manager  to receive
+       * lcs_frames from the Mobile network. If disabled, all Assistance Data
+       * and Position Requests from Mobile Network are not signalled to ofono.
+       */
+static void ifx_agps_receive_lcs_frames(struct ofono_agps *agps,
+                       int enabled, ofono_agps_receive_lcs_frame_cb_t cb,
+                       void *user_data)
+{
+       struct agps_data *data = ofono_agps_get_data(agps);
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       char *commbuf;
+       unsigned int id;
+
+       if (!cbd)
+               goto error;
+
+       commbuf = g_strdup_printf("AT%%XPOS=\"%d\"", enabled);
+
+       id = g_at_chat_send(data->chat, commbuf, none_prefix,
+                               ifx_agps_receive_lcs_frame_cb, cbd, g_free);
+
+       g_free(commbuf);
+
+       if (id > 0)
+               return;
+error:
+       if (cbd)
+               g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
+static void ifx_agps_send_lcs_frame_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       ofono_agps_send_lcs_frame_cb_t cb = cbd->cb;
+       struct ofono_error error;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+       cb(&error, cbd->data);
+}
+
+#define BUF_LEN 128
+       /* Assistance Data and Position Requests from the Mobile Network are
+        * signalled via the ofono_agps_lcs_frame_notify function and the
+        * oFono core to an external GPS manager. This GPS manager can reply
+        * to Position Requests with one or more Position Responses which
+        * are then send back to the modem via the send_lcs_frame function.
+        */
+static void ifx_agps_send_lcs_frame(struct ofono_agps *agps,
+                               struct ofono_lcs_frame *frame,
+                               ofono_agps_send_lcs_frame_cb_t cb,
+                               void *user_data)
+{
+       struct agps_data *data = ofono_agps_get_data(agps);
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       char buf[BUF_LEN * 2 + 1];
+       char *commbuf;
+       unsigned int id;
+       int buflen;
+
+       if (!cbd)
+               goto error;
+
+       if (!frame->frame_length) {
+               ofono_error("ifx_agps_send_lcs_frame: Frame length Invalid");
+               goto error;
+       }
+
+       if (frame->frame_length > BUF_LEN) {
+               ofono_error("ifx_agps_send_lcs_frame: Frame length too long!");
+               goto error;
+       }
+
+       encode_hex_own_buf(frame->raw_frame, frame->frame_length, 0, buf);
+       buflen = strlen(buf);
+       DBG("Encoded AGPS Frame = %s %d", buf, buflen);
+
+       commbuf = g_strdup_printf("AT%%XPOSR=%d,%d,\"%s\"",
+                       frame->lcs_frame_type, buflen, buf);
+
+       id = g_at_chat_send(data->chat, commbuf, none_prefix,
+                               ifx_agps_send_lcs_frame_cb, cbd, g_free);
+
+       g_free(commbuf);
+
+       if (id > 0)
+               return;
+error:
+       if (cbd)
+               g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
+static void ifx_agps_inject_time_cb(gboolean ok, GAtResult *result,
+                               gpointer user_data)
+{
+       GAtResultIter iter;
+       struct ofono_error error;
+       struct ofono_lcs_radio_fn rf;
+       struct cb_data *cbd = user_data;
+       struct agps_data *data = cbd->user;
+       ofono_agps_inject_time_cb_t cb = cbd->cb;
+
+       decode_at_error(&error, g_at_result_final_response(result));
+
+       if (!ok) {
+               cb(&error, NULL, cbd->data);
+               return;
+       }
+
+       if (!g_at_result_iter_next(&iter, "%%XFTI:"))
+               goto err;
+
+       if (RADIO_ACCESS_TECHNOLOGY_GSM == data->rad_acc_tech) {
+
+               int fn;         /* range 0 - 2715647 (2048*26*51) */
+               int ts;         /* range 0 - 7 */
+               int tsb;        /* range 0 - 156 */
+               int ta;         /* range 0 - 63 */
+               int ba;         /* range 0 - 1023 */
+               int bc;         /* range 0 - 64 */
+
+       /*       %XFTI:<frameNum>,<TimeSlot>,<TimeSlotBit>,<TimeAdv>,
+       *       <ChannelNum>,<ChannelId>
+       */
+               if (!g_at_result_iter_next_number(&iter, &fn))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &ts))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &tsb))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &ta))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &ba))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &bc))
+                       goto err;
+
+               DBG("GSM Inject Response: fn = %d ts = %d tsb = %d ta = %d"
+                               "ba = %d bc = %d ", fn, ts, tsb, ta, ba, bc);
+
+               rf.gsm_frame_number.TDMA_frame_number = fn;
+               rf.gsm_frame_number.TDMA_timeslot = ts;
+               rf.gsm_frame_number.timeslot_bit = tsb;
+               rf.gsm_frame_number.timing_advance = ta;
+               rf.gsm_frame_number.bcch_arfcn = ba;
+               rf.gsm_frame_number.bsic = bc;
+               rf.radio_access_technology = RADIO_ACCESS_TECHNOLOGY_GSM;
+
+       } else if (RADIO_ACCESS_TECHNOLOGY_UMTS == data->rad_acc_tech) {
+
+               int sfn;        /* range 0 - 4095 */
+               int rs;         /* enum ofono_rrc_state */
+               int rt;         /* range 0 - 32766 */
+
+               /* %XFTI:<frameNum>,<RadioState>,<TripTime> */
+               if (!g_at_result_iter_next_number(&iter, &sfn))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &rs))
+                       goto err;
+
+               if (!g_at_result_iter_next_number(&iter, &rt))
+                       goto err;
+
+               DBG("UMTS Inject Response: sfn = %d rs = %d tt = %d",
+                               sfn, rs, rt);
+
+               rf.utran_frame_number.sfn = sfn;
+               rf.utran_frame_number.rrc_state = rs;
+               rf.utran_frame_number.round_trip_time = rt;
+               rf.radio_access_technology = RADIO_ACCESS_TECHNOLOGY_UMTS;
+
+       } else
+               goto err;
+
+       cb(&error, &rf, cbd->data);
+               return;
+
+err:
+       CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+
+       /* The GPS manager can ask the modem to generate a HW pulse (time
+        * stamp) with a defined length and the modem replies indicates when
+        * it generates the pulse. But as the modem has no precise idae of
+        * Universal Time, it indicates at which radio frame number itgc
+        * generated the pulse. The GPS manager which knows the link between
+        * Universal Time and the Radio Frame number knows very precisely at
+        * what time the pulse was generated and its duration.
+        *
+        * Timing accuracy is typically a few microseconds.
+        */
+static void ifx_agps_inject_time(struct ofono_agps *agps,
+                       int radio_access_technology,/* enum access_technology */
+                       int pulse_length,/* duration of pulse in radio slots */
+                       ofono_agps_inject_time_cb_t cb, void *user_data)
+{
+       struct agps_data *data = ofono_agps_get_data(agps);
+       struct cb_data *cbd = cb_data_new(cb, user_data);
+       char *buf;
+       unsigned int id;
+
+       if (!cbd)
+               goto error;
+
+       cbd->user = data;
+
+       if (RADIO_ACCESS_TECHNOLOGY_GSM == radio_access_technology) {
+               data->rad_acc_tech = radio_access_technology;
+               buf = g_strdup_printf("AT%%XFTI=\"%s%d\"", "GSM",
+                                               pulse_length);
+
+       } else if (RADIO_ACCESS_TECHNOLOGY_UMTS == radio_access_technology) {
+                       data->rad_acc_tech = radio_access_technology;
+                       buf = g_strdup_printf("AT%%XFTI=\"%s%d\"", "UMTS",
+                                               pulse_length);
+       } else
+               goto error;
+
+       id = g_at_chat_send(data->chat, buf, none_prefix,
+                   ifx_agps_inject_time_cb, cbd, g_free);
+
+       g_free(buf);
+
+       if (id > 0)
+               return;
+
+error:
+       if (cbd)
+               g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, NULL, user_data);
+}
+
+static struct ofono_agps_driver driver = {
+       .name                                       = "ifxmodem",
+       .probe                                      = ifx_agps_probe,
+       .remove                                     = ifx_agps_remove,
+       .receive_lcs_frames                     = ifx_agps_receive_lcs_frames,
+       .send_lcs_frame                         = ifx_agps_send_lcs_frame,
+       .inject_time                            = ifx_agps_inject_time
+};
+
+void ifx_agps_init()
+{
+       ofono_agps_driver_register(&driver);
+       DBG("ifx_agps_init: ..");
+}
+
+void ifx_agps_exit()
+{
+       ofono_agps_driver_unregister(&driver);
+       DBG("ifx_agps_exit: ..");
+}
+
diff --git a/drivers/ifxmodem/ifxmodem.c b/drivers/ifxmodem/ifxmodem.c
index 8a9ac8f..2a2a273 100644
--- a/drivers/ifxmodem/ifxmodem.c
+++ b/drivers/ifxmodem/ifxmodem.c
@@ -39,12 +39,14 @@ static int ifxmodem_init(void)
        ifx_radio_settings_init();
        ifx_gprs_context_init();
        ifx_stk_init();
+       ifx_agps_init();

        return 0;
 }

 static void ifxmodem_exit(void)
 {
+       ifx_agps_exit();
        ifx_stk_exit();
        ifx_gprs_context_exit();
        ifx_radio_settings_exit();
diff --git a/drivers/ifxmodem/ifxmodem.h b/drivers/ifxmodem/ifxmodem.h
index 8ea52e5..e5accc2 100644
--- a/drivers/ifxmodem/ifxmodem.h
+++ b/drivers/ifxmodem/ifxmodem.h
@@ -35,3 +35,6 @@ extern void ifx_gprs_context_exit();

 extern void ifx_stk_init();
 extern void ifx_stk_exit();
+
+extern void ifx_agps_init();
+extern void ifx_agps_exit();
diff --git a/include/agps.h b/include/agps.h
new file mode 100644
index 0000000..7188eef
--- /dev/null
+++ b/include/agps.h
@@ -0,0 +1,159 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  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_AGPS_H_
+#define __OFONO_AGPS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+#include <glib.h>
+#include <gdbus.h>
+#include <ofono/modem.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+enum ofono_lcs_frame_type {
+       RRLP_ASSISTANCE_DATA = 0,               /* from modem */
+       /* Position request can include assistance data as well */
+       RRLP_MEASURE_POSITION_REQUEST = 1,      /* from modem */
+       RRLP_MEASURE_POSITION_RESPONSE = 2,     /* from GPS */
+       RRC_ASSISTANCE_DATA_DELIVERY = 3,       /* from modem */
+       /* Measurement control can include assistance data as well */
+       RRC_MEASUREMENT_CONTROL = 4,            /* from modem */
+       RRC_MEASUREMENT_REPORT = 5,             /* from GPS */
+};
+
+enum ofono_access_technology {
+       RADIO_ACCESS_TECHNOLOGY_GSM = 0,                /* GSM */
+       RADIO_ACCESS_TECHNOLOGY_UMTS = 1,               /* UMTS */
+};
+
+enum ofono_rrc_state {
+       RRC_CELL_PCH = 0,
+       RRC_CELL_FACH = 1,
+       RRC_CELL_DCH = 2,
+       RRC_URA_PCH = 3,
+};
+
+struct ofono_lcs_frame {
+       enum ofono_lcs_frame_type lcs_frame_type;
+       int frame_length;       /* size of raw_frame in bytes */
+       unsigned char  *raw_frame;
+};
+
+struct ofono_lcs_gsm_fn {
+       int TDMA_frame_number;  /* range 0 - 2715647 (2048*26*51) */
+       int TDMA_timeslot;              /* range 0 - 7 */
+       int timeslot_bit;               /* range 0 - 156 */
+       int timing_advance;             /* range 0 - 63 */
+       int bcch_arfcn;                 /* range 0 - 1023 */
+       int bsic;                               /* range 0 - 64 */
+};
+
+struct ofono_lcs_utran_fn {
+       int sfn;                                /* range 0 - 4095 */
+       int rrc_state;                  /* enum ofono_rrc_state */
+       int round_trip_time;    /* range 0 - 32766 */
+};
+
+struct ofono_lcs_radio_fn {
+       int radio_access_technology; /* enum access_technology */
+       union {
+               struct ofono_lcs_gsm_fn         gsm_frame_number;
+               struct ofono_lcs_utran_fn       utran_frame_number;
+       };
+};
+
+struct ofono_agps;
+
+typedef void (*ofono_agps_send_lcs_frame_cb_t)(const struct ofono_error *error,
+                               void *data);
+typedef void (*ofono_agps_receive_lcs_frame_cb_t)(
+                               const struct ofono_error *error,
+                               void *data);
+typedef void (*ofono_agps_inject_time_cb_t)(const struct ofono_error *error,
+                               struct ofono_lcs_radio_fn *radio_frame_number,
+                               void *data);
+
+       /*
+       * AGPS related functions, including LCS frame forwarding and
+       * fine time injection
+       */
+struct ofono_agps_driver {
+       const char *name;
+       int (*probe)(struct ofono_agps *agps, unsigned int vendor,
+                       void *data);
+       void (*remove)(struct ofono_agps *agps);
+       void (*receive_lcs_frames)(struct ofono_agps *agps, int enabled,
+                       ofono_agps_receive_lcs_frame_cb_t cb, void *data);
+
+       /* Assistance Data and Position Requests from the Mobile Network are
+        * signalled via the ofono_agps_lcs_frame_notify function and the
+        * oFono core to an external GPS manager. This GPS manager can reply
+        * to Position Requests with one or more Position Responses which
+        * are then send back to the modem via the send_lcs_frame function.
+        */
+       void (*send_lcs_frame)(struct ofono_agps *agps,
+                       struct ofono_lcs_frame *frame,
+                       ofono_agps_send_lcs_frame_cb_t cb, void *data);
+
+       /* The GPS manager can ask the modem to generate a HW pulse (time
+        * stamp) with a defined length and the modem replies indicates when
+        * it generates the pulse. But as the modem has no precise idea of
+        * Universal Time, it indicates at which radio frame number it
+        * generated the pulse. The GPS manager which knows the link between
+        * Universal Time and the Radio Frame number knows very precisely at
+        * what time the pulse was generated and its duration.
+        *
+        * Timing accuracy is typically a few microseconds.
+        */
+       void (*inject_time)(struct ofono_agps *agps,
+       int radio_access_technology, /* enum access_technology */
+       int pulse_length, /* duration of pulse in radio slots */
+       ofono_agps_inject_time_cb_t cb, void *data);
+};
+
+int ofono_agps_driver_register(const struct ofono_agps_driver *d);
+void ofono_agps_driver_unregister(const struct ofono_agps_driver *d);
+
+struct ofono_agps *ofono_agps_create(struct ofono_modem *modem,
+                                       unsigned int vendor, const char *driver,
+                                       void *data);
+
+void ofono_agps_register(struct ofono_agps *agps);
+void ofono_agps_remove(struct ofono_agps *agps);
+
+void ofono_agps_set_data(struct ofono_agps *agps, void *data);
+void *ofono_agps_get_data(struct ofono_agps *agps);
+
+void ofono_agps_lcs_frame_notify(struct ofono_agps *agps,
+                       struct ofono_lcs_frame frame);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_AGPS_H */
diff --git a/include/dbus.h b/include/dbus.h
index 59b2aae..c40ce8a 100644
--- a/include/dbus.h
+++ b/include/dbus.h
@@ -53,6 +53,7 @@ extern "C" {
 #define OFONO_VOICECALL_MANAGER_INTERFACE "org.ofono.VoiceCallManager"
 #define OFONO_STK_INTERFACE OFONO_SERVICE ".SimToolkit"
 #define OFONO_SIM_APP_INTERFACE OFONO_SERVICE ".SimToolkitAgent"
+#define OFONO_AGPS_MANAGER_INTERFACE "org.ofono.AgpsManager"

 /* Essentially a{sv} */
 #define OFONO_PROPERTIES_ARRAY_SIGNATURE DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
diff --git a/plugins/ifx.c b/plugins/ifx.c
index 037273a..3d26b4d 100644
--- a/plugins/ifx.c
+++ b/plugins/ifx.c
@@ -57,12 +57,13 @@
 #include <ofono/radio-settings.h>
 #include <ofono/audio-settings.h>
 #include <ofono/stk.h>
+#include <ofono/agps.h>
 #include <ofono/log.h>

 #include <drivers/atmodem/atutil.h>
 #include <drivers/atmodem/vendor.h>

-#define NUM_DLC  6
+#define NUM_DLC  7

 #define VOICE_DLC   0
 #define NETREG_DLC  1
@@ -70,13 +71,16 @@
 #define GPRS2_DLC   3
 #define GPRS3_DLC   4
 #define AUX_DLC     5
+#define AGPS_DLC    6

 static char *dlc_prefixes[NUM_DLC] = { "Voice: ", "Net: ", "GPRS1: ",
-                                       "GPRS2: ", "GPRS3: ", "Aux: " };
+                                       "GPRS2: ", "GPRS3: ",
+                                       "Aux: ",  "AGPS: " };

 static const char *dlc_nodes[NUM_DLC] = { "/dev/ttyGSM1", "/dev/ttyGSM2",
                                        "/dev/ttyGSM3", "/dev/ttyGSM4",
-                                       "/dev/ttyGSM5", "/dev/ttyGSM6" };
+                                       "/dev/ttyGSM5", "/dev/ttyGSM6",
+                                       "/dev/ttyGSM7"};

 static const char *none_prefix[] = { NULL };
 static const char *xdrv_prefix[] = { "+XDRV:", NULL };
@@ -754,6 +758,8 @@ static void ifx_post_online(struct ofono_modem *modem)
                                        "ifxmodem", data->dlcs[GPRS3_DLC]);
                if (gc)
                        ofono_gprs_add_context(gprs, gc);
+
+               ofono_agps_create(modem, 0, "ifxmodem", data->dlcs[AGPS_DLC]);
        }
 }

diff --git a/src/agps.c b/src/agps.c
new file mode 100644
index 0000000..516dddc
--- /dev/null
+++ b/src/agps.c
@@ -0,0 +1,229 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  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 <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include <ofono/log.h>
+#include <ofono/dbus.h>
+#include <ofono/modem.h>
+
+#include "ofono.h"
+#include "common.h"
+#include "util.h"
+
+static GSList *g_drivers;
+
+struct ofono_agps {
+       const struct ofono_agps_driver *driver;
+       void *driver_data;
+       struct ofono_atom *atom;
+       gboolean lcs_enabled;
+       gboolean lcs_enabled_pending;
+       DBusMessage *pending;
+       enum ofono_access_technology access_tech;
+       /*TODO - Implement  code here  */
+};
+
+static DBusMessage *agps_get_properties(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       /* TODO - Implement  code here  */
+       return msg;
+}
+
+static DBusMessage *agps_set_property(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
+{
+       /* TODO - Implement  code here  */
+       return msg;
+}
+
+static DBusMessage *agps_send_lcs_frame(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
+{
+       /* TODO - Implement  code here  */
+       return msg;
+}
+
+static DBusMessage *agps_request_fine_time_injection(DBusConnection *conn,
+                                                       DBusMessage *msg,
+                                                       void *data)
+{
+       /* TODO - Implement  code here  */
+       return msg;
+}
+
+static GDBusMethodTable agps_methods[] = {
+       { "GetProperties", "",  "a{sv}", agps_get_properties },
+       { "SetProperty", "sv",  "", agps_set_property },
+       { "SendLCSFrame", "sv", "", agps_send_lcs_frame },
+       { "RequestFineTimeInjection", "sv",     "",
+               agps_request_fine_time_injection },
+       { }
+};
+
+static GDBusSignalTable agps_signals[] = {
+       { "PropertyChanged",                            "sv" },
+       { "IncomingLCSFrame",                           "sq" },
+       { "FineTimeInjectionNotification",      "sq" },
+
+       { }
+};
+
+static void agps_unregister(struct ofono_atom *atom)
+{
+       DBusConnection *conn = ofono_dbus_get_connection();
+       struct ofono_agps *agps = __ofono_atom_get_data(atom);
+       struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+       const char *path = __ofono_atom_get_path(atom);
+
+       g_dbus_unregister_interface(conn, path, OFONO_AGPS_MANAGER_INTERFACE);
+       ofono_modem_remove_interface(modem, OFONO_AGPS_MANAGER_INTERFACE);
+       agps->lcs_enabled = FALSE;
+}
+
+void ofono_agps_register(struct ofono_agps *agps)
+{
+       struct ofono_modem *modem = __ofono_atom_get_modem(agps->atom);
+       const char *path = __ofono_atom_get_path(agps->atom);
+       DBusConnection *conn = ofono_dbus_get_connection();
+
+       if (!g_dbus_register_interface(conn, path,
+                       OFONO_AGPS_MANAGER_INTERFACE,
+                       agps_methods,
+                       agps_signals,
+                       NULL, NULL, NULL)) {
+               ofono_error("agps_dbus_register:Could not register AGPS Manager"
+               "Interface/Path");
+               return;
+       }
+
+       ofono_modem_add_interface(modem, OFONO_AGPS_MANAGER_INTERFACE);
+       __ofono_atom_register(agps->atom, agps_unregister);
+}
+
+void ofono_agps_remove(struct ofono_agps *agps)
+{
+       __ofono_atom_free(agps->atom);
+}
+
+static void agps_remove(struct ofono_atom *atom)
+{
+       struct ofono_agps *agps = __ofono_atom_get_data(atom);
+
+       DBG("atom: %p", atom);
+
+       if (agps == NULL)
+               return;
+
+       g_free(agps);
+}
+
+void ofono_agps_set_data(struct ofono_agps *agps, void *data)
+{
+       agps->driver_data = data;
+}
+
+void *ofono_agps_get_data(struct ofono_agps *agps)
+{
+       return agps->driver_data;
+}
+
+struct ofono_agps *ofono_agps_create(struct ofono_modem *modem,
+                                       unsigned int vendor,
+                                       const char *driver,
+                                       void *data)
+{
+       struct ofono_agps *agps;
+       GSList *l;
+
+       if (driver == NULL)
+               return NULL;
+
+       agps = g_try_new0(struct ofono_agps, 1);
+
+       if (agps == NULL)
+               return NULL;
+
+       agps->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_AGPS,
+                                               agps_remove, agps);
+
+       for (l = g_drivers; l; l = l->next) {
+               const struct ofono_agps_driver *drv = l->data;
+
+               if (g_strcmp0(drv->name, driver))
+                       continue;
+
+               if (drv->probe(agps, vendor, data) < 0)
+                       continue;
+
+               agps->driver = drv;
+               break;
+       }
+       return agps;
+}
+
+int ofono_agps_driver_register(const struct ofono_agps_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_agps_driver_unregister(const struct ofono_agps_driver *d)
+{
+       DBG("driver: %p, name: %s", d, d->name);
+
+       g_drivers = g_slist_remove(g_drivers, (void *)d);
+}
+
+void ofono_agps_lcs_frame_notify(struct ofono_agps *agps,
+                       struct ofono_lcs_frame frame)
+{
+
+       DBusConnection *conn = ofono_dbus_get_connection();
+       const char *path = __ofono_atom_get_path(agps->atom);
+
+       g_dbus_emit_signal(conn, path, OFONO_AGPS_MANAGER_INTERFACE,
+                               "PositionRequest",
+                               DBUS_TYPE_UINT16, &frame.lcs_frame_type,
+                               DBUS_TYPE_UINT16, &frame.frame_length,
+                               DBUS_TYPE_STRING, &frame.raw_frame,
+                               DBUS_TYPE_INVALID);
+}
+
+
+
diff --git a/src/ofono.h b/src/ofono.h
index bd7f33c..8048330 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -124,6 +124,7 @@ enum ofono_atom_type {
        OFONO_ATOM_TYPE_AUDIO_SETTINGS = 19,
        OFONO_ATOM_TYPE_STK = 20,
        OFONO_ATOM_TYPE_NETTIME = 21,
+       OFONO_ATOM_TYPE_AGPS = 22,
 };

 enum ofono_atom_watch_condition {
@@ -199,6 +200,7 @@ gboolean __ofono_call_settings_is_busy(struct ofono_call_settings *cs);
 #include <ofono/audio-settings.h>

 #include <ofono/voicecall.h>
+#include <ofono/agps.h>

 enum ofono_voicecall_interaction {
        OFONO_VOICECALL_INTERACTION_NONE        = 0,
--
1.7.0.4

[-- Attachment #2: 0001-Added-aGPS-Modem-API-implementation-for-Infineon-modem.txt --]
[-- Type: text/plain, Size: 27601 bytes --]

From fab1feadc9c9cf384aa42404bfba307c86f598db Mon Sep 17 00:00:00 2001
From: Robertino Benis <robertino.benis@intel.com>
Date: Fri, 29 Oct 2010 20:10:06 -0700
Subject: [CHANGE] Added aGPS Modem API implementation for Infineon modem
Organization: Intel 
Cc: robertino.benis@intel.com

---
 Makefile.am                 |    7 +-
 drivers/ifxmodem/agps.c     |  418 +++++++++++++++++++++++++++++++++++++++++++
 drivers/ifxmodem/ifxmodem.c |    2 +
 drivers/ifxmodem/ifxmodem.h |    3 +
 include/agps.h              |  159 ++++++++++++++++
 include/dbus.h              |    1 +
 plugins/ifx.c               |   12 +-
 src/agps.c                  |  229 +++++++++++++++++++++++
 src/ofono.h                 |    2 +
 9 files changed, 827 insertions(+), 6 deletions(-)
 create mode 100644 drivers/ifxmodem/agps.c
 create mode 100644 include/agps.h
 create mode 100644 src/agps.c

diff --git a/Makefile.am b/Makefile.am
index 2562160..6ec4761 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ include_HEADERS = include/log.h include/plugin.h include/history.h \
 			include/cbs.h include/call-volume.h \
 			include/gprs.h include/gprs-context.h \
 			include/radio-settings.h include/stk.h \
-			include/audio-settings.h include/nettime.h
+			include/audio-settings.h include/nettime.h include/agps.h
 
 nodist_include_HEADERS = include/version.h
 
@@ -218,7 +218,8 @@ builtin_sources += drivers/atmodem/atutil.h \
 			drivers/ifxmodem/audio-settings.c \
 			drivers/ifxmodem/radio-settings.c \
 			drivers/ifxmodem/gprs-context.c \
-			drivers/ifxmodem/stk.c
+			drivers/ifxmodem/stk.c \
+			drivers/ifxmodem/agps.c
 
 builtin_modules += stemodem
 builtin_sources += drivers/atmodem/atutil.h \
@@ -315,7 +316,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \
 			src/gprs.c src/idmap.h src/idmap.c \
 			src/radio-settings.c src/stkutil.h src/stkutil.c \
 			src/nettime.c src/stkagent.c src/stkagent.h \
-			src/simfs.c src/simfs.h src/audio-settings.c
+			src/simfs.c src/simfs.h src/audio-settings.c src/agps.c
 
 src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
 
diff --git a/drivers/ifxmodem/agps.c b/drivers/ifxmodem/agps.c
new file mode 100644
index 0000000..202795e
--- /dev/null
+++ b/drivers/ifxmodem/agps.c
@@ -0,0 +1,418 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  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 <gisi/client.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/agps.h>
+
+#include "util.h"
+#include "ifxmodem.h"
+
+struct agps_data {
+	GAtChat *chat;
+	unsigned int vendor;
+	enum ofono_access_technology rad_acc_tech;
+};
+
+struct ofono_agps;
+static const char *none_prefix[] = { NULL };
+
+#define FRAME_LEN 128
+
+static void pos_request_notify(GAtResult *result, gpointer user_data)
+{
+	struct ofono_agps *agps = user_data;
+	int framelen;
+	int frametype;
+	GAtResultIter iter;
+	struct ofono_lcs_frame lcsframe;
+	const char *messageframe;
+	unsigned char frame[FRAME_LEN];	/* TODO - Length TBD */
+	long hexframelen;
+
+	/* Assuming Pos Req format: %XPOSR: <frametype>,<framelen>,<frame> */
+
+	g_at_result_iter_init(&iter, result);
+
+	if (!g_at_result_iter_next(&iter, "%%XPOSR:"))
+		return;
+
+	if (!g_at_result_iter_next_number(&iter, &frametype))
+		return;
+
+	if (!g_at_result_iter_next_number(&iter, &framelen))
+		return;
+
+	if (framelen > FRAME_LEN) {
+		ofono_error("Got POS request message more than maximum buffer size!");
+		return;
+	}
+
+	messageframe = g_at_result_pdu(result);
+
+	if (strlen(messageframe) > sizeof(frame) * 2) { /* Hex, 2 chars / byte */
+		ofono_error("Message frame too long!");
+                return;
+	}
+
+	if (decode_hex_own_buf(messageframe, -1, &hexframelen, 0,
+				frame) == NULL) {
+		ofono_error("Unable to hex-decode the AGPS frame");
+		return;
+	}
+
+	DBG("Got POS request data: %s, %ld", frame, hexframelen);
+
+	if (hexframelen != framelen) {
+		ofono_error("hexframelen not equal to reported framelen");
+		return;
+	}
+
+	lcsframe.lcs_frame_type = frametype;
+	lcsframe.frame_length = framelen;
+	lcsframe.raw_frame = (unsigned char *)frame;
+
+	ofono_agps_lcs_frame_notify(agps, lcsframe);
+}
+
+static int ifx_agps_probe(struct ofono_agps *agps,
+					unsigned int vendor, void *data)
+{
+	GAtChat *chat = data;
+	struct agps_data *agd = ofono_agps_get_data(agps);
+
+	agd = g_try_new0(struct agps_data, 1);
+	if (!agd)
+		return -ENOMEM;
+
+	agd->chat = g_at_chat_clone(chat);
+	agd->vendor = vendor;
+
+	ofono_agps_set_data(agps, agd);
+
+	g_at_chat_register(agd->chat, "%%XPOSR:", pos_request_notify, TRUE,
+				agps, NULL);
+
+	ofono_agps_register(agps);
+
+	return 0;
+}
+
+static void ifx_agps_remove(struct ofono_agps *agps)
+{
+	struct agps_data *agd = ofono_agps_get_data(agps);
+
+	ofono_agps_set_data(agps, NULL);
+	g_at_chat_unref(agd->chat);
+	g_free(agd);
+}
+
+
+static void ifx_agps_receive_lcs_frame_cb(gboolean ok, GAtResult *result,
+				gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_agps_receive_lcs_frame_cb_t cb = cbd->cb;
+	struct ofono_error error;
+
+	decode_at_error(&error, g_at_result_final_response(result));
+	cb(&error, cbd->data);
+}
+
+   /*
+	* The GPS manager can enable or disable AGPS manager  to receive
+	* lcs_frames from the Mobile network. If disabled, all Assistance Data
+	* and Position Requests from Mobile Network are not signalled to ofono.
+	*/
+static void ifx_agps_receive_lcs_frames(struct ofono_agps *agps,
+			int enabled, ofono_agps_receive_lcs_frame_cb_t cb,
+			void *user_data)
+{
+	struct agps_data *data = ofono_agps_get_data(agps);
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+	char *commbuf;
+	unsigned int id;
+
+	if (!cbd)
+		goto error;
+
+	commbuf = g_strdup_printf("AT%%XPOS=\"%d\"", enabled);
+
+	id = g_at_chat_send(data->chat, commbuf, none_prefix,
+				ifx_agps_receive_lcs_frame_cb, cbd, g_free);
+
+	g_free(commbuf);
+
+	if (id > 0)
+		return;
+error:
+	if (cbd)
+		g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
+static void ifx_agps_send_lcs_frame_cb(gboolean ok, GAtResult *result,
+				gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_agps_send_lcs_frame_cb_t cb = cbd->cb;
+	struct ofono_error error;
+
+	decode_at_error(&error, g_at_result_final_response(result));
+	cb(&error, cbd->data);
+}
+
+#define BUF_LEN 128
+	/* Assistance Data and Position Requests from the Mobile Network are
+	 * signalled via the ofono_agps_lcs_frame_notify function and the
+	 * oFono core to an external GPS manager. This GPS manager can reply
+	 * to Position Requests with one or more Position Responses which
+	 * are then send back to the modem via the send_lcs_frame function.
+	 */
+static void ifx_agps_send_lcs_frame(struct ofono_agps *agps,
+				struct ofono_lcs_frame *frame,
+				ofono_agps_send_lcs_frame_cb_t cb,
+				void *user_data)
+{
+	struct agps_data *data = ofono_agps_get_data(agps);
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+	char buf[BUF_LEN * 2 + 1];
+	char *commbuf;
+	unsigned int id;
+	int buflen;
+
+	if (!cbd)
+		goto error;
+
+	if (!frame->frame_length) {
+		ofono_error("ifx_agps_send_lcs_frame: Frame length Invalid");
+		goto error;
+	}
+
+	if (frame->frame_length > BUF_LEN) {
+		ofono_error("ifx_agps_send_lcs_frame: Frame length too long!");
+		goto error;
+	}
+
+	encode_hex_own_buf(frame->raw_frame, frame->frame_length, 0, buf);
+	buflen = strlen(buf);
+	DBG("Encoded AGPS Frame = %s %d", buf, buflen);
+
+	commbuf = g_strdup_printf("AT%%XPOSR=%d,%d,\"%s\"",
+			frame->lcs_frame_type, buflen, buf);
+
+	id = g_at_chat_send(data->chat, commbuf, none_prefix,
+				ifx_agps_send_lcs_frame_cb, cbd, g_free);
+
+	g_free(commbuf);
+
+	if (id > 0)
+		return;
+error:
+	if (cbd)
+		g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, user_data);
+}
+
+static void ifx_agps_inject_time_cb(gboolean ok, GAtResult *result,
+				gpointer user_data)
+{
+	GAtResultIter iter;
+	struct ofono_error error;
+	struct ofono_lcs_radio_fn rf;
+	struct cb_data *cbd = user_data;
+	struct agps_data *data = cbd->user;
+	ofono_agps_inject_time_cb_t cb = cbd->cb;
+
+	decode_at_error(&error, g_at_result_final_response(result));
+
+	if (!ok) {
+		cb(&error, NULL, cbd->data);
+		return;
+	}
+
+	if (!g_at_result_iter_next(&iter, "%%XFTI:"))
+		goto err;
+
+	if (RADIO_ACCESS_TECHNOLOGY_GSM == data->rad_acc_tech) {
+
+		int fn;		/* range 0 - 2715647 (2048*26*51) */
+		int ts;		/* range 0 - 7 */
+		int tsb;	/* range 0 - 156 */
+		int ta;		/* range 0 - 63 */
+		int ba;		/* range 0 - 1023 */
+		int bc;		/* range 0 - 64 */
+
+	/*	 %XFTI:<frameNum>,<TimeSlot>,<TimeSlotBit>,<TimeAdv>,
+	*	<ChannelNum>,<ChannelId>
+	*/
+		if (!g_at_result_iter_next_number(&iter, &fn))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &ts))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &tsb))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &ta))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &ba))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &bc))
+			goto err;
+
+		DBG("GSM Inject Response: fn = %d ts = %d tsb = %d ta = %d"
+				"ba = %d bc = %d ", fn, ts, tsb, ta, ba, bc);
+
+		rf.gsm_frame_number.TDMA_frame_number = fn;
+		rf.gsm_frame_number.TDMA_timeslot = ts;
+		rf.gsm_frame_number.timeslot_bit = tsb;
+		rf.gsm_frame_number.timing_advance = ta;
+		rf.gsm_frame_number.bcch_arfcn = ba;
+		rf.gsm_frame_number.bsic = bc;
+		rf.radio_access_technology = RADIO_ACCESS_TECHNOLOGY_GSM;
+
+	} else if (RADIO_ACCESS_TECHNOLOGY_UMTS == data->rad_acc_tech) {
+
+		int sfn;	/* range 0 - 4095 */
+		int rs;		/* enum ofono_rrc_state */
+		int rt;		/* range 0 - 32766 */
+
+		/* %XFTI:<frameNum>,<RadioState>,<TripTime> */
+		if (!g_at_result_iter_next_number(&iter, &sfn))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &rs))
+			goto err;
+
+		if (!g_at_result_iter_next_number(&iter, &rt))
+			goto err;
+
+		DBG("UMTS Inject Response: sfn = %d rs = %d tt = %d",
+				sfn, rs, rt);
+
+		rf.utran_frame_number.sfn = sfn;
+		rf.utran_frame_number.rrc_state = rs;
+		rf.utran_frame_number.round_trip_time = rt;
+		rf.radio_access_technology = RADIO_ACCESS_TECHNOLOGY_UMTS;
+
+	} else
+		goto err;
+
+	cb(&error, &rf, cbd->data);
+		return;
+
+err:
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+
+	/* The GPS manager can ask the modem to generate a HW pulse (time
+	 * stamp) with a defined length and the modem replies indicates when
+	 * it generates the pulse. But as the modem has no precise idae of
+	 * Universal Time, it indicates at which radio frame number itgc
+	 * generated the pulse. The GPS manager which knows the link between
+	 * Universal Time and the Radio Frame number knows very precisely at
+	 * what time the pulse was generated and its duration.
+	 *
+	 * Timing accuracy is typically a few microseconds.
+	 */
+static void ifx_agps_inject_time(struct ofono_agps *agps,
+			int radio_access_technology,/* enum access_technology */
+			int pulse_length,/* duration of pulse in radio slots */
+			ofono_agps_inject_time_cb_t cb, void *user_data)
+{
+	struct agps_data *data = ofono_agps_get_data(agps);
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+	char *buf;
+	unsigned int id;
+
+	if (!cbd)
+		goto error;
+
+	cbd->user = data;
+
+	if (RADIO_ACCESS_TECHNOLOGY_GSM == radio_access_technology) {
+		data->rad_acc_tech = radio_access_technology;
+		buf = g_strdup_printf("AT%%XFTI=\"%s%d\"", "GSM",
+						pulse_length);
+
+	} else if (RADIO_ACCESS_TECHNOLOGY_UMTS == radio_access_technology) {
+			data->rad_acc_tech = radio_access_technology;
+			buf = g_strdup_printf("AT%%XFTI=\"%s%d\"", "UMTS",
+						pulse_length);
+	} else
+		goto error;
+
+	id = g_at_chat_send(data->chat, buf, none_prefix,
+		    ifx_agps_inject_time_cb, cbd, g_free);
+
+	g_free(buf);
+
+	if (id > 0)
+		return;
+
+error:
+	if (cbd)
+		g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, user_data);
+}
+
+static struct ofono_agps_driver driver = {
+	.name					    = "ifxmodem",
+	.probe					    = ifx_agps_probe,
+	.remove					    = ifx_agps_remove,
+	.receive_lcs_frames			= ifx_agps_receive_lcs_frames,
+	.send_lcs_frame				= ifx_agps_send_lcs_frame,
+	.inject_time				= ifx_agps_inject_time
+};
+
+void ifx_agps_init()
+{
+	ofono_agps_driver_register(&driver);
+	DBG("ifx_agps_init: ..");
+}
+
+void ifx_agps_exit()
+{
+	ofono_agps_driver_unregister(&driver);
+	DBG("ifx_agps_exit: ..");
+}
+
diff --git a/drivers/ifxmodem/ifxmodem.c b/drivers/ifxmodem/ifxmodem.c
index 8a9ac8f..2a2a273 100644
--- a/drivers/ifxmodem/ifxmodem.c
+++ b/drivers/ifxmodem/ifxmodem.c
@@ -39,12 +39,14 @@ static int ifxmodem_init(void)
 	ifx_radio_settings_init();
 	ifx_gprs_context_init();
 	ifx_stk_init();
+	ifx_agps_init();
 
 	return 0;
 }
 
 static void ifxmodem_exit(void)
 {
+	ifx_agps_exit();
 	ifx_stk_exit();
 	ifx_gprs_context_exit();
 	ifx_radio_settings_exit();
diff --git a/drivers/ifxmodem/ifxmodem.h b/drivers/ifxmodem/ifxmodem.h
index 8ea52e5..e5accc2 100644
--- a/drivers/ifxmodem/ifxmodem.h
+++ b/drivers/ifxmodem/ifxmodem.h
@@ -35,3 +35,6 @@ extern void ifx_gprs_context_exit();
 
 extern void ifx_stk_init();
 extern void ifx_stk_exit();
+
+extern void ifx_agps_init();
+extern void ifx_agps_exit();
diff --git a/include/agps.h b/include/agps.h
new file mode 100644
index 0000000..7188eef
--- /dev/null
+++ b/include/agps.h
@@ -0,0 +1,159 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  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_AGPS_H_
+#define __OFONO_AGPS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+#include <glib.h>
+#include <gdbus.h>
+#include <ofono/modem.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+enum ofono_lcs_frame_type {
+	RRLP_ASSISTANCE_DATA = 0,		/* from modem */
+	/* Position request can include assistance data as well */
+	RRLP_MEASURE_POSITION_REQUEST = 1,	/* from modem */
+	RRLP_MEASURE_POSITION_RESPONSE = 2,	/* from GPS */
+	RRC_ASSISTANCE_DATA_DELIVERY = 3,	/* from modem */
+	/* Measurement control can include assistance data as well */
+	RRC_MEASUREMENT_CONTROL = 4,		/* from modem */
+	RRC_MEASUREMENT_REPORT = 5,		/* from GPS */
+};
+
+enum ofono_access_technology {
+	RADIO_ACCESS_TECHNOLOGY_GSM = 0,		/* GSM */
+	RADIO_ACCESS_TECHNOLOGY_UMTS = 1,		/* UMTS */
+};
+
+enum ofono_rrc_state {
+	RRC_CELL_PCH = 0,
+	RRC_CELL_FACH = 1,
+	RRC_CELL_DCH = 2,
+	RRC_URA_PCH = 3,
+};
+
+struct ofono_lcs_frame {
+	enum ofono_lcs_frame_type lcs_frame_type;
+	int frame_length;	/* size of raw_frame in bytes */
+	unsigned char  *raw_frame;
+};
+
+struct ofono_lcs_gsm_fn {
+	int TDMA_frame_number;	/* range 0 - 2715647 (2048*26*51) */
+	int TDMA_timeslot;		/* range 0 - 7 */
+	int timeslot_bit;		/* range 0 - 156 */
+	int timing_advance;		/* range 0 - 63 */
+	int bcch_arfcn;			/* range 0 - 1023 */
+	int bsic;				/* range 0 - 64 */
+};
+
+struct ofono_lcs_utran_fn {
+	int sfn;				/* range 0 - 4095 */
+	int rrc_state;			/* enum ofono_rrc_state */
+	int round_trip_time;	/* range 0 - 32766 */
+};
+
+struct ofono_lcs_radio_fn {
+	int radio_access_technology; /* enum access_technology */
+	union {
+		struct ofono_lcs_gsm_fn		gsm_frame_number;
+		struct ofono_lcs_utran_fn	utran_frame_number;
+	};
+};
+
+struct ofono_agps;
+
+typedef void (*ofono_agps_send_lcs_frame_cb_t)(const struct ofono_error *error,
+				void *data);
+typedef void (*ofono_agps_receive_lcs_frame_cb_t)(
+				const struct ofono_error *error,
+				void *data);
+typedef void (*ofono_agps_inject_time_cb_t)(const struct ofono_error *error,
+				struct ofono_lcs_radio_fn *radio_frame_number,
+				void *data);
+
+	/*
+	* AGPS related functions, including LCS frame forwarding and
+	* fine time injection
+	*/
+struct ofono_agps_driver {
+	const char *name;
+	int (*probe)(struct ofono_agps *agps, unsigned int vendor,
+			void *data);
+	void (*remove)(struct ofono_agps *agps);
+	void (*receive_lcs_frames)(struct ofono_agps *agps, int enabled,
+			ofono_agps_receive_lcs_frame_cb_t cb, void *data);
+
+	/* Assistance Data and Position Requests from the Mobile Network are
+	 * signalled via the ofono_agps_lcs_frame_notify function and the
+	 * oFono core to an external GPS manager. This GPS manager can reply
+	 * to Position Requests with one or more Position Responses which
+	 * are then send back to the modem via the send_lcs_frame function.
+	 */
+	void (*send_lcs_frame)(struct ofono_agps *agps,
+			struct ofono_lcs_frame *frame,
+			ofono_agps_send_lcs_frame_cb_t cb, void *data);
+
+	/* The GPS manager can ask the modem to generate a HW pulse (time
+	 * stamp) with a defined length and the modem replies indicates when
+	 * it generates the pulse. But as the modem has no precise idea of
+	 * Universal Time, it indicates at which radio frame number it
+	 * generated the pulse. The GPS manager which knows the link between
+	 * Universal Time and the Radio Frame number knows very precisely at
+	 * what time the pulse was generated and its duration.
+	 *
+	 * Timing accuracy is typically a few microseconds.
+	 */
+	void (*inject_time)(struct ofono_agps *agps,
+	int radio_access_technology, /* enum access_technology */
+	int pulse_length, /* duration of pulse in radio slots */
+	ofono_agps_inject_time_cb_t cb, void *data);
+};
+
+int ofono_agps_driver_register(const struct ofono_agps_driver *d);
+void ofono_agps_driver_unregister(const struct ofono_agps_driver *d);
+
+struct ofono_agps *ofono_agps_create(struct ofono_modem *modem,
+					unsigned int vendor, const char *driver,
+					void *data);
+
+void ofono_agps_register(struct ofono_agps *agps);
+void ofono_agps_remove(struct ofono_agps *agps);
+
+void ofono_agps_set_data(struct ofono_agps *agps, void *data);
+void *ofono_agps_get_data(struct ofono_agps *agps);
+
+void ofono_agps_lcs_frame_notify(struct ofono_agps *agps,
+			struct ofono_lcs_frame frame);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_AGPS_H */
diff --git a/include/dbus.h b/include/dbus.h
index 59b2aae..c40ce8a 100644
--- a/include/dbus.h
+++ b/include/dbus.h
@@ -53,6 +53,7 @@ extern "C" {
 #define OFONO_VOICECALL_MANAGER_INTERFACE "org.ofono.VoiceCallManager"
 #define OFONO_STK_INTERFACE OFONO_SERVICE ".SimToolkit"
 #define OFONO_SIM_APP_INTERFACE OFONO_SERVICE ".SimToolkitAgent"
+#define OFONO_AGPS_MANAGER_INTERFACE "org.ofono.AgpsManager"
 
 /* Essentially a{sv} */
 #define OFONO_PROPERTIES_ARRAY_SIGNATURE DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
diff --git a/plugins/ifx.c b/plugins/ifx.c
index 037273a..3d26b4d 100644
--- a/plugins/ifx.c
+++ b/plugins/ifx.c
@@ -57,12 +57,13 @@
 #include <ofono/radio-settings.h>
 #include <ofono/audio-settings.h>
 #include <ofono/stk.h>
+#include <ofono/agps.h>
 #include <ofono/log.h>
 
 #include <drivers/atmodem/atutil.h>
 #include <drivers/atmodem/vendor.h>
 
-#define NUM_DLC  6
+#define NUM_DLC  7
 
 #define VOICE_DLC   0
 #define NETREG_DLC  1
@@ -70,13 +71,16 @@
 #define GPRS2_DLC   3
 #define GPRS3_DLC   4
 #define AUX_DLC     5
+#define AGPS_DLC    6
 
 static char *dlc_prefixes[NUM_DLC] = { "Voice: ", "Net: ", "GPRS1: ",
-					"GPRS2: ", "GPRS3: ", "Aux: " };
+					"GPRS2: ", "GPRS3: ",
+					"Aux: ",  "AGPS: " };
 
 static const char *dlc_nodes[NUM_DLC] = { "/dev/ttyGSM1", "/dev/ttyGSM2",
 					"/dev/ttyGSM3", "/dev/ttyGSM4",
-					"/dev/ttyGSM5", "/dev/ttyGSM6" };
+					"/dev/ttyGSM5", "/dev/ttyGSM6",
+					"/dev/ttyGSM7"};
 
 static const char *none_prefix[] = { NULL };
 static const char *xdrv_prefix[] = { "+XDRV:", NULL };
@@ -754,6 +758,8 @@ static void ifx_post_online(struct ofono_modem *modem)
 					"ifxmodem", data->dlcs[GPRS3_DLC]);
 		if (gc)
 			ofono_gprs_add_context(gprs, gc);
+
+		ofono_agps_create(modem, 0, "ifxmodem", data->dlcs[AGPS_DLC]);
 	}
 }
 
diff --git a/src/agps.c b/src/agps.c
new file mode 100644
index 0000000..516dddc
--- /dev/null
+++ b/src/agps.c
@@ -0,0 +1,229 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2010  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 <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include <ofono/log.h>
+#include <ofono/dbus.h>
+#include <ofono/modem.h>
+
+#include "ofono.h"
+#include "common.h"
+#include "util.h"
+
+static GSList *g_drivers;
+
+struct ofono_agps {
+	const struct ofono_agps_driver *driver;
+	void *driver_data;
+	struct ofono_atom *atom;
+	gboolean lcs_enabled;
+	gboolean lcs_enabled_pending;
+	DBusMessage *pending;
+	enum ofono_access_technology access_tech;
+	/*TODO - Implement  code here  */
+};
+
+static DBusMessage *agps_get_properties(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	/* TODO - Implement  code here  */
+	return msg;
+}
+
+static DBusMessage *agps_set_property(DBusConnection *conn, DBusMessage *msg,
+					void *data)
+{
+	/* TODO - Implement  code here  */
+	return msg;
+}
+
+static DBusMessage *agps_send_lcs_frame(DBusConnection *conn, DBusMessage *msg,
+					void *data)
+{
+	/* TODO - Implement  code here  */
+	return msg;
+}
+
+static DBusMessage *agps_request_fine_time_injection(DBusConnection *conn,
+							DBusMessage *msg,
+							void *data)
+{
+	/* TODO - Implement  code here  */
+	return msg;
+}
+
+static GDBusMethodTable agps_methods[] = {
+	{ "GetProperties", "",	"a{sv}", agps_get_properties },
+	{ "SetProperty", "sv",	"", agps_set_property },
+	{ "SendLCSFrame", "sv",	"", agps_send_lcs_frame },
+	{ "RequestFineTimeInjection", "sv",	"",
+		agps_request_fine_time_injection },
+	{ }
+};
+
+static GDBusSignalTable agps_signals[] = {
+	{ "PropertyChanged",				"sv" },
+	{ "IncomingLCSFrame",				"sq" },
+	{ "FineTimeInjectionNotification",	"sq" },
+
+	{ }
+};
+
+static void agps_unregister(struct ofono_atom *atom)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_agps *agps = __ofono_atom_get_data(atom);
+	struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+	const char *path = __ofono_atom_get_path(atom);
+
+	g_dbus_unregister_interface(conn, path, OFONO_AGPS_MANAGER_INTERFACE);
+	ofono_modem_remove_interface(modem, OFONO_AGPS_MANAGER_INTERFACE);
+	agps->lcs_enabled = FALSE;
+}
+
+void ofono_agps_register(struct ofono_agps *agps)
+{
+	struct ofono_modem *modem = __ofono_atom_get_modem(agps->atom);
+	const char *path = __ofono_atom_get_path(agps->atom);
+	DBusConnection *conn = ofono_dbus_get_connection();
+
+	if (!g_dbus_register_interface(conn, path,
+			OFONO_AGPS_MANAGER_INTERFACE,
+			agps_methods,
+			agps_signals,
+			NULL, NULL, NULL)) {
+		ofono_error("agps_dbus_register:Could not register AGPS Manager"
+		"Interface/Path");
+		return;
+	}
+
+	ofono_modem_add_interface(modem, OFONO_AGPS_MANAGER_INTERFACE);
+	__ofono_atom_register(agps->atom, agps_unregister);
+}
+
+void ofono_agps_remove(struct ofono_agps *agps)
+{
+	__ofono_atom_free(agps->atom);
+}
+
+static void agps_remove(struct ofono_atom *atom)
+{
+	struct ofono_agps *agps = __ofono_atom_get_data(atom);
+
+	DBG("atom: %p", atom);
+
+	if (agps == NULL)
+		return;
+
+	g_free(agps);
+}
+
+void ofono_agps_set_data(struct ofono_agps *agps, void *data)
+{
+	agps->driver_data = data;
+}
+
+void *ofono_agps_get_data(struct ofono_agps *agps)
+{
+	return agps->driver_data;
+}
+
+struct ofono_agps *ofono_agps_create(struct ofono_modem *modem,
+					unsigned int vendor,
+					const char *driver,
+					void *data)
+{
+	struct ofono_agps *agps;
+	GSList *l;
+
+	if (driver == NULL)
+		return NULL;
+
+	agps = g_try_new0(struct ofono_agps, 1);
+
+	if (agps == NULL)
+		return NULL;
+
+	agps->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_AGPS,
+						agps_remove, agps);
+
+	for (l = g_drivers; l; l = l->next) {
+		const struct ofono_agps_driver *drv = l->data;
+
+		if (g_strcmp0(drv->name, driver))
+			continue;
+
+		if (drv->probe(agps, vendor, data) < 0)
+			continue;
+
+		agps->driver = drv;
+		break;
+	}
+	return agps;
+}
+
+int ofono_agps_driver_register(const struct ofono_agps_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_agps_driver_unregister(const struct ofono_agps_driver *d)
+{
+	DBG("driver: %p, name: %s", d, d->name);
+
+	g_drivers = g_slist_remove(g_drivers, (void *)d);
+}
+
+void ofono_agps_lcs_frame_notify(struct ofono_agps *agps,
+			struct ofono_lcs_frame frame)
+{
+
+	DBusConnection *conn = ofono_dbus_get_connection();
+	const char *path = __ofono_atom_get_path(agps->atom);
+
+	g_dbus_emit_signal(conn, path, OFONO_AGPS_MANAGER_INTERFACE,
+				"PositionRequest",
+				DBUS_TYPE_UINT16, &frame.lcs_frame_type,
+				DBUS_TYPE_UINT16, &frame.frame_length,
+				DBUS_TYPE_STRING, &frame.raw_frame,
+				DBUS_TYPE_INVALID);
+}
+
+
+
diff --git a/src/ofono.h b/src/ofono.h
index bd7f33c..8048330 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -124,6 +124,7 @@ enum ofono_atom_type {
 	OFONO_ATOM_TYPE_AUDIO_SETTINGS = 19,
 	OFONO_ATOM_TYPE_STK = 20,
 	OFONO_ATOM_TYPE_NETTIME = 21,
+	OFONO_ATOM_TYPE_AGPS = 22,
 };
 
 enum ofono_atom_watch_condition {
@@ -199,6 +200,7 @@ gboolean __ofono_call_settings_is_busy(struct ofono_call_settings *cs);
 #include <ofono/audio-settings.h>
 
 #include <ofono/voicecall.h>
+#include <ofono/agps.h>
 
 enum ofono_voicecall_interaction {
 	OFONO_VOICECALL_INTERACTION_NONE	= 0,
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-10-30 10:58 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-30  3:43 Infineon modem API to support aGPS Benis, Robertino
2010-10-30 10:58 ` Marcel Holtmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.