summaryrefslogtreecommitdiffstats
path: root/drivers/isimodem/voicecall.c
diff options
context:
space:
mode:
authorAki Niemi <aki.niemi@nokia.com>2010-11-14 19:31:06 +0200
committerAki Niemi <aki.niemi@nokia.com>2010-12-22 17:13:47 +0200
commit346ee5b051d2abc16f55bd60f6846fee78b50c35 (patch)
treee33fd7db39fba7322273e70fd4d0af37384f24d3 /drivers/isimodem/voicecall.c
parent4f9c5b771389f3cc873da839a07d562e59fb8bb2 (diff)
downloadofono-346ee5b051d2abc16f55bd60f6846fee78b50c35.tar.bz2
isimodem: Adapt and refactor voicecall driver
Diffstat (limited to 'drivers/isimodem/voicecall.c')
-rw-r--r--drivers/isimodem/voicecall.c1384
1 files changed, 678 insertions, 706 deletions
diff --git a/drivers/isimodem/voicecall.c b/drivers/isimodem/voicecall.c
index f2fd53aa..fe4a5725 100644
--- a/drivers/isimodem/voicecall.c
+++ b/drivers/isimodem/voicecall.c
@@ -28,12 +28,11 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <assert.h>
#include <glib.h>
-#include <gisi/netlink.h>
#include <gisi/client.h>
+#include <gisi/message.h>
#include <gisi/iter.h>
#include <ofono/log.h>
@@ -45,249 +44,359 @@
#include "call.h"
#include "debug.h"
+#define ISI_CALL_TIMEOUT 1000
+
struct isi_call {
- uint8_t id, call_id, status, mode, mode_info, cause_type, cause;
- uint8_t addr_type, presentation;
+ uint8_t id;
+ uint8_t call_id;
+ uint8_t status;
+ uint8_t mode;
+ uint8_t mode_info;
+ uint8_t cause_type;
+ uint8_t cause;
+ uint8_t addr_type;
+ uint8_t presentation;
uint8_t reason;
- char address[20], addr_pad[4];
+ char address[20];
+ char addr_pad[4];
};
-struct isi_voicecall {
- GIsiClient *client;
-
- struct isi_call_req_context *queue;
-
- struct isi_call calls[8];
+struct call_addr_info {
+ uint8_t call_id;
+ uint8_t mode;
+ uint8_t mode_info;
+ uint8_t status;
+ uint8_t filler[2];
+ uint8_t addr_type;
+ uint8_t presentation;
+ uint8_t filler2;
+ uint8_t addr_len;
};
-/* ------------------------------------------------------------------------- */
-
-typedef void GIsiIndication(GIsiClient *client,
- const void *restrict data, size_t len,
- uint16_t object, void *opaque);
+struct call_info {
+ uint8_t call_id;
+ uint8_t mode;
+ uint8_t mode_info;
+ uint8_t status;
+};
-typedef void GIsiVerify(GIsiClient *client, gboolean alive, uint16_t object,
- void *opaque);
+struct isi_voicecall {
+ GIsiClient *client;
-typedef gboolean GIsiResponse(GIsiClient *client,
- void const *restrict data, size_t len,
- uint16_t object, void *opaque);
+ struct isi_call_req_ctx *queue;
-enum {
- ISI_CALL_TIMEOUT = 1000,
+ struct isi_call calls[8];
};
-/* ------------------------------------------------------------------------- */
-/* Request context for voicecall cb */
-
-typedef void isi_call_req_step(struct isi_call_req_context *,
- int id, int status);
+typedef void isi_call_req_step(struct isi_call_req_ctx *ctx, int reason);
-struct isi_call_req_context {
- struct isi_call_req_context *next;
- struct isi_call_req_context **prev;
+struct isi_call_req_ctx {
+ struct isi_call_req_ctx *next;
+ struct isi_call_req_ctx **prev;
isi_call_req_step *step;
- int id;
struct ofono_voicecall *ovc;
ofono_voicecall_cb_t cb;
void *data;
};
-static struct isi_call_req_context *isi_call_req_new(
- struct ofono_voicecall *ovc,
- ofono_voicecall_cb_t cb,
- void *data)
+static struct isi_call_req_ctx *isi_call_req(struct ofono_voicecall *ovc,
+ const void *__restrict req,
+ size_t len,
+ GIsiNotifyFunc handler,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
- struct isi_call_req_context *irc;
+ struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+ struct isi_call_req_ctx *irc;
- irc = g_try_new0(struct isi_call_req_context, 1);
- if (irc == NULL)
- goto failed;
+ irc = g_try_new0(struct isi_call_req_ctx, 1);
+ if (!irc) {
+ CALLBACK_WITH_FAILURE(cb, data);
+ return NULL;
+ }
irc->ovc = ovc;
irc->cb = cb;
irc->data = data;
+ if (!g_isi_client_send(ivc->client, req, len, ISI_CALL_TIMEOUT,
+ handler, irc, NULL)) {
+ g_free(irc);
+ return NULL;
+ }
+
return irc;
+}
-failed:
- if (cb)
- CALLBACK_WITH_FAILURE(cb, data);
+static void isi_ctx_queue(struct isi_call_req_ctx *irc, isi_call_req_step *next)
+{
+ struct isi_voicecall *ivc;
- return NULL;
+ if (irc->prev != NULL) {
+ irc->step = next;
+ return;
+ }
+
+ ivc = ofono_voicecall_get_data(irc->ovc);
+ if (ivc->queue) {
+ irc->next = ivc->queue;
+ irc->next->prev = &irc->next;
+ }
+
+ irc->prev = &ivc->queue;
+ ivc->queue = irc;
}
-static struct isi_call_req_context *isi_call_req(struct ofono_voicecall *ovc,
- void const *restrict req,
- size_t len,
- GIsiResponse *handler,
- ofono_voicecall_cb_t cb,
- void *data)
+static void isi_ctx_remove(struct isi_call_req_ctx *irc)
{
- struct isi_voicecall *ivc;
- struct isi_call_req_context *irc;
+ if (!irc->prev)
+ return;
- irc = isi_call_req_new(ovc, cb, data);
- if (irc == NULL)
- return NULL;
+ *irc->prev = irc->next;
- ivc = ofono_voicecall_get_data(ovc);
+ if (irc->next) {
+ irc->next->prev = irc->prev;
+ irc->next = NULL;
+ }
+ irc->prev = NULL;
+}
- if (g_isi_send(ivc->client, req, len,
- ISI_CALL_TIMEOUT, handler, irc, NULL))
- return irc;
+static void isi_ctx_free(struct isi_call_req_ctx *irc)
+{
+ if (!irc)
+ return;
+ isi_ctx_remove(irc);
g_free(irc);
+}
- if (cb)
- CALLBACK_WITH_FAILURE(cb, data);
+static gboolean isi_ctx_return(struct isi_call_req_ctx *irc,
+ enum ofono_error_type type, int error)
+{
+ if (!irc)
+ return TRUE;
+
+ if (irc->cb) {
+ struct ofono_error e = {
+ .type = type,
+ .error = error
+ };
+ irc->cb(&e, irc->data);
+ }
- return NULL;
+ isi_ctx_free(irc);
+ return TRUE;
}
-static void isi_ctx_queue(struct isi_call_req_context *irc,
- isi_call_req_step *next,
- int id)
+static gboolean isi_ctx_return_failure(struct isi_call_req_ctx *irc)
{
- if (irc->prev == NULL) {
- struct isi_voicecall *ivc = ofono_voicecall_get_data(irc->ovc);
+ return isi_ctx_return(irc, OFONO_ERROR_TYPE_FAILURE, 0);
+}
- if (ivc->queue) {
- irc->next = ivc->queue;
- irc->next->prev = &irc->next;
- }
- irc->prev = &ivc->queue;
- ivc->queue = irc;
- }
+static gboolean isi_ctx_return_success(struct isi_call_req_ctx *irc)
+{
+ if (!irc || !irc->step)
+ return isi_ctx_return(irc, OFONO_ERROR_TYPE_NO_ERROR, 0);
- irc->step = next;
- irc->id = id;
+ irc->step(irc, 0);
+ return TRUE;
}
-static void isi_ctx_remove(struct isi_call_req_context *irc)
+/* Decoding subblocks */
+static void isi_call_any_address_sb_proc(struct isi_voicecall *ivc,
+ struct isi_call *call,
+ GIsiSubBlockIter *sb)
{
- if (irc->prev) {
- *irc->prev = irc->next;
+ uint8_t type;
+ uint8_t pres;
+ uint8_t len;
+ char *addr;
+
+ if (!g_isi_sb_iter_get_byte(sb, &type, 2) ||
+ !g_isi_sb_iter_get_byte(sb, &pres, 3) ||
+ !g_isi_sb_iter_get_byte(sb, &len, 5) ||
+ !g_isi_sb_iter_get_alpha_tag(sb, &addr, 2 * len, 6))
+ return;
- if (irc->next) {
- irc->next->prev = irc->prev;
- irc->next = NULL;
- }
- irc->prev = NULL;
- }
+ call->addr_type = type | 0x80;
+ call->presentation = pres;
+ strncpy(call->address, addr, sizeof(call->address));
+
+ g_free(addr);
}
-static void isi_ctx_free(struct isi_call_req_context *irc)
+static void isi_call_origin_address_sb_proc(struct isi_voicecall *ivc,
+ struct isi_call *call,
+ GIsiSubBlockIter *sb)
{
- if (irc) {
- isi_ctx_remove(irc);
- g_free(irc);
- }
+ if (call->address[0] == '\0')
+ isi_call_any_address_sb_proc(ivc, call, sb);
}
-static gboolean isi_ctx_return(struct isi_call_req_context *irc,
- enum ofono_error_type type,
- int error)
+static void isi_call_destination_address_sb_proc(struct isi_voicecall *ivc,
+ struct isi_call *call,
+ GIsiSubBlockIter *sb)
{
- if (irc == NULL)
- return TRUE;
+ if (call->address[0] == '\0')
+ isi_call_any_address_sb_proc(ivc, call, sb);
+}
- if (irc->cb) {
- struct ofono_error e = { .type = type, .error = error };
- irc->cb(&e, irc->data);
- }
+static void isi_call_mode_sb_proc(struct isi_voicecall *ivc,
+ struct isi_call *call,
+ GIsiSubBlockIter *sb)
+{
+ uint8_t mode;
+ uint8_t info;
- isi_ctx_free(irc);
+ if (!g_isi_sb_iter_get_byte(sb, &mode, 2) ||
+ !g_isi_sb_iter_get_byte(sb, &info, 3))
+ return;
- return TRUE;
+ call->mode = mode;
+ call->mode_info = info;
}
-static gboolean isi_ctx_return_failure(struct isi_call_req_context *irc)
+static void isi_call_cause_sb_proc(struct isi_voicecall *ivc,
+ struct isi_call *call,
+ GIsiSubBlockIter *sb)
{
- return isi_ctx_return(irc, OFONO_ERROR_TYPE_FAILURE, 0);
+ uint8_t type;
+ uint8_t cause;
+
+ if (!g_isi_sb_iter_get_byte(sb, &type, 2) ||
+ !g_isi_sb_iter_get_byte(sb, &cause, 3))
+ return;
+
+ call->cause_type = type;
+ call->cause = cause;
}
-static gboolean isi_ctx_return_success(struct isi_call_req_context *irc)
+static void isi_call_status_sb_proc(struct isi_voicecall *ivc,
+ struct isi_call *call,
+ GIsiSubBlockIter *sb)
{
- if (irc && irc->step) {
- irc->step(irc, 0, 0);
- return TRUE;
+ uint8_t status;
+
+ if (!g_isi_sb_iter_get_byte(sb, &status, 2))
+ return;
+
+ call->status = status;
+}
+
+static struct isi_call *isi_call_status_info_sb_proc(struct isi_voicecall *ivc,
+ GIsiSubBlockIter *sb)
+{
+ struct isi_call *call = NULL;
+ int i;
+ struct call_info *ci;
+ size_t len = sizeof(struct call_info);
+
+ if (!g_isi_sb_iter_get_struct(sb, (void *)&ci, len, 2))
+ return NULL;
+
+ i = ci->call_id & 7;
+
+ if (1 <= i && i <= 7) {
+ call = &ivc->calls[i];
+ call->call_id = ci->call_id;
+ call->status = ci->status;
+ call->mode = ci->mode;
+ call->mode_info = ci->mode_info;
}
- return isi_ctx_return(irc, OFONO_ERROR_TYPE_NO_ERROR, 0);
+ return call;
}
-/* ------------------------------------------------------------------------- */
-/* Notify */
-
-enum clcc_status {
- CLCC_STATUS_EARLY = -1,
- CLCC_STATUS_ACTIVE = 0,
- CLCC_STATUS_HOLD = 1,
- CLCC_STATUS_DIALING = 2,
- CLCC_STATUS_ALERTING = 3,
- CLCC_STATUS_INCOMING = 4,
- CLCC_STATUS_WAITING = 5,
- CLCC_STATUS_DISCONNECTED = 6,
-};
+static struct isi_call *isi_call_addr_and_status_info_sb_proc(
+ struct isi_voicecall *ivc,
+ GIsiSubBlockIter *sb)
+{
+ struct isi_call *call = NULL;
+ int i;
+ struct call_addr_info *ci;
+ size_t len = sizeof(struct call_addr_info);
+ char *addr;
+
+ if (!g_isi_sb_iter_get_struct(sb, (void *)&ci, len, 2))
+ return NULL;
+
+ if (!g_isi_sb_iter_get_alpha_tag(sb, &addr, 2 * ci->addr_len, 12))
+ return NULL;
+
+ i = ci->call_id & 7;
+
+ if (1 <= i && i <= 7) {
+ call = &ivc->calls[i];
+ call->call_id = ci->call_id;
+ call->status = ci->status;
+ call->mode = ci->mode;
+ call->mode_info = ci->mode_info;
+ call->addr_type = ci->addr_type | 0x80;
+ call->presentation = ci->presentation;
+ strncpy(call->address, addr, sizeof call->address);
+ }
+
+ g_free(addr);
+ return call;
+}
-/** Get +CLCC status */
-static int isi_call_status_to_clcc(struct isi_voicecall const *ivc,
- struct isi_call const *call)
+static int isi_call_status_to_clcc(const struct isi_call *call)
{
switch (call->status) {
case CALL_STATUS_CREATE:
- return CLCC_STATUS_DIALING;
+ return 2;
case CALL_STATUS_COMING:
- return CLCC_STATUS_EARLY;
+ return 4;
case CALL_STATUS_PROCEEDING:
+
if ((call->mode_info & CALL_MODE_ORIGINATOR))
- return CLCC_STATUS_EARLY; /* MT */
+ return 4; /* MT */
else
- return CLCC_STATUS_DIALING; /* MO */
+ return 2; /* MO */
case CALL_STATUS_MO_ALERTING:
- return CLCC_STATUS_ALERTING;
+ return 3;
case CALL_STATUS_MT_ALERTING:
- return CLCC_STATUS_INCOMING;
+ return 4;
case CALL_STATUS_WAITING:
- return CLCC_STATUS_WAITING;
+ return 5;
case CALL_STATUS_ANSWERED:
case CALL_STATUS_ACTIVE:
+ case CALL_STATUS_MO_RELEASE:
+ case CALL_STATUS_MT_RELEASE:
case CALL_STATUS_HOLD_INITIATED:
- case CALL_STATUS_RECONNECT_PENDING:
- case CALL_STATUS_SWAP_INITIATED:
- return CLCC_STATUS_ACTIVE;
+ return 0;
case CALL_STATUS_HOLD:
case CALL_STATUS_RETRIEVE_INITIATED:
- return CLCC_STATUS_HOLD;
+ return 1;
- case CALL_STATUS_MO_RELEASE:
- case CALL_STATUS_MT_RELEASE:
+ case CALL_STATUS_RECONNECT_PENDING:
case CALL_STATUS_TERMINATED:
- case CALL_STATUS_IDLE:
- return CLCC_STATUS_DISCONNECTED;
+ case CALL_STATUS_SWAP_INITIATED:
+ return 0;
}
-
- return CLCC_STATUS_ACTIVE;
+ return 0;
}
-static struct ofono_call isi_call_as_ofono_call(struct isi_voicecall const *ivc,
- struct isi_call const *call)
+static struct ofono_call isi_call_as_ofono_call(const struct isi_call *call)
{
- struct ofono_call ocall = { call->id };
+ struct ofono_call ocall = {
+ call->id
+ };
struct ofono_phone_number *number = &ocall.phone_number;
ocall.type = 0; /* Voice call */
ocall.direction = call->mode_info & CALL_MODE_ORIGINATOR;
- ocall.status = isi_call_status_to_clcc(ivc, call);
+ ocall.status = isi_call_status_to_clcc(call);
+
memcpy(number->number, call->address, sizeof(number->number));
+
number->type = 0x80 | call->addr_type;
ocall.clip_validity = call->presentation & 3;
@@ -297,249 +406,130 @@ static struct ofono_call isi_call_as_ofono_call(struct isi_voicecall const *ivc,
return ocall;
}
+static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
+{
+ if (g_isi_msg_error(msg) < 0) {
+ DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
+ return FALSE;
+ }
+
+ if (g_isi_msg_id(msg) != msgid) {
+ DBG("Unexpected msg: %s",
+ net_message_id_name(g_isi_msg_id(msg)));
+ return FALSE;
+ }
+ return TRUE;
+}
+
static struct isi_call *isi_call_set_idle(struct isi_call *call)
{
uint8_t id;
+ if (!call)
+ return NULL;
+
id = call->id;
- memset(call, 0, sizeof(*call));
+ memset(call, 0, sizeof(struct isi_call));
call->id = id;
return call;
}
-static void isi_call_disconnected(struct ofono_voicecall *ovc,
- struct isi_call *call)
+static void isi_call_release(struct ofono_voicecall *ovc, struct isi_call *call)
{
- struct ofono_error error = { OFONO_ERROR_TYPE_NO_ERROR, 0 };
- enum ofono_disconnect_reason reason = call->reason;
+ struct ofono_error error = {
+ OFONO_ERROR_TYPE_NO_ERROR, 0
+ };
+ enum ofono_disconnect_reason reason;
- if (!reason)
+ switch (call->status) {
+ case CALL_STATUS_IDLE:
+ reason = OFONO_DISCONNECT_REASON_UNKNOWN;
+ break;
+
+ case CALL_STATUS_MO_RELEASE:
+ reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
+ break;
+
+ case CALL_STATUS_MT_RELEASE:
+ reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
+ break;
+
+ case CALL_STATUS_TERMINATED:
+ default:
reason = OFONO_DISCONNECT_REASON_ERROR;
+ break;
+ }
- DBG("disconnected id=%u reason=%u", call->id, reason);
- ofono_voicecall_disconnected(ovc, call->id, reason, &error);
- isi_call_set_idle(call);
+ if (!call->reason) {
+ call->reason = reason;
+ DBG("disconnected id=%u reason=%u", call->id, reason);
+ ofono_voicecall_disconnected(ovc, call->id, reason, &error);
+ }
+
+ if (!reason)
+ isi_call_set_idle(call);
}
-static void isi_call_notify(struct ofono_voicecall *ovc,
- struct isi_call *call)
+static void isi_call_notify(struct ofono_voicecall *ovc, struct isi_call *call)
{
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- struct isi_call_req_context *irc, **queue;
+ struct isi_call_req_ctx *irc, **queue;
struct ofono_call ocall;
DBG("called with status=%s (0x%02X)",
call_status_name(call->status), call->status);
for (queue = &ivc->queue; (irc = *queue);) {
- irc->step(irc, call->id, call->status);
+ irc->step(irc, call->status);
if (*queue == irc)
queue = &irc->next;
}
- ocall = isi_call_as_ofono_call(ivc, call);
-
- DBG("id=%u,\"%s\",%u,\"%s\",%u,%u",
- ocall.id,
- ocall.direction ? "mt" : "mo",
- ocall.status,
- ocall.phone_number.number,
- ocall.phone_number.type,
- ocall.clip_validity);
-
- if (ocall.status == CLCC_STATUS_EARLY)
- return;
-
- ofono_voicecall_notify(ovc, &ocall);
-
switch (call->status) {
+ case CALL_STATUS_IDLE:
case CALL_STATUS_MO_RELEASE:
- call->reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
- break;
-
case CALL_STATUS_MT_RELEASE:
- call->reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
- break;
-
- case CALL_STATUS_IDLE:
case CALL_STATUS_TERMINATED:
- isi_call_disconnected(ovc, call);
- break;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Decoding subblocks */
-
-static void isi_call_any_address_sb_proc(struct isi_voicecall *ivc,
- struct isi_call *call,
- GIsiSubBlockIter const *sb)
-{
- uint8_t addr_type, presentation, addr_len;
- char *address;
-
- if (!g_isi_sb_iter_get_byte(sb, &addr_type, 2) ||
- !g_isi_sb_iter_get_byte(sb, &presentation, 3) ||
- /* fillerbyte */
- !g_isi_sb_iter_get_byte(sb, &addr_len, 5) ||
- !g_isi_sb_iter_get_alpha_tag(sb, &address, 2 * addr_len, 6))
- return;
-
- call->addr_type = addr_type | 0x80;
- call->presentation = presentation;
- strncpy(call->address, address, sizeof call->address);
-
- g_free(address);
-}
-
-static void isi_call_origin_address_sb_proc(struct isi_voicecall *ivc,
- struct isi_call *call,
- GIsiSubBlockIter const *sb)
-{
- if (!call->address[0])
- isi_call_any_address_sb_proc(ivc, call, sb);
-}
-
-static void isi_call_destination_address_sb_proc(struct isi_voicecall *ivc,
- struct isi_call *call,
- GIsiSubBlockIter const *sb)
-{
- if (!call->address[0])
- isi_call_any_address_sb_proc(ivc, call, sb);
-}
-
-static void isi_call_mode_sb_proc(struct isi_voicecall *ivc,
- struct isi_call *call,
- GIsiSubBlockIter const *sb)
-{
- uint8_t mode, mode_info;
-
- if (!g_isi_sb_iter_get_byte(sb, &mode, 2) ||
- !g_isi_sb_iter_get_byte(sb, &mode_info, 3))
- return;
-
- call->mode = mode;
- call->mode_info = mode_info;
-}
-
-static void isi_call_cause_sb_proc(struct isi_voicecall *ivc,
- struct isi_call *call,
- GIsiSubBlockIter const *sb)
-{
- uint8_t cause_type, cause;
-
- if (!g_isi_sb_iter_get_byte(sb, &cause_type, 2) ||
- !g_isi_sb_iter_get_byte(sb, &cause, 3))
- return;
-
- call->cause_type = cause_type;
- call->cause = cause;
-}
-
-static void isi_call_status_sb_proc(struct isi_voicecall *ivc,
- struct isi_call *call,
- GIsiSubBlockIter const *sb)
-{
- uint8_t status;
-
- if (!g_isi_sb_iter_get_byte(sb, &status, 2))
+ isi_call_release(ovc, call);
return;
+ }
- call->status = status;
-}
-
-static struct isi_call *
-isi_call_status_info_sb_proc(struct isi_voicecall *ivc,
- GIsiSubBlockIter const *sb)
-{
- struct isi_call *call = NULL;
- int i;
- uint8_t call_id;
- uint8_t mode;
- uint8_t mode_info;
- uint8_t status;
-
- if (!g_isi_sb_iter_get_byte(sb, &call_id, 2) ||
- !g_isi_sb_iter_get_byte(sb, &mode, 3) ||
- !g_isi_sb_iter_get_byte(sb, &mode_info, 4) ||
- !g_isi_sb_iter_get_byte(sb, &status, 5))
- return NULL;
-
- i = call_id & 7;
+ ocall = isi_call_as_ofono_call(call);
- if (1 <= i && i <= 7) {
- call = &ivc->calls[i];
- call->call_id = call_id;
- call->status = status;
- call->mode = mode;
- call->mode_info = mode_info;
- }
+ DBG("id=%u,%s,%u,\"%s\",%u,%u",
+ ocall.id,
+ ocall.direction ? "terminated" : "originated",
+ ocall.status,
+ ocall.phone_number.number,
+ ocall.phone_number.type,
+ ocall.clip_validity);
- return call;
+ ofono_voicecall_notify(ovc, &ocall);
}
-static struct isi_call *
-isi_call_addr_and_status_info_sb_proc(struct isi_voicecall *ivc,
- GIsiSubBlockIter const *sb)
+static void isi_call_create_resp(const GIsiMessage *msg, void *data)
{
- struct isi_call *call = NULL;
- int i;
+ struct isi_call_req_ctx *irc = data;
uint8_t call_id;
- uint8_t mode;
- uint8_t mode_info;
- uint8_t status;
- uint8_t addr_type;
- uint8_t presentation;
- uint8_t addr_len;
- char *address;
-
- if (!g_isi_sb_iter_get_byte(sb, &call_id, 2) ||
- !g_isi_sb_iter_get_byte(sb, &mode, 3) ||
- !g_isi_sb_iter_get_byte(sb, &mode_info, 4) ||
- !g_isi_sb_iter_get_byte(sb, &status, 5) ||
- !g_isi_sb_iter_get_byte(sb, &addr_type, 8) ||
- !g_isi_sb_iter_get_byte(sb, &presentation, 9) ||
- !g_isi_sb_iter_get_byte(sb, &addr_len, 11) ||
- !g_isi_sb_iter_get_alpha_tag(sb, &address, 2 * addr_len, 12))
- return NULL;
-
- i = call_id & 7;
- if (1 <= i && i <= 7) {
- call = &ivc->calls[i];
- call->call_id = call_id;
- call->status = status;
- call->mode = mode;
- call->mode_info = mode_info;
- call->addr_type = addr_type | 0x80;
- call->presentation = presentation;
- strncpy(call->address, address, sizeof call->address);
+ if (!check_response_status(msg, CALL_CREATE_RESP) ||
+ !g_isi_msg_data_get_byte(msg, 0, &call_id) ||
+ call_id == CALL_ID_NONE) {
+ isi_ctx_return_failure(irc);
+ return;
}
- free(address);
-
- return call;
+ isi_ctx_return_success(irc);
}
-/* ------------------------------------------------------------------------- */
-/* PN_CALL messages */
-
-static GIsiResponse isi_call_status_resp,
- isi_call_create_resp,
- isi_call_answer_resp,
- isi_call_release_resp,
- isi_call_control_resp,
- isi_call_dtmf_send_resp;
-
-static struct isi_call_req_context *
-isi_call_create_req(struct ofono_voicecall *ovc,
- uint8_t presentation,
- uint8_t addr_type,
- char const address[21],
- ofono_voicecall_cb_t cb,
- void *data)
+static struct isi_call_req_ctx *isi_call_create_req(struct ofono_voicecall *ovc,
+ uint8_t presentation,
+ uint8_t addr_type,
+ char const address[21],
+ ofono_voicecall_cb_t cb,
+ void *data)
{
size_t addr_len = strlen(address);
size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
@@ -573,78 +563,48 @@ isi_call_create_req(struct ofono_voicecall *ovc,
return isi_call_req(ovc, req, rlen, isi_call_create_resp, cb, data);
}
-static gboolean isi_call_create_resp(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *irc)
-{
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
-
- if (m != NULL && len < (sizeof *m))
- return FALSE;
- if (m == NULL || m->message_id == CALL_COMMON_MESSAGE)
- return isi_ctx_return_failure(irc);
- if (m->message_id != CALL_CREATE_RESP)
- return FALSE;
-
- if (m->call_id != CALL_ID_NONE && m->sub_blocks == 0)
- return isi_ctx_return_success(irc);
-
- /* Cause ? */
- return isi_ctx_return_failure(irc);
-}
-
-static void isi_call_status_ind_cb(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *_ovc)
+static void isi_call_status_ind_cb(const GIsiMessage *msg, void *data)
{
- struct ofono_voicecall *ovc = _ovc;
+ struct ofono_voicecall *ovc = data;
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
struct isi_call *call;
- uint8_t old;
- GIsiSubBlockIter sb[1];
+ GIsiSubBlockIter iter;
- if (len < 3)
- return; /* runt */
+ uint8_t call_id;
+ uint8_t old_status;
- if ((m->call_id & 7) == 0)
+ if (!ivc || g_isi_msg_id(msg) != CALL_STATUS_IND ||
+ !g_isi_msg_data_get_byte(msg, 0, &call_id) ||
+ (call_id & 7) == 0)
return;
- call = &ivc->calls[m->call_id & 7];
+ call = &ivc->calls[call_id & 7];
+ old_status = call->status;
+ call->call_id = call_id;
- old = call->status;
- call->call_id = m->call_id;
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
- for (g_isi_sb_iter_init(sb, data, len, (sizeof *m));
- g_isi_sb_iter_is_valid(sb);
- g_isi_sb_iter_next(sb)) {
- switch (g_isi_sb_iter_get_id(sb)) {
+ switch (g_isi_sb_iter_get_id(&iter)) {
case CALL_STATUS:
- isi_call_status_sb_proc(ivc, call, sb);
+ isi_call_status_sb_proc(ivc, call, &iter);
break;
case CALL_MODE:
- isi_call_mode_sb_proc(ivc, call, sb);
+ isi_call_mode_sb_proc(ivc, call, &iter);
break;
case CALL_CAUSE:
- isi_call_cause_sb_proc(ivc, call, sb);
+ isi_call_cause_sb_proc(ivc, call, &iter);
break;
case CALL_DESTINATION_ADDRESS:
- isi_call_destination_address_sb_proc(ivc, call, sb);
+ isi_call_destination_address_sb_proc(ivc, call, &iter);
break;
case CALL_ORIGIN_ADDRESS:
- isi_call_origin_address_sb_proc(ivc, call, sb);
+ isi_call_origin_address_sb_proc(ivc, call, &iter);
break;
case CALL_GSM_DETAILED_CAUSE:
@@ -657,197 +617,243 @@ static void isi_call_status_ind_cb(GIsiClient *client,
}
}
- if (old != call->status)
- isi_call_notify(ovc, call);
-}
+ if (old_status != call->status) {
-static struct isi_call_req_context *
-isi_call_answer_req(struct ofono_voicecall *ovc,
- uint8_t call_id, ofono_voicecall_cb_t cb, void *data)
-{
- uint8_t const req[] = {
- CALL_ANSWER_REQ, call_id, 0
- };
- size_t rlen = sizeof req;
+ if (call->status == CALL_STATUS_IDLE) {
+ call->status = CALL_STATUS_TERMINATED;
- return isi_call_req(ovc, req, rlen, isi_call_answer_resp, cb, data);
+ isi_call_notify(ovc, call);
+ isi_call_set_idle(call);
+ return;
+ }
+ }
+
+ isi_call_notify(ovc, call);
}
-static gboolean isi_call_answer_resp(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *irc)
+static void isi_call_answer_resp(const GIsiMessage *msg, void *data)
{
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
-
- if (m != NULL && len < (sizeof *m))
- return FALSE;
- if (m == NULL || m->message_id == CALL_COMMON_MESSAGE)
- return isi_ctx_return_failure(irc);
- if (m->message_id != CALL_ANSWER_RESP)
- return FALSE;
+ struct isi_call_req_ctx *irc = data;
+ uint8_t call_id;
- if (m->call_id != CALL_ID_NONE && m->sub_blocks == 0)
- return isi_ctx_return_success(irc);
+ if (!check_response_status(msg, CALL_ANSWER_RESP) ||
+ !g_isi_msg_data_get_byte(msg, 0, &call_id) ||
+ call_id == CALL_ID_NONE) {
+ isi_ctx_return_failure(irc);
+ return;
+ }
- /* Cause ? */
- return isi_ctx_return_failure(irc);
+ isi_ctx_return_success(irc);
}
-static struct isi_call_req_context *
-isi_call_release_req(struct ofono_voicecall *ovc,
- uint8_t call_id, uint8_t cause,
- ofono_voicecall_cb_t cb, void *data)
+static struct isi_call_req_ctx *isi_call_answer_req(struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
- uint8_t const req[] = {
- CALL_RELEASE_REQ, call_id, 2,
- CALL_CAUSE, 4, CALL_CAUSE_TYPE_CLIENT, cause,
- CALL_STATE_AUTO_CHANGE, 4, 0, 0
+ const uint8_t req[] = {
+ CALL_ANSWER_REQ,
+ call_id,
+ 0
};
- size_t rlen = sizeof req;
- return isi_call_req(ovc, req, rlen, isi_call_release_resp, cb, data);
+ return isi_call_req(ovc, req, sizeof(req), isi_call_answer_resp,
+ cb, data);
}
-static gboolean isi_call_release_resp(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *irc)
+static void isi_call_release_resp(const GIsiMessage *msg, void *data)
{
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
- GIsiSubBlockIter i[1];
- uint8_t cause_type = 0, cause = 0;
+ struct isi_call_req_ctx *irc = data;
+ GIsiSubBlockIter iter;
+ uint8_t cause_type;
+ uint8_t cause;
- if (m != NULL && len < (sizeof *m))
- return FALSE;
- if (m == NULL || m->message_id == CALL_COMMON_MESSAGE)
- return isi_ctx_return_failure(irc);
- if (m->message_id != CALL_RELEASE_RESP)
- return FALSE;
+ if (!check_response_status(msg, CALL_RELEASE_RESP))
+ goto error;
- for (g_isi_sb_iter_init(i, m, len, (sizeof *m));
- g_isi_sb_iter_is_valid(i);
- g_isi_sb_iter_next(i)) {
- if (g_isi_sb_iter_get_id(i) != CALL_CAUSE ||
- !g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
- !g_isi_sb_iter_get_byte(i, &cause, 3))
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) != CALL_CAUSE)
continue;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &cause_type, 2) ||
+ !g_isi_sb_iter_get_byte(&iter, &cause, 3))
+ goto error;
}
if ((cause_type == CALL_CAUSE_TYPE_SERVER ||
cause_type == CALL_CAUSE_TYPE_CLIENT) &&
(cause == CALL_CAUSE_RELEASE_BY_USER ||
- cause == CALL_CAUSE_BUSY_USER_REQUEST))
- return isi_ctx_return_success(irc);
- else
- return isi_ctx_return_failure(irc);
+ cause == CALL_CAUSE_BUSY_USER_REQUEST)) {
+ isi_ctx_return_success(irc);
+ return;
+ }
+
+error:
+ isi_ctx_return_failure(irc);
}
-static struct isi_call_req_context *
-isi_call_status_req(struct ofono_voicecall *ovc,
- uint8_t id, uint8_t mode,
- ofono_voicecall_cb_t cb, void *data)
+static struct isi_call_req_ctx *isi_call_release_req(struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ enum call_cause_type cause_type,
+ uint8_t cause,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
- unsigned char req[] = {
- CALL_STATUS_REQ, id, 1,
- CALL_STATUS_MODE, 4, mode, 0,
+ const uint8_t req[] = {
+ CALL_RELEASE_REQ,
+ call_id,
+ 1, /* Sub-block count */
+ CALL_CAUSE,
+ 4, /* Sub-block length */
+ cause_type,
+ cause,
};
- size_t rlen = sizeof req;
- return isi_call_req(ovc, req, rlen, isi_call_status_resp, cb, data);
+ return isi_call_req(ovc, req, sizeof(req), isi_call_release_resp,
+ cb, data);
}
-
-static gboolean isi_call_status_resp(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *_irc)
+static void isi_call_status_resp(const GIsiMessage *msg, void *data)
{
- struct isi_call_req_context *irc = _irc;
+ struct isi_call_req_ctx *irc = data;
struct ofono_voicecall *ovc = irc->ovc;
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
- GIsiSubBlockIter sb[1];
+ GIsiSubBlockIter iter;
struct isi_call *call = NULL;
- if (m != NULL && len < (sizeof *m))
- return FALSE;
- if (m == NULL || m->message_id == CALL_COMMON_MESSAGE)
- return isi_ctx_return_failure(irc);
- if (m->message_id != CALL_STATUS_RESP)
- return FALSE;
+ if (!check_response_status(msg, CALL_STATUS_RESP)) {
+ isi_ctx_return_failure(irc);
+ return;
+ }
- for (g_isi_sb_iter_init(sb, m, len, (sizeof *m));
- g_isi_sb_iter_is_valid(sb);
- g_isi_sb_iter_next(sb)) {
- switch (g_isi_sb_iter_get_id(sb)) {
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+ switch (g_isi_sb_iter_get_id(&iter)) {
case CALL_STATUS_INFO:
- call = isi_call_status_info_sb_proc(ivc, sb);
+ call = isi_call_status_info_sb_proc(ivc, &iter);
break;
case CALL_ADDR_AND_STATUS_INFO:
- call = isi_call_addr_and_status_info_sb_proc(ivc, sb);
+ call = isi_call_addr_and_status_info_sb_proc(ivc, &iter);
if (call)
isi_call_notify(ovc, call);
break;
case CALL_CAUSE:
+
if (call)
- isi_call_cause_sb_proc(ivc, call, sb);
+ isi_call_cause_sb_proc(ivc, call, &iter);
break;
}
}
- return isi_ctx_return_success(irc);
+ isi_ctx_return_success(irc);
}
-static struct isi_call_req_context *
-isi_call_control_req(struct ofono_voicecall *ovc,
- uint8_t call_id, enum call_operation op, uint8_t info,
- ofono_voicecall_cb_t cb, void *data)
+static struct isi_call_req_ctx *isi_call_status_req(struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ uint8_t mode,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
- uint8_t const req[] = {
- CALL_CONTROL_REQ, call_id, 1,
- CALL_OPERATION, 4, op, info,
+ const uint8_t req[] = {
+ CALL_STATUS_REQ,
+ call_id,
+ 1, /* Sub-block count */
+ CALL_STATUS_MODE,
+ 4, /* Sub-block length */
+ mode, 0,
};
- size_t rlen = sizeof req;
- return isi_call_req(ovc, req, rlen, isi_call_control_resp, cb, data);
+ return isi_call_req(ovc, req, sizeof(req), isi_call_status_resp,
+ cb, data);
}
-static struct isi_call_req_context *
-isi_call_deflect_req(struct ofono_voicecall *ovc,
- uint8_t call_id, uint8_t address_type,
- char const address[21],
- ofono_voicecall_cb_t cb, void *data)
+static void isi_call_control_resp(const GIsiMessage *msg, void *data)
+{
+ struct isi_call_req_ctx *irc = data;
+ GIsiSubBlockIter iter;
+ uint8_t cause = CALL_CAUSE_NO_CAUSE;
+ uint8_t cause_type = 0;
+
+ if (!check_response_status(msg, CALL_CONTROL_RESP))
+ goto error;
+
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) != CALL_CAUSE)
+ continue;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &cause_type, 2) ||
+ !g_isi_sb_iter_get_byte(&iter, &cause, 3))
+ goto error;
+ }
+
+ if (cause == CALL_CAUSE_NO_CAUSE) {
+ isi_ctx_return_failure(irc);
+ return;
+ }
+
+error:
+ isi_ctx_return_failure(irc);
+}
+
+static struct isi_call_req_ctx *isi_call_control_req(struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ enum call_operation op,
+ uint8_t info,
+ ofono_voicecall_cb_t cb,
+ void *data)
+{
+ const uint8_t req[] = {
+ CALL_CONTROL_REQ,
+ call_id,
+ 1, /* Sub-block count */
+ CALL_OPERATION,
+ 4, /* Sub-block length */
+ op, info,
+ };
+
+ return isi_call_req(ovc, req, sizeof(req), isi_call_control_resp,
+ cb, data);
+}
+
+static struct isi_call_req_ctx *isi_call_deflect_req(struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ uint8_t address_type,
+ const char address[21],
+ ofono_voicecall_cb_t cb,
+ void *data)
{
size_t addr_len = strlen(address);
size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
size_t i, offset = 3 + 4 + 6;
size_t rlen = 3 + 4 + sub_len;
uint8_t req[3 + 4 + 6 + 40] = {
- CALL_CONTROL_REQ, call_id, 2,
- CALL_OPERATION, 4, CALL_GSM_OP_DEFLECT, 0,
- CALL_GSM_DEFLECTION_ADDRESS, sub_len,
+ CALL_CONTROL_REQ,
+ call_id,
+ 2, /* Sub-block count */
+ CALL_OPERATION,
+ 4, /* Sub-block length */
+ CALL_GSM_OP_DEFLECT, 0,
+ CALL_GSM_DEFLECTION_ADDRESS,
+ sub_len, /* Sub-block lenght */
address_type & 0x7F,
- 0x7, /* default presentation */
- 0, /* filler */
+ 0x7, /* Default presentation */
+ 0, /* Filler */
addr_len,
};
if (addr_len > 20) {
CALLBACK_WITH_FAILURE(cb, data);
- return FALSE;
+ return NULL;
}
for (i = 0; i < addr_len; i++)
@@ -856,44 +862,42 @@ isi_call_deflect_req(struct ofono_voicecall *ovc,
return isi_call_req(ovc, req, rlen, isi_call_control_resp, cb, data);
}
-static gboolean isi_call_control_resp(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *irc)
+static void isi_call_dtmf_send_resp(const GIsiMessage *msg, void *data)
{
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
- GIsiSubBlockIter i[1];
- uint8_t cause_type = 0, cause = 0;
+ struct isi_call_req_ctx *irc = data;
+ GIsiSubBlockIter iter;
+ uint8_t cause_type;
+ uint8_t cause;
- if (m != NULL && len < sizeof *m)
- return FALSE;
- if (m == NULL || m->message_id == CALL_COMMON_MESSAGE)
- return isi_ctx_return_failure(irc);
- if (m->message_id != CALL_CONTROL_RESP)
- return FALSE;
+ if (!check_response_status(msg, CALL_DTMF_SEND_RESP))
+ goto error;
- for (g_isi_sb_iter_init(i, m, len, (sizeof *m));
- g_isi_sb_iter_is_valid(i);
- g_isi_sb_iter_next(i)) {
- if (g_isi_sb_iter_get_id(i) != CALL_CAUSE ||
- !g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
- !g_isi_sb_iter_get_byte(i, &cause, 3))
+ for (g_isi_sb_iter_init(&iter, msg, 2);
+ g_isi_sb_iter_is_valid(&iter);
+ g_isi_sb_iter_next(&iter)) {
+
+ if (g_isi_sb_iter_get_id(&iter) != CALL_CAUSE)
continue;
+
+ if (!g_isi_sb_iter_get_byte(&iter, &cause_type, 2) ||
+ !g_isi_sb_iter_get_byte(&iter, &cause, 3))
+ goto error;
+ }
+
+ if (cause == CALL_CAUSE_NO_CAUSE) {
+ isi_ctx_return_success(irc);
+ return;
}
- if (!cause)
- return isi_ctx_return_success(irc);
- else
- return isi_ctx_return_failure(irc);
+error:
+ isi_ctx_return_failure(irc);
}
-static struct isi_call_req_context *
-isi_call_dtmf_send_req(struct ofono_voicecall *ovc,
- uint8_t call_id, char const *string,
- ofono_voicecall_cb_t cb, void *data)
+static struct isi_call_req_ctx *isi_call_dtmf_send_req(struct ofono_voicecall *ovc,
+ uint8_t call_id,
+ const char *string,
+ ofono_voicecall_cb_t cb,
+ void *data)
{
size_t str_len = strlen(string);
size_t sub_len = 4 + ((2 * str_len + 3) & ~3);
@@ -923,45 +927,6 @@ isi_call_dtmf_send_req(struct ofono_voicecall *ovc,
return isi_call_req(ovc, req, rlen, isi_call_dtmf_send_resp, cb, data);
}
-static gboolean isi_call_dtmf_send_resp(GIsiClient *client,
- void const *restrict data,
- size_t len,
- uint16_t object,
- void *irc)
-{
- struct {
- uint8_t message_id, call_id, sub_blocks;
- } const *m = data;
- GIsiSubBlockIter i[1];
- uint8_t cause_type = 0, cause = 0;
-
- if (m != NULL && len < (sizeof *m))
- return FALSE;
- if (m == NULL || m->message_id == CALL_COMMON_MESSAGE)
- return isi_ctx_return_failure(irc);
- if (m->message_id != CALL_DTMF_SEND_RESP)
- return FALSE;
-
- if (m->sub_blocks == 0)
- return isi_ctx_return_success(irc);
-
- for (g_isi_sb_iter_init(i, m, len, (sizeof *m));
- g_isi_sb_iter_is_valid(i);
- g_isi_sb_iter_next(i)) {
- if (g_isi_sb_iter_get_id(i) != CALL_CAUSE ||
- !g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
- !g_isi_sb_iter_get_byte(i, &cause, 3))
- continue;
- }
-
- if (!cause)
- return isi_ctx_return_success(irc);
- else
- return isi_ctx_return_failure(irc);
-}
-
-/* ---------------------------------------------------------------------- */
-
static void isi_dial(struct ofono_voicecall *ovc,
const struct ofono_phone_number *restrict number,
enum ofono_clir_option clir,
@@ -995,22 +960,21 @@ static void isi_dial(struct ofono_voicecall *ovc,
cb, data);
}
-static void isi_answer(struct ofono_voicecall *ovc,
- ofono_voicecall_cb_t cb, void *data)
+static void isi_answer(struct ofono_voicecall *ovc, ofono_voicecall_cb_t cb,
+ void *data)
{
isi_call_answer_req(ovc, CALL_ID_ALL, cb, data);
}
static void isi_hangup_current(struct ofono_voicecall *ovc,
- ofono_voicecall_cb_t cb, void *data)
+ ofono_voicecall_cb_t cb, void *data)
{
/*
* Hangup call(s) that are not held or waiting:
* active calls or calls in progress.
*/
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- int id;
- uint8_t cause = CALL_CAUSE_RELEASE_BY_USER;
+ int id = 0;
for (id = 1; id <= 7; id++) {
if (ivc->calls[id].call_id & CALL_ID_WAITING)
@@ -1020,14 +984,11 @@ static void isi_hangup_current(struct ofono_voicecall *ovc,
switch (ivc->calls[id].status) {
case CALL_STATUS_CREATE:
- case CALL_STATUS_MT_ALERTING:
- case CALL_STATUS_ANSWERED:
- goto release_by_id;
-
case CALL_STATUS_COMING:
case CALL_STATUS_PROCEEDING:
case CALL_STATUS_MO_ALERTING:
- cause = CALL_CAUSE_BUSY_USER_REQUEST;
+ case CALL_STATUS_MT_ALERTING:
+ case CALL_STATUS_ANSWERED:
goto release_by_id;
}
}
@@ -1035,14 +996,14 @@ static void isi_hangup_current(struct ofono_voicecall *ovc,
id = CALL_ID_ACTIVE;
release_by_id:
- isi_call_release_req(ovc, id, cause, cb, data);
+ isi_call_release_req(ovc, id, CALL_CAUSE_TYPE_CLIENT,
+ CALL_CAUSE_RELEASE_BY_USER, cb, data);
}
static void isi_release_all_held(struct ofono_voicecall *ovc,
- ofono_voicecall_cb_t cb, void *data)
+ ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=0 (w/out incoming calls) */
- isi_call_release_req(ovc, CALL_ID_HOLD,
+ isi_call_release_req(ovc, CALL_ID_HOLD, CALL_CAUSE_TYPE_CLIENT,
CALL_CAUSE_RELEASE_BY_USER, cb, data);
}
@@ -1051,6 +1012,7 @@ static void isi_set_udub(struct ofono_voicecall *ovc,
{
/* Release waiting calls */
isi_call_release_req(ovc, CALL_ID_WAITING,
+ CALL_CAUSE_TYPE_CLIENT,
CALL_CAUSE_BUSY_USER_REQUEST, cb, data);
}
@@ -1060,39 +1022,45 @@ static void isi_retrieve(struct ofono_voicecall *ovc,
isi_call_control_req(ovc, CALL_ID_HOLD, CALL_OP_RETRIEVE, 0, cb, data);
}
-static void isi_wait_and_answer(struct isi_call_req_context *irc,
- int id, int status)
+static void isi_wait_and_answer(struct isi_call_req_ctx *irc, int event)
{
- DBG("irc=%p id=%d status=%d", (void *)irc, id, status);
+ DBG("irc=%p event=%u", (void *)irc, event);
- if (id != irc->id)
+ if (event != CALL_STATUS_TERMINATED)
return;
- switch (status) {
- case CALL_STATUS_MT_ALERTING:
- isi_call_answer_req(irc->ovc, irc->id, irc->cb, irc->data);
- isi_ctx_free(irc);
- break;
+ isi_answer(irc->ovc, irc->cb, irc->data);
+ isi_ctx_free(irc);
+}
- default:
- isi_ctx_return_failure(irc);
- break;
- }
+static void isi_wait_and_retrieve(struct isi_call_req_ctx *irc, int event)
+{
+ DBG("irc=%p event=%u", (void *)irc, event);
+
+ if (event != CALL_STATUS_TERMINATED)
+ return;
+
+ isi_retrieve(irc->ovc, irc->cb, irc->data);
+ isi_ctx_free(irc);
}
static void isi_release_all_active(struct ofono_voicecall *ovc,
ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=1 */
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- struct isi_call_req_context *irc;
- int id;
- int waiting_id = 0;
+ struct isi_call_req_ctx *irc;
+ int id = 0;
+ int waiting = 0;
int active = 0;
+ int hold = 0;
for (id = 1; id <= 7; id++) {
+
if (ivc->calls[id].call_id & CALL_ID_WAITING)
- waiting_id = id;
+ waiting++;
+
+ if (ivc->calls[id].call_id & CALL_ID_HOLD)
+ hold++;
if (ivc->calls[id].call_id & CALL_ID_ACTIVE)
active++;
@@ -1104,113 +1072,128 @@ static void isi_release_all_active(struct ofono_voicecall *ovc,
}
irc = isi_call_release_req(ovc, CALL_ID_ACTIVE,
+ CALL_CAUSE_TYPE_CLIENT,
CALL_CAUSE_RELEASE_BY_USER,
cb, data);
- if (irc == NULL)
+ if (!irc)
return;
- if (waiting_id)
- isi_ctx_queue(irc, isi_wait_and_answer, waiting_id);
-
- /* Retrieving held calls is currently a unwanted side-effect */
+ if (waiting)
+ isi_ctx_queue(irc, isi_wait_and_answer);
+ else if (hold)
+ isi_ctx_queue(irc, isi_wait_and_retrieve);
}
static void isi_hold_all_active(struct ofono_voicecall *ovc,
ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=2 */
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- int id;
+ int id = 0;
+ int op = 0;
int waiting = 0;
int active = 0;
int hold = 0;
- int op;
for (id = 1; id <= 7; id++) {
+
if (ivc->calls[id].call_id & CALL_ID_WAITING)
waiting++;
- else if (ivc->calls[id].call_id & CALL_ID_HOLD)
+
+ if (ivc->calls[id].call_id & CALL_ID_HOLD)
hold++;
- else if (ivc->calls[id].call_id & CALL_ID_ACTIVE)
+
+ if (ivc->calls[id].call_id & CALL_ID_ACTIVE)
active++;
}
- if (waiting) {
- isi_call_answer_req(ovc, CALL_ID_WAITING, cb, data);
+ if (!waiting && !hold && !active) {
+ CALLBACK_WITH_FAILURE(cb, data);
return;
}
- if (active) {
- if (hold)
+ if (waiting) {
+ isi_call_answer_req(ovc, CALL_ID_WAITING, cb, data);
+
+ } else if (hold) {
+
+ if (active) {
op = CALL_OP_SWAP;
- else
- op = CALL_OP_HOLD;
+ id = CALL_ID_ACTIVE;
+ } else {
+ op = CALL_OP_RETRIEVE;
+ id = CALL_ID_HOLD;
+ }
+ isi_call_control_req(ovc, id, op, 0, cb, data);
- isi_call_control_req(ovc, CALL_ID_ACTIVE, op, 0, cb, data);
+ } else if (active) {
+ id = CALL_ID_ACTIVE;
+ op = CALL_OP_HOLD;
- } else if (hold)
- isi_retrieve(ovc, cb, data);
- else
- CALLBACK_WITH_FAILURE(cb, data);
+ isi_call_control_req(ovc, id, op, 0, cb, data);
+ }
}
static void isi_release_specific(struct ofono_voicecall *ovc, int id,
ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=1X */
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+ const struct isi_call *status;
+ uint8_t cause;
- if (1 <= id && id <= 7) {
- struct isi_call const *status = &ivc->calls[id];
- uint8_t cause = CALL_CAUSE_RELEASE_BY_USER;
+ if (id < 1 || id > 7) {
+ CALLBACK_WITH_FAILURE(cb, data);
+ return;
+ }
- switch (status->status) {
- case CALL_STATUS_COMING:
- case CALL_STATUS_MT_ALERTING:
- case CALL_STATUS_WAITING:
+ status = &ivc->calls[id];
+ cause = CALL_CAUSE_RELEASE_BY_USER;
+
+ switch (status->status) {
+ case CALL_STATUS_MT_ALERTING:
+ case CALL_STATUS_WAITING:
+ cause = CALL_CAUSE_BUSY_USER_REQUEST;
+ break;
+
+ case CALL_STATUS_PROCEEDING:
+
+ if ((status->mode_info & CALL_MODE_ORIGINATOR))
cause = CALL_CAUSE_BUSY_USER_REQUEST;
break;
- case CALL_STATUS_PROCEEDING:
- if ((status->mode_info & CALL_MODE_ORIGINATOR))
- cause = CALL_CAUSE_BUSY_USER_REQUEST;
- break;
- }
+ }
- isi_call_release_req(ovc, id, cause, cb, data);
- } else
- CALLBACK_WITH_FAILURE(cb, data);
+ isi_call_release_req(ovc, id, CALL_CAUSE_TYPE_CLIENT, cause, cb, data);
}
static void isi_private_chat(struct ofono_voicecall *ovc, int id,
ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=2X */
- if (1 <= id && id <= 7)
- isi_call_control_req(ovc, id, CALL_OP_CONFERENCE_SPLIT, 0,
- cb, data);
- else
+ if (id < 1 || id > 7) {
CALLBACK_WITH_FAILURE(cb, data);
+ return;
+ }
+
+ isi_call_control_req(ovc, id, CALL_OP_CONFERENCE_SPLIT, 0, cb, data);
}
static void isi_create_multiparty(struct ofono_voicecall *ovc,
ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=3 */
isi_call_control_req(ovc, CALL_ID_ALL, CALL_OP_CONFERENCE_BUILD, 0,
cb, data);
}
static void isi_transfer(struct ofono_voicecall *ovc,
- ofono_voicecall_cb_t cb, void *data)
+ ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CHLD=4 */
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
-
uint8_t id;
- for (id = 1; id <= 7; id++)
+ for (id = 1; id <= 7; id++) {
+
if (ivc->calls[id].status == CALL_STATUS_MO_ALERTING)
break;
+ }
+
if (id > 7)
id = CALL_ID_ACTIVE;
@@ -1221,30 +1204,37 @@ static void isi_deflect(struct ofono_voicecall *ovc,
const struct ofono_phone_number *ph,
ofono_voicecall_cb_t cb, void *data)
{
- /* AT+CTFR=<number>,<type> */
- int id = CALL_ID_WAITING;
- isi_call_deflect_req(ovc, id, ph->type, ph->number, cb, data);
+ isi_call_deflect_req(ovc, CALL_ID_WAITING, ph->type, ph->number,
+ cb, data);
}
static void isi_swap_without_accept(struct ofono_voicecall *ovc,
- ofono_voicecall_cb_t cb, void *data)
+ ofono_voicecall_cb_t cb, void *data)
{
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- int id = 0, op = 0, active = 0, hold = 0;
+ int id = 0;
+ int op = 0;
+ int active = 0;
+ int hold = 0;
for (id = 1; id <= 7; id++) {
+
if (ivc->calls[id].call_id & CALL_ID_HOLD)
hold++;
+
if (ivc->calls[id].call_id & CALL_ID_ACTIVE)
active++;
}
if (hold && active) {
- id = CALL_ID_ACTIVE, op = CALL_OP_SWAP;
+ id = CALL_ID_ACTIVE;
+ op = CALL_OP_SWAP;
} else if (active) {
- id = CALL_ID_ACTIVE, op = CALL_OP_HOLD;
+ id = CALL_ID_ACTIVE;
+ op = CALL_OP_HOLD;
} else if (hold) {
- id = CALL_ID_HOLD, op = CALL_OP_RETRIEVE;
+ id = CALL_ID_HOLD;
+ op = CALL_OP_RETRIEVE;
} else {
CALLBACK_WITH_FAILURE(cb, data);
return;
@@ -1259,69 +1249,50 @@ static void isi_send_tones(struct ofono_voicecall *ovc, const char *tones,
isi_call_dtmf_send_req(ovc, CALL_ID_ALL, tones, cb, data);;
}
-static gboolean isi_call_register(gpointer _ovc)
+static void isi_call_verify_cb(const GIsiMessage *msg, void *data)
{
- struct ofono_voicecall *ovc = _ovc;
+ struct ofono_voicecall *ovc = data;
struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
- const char *debug = getenv("OFONO_ISI_DEBUG");
- if (debug != NULL && (!strcmp(debug, "all") || !strcmp(debug, "call")))
- g_isi_client_set_debug(ivc->client, call_debug, NULL);
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
- g_isi_subscribe(ivc->client,
- CALL_STATUS_IND, isi_call_status_ind_cb,
- ovc);
+ g_isi_client_ind_subscribe(ivc->client, CALL_STATUS_IND,
+ isi_call_status_ind_cb, ovc);
- if (isi_call_status_req(ovc, CALL_ID_ALL,
+ if (!isi_call_status_req(ovc, CALL_ID_ALL,
CALL_STATUS_MODE_ADDR_AND_ORIGIN,
- NULL, NULL) == NULL)
+ NULL, NULL))
DBG("Failed to request call status");
ofono_voicecall_register(ovc);
-
- return FALSE;
-}
-
-static void isi_call_verify_cb(GIsiClient *client,
- gboolean alive, uint16_t object, void *ovc)
-{
- if (!alive) {
- DBG("Unable to bootstrap voice call driver");
- return;
- }
-
- DBG("%s (v%03d.%03d) reachable",
- pn_resource_name(g_isi_client_resource(client)),
- g_isi_version_major(client),
- g_isi_version_minor(client));
-
- g_idle_add(isi_call_register, ovc);
}
static int isi_voicecall_probe(struct ofono_voicecall *ovc,
unsigned int vendor, void *user)
{
- GIsiModem *idx = user;
+ GIsiModem *modem = user;
struct isi_voicecall *ivc;
int id;
ivc = g_try_new0(struct isi_voicecall, 1);
- if (ivc == NULL)
+ if (!ivc)
return -ENOMEM;
- for (id = 1; id <= 7; id++)
+ for (id = 0; id <= 7; id++)
ivc->calls[id].id = id;
- ivc->client = g_isi_client_create(idx, PN_CALL);
- if (ivc->client == NULL) {
+ ivc->client = g_isi_client_create(modem, PN_CALL);
+ if (!ivc->client) {
g_free(ivc);
return -ENOMEM;
}
ofono_voicecall_set_data(ovc, ivc);
- if (g_isi_verify(ivc->client, isi_call_verify_cb, ovc) == NULL)
- DBG("Unable to verify reachability");
+ g_isi_client_verify(ivc->client, isi_call_verify_cb, ovc, NULL);
return 0;
}
@@ -1330,10 +1301,11 @@ static void isi_voicecall_remove(struct ofono_voicecall *call)
{
struct isi_voicecall *data = ofono_voicecall_get_data(call);
- if (data == NULL)
+ ofono_voicecall_set_data(call, NULL);
+
+ if (!data)
return;
- ofono_voicecall_set_data(call, NULL);
g_isi_client_destroy(data->client);
g_free(data);
}