OSDN Git Service

update to huawei-ril 1.0.0.8 kitkat-x86 android-x86-4.4-r1 android-x86-4.4-r2 android-x86-4.4-r3
authorChih-Wei Huang <cwhuang@linux.org.tw>
Mon, 7 Jul 2014 03:06:54 +0000 (11:06 +0800)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Fri, 11 Jul 2014 06:48:05 +0000 (14:48 +0800)
22 files changed:
huaweigeneric-ril/Android.mk
huaweigeneric-ril/README
huaweigeneric-ril/agc.c [new file with mode: 0644]
huaweigeneric-ril/agc.h [new file with mode: 0644]
huaweigeneric-ril/at_tok.c
huaweigeneric-ril/atchannel.c
huaweigeneric-ril/atchannel.h
huaweigeneric-ril/audiochannel.cpp
huaweigeneric-ril/audiochannel.h
huaweigeneric-ril/audioqueue.c [new file with mode: 0644]
huaweigeneric-ril/audioqueue.h [new file with mode: 0644]
huaweigeneric-ril/echocancel.c [new file with mode: 0644]
huaweigeneric-ril/echocancel.h [new file with mode: 0644]
huaweigeneric-ril/fcp_parser.c
huaweigeneric-ril/gsm.c
huaweigeneric-ril/huaweigeneric-ril.c
huaweigeneric-ril/misc.c
huaweigeneric-ril/net-utils.c [new file with mode: 0644]
huaweigeneric-ril/net-utils.h [new file with mode: 0644]
huaweigeneric-ril/requestdatahandler.c
huaweigeneric-ril/sms.c
huaweigeneric-ril/sms_gsm.c

index 6321da7..6362bad 100644 (file)
@@ -4,12 +4,15 @@ LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
+    agc.c \
     at_tok.c \
     atchannel.c \
+    echocancel.c \
     fcp_parser.c \
     gsm.c \
     huaweigeneric-ril.c \
     misc.c \
+    net-utils.c \
     requestdatahandler.c \
     sms.c \
     sms_gsm.c \
index e9ace04..137cb49 100644 (file)
@@ -34,3 +34,52 @@ The modules has still a few problems:
 ----
 
        pppd must be suid ROOT, and kernel must include ppp support compiled in
+       /system/etc/ppp/ip-up and also /system/etc/ppp/ip-down must also be suid ROOT
+
+----
+
+       You also need the following files in /system/etc/ppp
+
+----
+/system/etc/ppp/ip-up:
+
+#!/system/bin/sh
+case $1 in
+    ppp1)
+       /android/bin/iptables --flush;
+       /android/bin/iptables --table nat --flush;
+       /android/bin/iptables --delete-chain;
+       /android/bin/iptables --table nat --append POSTROUTING --out-interface ppp0 -j MASQUERADE;
+       /android/bin/iptables --append FORWARD --in-interface ppp1 -j ACCEPT;
+       echo 0 > /proc/sys/net/ipv4/ip_forward;
+       echo 1 > /proc/sys/net/ipv4/ip_forward;
+       ;;
+    ppp0)
+    /system/bin/setprop "net.interfaces.defaultroute" "$LINKNAME";
+    ;;
+esac
+
+/system/bin/setprop "net.$LINKNAME.dns1" "$DNS1"
+/system/bin/setprop "net.$LINKNAME.dns2" "$DNS2"
+/system/bin/setprop "net.$LINKNAME.local-ip" "$IPLOCAL"
+/system/bin/setprop "net.$LINKNAME.remote-ip" "$IPREMOTE"
+/system/bin/setprop "net.$LINKNAME.gw" "$IPREMOTE"
+/system/bin/setprop "net.$LINKNAME.if" "$IFNAME"
+
+
+----
+/system/etc/ppp/ip-down:
+
+#!/system/bin/sh
+case $1 in
+    ppp1)
+       echo 0 > /proc/sys/net/ipv4/ip_forward;
+       ;;
+esac
+
+/system/bin/setprop "net.$LINKNAME.dns1" ""
+/system/bin/setprop "net.$LINKNAME.dns2" ""
+/system/bin/setprop "net.$LINKNAME.local-ip" ""
+/system/bin/setprop "net.$LINKNAME.remote-ip" ""
+/system/bin/setprop "net.$LINKNAME.gw" ""
+/system/bin/setprop "net.$LINKNAME.if" ""
diff --git a/huaweigeneric-ril/agc.c b/huaweigeneric-ril/agc.c
new file mode 100644 (file)
index 0000000..4a4b009
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+*  This AGC algorithm was taken from isdn2h323 (http://www.telos.de). It was
+*  converted from C++ to C, and modified to add control over the recording level.
+*  Converted to fixed point by Phil Frisbie, Jr. 4/12/2003
+*/
+
+#include "agc.h"
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "RILAudioAGC"
+#include <utils/Log.h>
+
+void agc_init(struct agc_ctx* ctx, short level /* 16384-32767*/ )
+{
+    ALOGD("[%p] Initializing AGC: level: %d",ctx, level);
+    ctx->sample_max = 1;
+    ctx->counter = 0;
+    ctx->igain = 65536;
+    if (level < 16384) {
+        level = 16384;
+    }
+    ctx->ipeak = (int)(level * 65536);
+    ctx->silence_counter = 0;
+}
+
+void agc_process_16bit(struct agc_ctx *ctx, short *buffer, int len)
+{
+    int i;
+    for (i=0; i<len; i++) {
+
+        long gain_new;
+        int sample;
+
+        /* get the abs of buffer[i] */
+        sample = buffer[i];
+        sample = (sample < 0 ? -(sample) : sample);
+
+        if(sample > (int)ctx->sample_max) {
+            /* update the max */
+            ctx->sample_max = (unsigned int)sample;
+        }
+        ctx->counter ++;
+
+        /* Will we get an overflow with the current gain factor? */
+        if (((sample * ctx->igain) >> 16) > ctx->ipeak) {
+            /* Yes: Calculate new gain. */
+            ctx->igain = ((ctx->ipeak / ctx->sample_max) * 62259) >> 16;
+            ctx->silence_counter = 0;
+            buffer[i] = (short) ((buffer[i] * ctx->igain) >> 16);
+            continue;
+        }
+
+        /* Calculate new gain factor 10x per second */
+        if (ctx->counter >= 8000/10) {
+            if (ctx->sample_max > 800) {      /* speaking? */
+                gain_new = ((ctx->ipeak / ctx->sample_max) * 62259) >> 16;
+
+                if (ctx->silence_counter > 40)  /* pause -> speaking */
+                    ctx->igain += (gain_new - ctx->igain) >> 2;
+                else
+                    ctx->igain += (gain_new - ctx->igain) / 20;
+
+                ctx->silence_counter = 0;
+            } else { /* silence */
+                ctx->silence_counter++;
+                /* silence > 2 seconds: reduce gain */
+                if ((ctx->igain > 65536) && (ctx->silence_counter >= 20))
+                    ctx->igain = (ctx->igain * 62259) >> 16;
+            }
+            ctx->counter = 0;
+            ctx->sample_max = 1;
+        }
+        buffer[i] = (short) ((buffer[i] * ctx->igain) >> 16);
+    }
+
+    //ALOGD("[%p] Gain: %d",ctx, ctx->igain);
+}
+
+void agc_process_8bit(struct agc_ctx *ctx, unsigned char *buffer, int len)
+{
+    int i;
+    for (i=0; i<len; i++) {
+
+        long gain_new;
+        int sample;
+
+        /* get the abs of buffer[i] */
+        sample = (buffer[i] - 128) << 8;
+        sample = (sample < 0 ? -(sample) : sample);
+
+        if(sample > (int)ctx->sample_max) {
+            /* update the max */
+            ctx->sample_max = (unsigned int)sample;
+        }
+        ctx->counter ++;
+
+        /* Will we get an overflow with the current gain factor? */
+        if (((sample * ctx->igain) >> 16) > ctx->ipeak) {
+            /* Yes: Calculate new gain. */
+            ctx->igain = ((ctx->ipeak / ctx->sample_max) * 62259) >> 16;
+            ctx->silence_counter = 0;
+            buffer[i] = (unsigned char) (( ((buffer[i] - 128) << 8) * ctx->igain) >> 24) + 128;
+            continue;
+        }
+
+        /* Calculate new gain factor 10x per second */
+        if (ctx->counter >= 8000/10) {
+            if (ctx->sample_max > 800) {      /* speaking? */
+                gain_new = ((ctx->ipeak / ctx->sample_max) * 62259) >> 16;
+
+                if (ctx->silence_counter > 40)  /* pause -> speaking */
+                    ctx->igain += (gain_new - ctx->igain) >> 2;
+                else
+                    ctx->igain += (gain_new - ctx->igain) / 20;
+
+                ctx->silence_counter = 0;
+            } else { /* silence */
+                ctx->silence_counter++;
+                /* silence > 2 seconds: reduce gain */
+                if ((ctx->igain > 65536) && (ctx->silence_counter >= 20))
+                    ctx->igain = (ctx->igain * 62259) >> 16;
+            }
+            ctx->counter = 0;
+            ctx->sample_max = 1;
+        }
+        buffer[i] = (unsigned char) (( ((buffer[i] - 128) << 8) * ctx->igain) >> 24) + 128;
+    }
+
+    //ALOGD("[%p] Gain: %d",ctx, ctx->igain);
+}
diff --git a/huaweigeneric-ril/agc.h b/huaweigeneric-ril/agc.h
new file mode 100644 (file)
index 0000000..d52fc1b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ **
+ ** Copyright 2006, The Android Open Source Project
+ ** Copyright 2012 Eduardo Jos[e Tagle <ejtagle@tutopia.com>
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef _AGC_H
+#define _AGC_H
+
+struct agc_ctx {
+    unsigned int sample_max;
+    int counter;
+    int igain;
+    int ipeak;
+    int silence_counter;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void agc_init(struct agc_ctx* ctx, short level /* 16384-32767*/ );
+void agc_process_16bit(struct agc_ctx *ctx, short *buffer, int samples);
+void agc_process_8bit(struct agc_ctx *ctx, unsigned char *buffer, int samples);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index aef475f..cce0aa7 100644 (file)
  */
 int at_tok_start(char **p_cur)
 {
-    if (*p_cur == NULL)
+    if (*p_cur == NULL) {
         return -1;
+    }
 
     /* Skip prefix,
        consume "^[^:]:". */
 
     *p_cur = strchr(*p_cur, ':');
 
-    if (*p_cur == NULL)
+    if (*p_cur == NULL) {
         return -1;
+    }
 
     (*p_cur)++;
 
@@ -45,33 +47,34 @@ int at_tok_start(char **p_cur)
 
 static void skipWhiteSpace(char **p_cur)
 {
-    if (*p_cur == NULL)
-        return;
+    if (*p_cur == NULL) return;
 
-    while (**p_cur != '\0' && isspace(**p_cur))
+    while (**p_cur != '\0' && isspace(**p_cur)) {
         (*p_cur)++;
     }
+}
 
 static void skipNextComma(char **p_cur)
 {
-    if (*p_cur == NULL)
-        return;
+    if (*p_cur == NULL) return;
 
-    while (**p_cur != '\0' && **p_cur != ',')
+    while (**p_cur != '\0' && **p_cur != ',') {
         (*p_cur)++;
+    }
 
-    if (**p_cur == ',')
+    if (**p_cur == ',') {
         (*p_cur)++;
     }
+}
 
 /**
  * If the first none space character is a quotation mark, returns the string
  * between two quotation marks, else returns the content before the first comma.
  * Updates *p_cur.
  */
-static char * nextTok(char **p_cur)
+static char *nextTok(char **p_cur)
 {
-    char *ret = NULL;
+    char *ret;
 
     skipWhiteSpace(p_cur);
 
@@ -85,47 +88,48 @@ static char * nextTok(char **p_cur)
 
         while (state != END) {
             switch (state) {
-            case NORMAL:
-                switch (**p_cur) {
-                case '\\':
-                    state = ESCAPE;
+                case NORMAL:
+                    switch (**p_cur) {
+                        case '\\':
+                            state = ESCAPE;
+                            break;
+                        case '"':
+                            state = END;
+                            break;
+                        case '\0':
+                            /*
+                             * Error case, parsing string is not quoted by ending
+                             * double quote, e.g. "bla bla, this function expects input
+                             * string to be NULL terminated, so that the loop can exit.
+                             */
+                            ret = NULL;
+                            goto exit;
+                        default:
+                            /* Stays in normal case. */
+                            break;
+                    }
                     break;
-                case '"':
-                    state = END;
+
+                case ESCAPE:
+                    state = NORMAL;
                     break;
-                case '\0':
-                    /*
-                     * Error case, parsing string is not quoted by ending
-                     * double quote, e.g. "bla bla, this function expects input
-                     * string to be NULL terminated, so that the loop can exit.
-                     */
-                    ret = NULL;
-                    goto exit;
+
                 default:
-                    /* Stays in normal case. */
+                    /* This should never happen. */
                     break;
-                }
-                break;
-
-            case ESCAPE:
-                state = NORMAL;
-                break;
-
-            default:
-                /* This should never happen. */
-                break;
             }
 
             if (state == END) {
                 **p_cur = '\0';
             }
 
-        (*p_cur)++;
+            (*p_cur)++;
         }
         skipNextComma(p_cur);
     } else {
         ret = strsep(p_cur, ",");
     }
+
 exit:
     return ret;
 }
@@ -148,9 +152,9 @@ static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int  uns)
 
     ret = nextTok(p_cur);
 
-    if (ret == NULL)
+    if (ret == NULL) {
         return -1;
-    else {
+    else {
         long l;
         char *end;
 
@@ -161,8 +165,9 @@ static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int  uns)
 
         *p_out = (int)l;
 
-        if (end == ret)
+        if (end == ret) {
             return -1;
+        }
     }
 
     return 0;
@@ -197,29 +202,34 @@ int at_tok_nextbool(char **p_cur, char *p_out)
 
     ret = at_tok_nextint(p_cur, &result);
 
-    if (ret < 0)
+    if (ret < 0) {
         return -1;
+    }
 
     /* Booleans should be 0 or 1. */
-    if (!(result == 0 || result == 1))
+    if (!(result == 0 || result == 1)) {
         return -1;
+    }
 
-    if (p_out != NULL)
+    if (p_out != NULL) {
         *p_out = (char)result;
-    else
+    } else {
         return -1;
+    }
 
     return ret;
 }
 
 int at_tok_nextstr(char **p_cur, char **p_out)
 {
-    if (*p_cur == NULL)
+    if (*p_cur == NULL) {
         return -1;
+    }
 
     *p_out = nextTok(p_cur);
-    if (*p_out == NULL)
+    if (*p_out == NULL) {
         return -1;
+    }
 
     return 0;
 }
@@ -236,8 +246,9 @@ int at_tok_charcounter(char *p_in, char needle, int *p_out)
     char *p_cur = p_in;
     int num_found = 0;
 
-    if (p_in == NULL)
+    if (p_in == NULL) {
         return -1;
+    }
 
     while (*p_cur != '\0') {
         if (*p_cur == needle) {
index 2382723..1be9af9 100644 (file)
@@ -138,14 +138,12 @@ static int initializeAtContext(void)
     ac = (struct atcontext *)pthread_getspecific(key);
 
     if (ac == NULL) {
-        ac = (struct atcontext *) malloc(sizeof(struct atcontext));
+        ac = (struct atcontext *) calloc(1, sizeof(struct atcontext));
         if (ac == NULL) {
             ALOGE("%s() Failed to allocate memory", __func__);
             goto error;
         }
 
-        memset(ac, 0, sizeof(struct atcontext));
-
         ac->fd = -1;
         ac->readerCmdFds[0] = -1;
         ac->readerCmdFds[1] = -1;
@@ -223,8 +221,8 @@ void  AT_DUMP(const char*  prefix, const char*  buff, int  len)
 
 #ifndef HAVE_ANDROID_OS
 int pthread_cond_timeout_np(pthread_cond_t *cond,
-                            pthread_mutex_t * mutex,
-                            unsigned msecs)
+        pthread_mutex_t * mutex,
+        unsigned msecs)
 {
     struct timespec ts;
     clock_gettime(CLOCK_REALTIME, &ts);
@@ -280,6 +278,7 @@ static const char * s_finalResponsesError[] = {
     "NO CARRIER",      /* Sometimes! */
     "NO ANSWER",
     "NO DIALTONE",
+    "COMMAND NOT SUPPORT",
 };
 
 static int isFinalResponseError(const char *line)
@@ -425,7 +424,7 @@ static void processLine(const char *line)
  *
  * returns NULL if there is no complete line.
  */
-static char * findNextEOL(char *cur)
+static char *findNextEOL(char *cur)
 {
     if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') {
         /* SMS prompt character...not \r terminated */
@@ -458,7 +457,7 @@ static const char *readline(void)
     char *ret = NULL;
 
     struct atcontext *ac = getAtContext();
-    read(ac->fd,NULL,0);
+    read(ac->fd, NULL, 0);
 
     /* This is a little odd. I use *s_ATBufferCur == 0 to mean
      * "buffer consumed completely". If it points to a character,
@@ -473,8 +472,9 @@ static const char *readline(void)
         /* There's data in the buffer from the last read. */
 
         /* skip over leading newlines */
-        while (*ac->ATBufferCur == '\r' || *ac->ATBufferCur == '\n')
+        while (*ac->ATBufferCur == '\r' || *ac->ATBufferCur == '\n') {
             ac->ATBufferCur++;
+        }
 
         p_eol = findNextEOL(ac->ATBufferCur);
 
@@ -540,14 +540,14 @@ static const char *readline(void)
         if (!(pfds[0].revents & POLLIN))
             continue;
 
-        do
+        do {
             /* The size argument should be synchronized to the ditch buffer
              * condition above.
              */
             count = read(ac->fd, p_read,
                          MAX_AT_RESPONSE - (p_read - ac->ATBuffer) - 2);
 
-        while (count < 0 && errno == EINTR);
+        while (count < 0 && errno == EINTR);
 
         if (count > 0) {
             AT_DUMP( "<< ", p_read, count );
@@ -626,7 +626,7 @@ static void *readerLoop(void *arg)
         if (line == NULL)
             break;
 
-        if(isSMSUnsolicited(line)) {
+        if (isSMSUnsolicited(line)) {
             char *line1;
             const char *line2;
 
@@ -645,9 +645,10 @@ static void *readerLoop(void *arg)
                 ac->unsolHandler(line1, line2);
 
             free(line1);
-        } else
+        } else {
             processLine(line);
         }
+    }
 
     onReaderClosed();
     ALOGI("Exiting readerloop!");
@@ -751,21 +752,21 @@ static void clearPendingCommand(void)
     ac->response = NULL;
     ac->responsePrefix = NULL;
     ac->smsPDU = NULL;
-    }
+}
 
 static AT_Error merror(int type, int error)
 {
     switch(type) {
-    case AT_ERROR :
-        return (AT_Error)(AT_ERROR_BASE + error);
-    case CME_ERROR :
-        return (AT_Error)(CME_ERROR_BASE + error);
-    case CMS_ERROR:
-        return (AT_Error)(CMS_ERROR_BASE + error);
-    case GENERIC_ERROR:
-        return (AT_Error)(GENERIC_ERROR_BASE + error);
-    default:
-        return (AT_Error)(GENERIC_ERROR_UNSPECIFIED);
+        case AT_ERROR :
+            return (AT_Error)(AT_ERROR_BASE + error);
+        case CME_ERROR :
+            return (AT_Error)(CME_ERROR_BASE + error);
+        case CMS_ERROR:
+            return (AT_Error)(CMS_ERROR_BASE + error);
+        case GENERIC_ERROR:
+            return (AT_Error)(GENERIC_ERROR_BASE + error);
+        default:
+            return (AT_Error)(GENERIC_ERROR_UNSPECIFIED);
     }
 }
 
@@ -796,7 +797,7 @@ static AT_Error at_get_error(const ATResponse *p_response)
     if (err < 0)
         return merror(GENERIC_ERROR, GENERIC_ERROR_UNSPECIFIED);
 
-    if(strStartsWith(p_response->finalResponse, "+CME ERROR:"))
+    if (strStartsWith(p_response->finalResponse, "+CME ERROR:"))
         return merror(CME_ERROR, ret);
     else if (strStartsWith(p_response->finalResponse, "+CMS ERROR:"))
         return merror(CMS_ERROR, ret);
@@ -902,8 +903,8 @@ void at_response_free(ATResponse *p_response)
         free(p_toFree);
     }
 
-    free (p_response->finalResponse);
-    free (p_response);
+    free(p_response->finalResponse);
+    free(p_response);
 }
 
 /**
@@ -932,11 +933,10 @@ static void reverseIntermediates(ATResponse *p_response)
  * timeoutMsec == 0 means infinite timeout.
  */
 static int at_send_command_full_nolock (const char *command, ATCommandType type,
-                    const char *responsePrefix, const char *smspdu,
-                    long long timeoutMsec, ATResponse **pp_outResponse)
+        const char *responsePrefix, const char *smspdu,
+        long long timeoutMsec, ATResponse **pp_outResponse)
 {
     int err = AT_NOERROR;
-
     struct atcontext *ac = getAtContext();
 
     /* Default to NULL, to allow caller to free securely even if
@@ -962,7 +962,7 @@ static int at_send_command_full_nolock (const char *command, ATCommandType type,
         goto finally;
     }
 
-    err = writeline (command);
+    err = writeline(command);
 
     if (err != AT_NOERROR)
         goto finally;
@@ -977,15 +977,15 @@ static int at_send_command_full_nolock (const char *command, ATCommandType type,
             err = AT_ERROR_TIMEOUT;
             goto finally;
         }
-        }
+    }
 
     if (ac->response->success == 0) {
         err = at_get_error(ac->response);
     }
 
-    if (pp_outResponse == NULL)
+    if (pp_outResponse == NULL) {
         at_response_free(ac->response);
-    else {
+    else {
         /* Line reader stores intermediate responses in reverse order. */
         reverseIntermediates(ac->response);
         *pp_outResponse = ac->response;
@@ -993,7 +993,7 @@ static int at_send_command_full_nolock (const char *command, ATCommandType type,
 
     ac->response = NULL;
 
-    if(ac->readerClosed > 0) {
+    if (ac->readerClosed > 0) {
         err = AT_ERROR_CHANNEL_CLOSED;
         goto finally;
     }
@@ -1013,8 +1013,8 @@ finally:
  * timeoutMsec == 0 means infinite timeout.
  */
 static int at_send_command_full (const char *command, ATCommandType type,
-                    const char *responsePrefix, const char *smspdu,
-                    long long timeoutMsec, ATResponse **pp_outResponse, int useap, va_list ap)
+        const char *responsePrefix, const char *smspdu,
+        long long timeoutMsec, ATResponse **pp_outResponse, int useap, va_list ap)
 {
     int err;
 
@@ -1029,16 +1029,17 @@ static int at_send_command_full (const char *command, ATCommandType type,
     pthread_mutex_lock(&ac->commandmutex);
     if (useap) {
         if (!vsnprintf(strbuf, BUFFSIZE, command, ap)) {
-           pthread_mutex_unlock(&ac->commandmutex);
-           return AT_ERROR_STRING_CREATION;
-    }
+            pthread_mutex_unlock(&ac->commandmutex);
+            return AT_ERROR_STRING_CREATION;
+        }
         ptr = strbuf;
-    } else
+    } else {
         ptr = command;
+    }
 
     err = at_send_command_full_nolock(ptr, type,
-                    responsePrefix, smspdu,
-                    timeoutMsec, pp_outResponse);
+            responsePrefix, smspdu,
+            timeoutMsec, pp_outResponse);
 
     pthread_mutex_unlock(&ac->commandmutex);
 
@@ -1054,9 +1055,9 @@ void at_send_escape (void)
     struct atcontext *ac = getAtContext();
     int written;
 
-    do
+    do {
         written = write (ac->fd, "\033" , 1);
-    while ((written < 0 && errno == EINTR) || (written == 0));
+    while ((written < 0 && errno == EINTR) || (written == 0));
 }
 
 /**
@@ -1102,8 +1103,8 @@ int at_send_command_raw (const char *command, ATResponse **pp_outResponse)
 }
 
 int at_send_command_singleline (const char *command,
-                                const char *responsePrefix,
-                                 ATResponse **pp_outResponse, ...)
+        const char *responsePrefix,
+        ATResponse **pp_outResponse, ...)
 {
     int err;
 
@@ -1111,8 +1112,8 @@ int at_send_command_singleline (const char *command,
     va_list ap;
     va_start(ap, pp_outResponse);
 
-    err = at_send_command_full (command, SINGLELINE, responsePrefix,
-                                    NULL, ac->timeoutMsec, pp_outResponse, 1, ap);
+    err = at_send_command_full(command, SINGLELINE, responsePrefix,
+            NULL, ac->timeoutMsec, pp_outResponse, 1, ap);
 
     if (err == AT_NOERROR && pp_outResponse != NULL
             && (*pp_outResponse) != NULL
@@ -1136,14 +1137,14 @@ int at_send_command_singleline (const char *command,
 }
 
 int at_send_command_numeric (const char *command,
-                                 ATResponse **pp_outResponse)
+        ATResponse **pp_outResponse)
 {
     int err;
 
     struct atcontext *ac = getAtContext();
 
-    err = at_send_command_full (command, NUMERIC, NULL,
-                                NULL, ac->timeoutMsec, pp_outResponse, 0, empty);
+    err = at_send_command_full(command, NUMERIC, NULL,
+            NULL, ac->timeoutMsec, pp_outResponse, 0, empty);
 
     if (err == AT_NOERROR && pp_outResponse != NULL
             && (*pp_outResponse) != NULL
@@ -1166,16 +1167,16 @@ int at_send_command_numeric (const char *command,
 
 
 int at_send_command_sms (const char *command,
-                                const char *pdu,
-                                const char *responsePrefix,
-                                 ATResponse **pp_outResponse)
+        const char *pdu,
+        const char *responsePrefix,
+        ATResponse **pp_outResponse)
 {
     int err;
 
     struct atcontext *ac = getAtContext();
 
-    err = at_send_command_full (command, SINGLELINE, responsePrefix,
-                                    pdu, ac->timeoutMsec, pp_outResponse, 0, empty);
+    err = at_send_command_full(command, SINGLELINE, responsePrefix,
+            pdu, ac->timeoutMsec, pp_outResponse, 0, empty);
 
     if (err == AT_NOERROR && pp_outResponse != NULL
             && (*pp_outResponse) != NULL
@@ -1198,8 +1199,8 @@ int at_send_command_sms (const char *command,
 
 
 int at_send_command_multiline (const char *command,
-                                const char *responsePrefix,
-                                 ATResponse **pp_outResponse, ...)
+        const char *responsePrefix,
+        ATResponse **pp_outResponse, ...)
 {
     int err;
 
@@ -1208,7 +1209,7 @@ int at_send_command_multiline (const char *command,
     va_start(ap, pp_outResponse);
 
     err = at_send_command_full (command, MULTILINE, responsePrefix,
-                                    NULL, ac->timeoutMsec, pp_outResponse, 1, ap);
+            NULL, ac->timeoutMsec, pp_outResponse, 1, ap);
     va_end(ap);
 
     /* Free response in case of error */
@@ -1304,7 +1305,7 @@ AT_Error at_get_at_error(int error)
         return (AT_Error)(error - AT_ERROR_BASE);
     else
         return AT_ERROR_NON_AT;
-    }
+}
 
 AT_CME_Error at_get_cme_error(int error)
 {
@@ -1313,7 +1314,7 @@ AT_CME_Error at_get_cme_error(int error)
         return (AT_CME_Error)(error - CME_ERROR_BASE);
     else
         return CME_ERROR_NON_CME;
-    }
+}
 
 AT_CMS_Error at_get_cms_error(int error)
 {
@@ -1331,7 +1332,7 @@ AT_Generic_Error at_get_generic_error(int error)
         return (AT_Generic_Error)(error - GENERIC_ERROR_BASE);
     else
         return GENERIC_ERROR_NON_GENERIC;
-    }
+}
 
 AT_Error_type at_get_error_type(int error)
 {
@@ -1352,7 +1353,7 @@ AT_Error_type at_get_error_type(int error)
         return GENERIC_ERROR;
 
     return UNKNOWN_ERROR;
-    }
+}
 
 #define quote(x) #x
 
@@ -1361,17 +1362,17 @@ const char *at_str_err(int error)
     const char *s = "--UNKNOWN--";
 
     error = -error;
-    switch(error) {
+    switch (error) {
 #define AT(name, num) case num + AT_ERROR_BASE: s = quote(AT_##name); break;
 #define CME(name, num) case num + CME_ERROR_BASE: s = quote(CME_##name); break;
 #define CMS(name, num) case num + CMS_ERROR_BASE: s = quote(CMS_##name); break;
 #define GENERIC(name, num) case num + GENERIC_ERROR_BASE: s = quote(GENERIC_##name); break;
-    mbm_error
+        mbm_error
 #undef AT
 #undef CME
 #undef CMS
 #undef GENERIC
-}
+    }
 
     return s;
 }
index 135d195..c623e1b 100644 (file)
@@ -99,17 +99,17 @@ void at_set_on_reader_closed(void (*onClose)(void));
 void at_send_escape(void);
 
 int at_send_command_singleline (const char *command,
-                                const char *responsePrefix,
-                                ATResponse **pp_outResponse,
-                                ...);
+        const char *responsePrefix,
+        ATResponse **pp_outResponse,
+        ...);
 
 int at_send_command_numeric (const char *command,
-                                 ATResponse **pp_outResponse);
+        ATResponse **pp_outResponse);
 
 int at_send_command_multiline (const char *command,
-                                const char *responsePrefix,
-                               ATResponse **pp_outResponse,
-                               ...);
+        const char *responsePrefix,
+        ATResponse **pp_outResponse,
+        ...);
 
 
 int at_handshake(void);
@@ -124,8 +124,8 @@ int at_send_command (const char *command, ...);
 int at_send_command_raw (const char *command, ATResponse **pp_outResponse);
 
 int at_send_command_sms (const char *command, const char *pdu,
-                            const char *responsePrefix,
-                            ATResponse **pp_outResponse);
+        const char *responsePrefix,
+        ATResponse **pp_outResponse);
 
 void at_response_free(ATResponse *p_response);
 
index 0211ed0..bffd7b1 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
+#include <sys/epoll.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <linux/socket.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
 #include "audiochannel.h"
 
 #define LOG_NDEBUG 0
 
 // ---- Android sound streaming ----
 
-/* modemAudioOut:
-    Output an audio frame (160 samples) to the 3G audio port of the cell modem
+/* Audio oversampling factor. To use higher sampling rates reduces latency quite a bit ... */
+#define AUDIO_OVERSAMPLING 1
 
-        data = Pointer to audio data to write
+// #define CHECK_MEM_OVERRUN 1
+#define AUDIOCHANNEL_DEBUG 0
+#if AUDIOCHANNEL_DEBUG
+#  define  D(...)   ALOGD(__VA_ARGS__)
+#else
+#  define  D(...)   ((void)0)
+#endif
 
-*/
-static int modemAudioOut(struct GsmAudioTunnel* ctx,const void* data)
+static inline int labs(int x)
 {
-    if (ctx->fd == -1)
-        return 0;
-
-    // Write audio to the 3G modem audio port in 320 bytes chunks... This is
-    //  required by huawei modems...
-
-    // Write audio chunk
-    int res = write(ctx->fd, data, ctx->frame_size * (ctx->bits_per_sample/8));
-    if (res < 0)
-        return -1;
-
-    // Write a 0 length frame to post data
-    res = write(ctx->fd, data, 0);
-    if (res < 0)
-        return -1;
-
-    return 0;
+    return (x < 0) ? -x : x;
 }
 
-/* modemAudioIn:
-    Input an audio frame (160 samples) from the 3G audio port of the cell modem
-
-        data = Pointer to buffer where data must be stored
+/* modemAudioIOThread:
+    Output/inputs an audio frame (160 samples) to the 3G audio port of the cell modem
+    We need to write to be able to read from modem
 */
-static int modemAudioIn(struct GsmAudioTunnel* ctx, void* data)
+static void* modemAudioIOThread(void* data)
 {
+    int            n;
+    int            max_fd;
+    fd_set         input;
+    struct timeval timeout;
+
+    struct GsmAudioTunnel* ctx = (struct GsmAudioTunnel*)data;
     int res = 0;
-    if (ctx->fd == -1)
-        return 0;
+    int bps = (ctx->bits_per_sample/8);
+    int frame_bytes = ctx->frame_size * bps;
+
+    ALOGD("modemAudioIOThread begin");
+
+    // Discard all pending data*/
+    ALOGD("Discarding old data....");
+    tcflush(ctx->fd, TCIOFLUSH);
+    ALOGD("Discarding old data... Done");
+
+    // Get audio from the queue and push it into the modem
+    while (AudioQueue_isrunning(&ctx->rec_q) &&
+            AudioQueue_isrunning(&ctx->play_q)) {
+
+        // Write audio to the 3G modem audio port in 320 bytes chunks... This is
+        //  required by huawei modems...
+        D("[T]Before AudioQueue_get");
+        res = AudioQueue_get(&ctx->rec_q,ctx->play_buf,ctx->frame_size, ctx->timeout);
+        D("[T]After AudioQueue_get: 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x",
+                ((short*)ctx->play_buf)[0],((short*)ctx->play_buf)[1],
+                ((short*)ctx->play_buf)[2],((short*)ctx->play_buf)[3],
+                ((short*)ctx->play_buf)[4]);
+
+#ifdef CHECK_MEM_OVERRUN
+        if (((int*)ctx->rec_buf)[-1] != 0x1A3B5C7D) {
+            ALOGE("recbuf: Corruption at start: 0x%08x",((int*)ctx->rec_buf)[-1]);
+        }
+        if (((int*)ctx->rec_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING * (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+            ALOGE("recbuf: Corruption at end: 0x%08x",((int*)ctx->rec_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+        }
+        if (((int*)ctx->play_buf)[-1] != 0x1A3B5C7D) {
+            ALOGE("playbuf: Corruption at start: 0x%08x",((int*)ctx->play_buf)[-1]);
+        }
+        if (((int*)ctx->play_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+            ALOGE("playbuf: Corruption at end: 0x%08x",((int*)ctx->play_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+        }
+#endif
+
+        if (!AudioQueue_isrunning(&ctx->rec_q) ||
+                !AudioQueue_isrunning(&ctx->play_q))
+            break;
 
+        /* Fill missing samples with silence, if needed */
+        if ((int)ctx->frame_size > res) {
+            memset((char*)ctx->play_buf + res * bps, 0, (ctx->frame_size - res) * bps);
+        }
+
+#ifdef CHECK_MEM_OVERRUN
+        if (((int*)ctx->rec_buf)[-1] != 0x1A3B5C7D) {
+            ALOGE("recbuf: Corruption at start: 0x%08x",((int*)ctx->rec_buf)[-1]);
+        }
+        if (((int*)ctx->rec_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+            ALOGE("recbuf: Corruption at end: 0x%08x",((int*)ctx->rec_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+        }
+        if (((int*)ctx->play_buf)[-1] != 0x1A3B5C7D) {
+            ALOGE("playbuf: Corruption at start: 0x%08x",((int*)ctx->play_buf)[-1]);
+        }
+        if (((int*)ctx->play_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+            ALOGE("playbuf: Corruption at end: 0x%08x",((int*)ctx->play_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+        }
+#endif
 
-    while (1) {
-        res = read(ctx->fd, data, ctx->frame_size * (ctx->bits_per_sample/8));
-        if (res == -1) {
+        // Write audio chunk
+        D("[T]Before write");
+        res = write(ctx->fd, ctx->play_buf, frame_bytes);
+        D("[T]After write: res: %d",res);
 
-            if (errno != EAGAIN && errno != EINTR) {
-                // A real error, not something that trying again will fix
-                break;
-            }
-        } else {
+        if (!AudioQueue_isrunning(&ctx->rec_q) ||
+                !AudioQueue_isrunning(&ctx->play_q) ||
+                res < 0)
             break;
-        }
-    }
 
-    /* Failure means 0 bytes */
-    if (res < 0)
-        res = 0;
+        // Read data from the modem
+        D("[T]Before Select");
 
-    /* If some samples missing, complete them with silence */
-    if (res < (int) (ctx->frame_size * (ctx->bits_per_sample/8) )) {
+        do {
+            // Initialize the input set
+            FD_ZERO(&input);
+            FD_SET(ctx->fd, &input);
+            max_fd = ctx->fd + 1;
 
-        /* Output silence */
-        memset( (char*)data + res, 0, (ctx->frame_size * (ctx->bits_per_sample/8) - res));
-    }
+            // Initialize the timeout structure: 40ms is enough for this waiting
+            timeout.tv_sec  = 0;
+            timeout.tv_usec = 40000;
 
-    return 0;
-}
+            // Do the select
+            n = select(max_fd, &input, NULL, NULL, &timeout);
 
-static void AndroidRecorderCallback(int event, void* userData, void* info)
-{
-    struct GsmAudioTunnel *ctx = (struct GsmAudioTunnel*) userData;
-    android::AudioRecord::Buffer* uinfo = (android::AudioRecord::Buffer*) info;
-    unsigned nsamples;
-    void *input;
+        } while (n == 0 &&
+                AudioQueue_isrunning(&ctx->rec_q) &&
+                AudioQueue_isrunning(&ctx->play_q));
 
-    if(!ctx || !uinfo)
-        return;
+        D("[T]After Select");
 
-    if (ctx->quit_flag)
-        goto on_break;
+        /* See if there was an error */
+        if (!AudioQueue_isrunning(&ctx->rec_q) ||
+                !AudioQueue_isrunning(&ctx->play_q) ||
+                n < 0)
+            break;
 
-    input = (void *) uinfo->raw;
+        /* If something to read, read it */
+        if (FD_ISSET(ctx->fd, &input)) {
+            D("[T]Before read");
+            res = read(ctx->fd, ctx->rec_buf, frame_bytes);
+            D("[T]After read: res: %d",res);
 
-    // Calculate number of total samples we've got
-    nsamples = uinfo->frameCount + ctx->rec_buf_count;
+            if (!AudioQueue_isrunning(&ctx->play_q) ||
+                !AudioQueue_isrunning(&ctx->rec_q) ||
+                 res < 0)
+                break;
 
-    if (nsamples >= ctx->frame_size) {
+#ifdef CHECK_MEM_OVERRUN
+            if (((int*)ctx->rec_buf)[-1] != 0x1A3B5C7D) {
+                ALOGE("recbuf: Corruption at start: 0x%08x",((int*)ctx->rec_buf)[-1]);
+            }
+            if (((int*)ctx->rec_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+                ALOGE("recbuf: Corruption at end: 0x%08x",((int*)ctx->rec_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+            }
+            if (((int*)ctx->play_buf)[-1] != 0x1A3B5C7D) {
+                ALOGE("playbuf: Corruption at start: 0x%08x",((int*)ctx->play_buf)[-1]);
+            }
+            if (((int*)ctx->play_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+                ALOGE("playbuf: Corruption at end: 0x%08x",((int*)ctx->play_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+            }
+#endif
 
-        /* If buffer is not empty, combine the buffer with the just incoming
-         * samples, then call put_frame.
-         */
-        if (ctx->rec_buf_count) {
+            // If muted, silence audio
+            if (ctx->ismuted) {
+                memset( ctx->rec_buf, 0, frame_bytes);
+            }
 
-            unsigned chunk_count = ctx->frame_size - ctx->rec_buf_count;
-            memcpy( (char*)ctx->rec_buf + ctx->rec_buf_count * (ctx->bits_per_sample/8), input, chunk_count * (ctx->bits_per_sample/8));
+#ifdef CHECK_MEM_OVERRUN
+            if (((int*)ctx->rec_buf)[-1] != 0x1A3B5C7D) {
+                ALOGE("recbuf: Corruption at start: 0x%08x",((int*)ctx->rec_buf)[-1]);
+            }
+            if (((int*)ctx->rec_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+                ALOGE("recbuf: Corruption at end: 0x%08x",((int*)ctx->rec_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+            }
+            if (((int*)ctx->play_buf)[-1] != 0x1A3B5C7D) {
+                ALOGE("playbuf: Corruption at start: 0x%08x",((int*)ctx->play_buf)[-1]);
+            }
+            if (((int*)ctx->play_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+                ALOGE("playbuf: Corruption at end: 0x%08x",((int*)ctx->play_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+            }
+#endif
+
+            // EM770W firmware corrupts received audio... Try to workaround the damage...
+
+            // 1st Pass: If received less data than requested, this means voice data corruption.
+            // More frequent than you could think. We must compensate it, or we end with garbled
+            // voice...
+            if (res < frame_bytes) {
+                int p;
+                signed char* b;
+                int tf;
+
+
+                // Try to reconstruct data . Determine variance of low and high nibbles.
+                b = (signed char*)ctx->rec_buf;
+                tf = frame_bytes - res;
+                for (p = 0; p < 317 && tf!=0; p+=2) {
+                    if (labs(b[p+2] - b[p]) < labs(b[p+1] - b[p+3]) ) {
+                        /* Probably, this is the point ... Insert an space */
+                        memmove(b+p+1,b+p,320-p-1);
+                        tf--;
+                        p+=2;
+                    }
+                }
+            }
 
-            /* Send the audio to the modem */
-            modemAudioOut(ctx, ctx->rec_buf);
+            /* 2nd pass: Detect endianness inversions and correct them */
+            {
+                signed short* d = (signed short*)ctx->rec_buf;
+                signed short ss, sp = 0, s = d[2]; // Handle first sample by reflection
+                int todo = 160;
+
+                while (todo--) {
+                    sp = s;     /* keep previous sample */
+                    s  = *d++;  /* Calculate the other possible samples */
+                    ss = (((unsigned short)s) << 8U) | ((((unsigned short)s) >> 8U) & 0xFFU);
+
+                    /* Choose the one that creates less volume difference */
+                    if (labs(sp - ss  ) < labs(sp - s ) ) {
+                        /* Inverted is closer to original. Keep inverted */
+                        s = ss;
+                        d[-1] = s;
+                    }
+                }
+            }
 
-            input = (char*) input + chunk_count * (ctx->bits_per_sample/8);
-            nsamples -= ctx->frame_size;
-            ctx->rec_buf_count = 0;
+            /* 3rd pass: Remove clicks - we use a 3 sample window to predict and correct 1-sample clicks...*/
+            {
+                signed short* d = (signed short*)ctx->rec_buf;
+                signed short spp = 0, sp = *d++, s = *d++;
+                signed short p;
+                int todo = 158;
+
+                while (todo--) {
+                    /* Store previous and get new sample */
+                    spp = sp;
+                    sp = s;
+                    s  = *d++;
+
+                    /* Estimate medium */
+                    p = (s + spp) / 2;
+
+                    /* If predicted is very different from real, assume noise and replace it */
+                    if ( labs( sp - p ) > labs(p >> 2) ) {
+                        sp = p;
+                        d[-2] = sp;
+                    }
+                }
+            }
+
+            /* 4th pass: Remove 6 Sample clicks... The modem also sometimes creates them. Detect and remove them if possible */
+            {
+                signed short* d = (signed short*)ctx->rec_buf;
+                signed short sp = 0, s = *d++;
+                signed short p;
+                int todo = 154;
+
+                while (todo--) {
+                    /* Store previous and get new sample */
+                    sp = s;
+                    s  = *d++;
+
+                    /* If a 4 times jump in value is detected, and 6 samples later we are on track, assume it is a modem generated
+                       click and remove it - We prefer to remove in excess here*/
+                    if (labs(s) > labs(sp  )*4 &&
+                            labs(s) > labs(d[6])*4 ) {
+
+                        /* Detected an undesired click, remove it! */
+                        int step = ((d[6] - sp) << (16 - 3));
+                        int x = sp << 16;
+                        x+= step;
+                        s = d[-1] = x >> 16;
+                        x+= step;
+                        d[ 0] = x >> 16;
+                        x+= step;
+                        d[ 1] = x >> 16;
+                        x+= step;
+                        d[ 2] = x >> 16;
+                        x+= step;
+                        d[ 3] = x >> 16;
+                        x+= step;
+                        d[ 4] = x >> 16;
+                        x+= step;
+                        d[ 5] = x >> 16;
+                    }
+                }
+            }
+
+#if LOG_MODEM_AUDIO
+            /* Log audio into SD */
+            write(ctx->logfd, ctx->rec_buf, frame_bytes);
+#endif
+
+            // Write it to the audio queue
+            D("[T]Before AudioQueue_add: %04x %04x %04x %04x %04x",
+                    ((short*)ctx->rec_buf)[0] & 0xFFFF,
+                    ((short*)ctx->rec_buf)[1] & 0xFFFF,
+                    ((short*)ctx->rec_buf)[2] & 0xFFFF,
+                    ((short*)ctx->rec_buf)[3] & 0xFFFF,
+                    ((short*)ctx->rec_buf)[4] & 0xFFFF);
+            AudioQueue_add(&ctx->play_q, ctx->rec_buf, ctx->frame_size);
+            D("[T]After AudioQueue_add");
+
+#ifdef CHECK_MEM_OVERRUN
+            if (((int*)ctx->rec_buf)[-1] != 0x1A3B5C7D) {
+                ALOGE("recbuf: Corruption at start: 0x%08x",((int*)ctx->rec_buf)[-1]);
+            }
+            if (((int*)ctx->rec_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+                ALOGE("recbuf: Corruption at end: 0x%08x",((int*)ctx->rec_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+            }
+            if (((int*)ctx->play_buf)[-1] != 0x1A3B5C7D) {
+                ALOGE("playbuf: Corruption at start: 0x%08x",((int*)ctx->play_buf)[-1]);
+            }
+            if (((int*)ctx->play_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING *  (ctx->bits_per_sample/8))>>2] != 0xD7C5B3A1) {
+                ALOGE("playbuf: Corruption at end: 0x%08x",((int*)ctx->play_buf)[(ctx->frame_size * (ctx->bits_per_sample/8))>>2]);
+            }
+#endif
         }
 
-        // Give all frames we have
-        while (nsamples >= ctx->frame_size) {
+    };
 
-            /* Send the audio to the modem */
-            modemAudioOut(ctx, input);
+    ALOGD("modemAudioIOThread ended");
+    return NULL;
+}
 
-            input = (char*) input + ctx->frame_size * (ctx->bits_per_sample/8);
-            nsamples -= ctx->frame_size;
-        }
+/* Called with audio sampled from mic */
+static void AndroidRecorderCallback(int event, void* userData, void* info)
+{
+    struct GsmAudioTunnel *ctx = (struct GsmAudioTunnel*) userData;
+    android::AudioRecord::Buffer *uinfo = (android::AudioRecord::Buffer*) info;
+    int bps, frames;
+
+    if (!ctx || !uinfo || event != android::AudioRecord::EVENT_MORE_DATA)
+        return;
+
+    if (!AudioQueue_isrunning(&ctx->rec_q))
+        goto on_break;
 
-        // Store the remaining samples into the buffer
-        if (nsamples) {
-            ctx->rec_buf_count = nsamples;
-            memcpy(ctx->rec_buf, input, nsamples * (ctx->bits_per_sample/8));
+    /* Bytes per sample */
+    bps = ctx->bits_per_sample/8;
+
+    /* Calculate total frames */
+    frames = uinfo->size / bps;
+
+#if AUDIO_OVERSAMPLING > 1
+    /* Subsample */
+    {
+        short *src = (short *)uinfo->raw + frames - 1;
+        short *dst = (short *)uinfo->raw + frames - 1;
+        int p;
+        short v = *src++,vold = 0;
+        for (p = 0; p < ctx->frame_size-1; p++) {
+            int x,d,s;
+
+            // Current and target values
+            vold = v;
+            v = *src++;
+
+            // Calculate delta and start value
+            d = (v - vold) * (65536 / AUDIO_OVERSAMPLING);
+            s =  vold << 16;
+
+            // Interpolate values (linear interpolation)
+            for (x = 0; x < AUDIO_OVERSAMPLING; x++) {
+                *dst++ = s >> 16;
+                s += d;
+            }
         }
 
-    } else {
-        // Not enough samples, let's just store them in the buffer
-        memcpy((char*)ctx->rec_buf + ctx->rec_buf_count * (ctx->bits_per_sample/8), input, uinfo->frameCount * (ctx->bits_per_sample/8));
-        ctx->rec_buf_count += uinfo->frameCount;
+        // Last sample can't be interpolated...
+        for (x = 0; x < AUDIO_OVERSAMPLING; x++) {
+            *dst++ = v;
+        }
     }
+#endif
 
+    // Post data into the recording queue. Queue should self adapt and adjust sampling rate
+    D("[A]Before AudioQueue_add");
+    uinfo->size = AudioQueue_add(&ctx->rec_q, uinfo->raw, frames) * bps;
+    D("[A]After AudioQueue_add");
     return;
 
 on_break:
-    ALOGD("Record thread stopped");
-    ctx->rec_thread_exited = 1;
+    if (!ctx->rec_thread_exited) {
+        ALOGD("Record thread stopped");
+        ctx->rec_thread_exited = 1;
+    }
     return;
 }
 
+/* Called to get audio samples to playback */
 static void AndroidPlayerCallback( int event, void* userData, void* info)
 {
-    unsigned nsamples_req;
-    void *output;
     struct GsmAudioTunnel *ctx = (struct GsmAudioTunnel*) userData;
     android::AudioTrack::Buffer* uinfo = (android::AudioTrack::Buffer*) info;
+    int bps,frames;
 
-    if (!ctx || !uinfo)
+    if (!ctx || !uinfo || event != android::AudioTrack::EVENT_MORE_DATA)
         return;
 
-    if (ctx->quit_flag)
+    if (!AudioQueue_isrunning(&ctx->play_q))
         goto on_break;
 
-    nsamples_req = uinfo->frameCount;
-    output = (void*) uinfo->raw;
-
-    // Check if any buffered samples
-    if (ctx->play_buf_count) {
-
-        // samples buffered >= requested by sound device
-        if (ctx->play_buf_count >= nsamples_req) {
-
-            memcpy(output, ctx->play_buf, nsamples_req * (ctx->bits_per_sample/8));
-            ctx->play_buf_count -= nsamples_req;
-
-            memmove(ctx->play_buf,
-                (char*)ctx->play_buf + nsamples_req * (ctx->bits_per_sample/8), ctx->play_buf_count * (ctx->bits_per_sample/8));
-            nsamples_req = 0;
-            return;
+    // Read data from the Playback audioqueue
+    D("[A]Before AudioQueue_get");
+    bps = ctx->bits_per_sample/8;
+    uinfo->size = (frames = AudioQueue_get(&ctx->play_q, uinfo->raw, uinfo->size / bps, ctx->timeout)) * bps;
+    D("[A]After AudioQueue_get");
+
+#if AUDIO_OVERSAMPLING > 1
+    /* Oversample to send them to the Android playback channel*/
+    if (frames) {
+        short *src = uinfo->raw;
+        short *dst = uinfo->raw;
+        int p;
+        short v = *src++,vold = 0;
+        for (p = 0; p < frames-1; p++) {
+            int x,d,s;
+
+            // Current and target values
+            vold = v;
+            v = *src++;
+
+            // Calculate delta and start value
+            d = (v - vold) * (65536 / AUDIO_OVERSAMPLING);
+            s =  vold << 16;
+
+            // Interpolate values (linear interpolation)
+            for (x = 0; x < AUDIO_OVERSAMPLING; x++) {
+                *dst++ = s >> 16;
+                s += d;
+            }
         }
 
-        // samples buffered < requested by sound device
-        memcpy(output, ctx->play_buf,
-                        ctx->play_buf_count * (ctx->bits_per_sample/8));
-        nsamples_req -= ctx->play_buf_count;
-        output = (char*)output + ctx->play_buf_count * (ctx->bits_per_sample/8);
-        ctx->play_buf_count = 0;
-    }
-
-    // Fill output buffer as requested in chunks
-    while (nsamples_req) {
-        if (nsamples_req >= ctx->frame_size) {
-
-            /* get a frame from the modem */
-            modemAudioIn(ctx, output);
-
-            nsamples_req -= ctx->frame_size;
-            output = (char*)output + ctx->frame_size * (ctx->bits_per_sample/8);
-
-        } else {
-
-            /* get a frame from the modem */
-            modemAudioIn(ctx, ctx->play_buf);
-
-            memcpy(output, ctx->play_buf,
-                            nsamples_req * (ctx->bits_per_sample/8));
-            ctx->play_buf_count = ctx->frame_size - nsamples_req;
-            memmove(ctx->play_buf,
-                            (char*)ctx->play_buf + nsamples_req * (ctx->bits_per_sample/8),
-                            ctx->play_buf_count * (ctx->bits_per_sample/8));
-            nsamples_req = 0;
+        // Last sample can't be interpolated...
+        for (x = 0; x < AUDIO_OVERSAMPLING; x++) {
+            *dst++ = v;
         }
     }
+#endif
 
     return;
 
 on_break:
-    ALOGD("Play thread stopped");
-    ctx->play_thread_exited = 1;
+    if (!ctx->play_thread_exited) {
+        ALOGD("Play thread stopped");
+        ctx->play_thread_exited = 1;
+    }
+
+    /* Silence output if we are not running */
+    memset(uinfo->raw, 0, uinfo->size);
     return;
 }
 
  //AT^DDSETEX=2
 
-int gsm_audio_tunnel_start(struct GsmAudioTunnel *ctx,const char* gsmvoicechannel,unsigned int sampling_rate,unsigned int frame_size,unsigned int bits_per_sample)
+int gsm_audio_tunnel_start(struct GsmAudioTunnel *ctx, const char *gsmvoicechannel, unsigned int sampling_rate, unsigned int frame_size, unsigned int bits_per_sample)
 {
+    pthread_attr_t modem_attr;
     struct termios newtio;
-    int format = (bits_per_sample > 8)
-        ? AUDIO_FORMAT_PCM_16_BIT
-        : AUDIO_FORMAT_PCM_8_BIT;
+    int create_result = 0;
+    size_t playBuffSize = 0;
+    size_t playNotifyBuffSize = 0;
+    size_t recBuffSize = 0;
+    size_t recNotifyBuffSize = 0;
+    int play_qsize;
+    int rec_qsize;
+
+    audio_format_t format = (bits_per_sample > 8)
+            ? AUDIO_FORMAT_PCM_16_BIT
+            : AUDIO_FORMAT_PCM_8_BIT;
 
     /* If already running, dont do it again */
-    if (ctx->running)
+    if (AudioQueue_isrunning(&ctx->rec_q) ||
+            AudioQueue_isrunning(&ctx->play_q))
         return 0;
 
     memset(ctx,0,sizeof(struct GsmAudioTunnel));
+    ctx->fd = -1;
 
     ctx->sampling_rate = sampling_rate;
     ctx->frame_size = frame_size;
     ctx->bits_per_sample = bits_per_sample;
+    ctx->timeout = 1000 * frame_size / sampling_rate;
 
     ALOGD("Opening GSM voice channel '%s', sampling_rate:%u hz, frame_size:%u, bits_per_sample:%u  ...",
-        gsmvoicechannel,sampling_rate,frame_size,bits_per_sample);
+            gsmvoicechannel,sampling_rate,frame_size,bits_per_sample);
 
-    // Open the device(com port) to be non-blocking (read will return immediately)
-    ctx->fd = open(gsmvoicechannel, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
+#if LOG_MODEM_AUDIO
+    ctx->logfd = open("/sdcard/modemlog", O_RDWR);
+#endif
+
+    // Compute buffer sizes for record and playback
+#if 0
+    playBuffSize = 0;
+    android::AudioSystem::getInputBufferSize(
+                    ctx->sampling_rate * AUDIO_OVERSAMPLING, // Samples per second
+                    format,
+                    AUDIO_CHANNEL_IN_MONO,
+                    &playBuffSize);
+    recBuffSize = playBuffSize;
+#else
+    android::AudioRecord::getMinFrameCount((int*)&recBuffSize,
+            ctx->sampling_rate * AUDIO_OVERSAMPLING, // Samples per second
+            format,
+            1);
+
+    //android::AudioSystem::getInputBufferSize(
+    //                ctx->sampling_rate, // Samples per second
+    //                format,
+    //                AUDIO_CHANNEL_IN_MONO,
+    //                &recBuffSize);
+    //recBuffSize   <<= 1; // Convert to bytes
+    //recBuffSize <<= 1; // Convert to bytes
+    //while (recBuffSize < frame_size)  recBuffSize <<= 1;
+    //while (playBuffSize < frame_size) playBuffSize <<= 1;
+
+    android::AudioTrack::getMinFrameCount((int*)&playBuffSize,
+            AUDIO_STREAM_VOICE_CALL,
+            ctx->sampling_rate * AUDIO_OVERSAMPLING); // Samples per second
+
+    // Do not accept less than the frame size ... Makes no point going lower than that
+    if (playBuffSize < frame_size)
+        playBuffSize = frame_size;
+    if (recBuffSize < frame_size)
+        recBuffSize = frame_size;
+
+    // Compute minimum playback queue size as a power of 2
+    play_qsize = 0;
+    while ((1 << play_qsize) < playBuffSize) play_qsize++;
+    play_qsize += 2; // And quad it
+
+    // Compute minimum record queue size as a power of 2
+    rec_qsize = 0;
+    while ((1 << rec_qsize) < recBuffSize) rec_qsize++;
+    rec_qsize += 2; // And quad it
+
+#endif
+
+    // We use 2 * size of input/output buffer for ping pong use of record/playback buffers.
+    playNotifyBuffSize = playBuffSize;
+    playBuffSize <<= 1;
+    recNotifyBuffSize = recBuffSize;
+    recBuffSize <<= 1;
+    ALOGD("play samples: %d [q:%d], record samples: %d [q:%d]",
+            playNotifyBuffSize, play_qsize, recNotifyBuffSize, rec_qsize);
+
+    // Init the audioqueues
+    if (AudioQueue_init(&ctx->play_q,play_qsize,bits_per_sample>>3) < 0) {
+        ALOGE("Could not init Playback AudioQueue");
+        goto error;
+    }
+    if (AudioQueue_init(&ctx->rec_q,rec_qsize,bits_per_sample>>3) < 0) {
+        ALOGE("Could not init Record AudioQueue");
+        goto error;
+    }
+
+    ALOGD("Opening voice channel....");
+
+/*  if (echocancel_init(&ctx->echo, recNotifyBuffSize ) < 0) {
+        ALOGE("Could not init Record AudioQueue");
+        goto error;
+    }
+*/
+    // Open the device(com port) in blocking mode
+    ctx->fd = open(gsmvoicechannel, O_RDWR | O_NOCTTY);
     if (ctx->fd < 0) {
         ALOGE("Could not open '%s'",gsmvoicechannel);
-        return -1;
+        goto error;
     }
 
     // Configure it to get data as raw as possible
@@ -278,122 +619,108 @@ int gsm_audio_tunnel_start(struct GsmAudioTunnel *ctx,const char* gsmvoicechanne
     newtio.c_iflag = IGNPAR | IGNBRK | IGNCR | IXOFF;
     newtio.c_oflag = 0;
     newtio.c_lflag = 0;
-    newtio.c_cc[VMIN]=0;
-    newtio.c_cc[VTIME]=5;   // You may want to tweak this; 5 = 1/2 second, 10 = 1 second
+    newtio.c_cc[VMIN]=1;
+    newtio.c_cc[VTIME]=1;
     tcsetattr(ctx->fd,TCSANOW, &newtio);
 
     ALOGD("Creating streams....");
-    ctx->rec_buf = malloc(ctx->frame_size * (ctx->bits_per_sample/8));
+#ifdef CHECK_MEM_OVERRUN
+    ctx->rec_buf = malloc(8 + ctx->frame_size * (ctx->bits_per_sample/8) * AUDIO_OVERSAMPLING);
     if (!ctx->rec_buf) {
-        close(ctx->fd);
-        return -1;
+        ALOGE("Failed to allocate buffer for playback");
+        goto error;
     }
 
-    ctx->play_buf = malloc(ctx->frame_size * (ctx->bits_per_sample/8));
+    ctx->play_buf = malloc(8 + ctx->frame_size * (ctx->bits_per_sample/8) * AUDIO_OVERSAMPLING);
     if (!ctx->play_buf) {
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
+        ALOGE("Failed to allocate buffer for record");
+        goto error;
     }
 
-    // Compute buffer size
-    size_t inputBuffSize = 0;
-    android::AudioSystem::getInputBufferSize(
-                    ctx->sampling_rate, // Samples per second
-                    format,
-                    AUDIO_CHANNEL_IN_MONO,
-                    &inputBuffSize);
+    ctx->rec_buf = (int*)ctx->rec_buf + 1;
+    ((int*)ctx->rec_buf)[-1] = 0x1A3B5C7D;
+    ((int*)ctx->rec_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING * (ctx->bits_per_sample/8))>>2] = 0xD7C5B3A1;
+    ctx->play_buf = (int*)ctx->play_buf + 1;
+    ((int*)ctx->play_buf)[-1] = 0x1A3B5C7D;
+    ((int*)ctx->play_buf)[(ctx->frame_size * AUDIO_OVERSAMPLING * (ctx->bits_per_sample/8))>>2] = 0xD7C5B3A1;
 
-    // We use 2* size of input buffer for ping pong use of record buffer.
-    inputBuffSize = 2 * inputBuffSize;
+#else
+    ctx->rec_buf = malloc(ctx->frame_size * (ctx->bits_per_sample/8) * AUDIO_OVERSAMPLING);
+    if (!ctx->rec_buf) {
+        ALOGE("Failed to allocate buffer for playback");
+        goto error;
+    }
+
+    ctx->play_buf = malloc(ctx->frame_size * (ctx->bits_per_sample/8) * AUDIO_OVERSAMPLING);
+    if (!ctx->play_buf) {
+        ALOGE("Failed to allocate buffer for record");
+        goto error;
+    }
+#endif
 
     // Create audio record channel
     ctx->rec_strm = new android::AudioRecord();
     if(!ctx->rec_strm) {
         ALOGE("fail to create audio record");
-        free(ctx->play_buf);
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
+        goto error;
+    }
+
+    // Create audio playback channel
+    ctx->play_strm = new android::AudioTrack();
+    if(!ctx->play_strm) {
+        ALOGE("Failed to create AudioTrack");
+        goto error;
     }
 
     // Unmute microphone
     // android::AudioSystem::muteMicrophone(false);
-    int create_result = ((android::AudioRecord*)ctx->rec_strm)->set(
-                    AUDIO_SOURCE_MIC,
-                    ctx->sampling_rate,
-                    format,
-                    AUDIO_CHANNEL_IN_MONO,
-                    inputBuffSize,
-                    0,                  //flags
-                    &AndroidRecorderCallback,
-                    (void *) ctx,
-                    (inputBuffSize / 2), // Notification frames
-                    false,
-                    0);
+    create_result = ((android::AudioRecord*)ctx->rec_strm)->set(
+            AUDIO_SOURCE_MIC,
+            ctx->sampling_rate * AUDIO_OVERSAMPLING,
+            format,
+            AUDIO_CHANNEL_IN_MONO,
+            recBuffSize,
+            &AndroidRecorderCallback,
+            (void *) ctx,
+            recNotifyBuffSize, // Notification frames
+            false,
+            0);
 
     if(create_result != android::NO_ERROR){
         ALOGE("fail to check audio record : error code %d", create_result);
-        delete ((android::AudioRecord*)ctx->rec_strm);
-        free(ctx->play_buf);
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
+        goto error;
     }
 
     if(((android::AudioRecord*)ctx->rec_strm)->initCheck() != android::NO_ERROR) {
-        ALOGE("fail to check audio record : buffer size is : %d, error code : %d", inputBuffSize, ((android::AudioRecord*)ctx->rec_strm)->initCheck() );
-        delete ((android::AudioRecord*)ctx->rec_strm);
-        free(ctx->play_buf);
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
-    }
-
-    // Create audio playback channel
-    ctx->play_strm = new android::AudioTrack();
-    if(!ctx->play_strm) {
-        ALOGE("Failed to create AudioTrack");
-        delete ((android::AudioRecord*)ctx->rec_strm);
-        free(ctx->play_buf);
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
+        ALOGE("fail to check audio record : buffer size is : %d, error code : %d",
+                recBuffSize, ((android::AudioRecord*)ctx->rec_strm)->initCheck());
+        goto error;
     }
 
     // android::AudioSystem::setMasterMute(false);
     create_result = ((android::AudioTrack*)ctx->play_strm)->set(
-                    AUDIO_STREAM_VOICE_CALL,
-                    ctx->sampling_rate, //this is sample rate in Hz (16000 Hz for example)
-                    format,
-                    AUDIO_CHANNEL_OUT_MONO, //For now this is mono (we expect 1)
-                    inputBuffSize,
-                    0, //flags
-                    &AndroidPlayerCallback,
-                    (void *) ctx,
-                    (inputBuffSize / 2),
-                    0,
-                    false,
-                    0);
-
-    if(create_result != android::NO_ERROR){
+            AUDIO_STREAM_VOICE_CALL,
+            ctx->sampling_rate * AUDIO_OVERSAMPLING, //this is sample rate in Hz (16000 Hz for example)
+            format,
+            AUDIO_CHANNEL_OUT_MONO, //For now this is mono (we expect 1)
+            playBuffSize,
+            AUDIO_OUTPUT_FLAG_NONE, //flags
+            &AndroidPlayerCallback,
+            (void *) ctx,
+            playNotifyBuffSize,
+            0,
+            false,
+            0);
+
+    if (create_result != android::NO_ERROR){
         ALOGE("fail to check audio record : error code %d", create_result);
-        delete ((android::AudioTrack*)ctx->play_strm);
-        delete ((android::AudioRecord*)ctx->rec_strm);
-        free(ctx->play_buf);
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
+        goto error;
     }
 
     if(((android::AudioTrack*)ctx->play_strm)->initCheck() != android::NO_ERROR) {
-        ALOGE("fail to check audio playback : buffer size is : %d, error code : %d", inputBuffSize, ((android::AudioTrack*)ctx->play_strm)->initCheck() );
-        delete ((android::AudioTrack*)ctx->play_strm);
-        delete ((android::AudioRecord*)ctx->rec_strm);
-        free(ctx->play_buf);
-        free(ctx->rec_buf);
-        close(ctx->fd);
-        return -1;
+        ALOGE("fail to check audio playback : buffer size is : %d, error code : %d",
+                playBuffSize, ((android::AudioTrack*)ctx->play_strm)->initCheck());
+        goto error;
     }
 
     /* Save the current audio routing setting, then switch it to earpiece. */
@@ -413,44 +740,85 @@ int gsm_audio_tunnel_start(struct GsmAudioTunnel *ctx,const char* gsmvoicechanne
         ((android::AudioRecord*)ctx->rec_strm)->start();
     }
 
-    ALOGD("Done");
+    // Create the playback thread
+    pthread_attr_init(&modem_attr);
+    if (pthread_create(&ctx->modem_t,&modem_attr,modemAudioIOThread,ctx) < 0) {
+        ALOGE("Failed to start modemAudioIO Thread");
+error:
+        AudioQueue_end(&ctx->rec_q);
+        AudioQueue_end(&ctx->play_q);
+        if (ctx->play_strm) delete ((android::AudioTrack*)ctx->play_strm);
+        if (ctx->rec_strm) delete ((android::AudioRecord*)ctx->rec_strm);
+#ifdef CHECK_MEM_OVERRUN
+        if (ctx->play_buf) free(((int*)ctx->play_buf)-1);
+        if (ctx->rec_buf) free(((int*)ctx->rec_buf)-1);
+#else
+        if (ctx->play_buf) free(ctx->play_buf);
+        if (ctx->rec_buf) free(ctx->rec_buf);
+#endif
+        if (ctx->fd) close(ctx->fd);
+#if LOG_MODEM_AUDIO
+        if (ctx->logfd) close(ctx->logfd);
+#endif
 
-    ctx->running = 1;
+        return -1;
+    }
+
+    ALOGD("Done");
 
     // OK, done
     return 0;
 }
 
+/* API: mute audio record channel */
+int gsm_audio_tunnel_mute(struct GsmAudioTunnel *ctx, int muteit)
+{
+    ctx->ismuted = muteit;
+    return 0;
+}
+
+/* API: query if tunnel is running */
+int gsm_audio_tunnel_running(struct GsmAudioTunnel *ctx)
+{
+    if (AudioQueue_isrunning(&ctx->rec_q) ||
+            AudioQueue_isrunning(&ctx->play_q))
+        return 1;
+    return 0;
+}
+
 /* API: destroy ctx. */
 int gsm_audio_tunnel_stop(struct GsmAudioTunnel *ctx)
 {
-    int i = 0;
+    int i;
 
     /* If not running, dont do it again */
-    if (!ctx->running)
+    if (!AudioQueue_isrunning(&ctx->rec_q) ||
+            !AudioQueue_isrunning(&ctx->play_q))
         return 0;
 
+    ALOGD("Signal all audio threads to stop");
+    AudioQueue_end(&ctx->play_q);
+    AudioQueue_end(&ctx->rec_q);
 
-    ALOGD("Will Stop ctx, wait for all audio callback clean");
-    ctx->quit_flag = 1;
-    for (i=0; !ctx->rec_thread_exited && i<100; ++i){
-        usleep(100000);
-    }
-    for (i=0; !ctx->play_thread_exited && i<100; ++i){
+    // Wait until android audio threads are "idling"
+    for (i=0; (!ctx->rec_thread_exited || !ctx->play_thread_exited) && i<100; ++i) {
         usleep(100000);
     }
+    // After all sleep for 0.2 seconds since android device can be slow
+    usleep(200000);
+    ALOGD("Android audio threads are idle");
 
-    // After all sleep for 0.1 seconds since android device can be slow
-    usleep(100000);
-
-    ALOGD("Stopping ctx..");
     if (ctx->rec_strm) {
         ((android::AudioRecord*)ctx->rec_strm)->stop();
     }
-
     if (ctx->play_strm) {
         ((android::AudioTrack*)ctx->play_strm)->stop();
     }
+    usleep(200000);
+    ALOGD("Stopped android audio streaming");
+
+    pthread_join(ctx->modem_t,NULL);
+    ALOGD("End modemIO thread");
 
     // Restore the audio routing setting
     //      android::AudioSystem::setRouting(ctx->saved_audio_mode,
@@ -460,20 +828,21 @@ int gsm_audio_tunnel_stop(struct GsmAudioTunnel *ctx)
 
     ALOGD("Closing streaming");
 
-    if (ctx->play_strm) {
-        delete ((android::AudioTrack*)ctx->play_strm);
-        ctx->play_strm = NULL;
-    }
-
-    if (ctx->rec_strm) {
-        delete ((android::AudioRecord*)ctx->rec_strm);
-        ctx->rec_strm = NULL;
-    }
-
-    free(ctx->play_buf);
-    free(ctx->rec_buf);
+    if (ctx->play_strm) delete ((android::AudioTrack*)ctx->play_strm);
+    if (ctx->rec_strm) delete ((android::AudioRecord*)ctx->rec_strm);
+#ifdef CHECK_MEM_OVERRUN
+    if (ctx->play_buf) free(((int*)ctx->play_buf)-1);
+    if (ctx->rec_buf) free(((int*)ctx->rec_buf)-1);
+#else
+    if (ctx->play_buf) free(ctx->play_buf);
+    if (ctx->rec_buf) free(ctx->rec_buf);
+#endif
+    if (ctx->fd) close(ctx->fd);
+
+#if LOG_MODEM_AUDIO
+    if (ctx->logfd) close(ctx->logfd);
+#endif
 
-    close(ctx->fd);
     memset(ctx,0,sizeof(struct GsmAudioTunnel));
 
     ALOGD("Done");
index 6cc59b5..24073de 100644 (file)
@@ -1,6 +1,6 @@
 /*
 **
-** Copyright (C) 2010 Eduardo José Tagle <ejtagle@tutopia.com>
+** Copyright (C) 2012 Eduardo José Tagle <ejtagle@tutopia.com>
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 **
-** Author: Christian Bejram <christian.bejram@stericsson.com>
 */
 #ifndef _AUDIOCHANNEL_H
 #define _AUDIOCHANNEL_H 1
 
+#include "audioqueue.h"
+#include "echocancel.h"
+#include <pthread.h>
+
+#define LOG_MODEM_AUDIO 0
+
 struct GsmAudioTunnel {
-    int running;                    // If running
 
     // 3G voice modem
     int fd;                         // Voice data serial port handler
 
+#if LOG_MODEM_AUDIO
+    int logfd;
+#endif
+
     // Common properties
-    volatile int quit_flag;         // If threads should quit
     unsigned int frame_size;        // Frame size
     unsigned int sampling_rate;     // Sampling rate
     unsigned int bits_per_sample;   // Bits per sample. valid values = 16/8
+    unsigned int timeout;           // Maximum wait timeout
+    pthread_t modem_t;              // 3G modem playback/record thread
+    int ismuted;                    // If audio record is muted
 
     // Playback
     void* play_strm;                // Playback stream
     volatile int play_thread_exited;// If play thread has exited
     void* play_buf;                 // Pointer to the playback buffer
-    unsigned int play_buf_count;    // Count of already stored samples in the playback buffer
+    struct AudioQueue play_q;       // Audio playback queue
 
     // Record
     void* rec_strm;                 // Record stream
     volatile int rec_thread_exited; // If record thread has exited
     void* rec_buf;                  // Pointer to the recording buffer
-    unsigned int rec_buf_count;     // Count of already stored samples in the recording buffer
+    struct AudioQueue rec_q;        // Audio record queue
+
+    // Echo cancellation
+    struct echocancel_ctx echo;     // Echo cancellator
 };
 
-#define GSM_AUDIO_CHANNEL_STATIC_INIT { 0, 0, 0,0,0,0, 0,0,0,0 ,0,0,0,0 }
+#define GSM_AUDIO_CHANNEL_STATIC_INIT { -1, 0,0,0,0,0,0, 0,0,0,{0} ,0,0,0,{0}, {0} }
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 int gsm_audio_tunnel_start(struct GsmAudioTunnel *stream,
-    const char* gsmvoicechannel,
-    unsigned int sampling_rate,
-    unsigned int frame_size,
-    unsigned int bits_per_sample);
+        const char* gsmvoicechannel,
+        unsigned int sampling_rate,
+        unsigned int frame_size,
+        unsigned int bits_per_sample);
 
 int gsm_audio_tunnel_stop(struct GsmAudioTunnel *stream);
 
+int gsm_audio_tunnel_running(struct GsmAudioTunnel *ctx);
+
+int gsm_audio_tunnel_mute(struct GsmAudioTunnel *stream, int muteit);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/huaweigeneric-ril/audioqueue.c b/huaweigeneric-ril/audioqueue.c
new file mode 100644 (file)
index 0000000..d206dc0
--- /dev/null
@@ -0,0 +1,421 @@
+#include "audioqueue.h"
+#include <string.h>
+#include <stdio.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "RILAudioQueue"
+#include <utils/Log.h>
+
+#define f_mul(a,b)     (((long long)(a))*(b) >> 28)
+#define f_div(a,b)     ((((long long)(a)) << 28) / (b))
+#define f_fract(a)     ((a) & ((1<<28)-1))
+#define f_intp(a)      ((a) >> 28)
+#define F_ONE          (1<<28)
+#define F_NBR(x)       ((int)((1<<28) * (x)))
+
+//#define CHECK_MEM_OVERRUN
+#define  AUDIOQUEUE_DEBUG 0
+#if AUDIOQUEUE_DEBUG
+#  define  D(...)   ALOGD(__VA_ARGS__)
+#else
+#  define  D(...)   ((void)0)
+#endif
+
+/* Return count in buffer.  */
+#define CIRC_CNT(wr_pos,rd_pos,size) (((wr_pos) - (rd_pos)) & ((size)-1))
+
+/* Return space available, 0..size-1.  We always leave one free char
+   as a completely full buffer has wr_pos == rd_pos, which is the same as
+   empty.  */
+#define CIRC_SPACE(wr_pos,rd_pos,size) CIRC_CNT((rd_pos),((wr_pos)+1),(size))
+
+/* Return count up to the end of the buffer.  Carefully avoid
+   accessing wr_pos and rd_pos more than once, so they can change
+   underneath us without returning inconsistent results.  */
+#define CIRC_CNT_TO_END(wr_pos,rd_pos,size) \
+       ({int end = (size) - (rd_pos); \
+         int n = ((wr_pos) + end) & ((size)-1); \
+         n < end ? n : end;})
+
+/* Return space available up to the end of the buffer.  */
+#define CIRC_SPACE_TO_END(wr_pos,rd_pos,size) \
+       ({int end = (size) - 1 - (wr_pos); \
+         int n = (end + (rd_pos)) & ((size)-1); \
+         n <= end ? n : end+1;})
+
+
+
+// Init the audio queue
+int AudioQueue_init(struct AudioQueue* ctx,unsigned int p2maxsamples, unsigned int sample_sz)
+{
+       unsigned int maxsamples = 1U << p2maxsamples;
+       memset(ctx,0,sizeof(*ctx));
+
+       ctx->size = maxsamples;
+#if NEW_SYNC_ALGO
+       ctx->waitidx = 1;
+#endif
+       ctx->sample_sz = sample_sz;
+
+       /* Linear resampler */
+       ctx->ratio = F_ONE;
+
+       ALOGD("[%p] Initializing audio queue: size: %d, low: %d, high: %d, sample_sz: %d",
+            ctx,ctx->size,ctx->low,ctx->high,ctx->sample_sz);
+
+#ifdef CHECK_MEM_OVERRUN
+       ctx->data = malloc(8 + maxsamples * sample_sz);
+       if (!ctx->data) {
+               ALOGE("{%p} Failed to allocate %d memory",ctx, 8 + maxsamples * sample_sz);
+               return -1;
+       }
+       ctx->data = (int*)ctx->data + 1;
+       ((int*)ctx->data)[-1] = 0x1A2B6C7D;
+       ((int*)ctx->data)[(ctx->size*ctx->sample_sz)>>2] = 0xD7C6B2A1;
+#else
+       ctx->data = malloc(maxsamples * sample_sz);
+       if (!ctx->data) {
+               ALOGE("{%p} Failed to allocate %d memory",ctx, maxsamples * sample_sz);
+               return -1;
+       }
+#endif
+
+       // Init audio AGC
+       agc_init(&ctx->agc, 31000);
+
+       ctx->running = 1;
+
+       return 0;
+}
+
+int AudioQueue_isrunning(struct AudioQueue* ctx)
+{
+       return ctx->running;
+}
+
+int AudioQueue_add(struct AudioQueue* ctx, void* data,unsigned int samples)
+{
+       unsigned int samples_todo = samples;
+
+       // If exited, avoid adding
+       if (!ctx->running)
+               return 0;
+
+       D("add[%p]: begin: Store %d samples",ctx,samples);
+
+       // Not filled, add to the queue.
+    while (ctx->running && samples_todo) {
+
+        // Calculate remaining space until end of buffer. We always leave a byte free
+        //  so we can differenciate between empty and full buffers
+        unsigned int rem = CIRC_SPACE_TO_END(ctx->wr_pos,ctx->rd_pos,ctx->size);
+
+        D("add[%p]: samples_todo: %u, rem: %u, rd: %u, wr: %u, sz: %u",
+                ctx, samples_todo, rem, ctx->rd_pos, ctx->wr_pos, ctx->size);
+
+        if (rem == 0) {
+            /* not enough data... Ignore the part we can't store */
+            D("add[%p]: Not enough space on queue...",ctx);
+            break;
+
+        } else {
+            // Do not store more than needed
+            if (rem > samples_todo) {
+                rem = samples_todo;
+            }
+
+            // Store data in queue
+            memcpy( (char*)ctx->data + ctx->wr_pos * ctx->sample_sz, data, rem * ctx->sample_sz);
+            data = (char*) data + rem * ctx->sample_sz;
+            ctx->wr_pos = (ctx->wr_pos + rem) & (ctx->size-1);
+            samples_todo -= rem;
+        }
+    }
+
+       D("add[%p]: end: Stored %d samples, size %d, rd:%d, wr:%d",ctx,samples - samples_todo,ctx->size, ctx->rd_pos, ctx->wr_pos);
+
+#if !NEW_SYNC_ALGO
+       // Adjust ratio if queue is getting full, to keep fullness under control
+       if (ctx->high && CIRC_CNT(ctx->wr_pos,ctx->rd_pos,ctx->size) > ctx->high) {
+               unsigned int ratio = ctx->ratio;
+
+               // Adjust ratio to avoid this the next time
+               ratio += ratio/200;
+
+               // Limit to sensible values
+               if (ratio > F_NBR(1.05)) {
+                       ratio = F_NBR(1.05);
+               }
+               ctx->ratio = ratio;
+               D("add[%p]: Adjusting ratio to keep queue 3/4 full: New ratio: %u",ctx, ratio);
+       }
+#endif
+
+#ifdef CHECK_MEM_OVERRUN
+       if (((int*)ctx->data)[-1] != 0x1A2B6C7D) {
+               ALOGE("add[%p] Memory corruption at start: Found: %08x",ctx, ((int*)ctx->data)[-1]);
+       }
+
+       if (((int*)ctx->data)[(ctx->size*ctx->sample_sz)>>2] != 0xD7C6B2A1) {
+               ALOGE("add[%p] Memory corruption at end: Found: %08x",ctx, ((int*)ctx->data)[ctx->size*ctx->sample_sz]);
+       }
+#endif
+
+       // Return the count of stored samples
+       return samples - samples_todo;
+}
+
+int AudioQueue_get(struct AudioQueue* ctx, void* data,unsigned int samples,unsigned int timeoutms)
+{
+       unsigned int maxgetreq;
+       unsigned int samples_todo = samples;
+       void* pdata = data;
+#if NEW_SYNC_ALGO
+       struct timeval startop;
+       struct timeval curr;
+       unsigned int deltatm = 0;
+#endif
+
+       // If exited, avoid adding
+       if (!ctx->running)
+               return 0;
+
+       D("get[%p]: begin: Read of %d samples",ctx,samples);
+
+#if !NEW_SYNC_ALGO
+       /* Keep track of the maximum read size, as we will use it as low/high limit */
+       maxgetreq = ctx->maxgetreq;
+       if (samples > maxgetreq) {
+               maxgetreq = samples;
+               ctx->maxgetreq = maxgetreq;
+
+               /* Limit to something we can use */
+               if (maxgetreq > ctx->size / 4) {
+                       maxgetreq = ctx->size / 4;
+               }
+
+               ctx->low  = maxgetreq*2;     // Low limit: 2 read pending
+               ctx->high = maxgetreq*3;         // High limit: 3 reads pending
+
+               D("get[%p]: new limits: low:%u, high:%u",ctx,ctx->low,ctx->high);
+       }
+#endif
+
+#if NEW_SYNC_ALGO
+       // Store the time of the start of this operation
+       gettimeofday(&startop,NULL);
+#endif
+
+       // While samples to be read
+       while (ctx->running && samples_todo) {
+
+               // Read the first free position
+               int av = CIRC_CNT(ctx->wr_pos,ctx->rd_pos,ctx->size);
+               unsigned int step = ctx->step, mask = ctx->size-1;
+               unsigned int rd_pos = ctx->rd_pos;
+
+               D("get[%p]: [1] samples_todo: %u, rd: %u, wr: %u, sz: %u",
+                ctx, samples_todo, ctx->rd_pos, ctx->wr_pos, ctx->size);
+
+               // linear interpolation resampling until all requested data is provided
+               if (ctx->sample_sz == 2) {
+
+                       short const *psrc = ctx->data;
+                       short *pdst = (short*)pdata;
+
+                       /* We use the current one and next one samples */
+                       while (samples_todo) {
+                               int ipart = f_intp(step);
+                               rd_pos  = (rd_pos + ipart) & mask;
+                               av         -= ipart;
+                               step    = f_fract(step);
+
+                               // If not enough data, break now
+                               if (av < 2)
+                                       break;
+
+                               *pdst++ = psrc[rd_pos] + f_mul(psrc[(rd_pos+1) & mask] - psrc[rd_pos], step);
+                               samples_todo--;
+                               step   += ctx->ratio;
+
+                               // Update buffer pointers and linear resampler step
+                               ctx->step = step;
+                               ctx->rd_pos = rd_pos;
+                       }
+                       pdata = pdst;
+
+        } else {
+            unsigned char const *psrc = ctx->data;
+            unsigned char *pdst = (unsigned char*)pdata;
+
+            /* We use the current one and next one samples */
+            while (samples_todo) {
+                int ipart = f_intp(step);
+                rd_pos  = (rd_pos + ipart) & mask;
+                av        -= ipart;
+                step    = f_fract(step);
+
+                // If not enough data, break now
+                if (av < 2)
+                    break;
+
+                *pdst++ = psrc[rd_pos] + f_mul(psrc[(rd_pos+1) & mask] - psrc[rd_pos], step);
+                samples_todo--;
+                step   += ctx->ratio;
+
+                // Update buffer pointers and linear resampler step
+                ctx->step = step;
+                ctx->rd_pos = rd_pos;
+            }
+            pdata = pdst;
+        }
+
+               D("get[%p]: [2] samples_todo: %u, rd: %u, wr: %u, sz: %u",
+                ctx, samples_todo, ctx->rd_pos, ctx->wr_pos, ctx->size);
+               if (samples_todo) {
+
+#if NEW_SYNC_ALGO
+                       /* Get actual time */
+                       gettimeofday(&curr,NULL);
+
+                       /* Yield a bit - 1 ms */
+                       usleep(1000);
+
+                       /* Calculate waiting time */
+                       deltatm = (curr.tv_sec - startop.tv_sec) * 1000000 + (curr.tv_usec - startop.tv_usec);
+
+                       /* If we are allowed to wait a bit to get those samples, keep trying */
+                       if (deltatm < timeoutms)
+                               continue;
+#endif
+
+                       // No more samples to provide....
+                       D("get[%p]: Not enough data on queue...",ctx);
+
+                       // Return what we have...
+                       break;
+               }
+       };
+
+       D("get[%p]: end: got %d samples, total: %d, rd:%d, wr:%d",
+            ctx, samples - samples_todo, ctx->size,ctx->rd_pos, ctx->wr_pos);
+
+#if NEW_SYNC_ALGO
+       // The idea is that we want to keep nearly in sync adds with gets, but this is not easy, as
+       // there is a lot of jitter in the add and get operations. So, instead of that, what we strive
+       // is to adjust sampling rate so if we had to wait, wait more than 0 but less than 2ms.
+
+       if (deltatm == 0) {
+               // We didn't had to wait. Everything could be fine, or we could be running the queue
+               //  too slow. try to speed it up a bit: We want to hit the 1ms waiting mark...
+
+               unsigned int ratio = ctx->ratio;
+
+               // Adjust ratio to avoid this the next time.
+               ratio += ratio * ctx->waitidx / samples;
+
+               // Limit to sensible values
+               if (ratio > F_NBR(1.05)) {
+                       ratio = F_NBR(1.05);
+               }
+               ctx->ratio = ratio;
+
+               // Increment the nowaitctr, as this time we did not had to wait
+               if (ctx->nowaitctr < 50)
+                       ctx->nowaitctr ++;
+
+               D("get[%p]: Adjusting ratio to try to queue as empty as possible: New ratio: %u",ctx, ratio);
+
+       } else {
+               // We had to wait. The queue is running too fast. Adjust it so the next time we don´t
+               //  have to wait...
+               unsigned int waitidx = ctx->waitidx;
+               unsigned int ratio = ctx->ratio;
+               ratio -= ratio * deltatm / samples;
+
+               // Limit to sensible values
+               if (ratio < F_NBR(0.95)) {
+                       ratio = F_NBR(0.95);
+               }
+               ctx->ratio = ratio;
+
+               // We had to wait... Adjust the wait index to try to make it nonwait most of the time
+               if (ctx->nowaitctr < 50) {
+                       if (waitidx > 1)
+                               waitidx --;
+        } else if (ctx->nowaitctr > 50) {
+            if (waitidx < 50)
+                waitidx ++;
+        }
+               ctx->waitidx = waitidx;
+
+               // And restart counting
+               ctx->nowaitctr = 0;
+
+               D("get[%p]: Adjusting rate to try to avoid waiting: New ratio: %u, waitidx: %u",ctx,ratio,waitidx);
+       }
+#endif
+
+#if !NEW_SYNC_ALGO
+       // Adjust ratio if queue is getting empty, to keep fullness under control
+       if (samples != samples_todo &&  /* Something output */
+               ctx->low && /* Limit set */
+               CIRC_CNT(ctx->wr_pos,ctx->rd_pos,ctx->size) < ctx->low) {
+
+               unsigned int ratio = ctx->ratio;
+               ratio -= ratio / 200;
+
+               // Limit to sensible values
+               if (ratio < F_NBR(0.95)) {
+                       ratio = F_NBR(0.95);
+               }
+               ctx->ratio = ratio;
+
+               D("get[%p]: Adjusting rate to keep queue at least 1/4 full: New ratio: %u",ctx,ratio);
+       }
+#endif
+
+       // Apply AGC to the samples
+       if (ctx->sample_sz == 2 ) {
+               agc_process_16bit(&ctx->agc,(short*) data, samples - samples_todo);
+       } else {
+               agc_process_8bit(&ctx->agc,(unsigned char*) data, samples - samples_todo);
+       }
+
+#ifdef CHECK_MEM_OVERRUN
+       if (((int*)ctx->data)[-1] != 0x1A2B6C7D) {
+               ALOGE("get[%p] Memory corruption at start: Found: %08x",ctx, ((int*)ctx->data)[-1]);
+       }
+
+       if (((int*)ctx->data)[(ctx->size*ctx->sample_sz)>>2] != 0xD7C6B2A1) {
+               ALOGE("get[%p] Memory corruption at end: Found: %08x",ctx, ((int*)ctx->data)[ctx->size*ctx->sample_sz]);
+       }
+#endif
+
+
+       // Return the count of read samples
+       return samples - samples_todo;
+}
+
+int AudioQueue_end(struct AudioQueue* ctx)
+{
+
+       // If exited, avoid reexecuting deinitialization
+       if (!ctx->running)
+               return 0;
+
+       // Signal end
+       ctx->running = 0;
+
+       // Some delay to let add and get end...
+       sleep(1);
+
+#ifdef CHECK_MEM_OVERRUN
+       free(((int*)ctx->data)-1);
+#else
+       free(ctx->data);
+#endif
+
+       memset(ctx,0,sizeof(struct AudioQueue));
+       return 0;
+}
diff --git a/huaweigeneric-ril/audioqueue.h b/huaweigeneric-ril/audioqueue.h
new file mode 100644 (file)
index 0000000..7d1c122
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+**
+** Copyright (C) 2012 Eduardo José Tagle <ejtagle@tutopia.com>
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+**
+*/
+
+/* A resampling Audio queue with AGC */
+
+#ifndef __AUDIOQUEUE_H
+#define __AUDIOQUEUE_H 1
+
+#include <pthread.h>
+#include <sys/time.h>
+#include "agc.h"
+
+#define NEW_SYNC_ALGO 0
+
+struct AudioQueue {
+       volatile int running;   // != 0 if running
+       unsigned int size;              // Queue size in samples
+#if !NEW_SYNC_ALGO
+       unsigned int maxgetreq; // Maximum request size
+       unsigned int low;               // Low limit
+       unsigned int high;              // High limit
+#else
+       unsigned int nowaitctr; // No waiting counter
+       unsigned int waitidx;   // Wait index
+#endif
+       unsigned int sample_sz; // Sample size in bytes
+       unsigned int wr_pos;    // Write position in samples
+       unsigned int rd_pos;    // Read position in samples
+       unsigned int ratio;             // Resampling ratio including speedup/speeddown due to fullness
+       unsigned int step;              // Linear interpolation step
+       struct agc_ctx agc;             // AGC control
+       void* data;                             // Queue Data buffer
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int AudioQueue_init(struct AudioQueue* ctx,unsigned int p2maxsamples, unsigned int sample_sz);
+int AudioQueue_isrunning(struct AudioQueue* ctx);
+int AudioQueue_add(struct AudioQueue* ctx, void* data,unsigned int samples);
+int AudioQueue_get(struct AudioQueue* ctx, void* data,unsigned int samples,unsigned int timeout);
+int AudioQueue_end(struct AudioQueue* ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/huaweigeneric-ril/echocancel.c b/huaweigeneric-ril/echocancel.c
new file mode 100644 (file)
index 0000000..a6892e3
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyrightm (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+
+#define LOG_TAG "EchoCancel"
+#include <utils/Log.h>
+
+#include "echocancel.h"
+
+// It is very difficult to do echo cancellation at this level due to the lack of
+// the timing information of the samples being played and recorded. Therefore,
+// for the first release only echo suppression is implemented.
+
+// The algorithm is derived from the "previous works" summarized in
+//   A new class of doubletalk detectors based on cross-correlation,
+//   J Benesty, DR Morgan, JH Cho, IEEE Trans. on Speech and Audio Processing.
+// The method proposed in that paper is not used because of its high complexity.
+
+// It is well known that cross-correlation can be computed using convolution,
+// but unfortunately not every mobile processor has a (fast enough) FPU. Thus
+// we use integer arithmetic as much as possible and do lots of bookkeeping.
+// Again, parameters and thresholds are chosen by experiments.
+
+int echocancel_init(struct echocancel_ctx* ctx,int sampleCount, int tailLength)
+{
+    int shift;
+
+    tailLength += sampleCount * 4;
+
+    shift = 0;
+    while ((sampleCount >> shift) > 1 && (tailLength >> shift) > 256) {
+        ++shift;
+    }
+
+    ctx->Shift = shift + 4;
+    ctx->Scale = 1 << shift;
+    ctx->SampleCount = sampleCount;
+    ctx->WindowSize = sampleCount >> shift;
+    ctx->TailLength = tailLength >> shift;
+    ctx->RecordLength = tailLength * 2 / sampleCount;
+    ctx->RecordOffset = 0;
+
+    ctx->Xs = calloc(sizeof(*ctx->Xs), (ctx->TailLength + ctx->WindowSize));
+    ctx->XSums = calloc(sizeof(*ctx->XSums), (ctx->TailLength));
+    ctx->X2Sums = calloc(sizeof(*ctx->X2Sums), ctx->TailLength);
+    ctx->XRecords = calloc(sizeof(*ctx->XRecords), (ctx->RecordLength * ctx->WindowSize));
+
+    ctx->YSum = 0;
+    ctx->Y2Sum = 0;
+    ctx->YRecords = calloc(sizeof(*ctx->YRecords), ctx->RecordLength);
+    ctx->Y2Records = calloc(sizeof (*ctx->Y2Records), ctx->RecordLength);
+
+    ctx->XYSums = calloc(sizeof(*ctx->XYSums), ctx->TailLength);
+    ctx->XYRecords = calloc(sizeof(*ctx->XYRecords), ctx->RecordLength * ctx->TailLength);
+
+    ctx->LastX = 0;
+    ctx->LastY = 0;
+    ctx->Weight = 1.0f / (ctx->RecordLength * ctx->WindowSize);
+
+    return 0;
+}
+
+void echocancel_end(struct echocancel_ctx* ctx)
+{
+    free(ctx->Xs);
+    free(ctx->XSums);
+    free(ctx->X2Sums);
+    free(ctx->XRecords);
+    free(ctx->YRecords);
+    free(ctx->Y2Records);
+    free(ctx->XYSums);
+    free(ctx->XYRecords);
+    memset(ctx, 0, sizeof(*ctx));
+}
+
+void echocancel_run(struct echocancel_ctx* ctx,int16_t *playbacked, int16_t *recorded)
+{
+    uint16_t *xRecords;
+    uint16_t ys[ctx->WindowSize];
+    uint32_t ySum = 0;
+    uint32_t y2Sum = 0;
+    uint32_t *xyRecords;
+    int latency = 0;
+    float corr2 = 0.0f;
+    float varX = 0.0f;
+    float varY;
+    int i,j;
+
+    // Update Xs.
+    for (i = ctx->TailLength - 1; i >= 0; --i) {
+        ctx->Xs[i + ctx->WindowSize] = ctx->Xs[i];
+    }
+    for (i = ctx->WindowSize - 1, j = 0; i >= 0; --i, j += ctx->Scale) {
+        uint32_t sum = 0;
+        int k;
+        for (k = 0; k < ctx->Scale; ++k) {
+            int32_t x = playbacked[j + k] << 15;
+            ctx->LastX += x;
+            sum += ((ctx->LastX >= 0) ? ctx->LastX : -ctx->LastX) >> 15;
+            ctx->LastX -= (ctx->LastX >> 10) + x;
+        }
+        ctx->Xs[i] = sum >> ctx->Shift;
+    }
+
+    // Update XSums, X2Sums, and XRecords.
+    for (i = ctx->TailLength - ctx->WindowSize - 1; i >= 0; --i) {
+        ctx->XSums[i + ctx->WindowSize] = ctx->XSums[i];
+        ctx->X2Sums[i + ctx->WindowSize] = ctx->X2Sums[i];
+    }
+    xRecords = &ctx->XRecords[ctx->RecordOffset * ctx->WindowSize];
+    for (i = ctx->WindowSize - 1; i >= 0; --i) {
+        uint16_t x = ctx->Xs[i];
+        ctx->XSums[i] = ctx->XSums[i + 1] + x - xRecords[i];
+        ctx->X2Sums[i] = ctx->X2Sums[i + 1] + x * x - xRecords[i] * xRecords[i];
+        xRecords[i] = x;
+    }
+
+    // Compute Ys.
+    for (i = ctx->WindowSize - 1, j = 0; i >= 0; --i, j += ctx->Scale) {
+        uint32_t sum = 0;
+        int k;
+        for (k = 0; k < ctx->Scale; ++k) {
+            int32_t y = recorded[j + k] << 15;
+            ctx->LastY += y;
+            sum += ((ctx->LastY >= 0) ? ctx->LastY : -ctx->LastY) >> 15;
+            ctx->LastY -= (ctx->LastY >> 10) + y;
+        }
+        ys[i] = sum >> ctx->Shift;
+    }
+
+    // Update YSum, Y2Sum, YRecords, and Y2Records.
+    ySum = 0;
+    y2Sum = 0;
+    for (i = ctx->WindowSize - 1; i >= 0; --i) {
+        ySum += ys[i];
+        y2Sum += ys[i] * ys[i];
+    }
+    ctx->YSum += ySum - ctx->YRecords[ctx->RecordOffset];
+    ctx->Y2Sum += y2Sum - ctx->Y2Records[ctx->RecordOffset];
+    ctx->YRecords[ctx->RecordOffset] = ySum;
+    ctx->Y2Records[ctx->RecordOffset] = y2Sum;
+
+    // Update XYSums and XYRecords.
+    xyRecords = &ctx->XYRecords[ctx->RecordOffset * ctx->TailLength];
+    for (i = ctx->TailLength - 1; i >= 0; --i) {
+        uint32_t xySum = 0;
+        for (j = ctx->WindowSize - 1; j >= 0; --j) {
+            xySum += ctx->Xs[i + j] * ys[j];
+        }
+        ctx->XYSums[i] += xySum - xyRecords[i];
+        xyRecords[i] = xySum;
+    }
+
+    // Compute correlations.
+    latency = 0;
+    corr2 = 0.0f;
+    varX = 0.0f;
+    varY = ctx->Y2Sum - ctx->Weight * ctx->YSum * ctx->YSum;
+    for (i = ctx->TailLength - 1; i >= 0; --i) {
+        float cov = ctx->XYSums[i] - ctx->Weight * ctx->XSums[i] * ctx->YSum;
+        if (cov > 0.0f) {
+            float varXi = ctx->X2Sums[i] - ctx->Weight * ctx->XSums[i] * ctx->XSums[i];
+            float corr2i = cov * cov / (varXi * varY + 1);
+            if (corr2i > corr2) {
+                varX = varXi;
+                corr2 = corr2i;
+                latency = i;
+            }
+        }
+    }
+    //ALOGI("corr^2 %.5f, var %8.0f %8.0f, latency %d", corr2, varX, varY,
+    //        latency * mScale);
+
+    // Do echo suppression.
+    if (corr2 > 0.1f && varX > 10000.0f) {
+        int factor = (corr2 > 1.0f) ? 0 : (1.0f - sqrtf(corr2)) * 4096;
+        for (i = 0; i < ctx->SampleCount; ++i) {
+            recorded[i] = recorded[i] * factor >> 16;
+        }
+    }
+
+    // Increase RecordOffset.
+    ++ctx->RecordOffset;
+    if (ctx->RecordOffset == ctx->RecordLength) {
+        ctx->RecordOffset = 0;
+    }
+}
diff --git a/huaweigeneric-ril/echocancel.h b/huaweigeneric-ril/echocancel.h
new file mode 100644 (file)
index 0000000..656f22b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyrightm (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ECHO_CANCEL_H
+#define __ECHO_CANCEL_H
+
+#include <stdint.h>
+
+struct echocancel_ctx {
+    int Shift;
+    int Scale;
+    int SampleCount;
+    int WindowSize;
+    int TailLength;
+    int RecordLength;
+    int RecordOffset;
+
+    uint16_t *Xs;
+    uint32_t *XSums;
+    uint32_t *X2Sums;
+    uint16_t *XRecords;
+
+    uint32_t YSum;
+    uint32_t Y2Sum;
+    uint32_t *YRecords;
+    uint32_t *Y2Records;
+
+    uint32_t *XYSums;
+    uint32_t *XYRecords;
+
+    int32_t LastX;
+    int32_t LastY;
+
+    float Weight;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The sampleCount must be power of 2.
+int echocancel_init(struct echocancel_ctx* ctx,int sampleCount, int tailLength);
+void echocancel_end(struct echocancel_ctx* ctx);
+void echocancel_run(struct echocancel_ctx* ctx,int16_t *playbacked, int16_t *recorded);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 65cbf34..2a5f932 100644 (file)
@@ -124,6 +124,6 @@ int fcp_to_ts_51011(/*in*/ const char *stream, /*in*/ size_t len,
 
  except:
  #undef FCP_CVT_THROW
-    ALOGE("%s() FCP to TS 510 11: Specification violation: %s.", __func__, what);
+    ALOGW("%s() FCP to TS 510 11: Specification violation: %s.", __func__, what);
     goto finally;
 }
index 274e7db..1dac412 100644 (file)
@@ -171,7 +171,7 @@ gsm_hex_to_bytes( cbytes_t  hex, int  hexlen, bytes_t  dst )
     int  nn;
 
     for (nn = 0; nn < hexlen/2; nn++ ) {
-        dst[nn] = (byte_t) gsm_hex2_to_byte0( hex+2*nn );
+        dst[nn] = (byte_t) gsm_hex2_to_byte0( (char const*) hex+2*nn );
     }
     if (hexlen & 1) {
         dst[nn] = gsm_hexchar_to_int0( hex[2*nn] ) << 4;
@@ -282,7 +282,8 @@ gsm_rope_can_grow( GsmRope  rope, int  count )
     if (!rope->data || rope->error)
         return 0;
 
-    if (rope->pos + count > rope->max) {
+    if (rope->pos + count > rope->max)
+    {
         if (rope->data == NULL)
             rope->max = rope->pos + count;
 
@@ -316,7 +317,8 @@ gsm_rope_reserve( GsmRope  rope, int  count )
 {
     void*  result = NULL;
 
-    if (gsm_rope_can_grow(rope, count)) {
+    if (gsm_rope_can_grow(rope, count))
+    {
         if (rope->data != NULL)
             result = rope->data + rope->pos;
     }
@@ -1100,7 +1102,7 @@ sim_adn_record_from_bytes( SimAdnRecord  rec, cbytes_t  data, int  len )
     /* alpha is optional */
     if (len > ADN_FOOTER_SIZE) {
         cbytes_t  dataend = data + len - ADN_FOOTER_SIZE;
-        int       count   = sim_adn_alpha_to_utf8(data, dataend, NULL);
+        unsigned int count = sim_adn_alpha_to_utf8(data, dataend, NULL);
 
         if (count > sizeof(rec->adn.alpha)-1)  /* too long */
             return -1;
@@ -1116,7 +1118,7 @@ sim_adn_record_from_bytes( SimAdnRecord  rec, cbytes_t  data, int  len )
     /* decode TON and number to ASCII, NOTE: this is lossy !! */
     {
         int      ton    = footer[ADN_OFFSET_TON_NPI];
-        bytes_t  number = rec->adn.number;
+        bytes_t  number = (bytes_t) rec->adn.number;
         int      len    = sizeof(rec->adn.number)-1;
         int      count;
 
@@ -1141,13 +1143,13 @@ sim_adn_record_to_bytes( SimAdnRecord  rec, bytes_t   data, int  datalen )
     bytes_t   end    = data + datalen;
     bytes_t   footer = end - ADN_FOOTER_SIZE;
     int       ton    = 0x81;
-    cbytes_t  number = rec->adn.number;
+    cbytes_t  number = (cbytes_t) rec->adn.number;
     int       len;
 
     if (number[0] == '+') {
         ton     = 0x91;
         number += 1;
     }
-    footer[0] = (strlen(number)+1)/2 + 1;
+    footer[0] = (strlen((const char*) number)+1)/2 + 1;
     return 0;
 }
index b016881..3b25681 100644 (file)
@@ -1,4 +1,4 @@
-/* //device/system/htcgeneric-ril/htcgeneric-ril.c
+/*
  **
  ** Copyright 2006, The Android Open Source Project
  ** Copyright 2012 Eduardo Jos[e Tagle <ejtagle@tutopia.com>
  ** limitations under the License.
  */
 
-/*
-AT^CURC=0
-ATQ0V1
-
-^MODE:
-^RSSI:
-^SRVST:
-+CCCM:
-^CONN:
-^CEND:
-+CDSI:
-^SMMEMFULL:
-+CSSU:
-^DCONN
-^DEND
-^SIMST      Â¡
-+CRING:
-AT^SYSCFG=2,3,%s,1,2
-^RSSI
-^SMMEMFULL
-*/
-
-/*
-AT^SYSCFG=2,1,3FFFFFFF,1,2 for GPRS/EDGE Preferred
-AT^SYSCFG=2,2,3FFFFFFF,1,2 for 3G Preferred
-AT^SYSCFG=13,1,3FFFFFFF,1,2 for GPRS/EDGE Only
-AT^SYSCFG=14,2,3FFFFFFF,1,2 for 3G Only
-
-The third parameter, 0x3FFFFFFF tells the card to use all bands. A value of 0x400380 here means GSM900/1800/WCDMA2100 only and a value of 0x200000 here means GSM1900 only.
+//#define BYPASS_AUDIO_CHECK 1
 
-I don't know what the final "1,2" parameter is for. But for some it has to be "2,4" instead for some reason.
 
+/*
 The status updates from the second port are prefixed with a caret and are of these forms:
 
 ^MODE:3,2 indicates GPRS
@@ -92,6 +64,23 @@ then I plug in on my Linux Ubuntu computer, use minicom and type AT^U2DIAG=0 to
 Maybe it's better to first type AT^U2DIAG=0 and then AT^U2DIAG=5 ...
 
 Regards, Phil.
+
+
+-----
+1)with unaccepted sim
+-> AT^CARDLOCK?
+<-^CARDLOCK: 1,10,0 ............ locked
+<-^CARDLOCK: 2,10,0 ............ unlocked
+Quote:
+Originally Posted by sergeymkl
+4. second number of reply to CARDLOCK inquiry.
+<-^CARDLOCK: 1,10,0 ............ locked
+<-^CARDLOCK: 2,10,0 ............ unlocked
+<-^CARDLOCK: A,B,C ............
+A = is to verify if locked or unlocked
+B = attempts left? or total given attempts?
+C = is for?
+
 */
 
 #define LOG_NDEBUG 0
@@ -112,6 +101,7 @@ Regards, Phil.
 #include "atchannel.h"
 #include "at_tok.h"
 #include "misc.h"
+#include "net-utils.h"
 #include "gsm.h"
 #include "requestdatahandler.h"
 #include "fcp_parser.h"
@@ -121,11 +111,18 @@ Regards, Phil.
 #include <cutils/sockets.h>
 #include <termios.h>
 #include <cutils/properties.h>
+#include <log/logger.h>
 #include <stdbool.h>
+#include <stddef.h>
 
-#define D ALOGD
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/route.h>
+#include <linux/wireless.h>
 
-#define RIL_VERSION_STRING "Huawei-ril 1.0.0.0"
+#define D ALOGI
+
+#define RIL_VERSION_STRING "Huawei-ril 1.0.0.8 (Built on " __DATE__" " __TIME__ ")"
 
 #define timespec_cmp(a, b, op)         \
         ((a).tv_sec == (b).tv_sec    \
@@ -136,10 +133,6 @@ Regards, Phil.
 #define TIMEOUT_EMRDY 10 /* Module should respond at least within 10s */
 #define MAX_BUF 1024
 
-/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
-#define PPP_TTY_PATH "ppp0"
-
-
 /** declarations */
 static const char *getVersion();
 static void signalCloseQueues(void);
@@ -154,8 +147,9 @@ static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
 static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
 static void onDataCallListChanged(void *param);
 static int killConn(const char * cid);
-static int wait_for_property(const char *name, const char *desired_value, int maxwait);
+static int wait_for_property(const char *name, const char *desired_value, int maxwait, int allowempty);
 static void checkMessageStorageReady(void *p);
+static int pppSupported(void);
 static void onSIMReady(void *p);
 static void pollSIMState(void *param);
 static void checkMessageStorageReady(void *p);
@@ -172,6 +166,19 @@ static const RIL_RadioFunctions s_callbacks = {
     getVersion
 };
 
+static char* rndis_iface_dev = "/dev/ttyUSB0";
+static char* ppp_iface_dev   = "/dev/ttyUSB0";
+static int using_rndis = 0;
+
+/* Last call index status */
+static int lastCallIdx = 0;
+
+/* Last call fail cause */
+static int lastCallFailCause = CALL_FAIL_NORMAL;
+
+#define RNDIS_IFACE "rmnet0"
+#define PPP_IFACE   "ppp0"
+
 static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
 static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
 static const struct timespec TIMEVAL_SIMPOLL = {1,0};
@@ -223,12 +230,15 @@ static RequestQueue *s_requestQueues[] = {
 };
 
 /* The Audio channel */
-static struct GsmAudioTunnel sAudioChannel = GSM_AUDIO_CHANNEL_STATIC_INIT;
+static struct GsmAudioTunnel sAudioChannel;
 static char  sAudioDevice[64] = {0};
 
+static int audioTunnelMuted = 0; // If audio tunnel is muted
+
 /* Starts the audio tunnel channel */
-static void startAudioTunnel(void)
+static void startAudioTunnel(void* param)
 {
+    ALOGD("call startAudioTunnel");
 #if 0
     ATResponse *atResponse = NULL;
     int err;
@@ -236,16 +246,16 @@ static void startAudioTunnel(void)
     int voice_disabled = 0, sampling_rate = 8000,
         bits_per_sample = 16, framesize_ms = 20;
 
-    if (sAudioChannel.running)
+    if (gsm_audio_tunnel_running(&sAudioChannel))
         return;
 
-    // Enable voice function
+    // Enable voice function - Some firmwares fail this command, but
+    // nevertheless, it works. Leave validation for the next one.
     err = at_send_command("AT^CVOICE=0");
-    if (err != AT_NOERROR)
-        goto error;
 
-    // Check status.
-    err = at_send_command_singleline("AT^CVOICE=?", "^CVOICE:", &atResponse);
+#ifndef BYPASS_AUDIO_CHECK
+    // Check status - This is the check that matters!
+    err = at_send_command_singleline("AT^CVOICE?", "^CVOICE:", &atResponse);
     if (err != AT_NOERROR)
         goto error;
 
@@ -256,6 +266,9 @@ static void startAudioTunnel(void)
     err = at_tok_nextint(&line, &voice_disabled);
     if (err < 0) goto error;
 
+    // Check if voice was really enabled
+    if (voice_disabled != 0) goto error;
+
     err = at_tok_nextint(&line, &sampling_rate);
     if (err < 0) goto error;
 
@@ -264,11 +277,17 @@ static void startAudioTunnel(void)
 
     err = at_tok_nextint(&line, &framesize_ms);
     if (err < 0) goto error;
+#else
+    sampling_rate = 8000;
+    bits_per_sample = 16;
+    framesize_ms = 20;
+#endif
 
-    /* Switch to audio from USB1 */
-    err = at_send_command("AT^DDSETEX=2");
-    if (err != AT_NOERROR)
-        goto error;
+    /* Increase volume to maximum. Some modems do not set the volume if not
+      actually changing values.... And some of them do not understand the
+      command at all. Try to switch volume to maximum - DerArtem */
+    err = at_send_command("AT+CLVL=1"); /* Lo volume */
+    err = at_send_command("AT+CLVL=5"); /* Maximum volume */
 
     /* Start the audio channel */
     err = gsm_audio_tunnel_start(&sAudioChannel,sAudioDevice,
@@ -276,7 +295,10 @@ static void startAudioTunnel(void)
     if (err)
         goto error;
 
-    ALOGE("Audio Tunnel enabled");
+    // Mute/Ummute audioTunnel as requested
+    gsm_audio_tunnel_mute(&sAudioChannel,audioTunnelMuted);
+
+    ALOGD("Audio Tunnel enabled");
     at_response_free(atResponse);
     return;
 
@@ -284,21 +306,37 @@ error:
     ALOGE("Failed to start audio tunnel");
 
     at_response_free(atResponse);
-    return;
 #endif
+    return;
 }
 
 /* Stops the audio tunnel channel */
-static void stopAudioTunnel(void)
+static void stopAudioTunnel(void* param)
 {
 #if 0
-    if (!sAudioChannel.running)
+    if (!gsm_audio_tunnel_running(&sAudioChannel))
         return;
 
     // Stop the audio tunnel
     gsm_audio_tunnel_stop(&sAudioChannel);
+#endif
+
+    ALOGD("Audio Tunnel disabled");
+}
+
+static void muteAudioTunnel(int muteit)
+{
+    ALOGD("call muteAudioTunnel");
+#if 0
+    audioTunnelMuted = muteit;
 
-    D("Audio Tunnel disabled");
+    ALOGD("Audio Tunnel %smuted",muteit?"":"un");
+
+    if (!gsm_audio_tunnel_running(&sAudioChannel))
+        return;
+
+    // Mute/Ummute audioTunnel if requested
+    gsm_audio_tunnel_mute(&sAudioChannel,audioTunnelMuted);
 #endif
 }
 
@@ -313,15 +351,14 @@ static void enqueueRILEvent(void (*callback) (void *param),
     char done = 0;
     RequestQueue *q = NULL;
 
-    RILEvent *e = (RILEvent *) malloc(sizeof(RILEvent));
-    memset(e, 0, sizeof(RILEvent));
+    RILEvent *e = (RILEvent *) calloc(1, sizeof(RILEvent));
 
     e->eventCallback = callback;
     e->param = param;
 
     if (relativeTime == NULL) {
         relativeTime = (const struct timespec *) alloca(sizeof(struct timespec));
-        memset((struct timespec *) relativeTime, 0, sizeof(struct timespec));
+        memset((void *) relativeTime, 0, sizeof(struct timespec));
     }
 
     clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -376,16 +413,16 @@ again:
 
 }
 
+
 /** returns 1 if on, 0 if off, and -1 on error */
 static int isRadioOn()
 {
     ATResponse *atResponse = NULL;
-    int err,ison;
+    int err;
     char *line;
-    char ret1,ret2;
-
-    err = at_send_command_singleline("AT^RFSWITCH?", "^RFSWITCH:", &atResponse);
+    char ret1;
 
+    err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &atResponse);
     if (err != AT_NOERROR) {
         // assume radio is off
         goto error;
@@ -399,20 +436,14 @@ static int isRadioOn()
     err = at_tok_nextbool(&line, &ret1);
     if (err < 0) goto error;
 
-    err = at_tok_nextbool(&line, &ret2);
-    if (err < 0) goto error;
-
     at_response_free(atResponse);
 
-    /* 1 is ON, 0 is OFF */
-    ison = (ret1 == 1 && ret2 == 1);
+    ALOGD("Radio is %s", (ret1 == 1) ? "On" : "Off");
 
-    ALOGD("Radio is %s", ison ? "On" : "Off");
-
-    return ison;
+    /* 1=means online, all the others, mean offline */
+    return (ret1 == 1) ? 1 : 0;
 
 error:
-
     at_response_free(atResponse);
     return -1;
 }
@@ -423,39 +454,39 @@ static const char *radioStateToString(RIL_RadioState radioState)
     const char *state;
 
     switch (radioState) {
-    case RADIO_STATE_OFF:
-        state = "RADIO_STATE_OFF";
-        break;
-    case RADIO_STATE_UNAVAILABLE:
-        state = "RADIO_STATE_UNAVAILABLE";
-        break;
-    case RADIO_STATE_SIM_NOT_READY:
-        state = "RADIO_STATE_SIM_NOT_READY";
-        break;
-    case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
-        state = "RADIO_STATE_SIM_LOCKED_OR_ABSENT";
-        break;
-    case RADIO_STATE_SIM_READY:
-        state = "RADIO_STATE_SIM_READY";
-        break;
-    case RADIO_STATE_RUIM_NOT_READY:
-        state = "RADIO_STATE_RUIM_NOT_READY";
-        break;
-    case RADIO_STATE_RUIM_READY:
-        state = "RADIO_STATE_RUIM_READY";
-        break;
-    case RADIO_STATE_RUIM_LOCKED_OR_ABSENT:
-        state = "RADIO_STATE_RUIM_READY";
-        break;
-    case RADIO_STATE_NV_NOT_READY:
-        state = "RADIO_STATE_NV_NOT_READY";
-        break;
-    case RADIO_STATE_NV_READY:
-        state = "RADIO_STATE_NV_READY";
-        break;
-    default:
-        state = "RADIO_STATE_<> Unknown!";
-        break;
+        case RADIO_STATE_OFF:
+            state = "RADIO_STATE_OFF";
+            break;
+        case RADIO_STATE_UNAVAILABLE:
+            state = "RADIO_STATE_UNAVAILABLE";
+            break;
+        case RADIO_STATE_SIM_NOT_READY:
+            state = "RADIO_STATE_SIM_NOT_READY";
+            break;
+        case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
+            state = "RADIO_STATE_SIM_LOCKED_OR_ABSENT";
+            break;
+        case RADIO_STATE_SIM_READY:
+            state = "RADIO_STATE_SIM_READY";
+            break;
+        case RADIO_STATE_RUIM_NOT_READY:
+            state = "RADIO_STATE_RUIM_NOT_READY";
+            break;
+        case RADIO_STATE_RUIM_READY:
+            state = "RADIO_STATE_RUIM_READY";
+            break;
+        case RADIO_STATE_RUIM_LOCKED_OR_ABSENT:
+            state = "RADIO_STATE_RUIM_READY";
+            break;
+        case RADIO_STATE_NV_NOT_READY:
+            state = "RADIO_STATE_NV_NOT_READY";
+            break;
+        case RADIO_STATE_NV_READY:
+            state = "RADIO_STATE_NV_READY";
+            break;
+        default:
+            state = "RADIO_STATE_<> Unknown!";
+            break;
     }
 
     return state;
@@ -471,7 +502,6 @@ static RIL_RadioState getRadioState()
     return sState;
 }
 
-
 static void setRadioState(RIL_RadioState newState)
 {
     RIL_RadioState oldState;
@@ -483,7 +513,7 @@ static void setRadioState(RIL_RadioState newState)
     oldState = sState;
 
     ALOGI("%s() oldState=%s newState=%s", __func__, radioStateToString(oldState),
-         radioStateToString(newState));
+            radioStateToString(newState));
 
     sState = newState;
 
@@ -493,16 +523,63 @@ static void setRadioState(RIL_RadioState newState)
     /* Do these outside of the mutex. */
     if (sState != oldState || sState == RADIO_STATE_SIM_LOCKED_OR_ABSENT) {
         RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
-                                  NULL, 0);
+                NULL, 0);
 
         if (sState == RADIO_STATE_SIM_READY) {
             enqueueRILEvent(checkMessageStorageReady, NULL, NULL);
             enqueueRILEvent(onSIMReady, NULL, NULL);
-        } else if (sState == RADIO_STATE_SIM_NOT_READY)
+        } else if (sState == RADIO_STATE_SIM_NOT_READY) {
             enqueueRILEvent(pollSIMState, NULL, NULL);
+        }
+    }
+}
+
+/*
+-> AT^CARDLOCK?
+<-^CARDLOCK: 1,10,0 ............ locked to an operator: Can be unlocked by code
+<-^CARDLOCK: 2,10,0 ............ unlocked
+<-^CARDLOCK: 3,10,0 ............ locked: Datacard is locked forever to an operator
+<-^CARDLOCK: A,B,C ............
+A = is to verify if locked or unlocked
+B = attempts left? or total given attempts?
+C = is for?
+*/
+
+static int getSimLockStatus(int* status, int* times)
+{
+    ATResponse *atResponse = NULL;
+    int err;
+    char *line;
+
+    err = at_send_command_singleline("AT^CARDLOCK?", "^CARDLOCK:", &atResponse);
+
+    if (err != AT_NOERROR) {
+        // assume locked
+        goto error;
     }
+
+    line = atResponse->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, status);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, times);
+    if (err < 0) goto error;
+
+    at_response_free(atResponse);
+
+    ALOGD("Card %s, times: %d", *status == 1 ? "Locked" : "Unlocked" , *times);
+    return 0;
+
+error:
+    at_response_free(atResponse);
+    return -1;
 }
 
+
 typedef enum {
     SIM_ABSENT = 0,                     /* SIM card is not inserted */
     SIM_NOT_READY = 1,                  /* SIM card is not ready */
@@ -534,6 +611,8 @@ typedef enum {
     UICC_TYPE_UIM,
 } UICC_Type;
 
+
+
 /** Returns one of SIM_*. Returns SIM_NOT_READY on error. */
 static SIM_Status getSIMStatus(void)
 {
@@ -542,6 +621,7 @@ static SIM_Status getSIMStatus(void)
     SIM_Status ret = SIM_ABSENT;
     char *cpinLine;
     char *cpinResult;
+    int status, times;
 
     if (getRadioState() == RADIO_STATE_OFF ||
         getRadioState() == RADIO_STATE_UNAVAILABLE) {
@@ -557,51 +637,51 @@ static SIM_Status getSIMStatus(void)
         }
 
         switch (at_get_cme_error(err)) {
-        case CME_SIM_NOT_INSERTED:
-            ret = SIM_ABSENT;
-            break;
-        case CME_SIM_PIN_REQUIRED:
-            ret = SIM_PIN;
-            break;
-        case CME_SIM_PUK_REQUIRED:
-            ret = SIM_PUK;
-            break;
-        case CME_SIM_PIN2_REQUIRED:
-            ret = SIM_PIN2;
-            break;
-        case CME_SIM_PUK2_REQUIRED:
-            ret = SIM_PUK2;
-            break;
-        case CME_NETWORK_PERSONALIZATION_PIN_REQUIRED:
-            ret = SIM_NETWORK_PERSO;
-            break;
-        case CME_NETWORK_PERSONALIZATION_PUK_REQUIRED:
-            ret = SIM_NETWORK_PERSO_PUK;
-            break;
-        case CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED:
-            ret = SIM_NETWORK_SUBSET_PERSO;
-            break;
-        case CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED:
-            ret = SIM_NETWORK_SUBSET_PERSO_PUK;
-            break;
-        case CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED:
-            ret = SIM_SERVICE_PROVIDER_PERSO;
-            break;
-        case CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED:
-            ret = SIM_SERVICE_PROVIDER_PERSO_PUK;
-            break;
-        case CME_PH_SIMLOCK_PIN_REQUIRED: /* PUK not in use by modem */
-            ret = SIM_SIM_PERSO;
-            break;
-        case CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED:
-            ret = SIM_CORPORATE_PERSO;
-            break;
-        case CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED:
-            ret = SIM_CORPORATE_PERSO_PUK;
-            break;
-        default:
-            ret = SIM_NOT_READY;
-            break;
+            case CME_SIM_NOT_INSERTED:
+                ret = SIM_ABSENT;
+                break;
+            case CME_SIM_PIN_REQUIRED:
+                ret = SIM_PIN;
+                break;
+            case CME_SIM_PUK_REQUIRED:
+                ret = SIM_PUK;
+                break;
+            case CME_SIM_PIN2_REQUIRED:
+                ret = SIM_PIN2;
+                break;
+            case CME_SIM_PUK2_REQUIRED:
+                ret = SIM_PUK2;
+                break;
+            case CME_NETWORK_PERSONALIZATION_PIN_REQUIRED:
+                ret = SIM_NETWORK_PERSO;
+                break;
+            case CME_NETWORK_PERSONALIZATION_PUK_REQUIRED:
+                ret = SIM_NETWORK_PERSO_PUK;
+                break;
+            case CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED:
+                ret = SIM_NETWORK_SUBSET_PERSO;
+                break;
+            case CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED:
+                ret = SIM_NETWORK_SUBSET_PERSO_PUK;
+                break;
+            case CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED:
+                ret = SIM_SERVICE_PROVIDER_PERSO;
+                break;
+            case CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED:
+                ret = SIM_SERVICE_PROVIDER_PERSO_PUK;
+                break;
+            case CME_PH_SIMLOCK_PIN_REQUIRED: /* PUK not in use by modem */
+                ret = SIM_SIM_PERSO;
+                break;
+            case CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED:
+                ret = SIM_CORPORATE_PERSO;
+                break;
+            case CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED:
+                ret = SIM_CORPORATE_PERSO_PUK;
+                break;
+            default:
+                ret = SIM_NOT_READY;
+                break;
         }
         return ret;
     }
@@ -625,6 +705,11 @@ static SIM_Status getSIMStatus(void)
 
     if (0 == strcmp(cpinResult, "READY")) {
         ret = SIM_READY;
+        if (getSimLockStatus(&status,&times) < 0)
+            goto done;
+        if (status == 1 || status == 3) {
+            ret = SIM_NETWORK_PERSO;
+        }
     } else if (0 == strcmp(cpinResult, "SIM PIN")) {
         ret = SIM_PIN;
     } else if (0 == strcmp(cpinResult, "SIM PUK")) {
@@ -681,41 +766,39 @@ static void pollSIMState(void *param)
         return;
 
     switch (getSIMStatus()) {
-    case SIM_NOT_READY:
-        ALOGI("SIM_NOT_READY, poll for sim state.");
-        enqueueRILEvent(pollSIMState, NULL, &TIMEVAL_SIMPOLL);
-        return;
+        case SIM_NOT_READY:
+            ALOGI("SIM_NOT_READY, poll for sim state.");
+            enqueueRILEvent(pollSIMState, NULL, &TIMEVAL_SIMPOLL);
+            return;
 
-    case SIM_PIN2:
-    case SIM_PUK2:
-    case SIM_PUK2_PERM_BLOCKED:
-    case SIM_READY:
-        setRadioState(RADIO_STATE_SIM_READY);
-        return;
-    case SIM_ABSENT:
-    case SIM_PIN:
-    case SIM_PUK:
-    case SIM_NETWORK_PERSO:
-    case SIM_NETWORK_SUBSET_PERSO:
-    case SIM_SERVICE_PROVIDER_PERSO:
-    case SIM_CORPORATE_PERSO:
-    case SIM_SIM_PERSO:
-    case SIM_STERICSSON_LOCK:
-    case SIM_BLOCKED:
-    case SIM_PERM_BLOCKED:
-    case SIM_NETWORK_PERSO_PUK:
-    case SIM_NETWORK_SUBSET_PERSO_PUK:
-    case SIM_SERVICE_PROVIDER_PERSO_PUK:
-    case SIM_CORPORATE_PERSO_PUK:
-    /* pass through, do not break */
-    default:
-        setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
-        return;
+        case SIM_PIN2:
+        case SIM_PUK2:
+        case SIM_PUK2_PERM_BLOCKED:
+        case SIM_READY:
+            setRadioState(RADIO_STATE_SIM_READY);
+            return;
+        case SIM_ABSENT:
+        case SIM_PIN:
+        case SIM_PUK:
+        case SIM_NETWORK_PERSO:
+        case SIM_NETWORK_SUBSET_PERSO:
+        case SIM_SERVICE_PROVIDER_PERSO:
+        case SIM_CORPORATE_PERSO:
+        case SIM_SIM_PERSO:
+        case SIM_STERICSSON_LOCK:
+        case SIM_BLOCKED:
+        case SIM_PERM_BLOCKED:
+        case SIM_NETWORK_PERSO_PUK:
+        case SIM_NETWORK_SUBSET_PERSO_PUK:
+        case SIM_SERVICE_PROVIDER_PERSO_PUK:
+        case SIM_CORPORATE_PERSO_PUK:
+            /* pass through, do not break */
+        default:
+            setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
+            return;
     }
 }
 
-
-
 static void sendCallStateChanged(void *param)
 {
     RIL_onUnsolicitedResponse (
@@ -725,9 +808,8 @@ static void sendCallStateChanged(void *param)
 
 
 static int clccStateToRILState(int state, RIL_CallState *p_state)
-
 {
-    switch(state) {
+    switch (state) {
         case 0: *p_state = RIL_CALL_ACTIVE;   return 0;
         case 1: *p_state = RIL_CALL_HOLDING;  return 0;
         case 2: *p_state = RIL_CALL_DIALING;  return 0;
@@ -868,16 +950,20 @@ static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t)
 
     ALOGI("Calls=%d,Valid=%d", countCalls, countValidCalls);
 
-    /* If some voice calls are active, enable audio tunnel */
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
+            countValidCalls * sizeof (RIL_Call *));
+
+    /* Start/stop audio tunnel if a valid voice call is detected -
+       This will restart the audiotunnel when we preventively shut it
+       down after user hangs call (but should be restarted if in conference
+       Stopping should be handled by the connection end notification, but,
+       just in case, we also handle it here*/
     if (countValidCalls) {
-        startAudioTunnel();
+        startAudioTunnel(NULL);
     } else {
-        stopAudioTunnel();
+        stopAudioTunnel(NULL);
     }
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
-            countValidCalls * sizeof (RIL_Call *));
-
     at_response_free(atResponse);
 
     if (needRepoll) {
@@ -946,204 +1032,770 @@ error:
 
 
 /* wait for a propertyvalue change */
-static int wait_for_property(const char *name, const char *desired_value, int maxwait)
+static int wait_for_property(const char *name, const char *desired_value, int maxwait, int allowempty)
 {
     char value[PROPERTY_VALUE_MAX] = {'\0'};
-    int maxnaps = maxwait / 1;
+    int maxnaps = maxwait;
 
     if (maxnaps < 1) {
         maxnaps = 1;
     }
 
     while (maxnaps-- > 0) {
-        usleep(1000000);
         if (property_get(name, value, NULL)) {
-            if (desired_value == NULL ||
-                    strcmp(value, desired_value) == 0) {
-                return 0;
+            if (allowempty || (!allowempty && value[0]!=0)) {
+                if (desired_value == NULL ||
+                        strcmp(value, desired_value) == 0) {
+                    return 0;
+                }
             }
         }
+        sleep(1);
     }
     return -1; /* failure */
 }
 
-static int killConn(const char * cid)
+/* Write an string to the modem */
+static int dial_at_modem(const char* cmd, int skipanswerwait)
 {
-    int err;
-    int fd;
-    int i=0;
+    int i, n, ret;
+    int fd = -1;
+    char buf[64+1];
+
+    ALOGD("dial_at_modem: opening modem %s", ppp_iface_dev);
+    do {
+        fd = open( ppp_iface_dev, O_RDWR | O_NOCTTY | O_NDELAY); /* nonblocking */
+    } while (fd < 0 && errno == EINTR);
+
+    if (fd < 0) {
+        ALOGE("could not open modem %s: %s", ppp_iface_dev, strerror(errno) );
+        return -1;
+    }
+
+    // disable echo on serial lines and set a 10 second timeout
+    if ( isatty( fd ) ) {
+        struct termios  ios;
+        tcgetattr( fd, &ios );
+        ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
+        ios.c_oflag &= (~ONLCR); /* Stop \n -> \r\n translation on output */
+        ios.c_iflag &= (~(ICRNL | INLCR)); /* Stop \r -> \n & \n -> \r translation on input */
+        ios.c_iflag |= (IGNCR | IXOFF);  /* Ignore \r & XON/XOFF on input */
+        ios.c_cc[VTIME] = 10; /* Timeout in 1/10 of a second */
+        ios.c_cc[VMIN] = 0; /* Minimum number of chars returned: 0*/
+        tcsetattr( fd, TCSANOW, &ios );
+    }
+
+    // Discard all pending data */
+    tcflush(fd, TCIOFLUSH);
+
+    // If hangup sequence, wait a bit...
+    if (!strcmp(cmd,"+++")) {
+        sleep(1);
+    }
+
+    // Write command to modem
+    ALOGD("dial_at_modem: writing command: %s", cmd);
+    i = strlen(cmd);
+    n = 0;
+    do {
+        ret = write(fd, cmd + n, i - n);
+        if (ret < 0 && errno == EINTR)
+            continue;
+        if (ret < 0) {
+            ALOGE("Error writing to modem: %s", strerror(errno) );
+            close(fd);
+            return -1;
+        }
+        n += ret;
+    } while (n < i);
 
-    D("killConn");
+    // Force all the data to be transmitted
+    tcdrain(fd);
+
+    // If hangup sequence, wait a bit... and we are done. Modem won't answer it
+    if (!strcmp(cmd,"+++")) {
+        sleep(1);
+
+        // Leave line ready */
+        write(fd, "\r\n", 2);
+        tcdrain(fd);
 
-#if 0
-    while ((fd = open("/sys/class/net/ppp0/ifindex",O_RDONLY)) > 0)
-    {
-        if(i%5 == 0)
-            system("killall pppd");
-        if(i>25)
-            goto error;
-        i++;
         close(fd);
-        sleep(2);
-    }
-#elif 0
-    // Requires root access...
-    property_set("ctl.stop", "pppd_gprs");
-    if (wait_for_property("init.svc.pppd_gprs", "stopped", 10) < 0) {
-        goto error;
+        return 0;
     }
-#endif
 
-    D("killall pppd finished");
+    // If we must skip waiting for an answer
+    if (skipanswerwait) {
+        close(fd);
+        return 0;
+    }
 
-    err = at_send_command("AT+CGACT=0,%s", cid);
-    if (err != AT_NOERROR)
-        goto error;
+    // Read answer with timeout
+    ALOGD("dial_at_modem: waiting for response");
+    do {
 
-    at_send_command("ATH");
-    return 0;
+        /* Receive a line with timeout */
+        int waitc = 5;
+        n = 0;
+        do {
+            ret = read(fd, &buf[n], 1);
+            if (ret < 0 && (errno == EINTR || errno == EAGAIN))
+                continue;
 
-error:
-    return -1;
-}
+            if (ret < 0) {
+                ALOGE("dial_at_modem: Error reading from serial port: %d",errno);
+                close(fd);
+                return -1;
+            }
 
+            if (ret == 0) {
+                waitc --;
+                if (waitc <= 0) {
+                    ALOGE("dial_at_modem: No answer from modem");
+                    close(fd);
+                    return -1;
+                }
 
-//static char userPassStatic[512] = "preload";
+                // not timed out yet, sleep a second
+                sleep(1);
+            } else {
+                /* Something received, restart timeout */
+                waitc = 5;
+            }
 
-static void requestSetupDefaultPDP(void *data, size_t datalen, RIL_Token t)
-{
-    const char *apn;
-    const char *user = NULL;
-    const char *pass = NULL;
-    char pppdcmd[512] = "/system/bin/pppd ";
-    int err;
-    int fd, pppstatus,i;
-    FILE *pppconfig;
-    size_t cur = 0;
-    ssize_t written, rlen;
-    char status[32] = {0};
-    char *buffer;
-    long buffSize, len;
-    int retry = 10;
-
-    int n = 1;
-    RIL_Data_Call_Response_v6 responses;
-    char ppp_dnses[(PROPERTY_VALUE_MAX * 2) + 3] = {'\0'};
-    char ppp_local_ip[PROPERTY_VALUE_MAX] = {'\0'};
-    char ppp_dns1[PROPERTY_VALUE_MAX] = {'\0'};
-    char ppp_dns2[PROPERTY_VALUE_MAX] = {'\0'};
-    char ppp_gw[PROPERTY_VALUE_MAX] = {'\0'};
+            // Count of read chars
+            n += ret;
+        } while (n < 64 && buf[n-1] != '\n');
 
-    apn = ((const char **)data)[2];
-    user = ((char **)data)[3];
-    if (user == NULL || strlen(user) < 2) {
-        user = "dummy";
-    }
+        /*buf[n] = 0; ALOGD("dial_at_modem: read %d bytes ['%s']",n,&buf[0]);*/
 
-    pass = ((char **)data)[4];
-    if (pass == NULL || strlen(pass) < 2) {
-        pass = "dummy";
-    }
+        // Remove the trailing spaces
+        while (n > 0 && buf[n-1] <= ' '  && buf[n-1] != 0)
+            n--;
+        buf[n] = 0;
 
-    D("requesting data connection to APN '%s'", apn);
+        // Remove the leading spaces
+        n = 0;
+        while (buf[n]<= ' '  && buf[n] != 0)
+            n++;
 
-    // Make sure there is no existing connection or pppd instance running
-    if (killConn("1") < 0) {
-        ALOGE("killConn Error!");
-        goto error;
-    }
+    } while (buf[0] == 0); // Ignore blank lines
 
-    /* Switch radio ON */
-    err = at_send_command("AT^RFSWITCH=1");
-    err = at_send_command("AT+CFUN=1");
+    close(fd);
 
-    /* Define the PDP context */
-    err = at_send_command("AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);
+    ALOGD("dial_at_modem: got answer : '%s'",&buf[n]);
+    if (strstr(&buf[n],"OK")) return 0;
+    if (strstr(&buf[n],"CONNECT")) return 0;
 
-    /* Set required QoS params to default */
-    err = at_send_command("AT+CGQREQ=1");
+    return -1;
+}
 
-    /* Set minimum QoS params to default */
-    err = at_send_command("AT+CGQMIN=1");
+static int killConn(const char* cididx)
+{
+    /* Leave NDIS mode */
+    if (!pppSupported())
+        at_send_command("AT^NDISDUP=%s,0",cididx);
 
-    /* packet-domain event reporting */
-    err = at_send_command("AT+CGEREP=1,0");
+    /* Leave Data context mode */
+    at_send_command("AT+CGACT=0,%s", cididx);
 
-    /* Hangup anything that's happening there now */
-    err = at_send_command("AT+CGACT=0,1");
+    /* Hang up */
+    at_send_command("ATH");
 
-    /* Start data on PDP context 1 */
-    err = at_send_command("ATD*99***1#");
-//  if (err != AT_NOERROR) {
-//      goto error;
-//  }
-    sleep(2); //Wait for the modem to finish
+    /* Kill pppd daemon (just in case)*/
+    system("killall pppd");
 
-    // set up the pap/chap secrets file
-//  sprintf(userpass, "%s * %s", user, pass);
+    /* Hang up modem, if needed */
+    //dial_at_modem("+++",1);
+    dial_at_modem("ATH\r\n",1);
 
-    /* start the gprs pppd */
-#if 1
-    property_get("rild.ppp.tty", pppdcmd + strlen(pppdcmd), "/dev/ttyUSB0");
-    strcat(pppdcmd, " call gprs");
-    system(pppdcmd);
-#else
-    // Requires root access...
-    property_set("ctl.start", "ppp");
-    if (wait_for_property("init.svc.ppp", "running", 10) < 0) {
-        ALOGE("Timeout waiting init.svc.ppp - giving up!");
-        goto error;
+    /* Bring down all interfaces */
+    if (ifc_init() == 0) {
+        ifc_down(RNDIS_IFACE);
+        ifc_down(PPP_IFACE);
+        ifc_close();
     }
-#endif
 
-    sleep(10); // Allow time for ip-up to complete
+    return 0;
+}
 
-    if (wait_for_property("net.ppp0.local-ip", NULL, 10) < 0) {
-        ALOGE("Timeout waiting net.ppp0.local-ip - giving up!");
-        goto error;
-    }
+#define LOG_FILE_DIR    "/dev/log/"
 
-    property_get("net.ppp0.local-ip", ppp_local_ip, NULL);
-    property_get("net.dns1", ppp_dns1, NULL);
-    property_get("net.dns2", ppp_dns2, NULL);
-    property_get("net.ppp0.gw", ppp_gw, NULL);
-    sprintf(ppp_dnses, "%s %s", ppp_dns1, ppp_dns2);
+struct lc_entry {
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
+        struct logger_entry entry __attribute__((aligned(4)));
+    };
+};
 
-    ALOGI("Got net.ppp0.local-ip: %s", ppp_local_ip);
+/* Get the connection data used by pppd from the android logcat */
+int get_pppd_info(struct timeval* from, char* local_ip, char* dns1, char* dns2, char* gw)
+{
+    struct lc_entry* lce;
 
-    responses.status = 0;
-    responses.suggestedRetryTime = -1;
-    responses.cid = 1;
-    responses.active = 2;
-    responses.type = (char*)"PPP";
-    responses.ifname = (char*)PPP_TTY_PATH;
-    responses.addresses = ppp_local_ip;
-    responses.dnses = ppp_dnses;
-    responses.gateways = ppp_gw;
+    const char mainlog[] = LOG_FILE_DIR "main";
+    const char pppd_str[] = "pppd";
+    const char local_ip_str[] = "local  IP address ";
+    const char remote_ip_str[] = "remote IP address ";
+    const char primary_dns_str[] = "primary   DNS address ";
+    const char secondary_dns_str[] = "secondary DNS address ";
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
-    return;
+    int fd;
+    int result;
+    fd_set readset;
+    int search_tmout = 500; //
 
-error:
-    ALOGE("Unable to setup PDP");
-    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    local_ip[0] = 0;
+    dns1[0] = 0;
+    dns2[0] = 0;
+    gw[0] = 0;
 
-}
+    lce = malloc(sizeof(struct lc_entry));
+    if (!lce) {
+        ALOGE("Failed to allocate logcat entry buffer");
+        return -1;
+    }
 
-/* CHECK There are several error cases if PDP deactivation fails
- * 24.008: 8, 25, 36, 38, 39, 112
- */
-static void requestDeactivateDefaultPDP(void *data, size_t datalen, RIL_Token t)
-{
-    char * cid;
+    fd = open(mainlog, O_RDONLY);
+    if (fd < 0) {
+        ALOGE("Unable to open log device '%s': %s", mainlog, strerror(errno));
+        free(lce);
+        return -1;
+    }
 
-    D("requestDeactivateDefaultPDP()");
+    /*ALOGD("filter: sec:%d, usec:%d", from->tv_sec, from->tv_usec);*/
 
-    cid = ((char **)data)[0];
-    if (killConn(cid) < 0)
-        goto error;
+    while (1) {
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+        do {
+            struct timeval timeout = { 0, 10000 /* 10ms */ };
+            FD_ZERO(&readset);
+            FD_SET(fd, &readset);
+            result = select(fd + 1, &readset, NULL, NULL, &timeout);
+        } while (result < 0 && errno == EINTR);
+
+        // Wait until we find something...
+        if (result == 0) {
+            if (search_tmout > 0) {
+                search_tmout --;
+                continue;
+            } else
+                break;
+        }
+
+        if (result > 0 && FD_ISSET(fd, &readset)) {
+
+            /* NOTE: driver guarantees we read exactly one full entry */
+            int ret = read(fd, lce, LOGGER_ENTRY_MAX_LEN);
+            if (ret < 0) {
+                if (errno == EINTR) {
+                    continue;
+                }
+                if (errno == EAGAIN) {
+                    continue;
+                }
+                ALOGE("logcat read");
+                continue;
+            }
+            else if (!ret) {
+                ALOGE("read: Unexpected EOF!");
+                continue;
+            }
+            else if (lce->entry.len != ret - sizeof(struct logger_entry)) {
+                ALOGE("read: unexpected length. Expected %d, got %d",
+                        lce->entry.len, ret - sizeof(struct logger_entry));
+                continue;
+            }
+
+            lce->entry.msg[lce->entry.len] = '\0';
+
+            /*
+             * format: <priority:1><tag:N>\0<message:N>\0
+             *
+             * tag str
+             *   starts at buf->msg+1
+             * msg
+             *   starts at buf->msg+1+len(tag)+1
+             *
+             * The message may have been truncated by the kernel log driver.
+             * When that happens, we must null-terminate the message ourselves.
+             */
+
+            /*ALOGD("entry: tag:%d[%c], sec:%d, usec:%d, n:%s, m:%s", lce->entry.msg[0], lce->entry.msg[0], lce->entry.sec, lce->entry.nsec/1000, &lce->entry.msg[1],(&lce->entry.msg[1])+strlen(&lce->entry.msg[1])+1); */
+
+            // We are interested in pppd entries with I priority newer than specified
+            if ((lce->entry.msg[0] == 'i' || lce->entry.msg[0] == 'I' || lce->entry.msg[0] == 4) &&
+                (lce->entry.sec > from->tv_sec ||
+                    (lce->entry.sec == from->tv_sec && (lce->entry.nsec/1000) >= from->tv_usec)) &&
+                !strcmp(&lce->entry.msg[1],pppd_str)) {
+                char * pos = NULL;
+
+                // Dealing with PPPD entries in logcat - Get a pointer to the message
+                char * msg = (&lce->entry.msg[1]) + strlen(&lce->entry.msg[1]) + 1;
+
+                // Strip leading spaces
+                while (*msg != 0 && *msg <= ' ') msg++;
+
+                // And also strip trailing spaces...
+                pos = msg + strlen(msg);
+                while (pos != msg && pos[-1] <= ' ') pos--;
+                *pos = 0;
+
+                // An entry we are interested in ?
+                if ((pos = strstr(msg,local_ip_str)) != NULL) {
+                    strcpy(local_ip,msg + sizeof(local_ip_str) - 1);
+                    strcpy(gw,msg + sizeof(local_ip_str) - 1);
+                } else
+                if ((pos = strstr(msg,remote_ip_str)) != NULL) {
+                    // We found the remote_ip address ... Give no more than 3 seconds for the next entry to appear
+                    // (those entries are not mandatory)
+                    search_tmout = 300;
+                } else
+                if ((pos = strstr(msg,primary_dns_str)) != NULL) {
+                    strcpy(dns1,msg + sizeof(primary_dns_str) - 1);
+                } else
+                if ((pos = strstr(msg,secondary_dns_str)) != NULL) {
+                    strcpy(dns2,msg + sizeof(secondary_dns_str) - 1);
+                }
+            }
+
+            // If we have all required data, break now!
+            if (local_ip[0] && gw[0] && dns1[0] && dns2[0]) {
+                break;
+            }
+        }
+    }
+
+    close(fd);
+    free(lce);
+
+    // Return if we succeeded or not
+    return local_ip[0] ? 0 : -1;
+}
+
+
+/* Setup connection using PPP */
+static int setupPPP(RIL_Token t,const char* ctxid,const char* user,const char* pass)
+{
+    int err;
+    char* cmd = NULL;
+    const char* fmt;
+    in_addr_t addr;
+    in_addr_t mask;
+    unsigned flags = 0;
+    int ctr = 10;
+    struct timeval from_tm;
+
+    RIL_Data_Call_Response_v6 responses;
+    char ppp_ifname[PROPERTY_VALUE_MAX] = {'\0'};
+    char ppp_local_ip[PROPERTY_VALUE_MAX] = {'\0'};
+    char ppp_dns1[PROPERTY_VALUE_MAX] = {'\0'};
+    char ppp_dns2[PROPERTY_VALUE_MAX] = {'\0'};
+    char ppp_dnses[(PROPERTY_VALUE_MAX * 2) + 3] = {'\0'};
+    char ppp_gw[PROPERTY_VALUE_MAX] = {'\0'};
+    char pbuf[32] = {'\0'};
+
+
+    ALOGD("Trying to setup PPP connnection...");
+
+#if 1
+    /* PDP context activation */
+    //err = at_send_command("AT+CGACT=0,%s",ctxid);
+    err = at_send_command("ATD*99***%s#", ctxid);
+#else
+    /* Try just with data context activation */
+    asprintf(&cmd,"AT+CGDATA=\"PPP\",%s\r\n",ctxid);
+    err = dial_at_modem(cmd,0);
+    free(cmd);
+    if (err) {
+        /* If failed, retry with dial command */
+        asprintf(&cmd,"ATD*99***%s#\r\n",ctxid);
+        err = dial_at_modem(cmd,0);
+        free(cmd);
+        if (err) {
+            ALOGE("Failed to dial");
+            return -1;
+        }
+    }
+#endif
+
+    /* Wait for the modem to finish */
+    sleep(2);
+
+    /* original options
+    "nodetach debug noauth defaultroute usepeerdns "
+    "connect-delay 1000 "
+    "user NotUsed@nobody.com password NotUsed "
+    "crtscts lcp-echo-failure 0 lcp-echo-interval 0 ipcp-max-configure 30 "
+    "ipcp-max-failure 30 ipcp-max-terminate 10 novj linkname ril";
+    */
+
+#if 0
+    /* start the gprs pppd - pppd must be suid root */
+    if (user == NULL || user[0] == 0 ||
+        pass == NULL || pass[0] == 0 ) {
+
+        fmt = "/system/bin/pppd %s "
+        "115200 "
+        "crtscts modem "
+        "linkname ril%s "
+        "noauth "
+        "user %s password %s "
+        "defaultroute usepeerdns noipdefault "
+        "novj novjccomp nobsdcomp "
+        "ipcp-accept-remote ipcp-accept-local "
+        "dump debug "
+        "lcp-echo-failure 0 lcp-echo-interval 0 ipcp-max-configure 30 "
+        "ipcp-max-failure 30 ipcp-max-terminate 10";
+
+    } else {
+
+        fmt = "/system/bin/pppd %s "
+        "115200 "
+        "crtscts modem "
+        "linkname ril%s "
+        "user %s password %s "
+        "defaultroute usepeerdns noipdefault "
+        "novj novjccomp nobsdcomp "
+        "ipcp-accept-remote ipcp-accept-local "
+        "dump debug "
+        "lcp-echo-failure 0 lcp-echo-interval 0 ipcp-max-configure 30 "
+        "ipcp-max-failure 30 ipcp-max-terminate 10";
+    }
+
+    asprintf(&cmd,fmt,ppp_iface_dev,ctxid, ((user && user[0])? user: "guest"), ((pass && pass[0])? pass: "guest") );
+#else
+    fmt = "/system/bin/pppd %s call gprs";
+    asprintf(&cmd, fmt, ppp_iface_dev);
+#endif
+
+    ALOGD("Starting pppd w/command line: '%s'", cmd);
+
+    // Get current time
+    gettimeofday(&from_tm,NULL);
+
+    // Start PPPD
+    system(cmd);
+    free(cmd);
+
+#if 0
+    /* Try not to depend on ip-up/down scripts ... */
+
+    // Wait until network interface is up and running
+    if (ifc_init() < 0) {
+        ALOGE("Failed initialization of net ifc");
+        return -1;
+    }
+
+    ALOGD("Waiting until net ifc %s is up", PPP_IFACE);
+    ctr = 20;
+    do {
+        sleep(1); // wait one second...
+        flags = 0;
+        ifc_get_info(PPP_IFACE, &addr, &mask, &flags);
+    } while (--ctr > 0 && !(flags & IFF_UP));
+    ifc_close();
+
+    if (ctr <= 0) {
+        ALOGE("Net ifc %s was never upped!", PPP_IFACE);
+        return -1;
+    }
+
+    /* Get PPP information by reading and parsing the PPPD log */
+    if (get_pppd_info(&from_tm, ppp_local_ip, ppp_dns1, ppp_dns2, ppp_gw) < 0) {
+        ALOGE("Unable to get dns/gw");
+        return -1;
+    }
+
+    strcpy(ppp_ifname,PPP_IFACE);
+
+#elif 0
+    // Wait until ppp ip-up script has completely executed...
+    sprintf(pbuf,"net.ril%s.if",ctxid);
+    if (wait_for_property(pbuf, NULL, 20, 0) < 0) {
+        ALOGE("Timeout waiting %s - giving up!", pbuf);
+        return -1;
+    }
+    property_get(pbuf, ppp_ifname, NULL);
+
+    // Get local IP
+    sprintf(pbuf,"net.ril%s.local-ip",ctxid);
+    property_get(pbuf, ppp_local_ip, NULL);
+
+    sprintf(pbuf,"net.ril%s.dns1",ctxid);
+    property_get(pbuf, ppp_dns1, NULL);
+
+    sprintf(pbuf,"net.ril%s.dns2",ctxid);
+    property_get(pbuf, ppp_dns2, NULL);
+
+    sprintf(pbuf,"net.ril%s.gw",ctxid);
+    property_get(pbuf, ppp_gw, NULL);
+
+#else
+    strcpy(ppp_ifname,PPP_IFACE);
+    strcpy(pbuf, "net." PPP_IFACE ".local-ip");
+    if (wait_for_property(pbuf, NULL, 20, 0) < 0) {
+        ALOGE("Timeout waiting %s - giving up!", pbuf);
+        return -1;
+    }
+    property_get("net.ppp0.local-ip", ppp_local_ip, NULL);
+    property_get("net.ppp0.gw", ppp_gw, NULL);
+    property_get("net.dns1", ppp_dns1, NULL);
+    property_get("net.dns2", ppp_dns2, NULL);
+
+#endif
+
+    sprintf(ppp_dnses, "%s %s", ppp_dns1, ppp_dns2);
+
+    ALOGI("Got ifname: %s, local-ip: %s, dns1: %s, dns2: %s, gw: %s",
+            ppp_ifname, ppp_local_ip, ppp_dns1, ppp_dns2, ppp_gw);
+
+    responses.status = 0;
+    responses.suggestedRetryTime = -1;
+    responses.cid = (ctxid[0] - '0');
+    responses.active = 2;
+    responses.type = (char*)"PPP";
+    responses.ifname    = ppp_ifname;
+    responses.addresses = ppp_local_ip;
+    responses.dnses     = ppp_dnses;
+    responses.gateways  = ppp_gw;
+
+    using_rndis = 0;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
+    return 0;
+}
+
+/* Converts a hex encoded addr to an std addr */
+static void str2addr(char* addr,const char* str)
+{
+    unsigned int val = (unsigned int) strtoul(str, NULL, 16);
+    sprintf(addr,"%u.%u.%u.%u",
+            (val & 0x000000ffU),
+            (val & 0x0000ff00U) >> 8U,
+            (val & 0x00ff0000U) >> 16U,
+            (val & 0xff000000U) >> 24U);
+}
+
+/* Setup connection using NDIS */
+static int setupNDIS(RIL_Token t,const char* ctxid)
+{
+    ATResponse *atResponse = NULL;
+    RIL_Data_Call_Response_v6 responses;
+    char rndis_dnses[64 + 3] = {'\0'};
+    char rndis_local_ip[32] = {'\0'};
+    char rndis_dns1[32] = {'\0'};
+    char rndis_dns2[32] = {'\0'};
+    char rndis_gw[32] = {'\0'};
+
+    in_addr_t in_addr;
+    in_addr_t in_gateway;
+
+    int err;
+    char *line;
+    char *ip = NULL;
+    char *netmask = NULL;
+    char *gateway = NULL;
+    char *unk = NULL;
+    char *dns1 = NULL;
+    char *dns2 = NULL;
+
+    ALOGD("Trying to setup NDIS connnection...");
+
+    /* Enter data state using context #1 as NDIS */
+    err = at_send_command("AT^NDISDUP=%s,1",ctxid);
+    if (err != AT_NOERROR)
+        return -1;
+
+    /* Leave 10 seconds for startup */
+    sleep(10);
+
+    /* Check DHCP status */
+    err = at_send_command_singleline("AT^DHCP?", "^DHCP:", &atResponse);
+    if (err != AT_NOERROR)
+        goto error;
+
+    line = atResponse->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &ip);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &netmask);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &gateway);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &unk);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &dns1);
+    if (err < 0) goto error;
+
+    err = at_tok_nextstr(&line, &dns2);
+    if (err < 0) goto error;
+
+    ALOGD("IP: %s, netmask: %s, gateway: %s, dns1:%s, dns2:%s",ip,netmask,gateway,dns1,dns2);
+
+    str2addr(rndis_local_ip, ip);
+    if (inet_pton(AF_INET, rndis_local_ip, &in_addr) <= 0) {
+        ALOGE("%s() inet_pton() failed for %s!", __func__, rndis_local_ip);
+        goto error;
+    }
+
+    str2addr(rndis_dns1, dns1);
+    str2addr(rndis_dns2, dns2);
+    sprintf(rndis_dnses, "%s %s", rndis_dns1, rndis_dns2);
+
+    str2addr(rndis_gw, gateway);
+    if (inet_pton(AF_INET, rndis_gw, &in_gateway) <= 0) {
+        ALOGE("%s() inet_pton() failed for %s!", __func__, rndis_gw);
+        goto error;
+    }
+
+    at_response_free(atResponse);
+
+    responses.status = 0;
+    responses.suggestedRetryTime = -1;
+    responses.cid = 1;
+    responses.active = 2;
+    responses.type = (char*)"RNDIS";
+    responses.ifname = (char*)RNDIS_IFACE;
+    responses.addresses = rndis_local_ip;
+    responses.dnses     = rndis_dnses;
+    responses.gateways  = rndis_gw;
+
+    /* Don't use android netutils. We use our own and get the routing correct.
+     * Carl Nordbeck */
+    if (ifc_configure(RNDIS_IFACE, in_addr, in_gateway))
+        ALOGE("%s() Failed to configure the interface %s", __func__, RNDIS_IFACE);
+
+    using_rndis = 1;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
+    return 0;
+
+error:
+    ALOGE("Failed to start NDIS mode");
+
+    at_response_free(atResponse);
+    return -1;
+}
+
+/* Query if modem supports PPP. Otherwise, RNDIS will be used */
+static int pppSupported(void)
+{
+    ATResponse *atResponse = NULL;
+
+    int err;
+    int supp_mode = 0; // PPP
+    char *line;
+
+    ALOGD("Identifying modem capabilities...");
+
+    /* Check Modem capabilities */
+    err = at_send_command_singleline("AT^DIALMODE?", "^DIALMODE:", &atResponse);
+    if (err != AT_NOERROR)
+        goto error;
+
+    line = atResponse->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &supp_mode);
+    if (err < 0) goto error;
+
+    ALOGD("Modem mode: %d [0=ppp,1=ndis,2=ppp&ndis]",supp_mode);
+
+    at_response_free(atResponse);
+
+    return supp_mode != 1; // ppp supported
+
+error:
+    ALOGD("Assuming PPP mode");
+    at_response_free(atResponse);
+    return 1;
+}
+
+static void requestSetupDefaultPDP(void *data, size_t datalen, RIL_Token t)
+{
+    const char *apn;
+    const char *user = NULL;
+    const char *pass = NULL;
+    int err;
+    const char* ctxid = "1";
+    int use_ppp;
+
+    apn = ((const char **)data)[2];
+    user = ((char **)data)[3];
+    if (user == NULL || strlen(user) < 2) {
+        user = "dummy";
+    }
+
+    pass = ((char **)data)[4];
+    if (pass == NULL || strlen(pass) < 2) {
+        pass = "dummy";
+    }
+
+    /* Check if PPP is supported */
+    use_ppp = pppSupported();
+
+    D("requesting data connection to APN '%s' use_ppp=%d", apn, use_ppp);
+
+    // Make sure there is no existing connection
+    killConn(ctxid);
+
+
+    /* packet-domain event reporting */
+    err = at_send_command("AT+CGEREP=1,0");
+
+    /* Define the PDP context #1*/
+    err = at_send_command("AT+CGDCONT=%s,\"IP\",\"%s\"",ctxid, apn);
+
+    /* Set required QoS params to default */
+    err = at_send_command("AT+CGQREQ=%s",ctxid);
+
+    /* Set minimum QoS params to default */
+    err = at_send_command("AT+CGQMIN=%s",ctxid);
+
+    /* Attach to GPRS network */
+    err = at_send_command("AT+CGATT=1");
+
+    if (use_ppp) {
+        if (setupPPP(t,ctxid,user,pass) < 0) {
+            goto error;
+        }
+    } else {
+        if (setupNDIS(t,ctxid) < 0) {
+            goto error;
+        }
+    }
+
+    ALOGD("Data connection established!");
+    return;
+
+error:
+    ALOGE("Unable to setup PDP");
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+}
+
+/* CHECK There are several error cases if PDP deactivation fails
+ * 24.008: 8, 25, 36, 38, 39, 112
+ */
+static void requestDeactivateDefaultPDP(void *data, size_t datalen, RIL_Token t)
+{
+    char * cid;
+
+    D("requestDeactivateDefaultPDP()");
+
+    cid = ((char **)data)[0];
+    if (killConn(cid) < 0)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
     return;
 
 error:
@@ -1204,7 +1856,7 @@ static void requestOrSendPDPContextList(RIL_Token *t)
         responses[i].cid = -1;
         responses[i].active = -1;
         responses[i].type = (char*)"";
-        responses[i].ifname = (char*)PPP_TTY_PATH;
+        responses[i].ifname = using_rndis ? (char*)RNDIS_IFACE : (char*)PPP_IFACE;
         responses[i].addresses = (char*)"";
         responses[i].dnses = (char*)"";
         responses[i].gateways = (char*)"";
@@ -1277,7 +1929,7 @@ static void requestOrSendPDPContextList(RIL_Token *t)
         if (err < 0)
             goto error;
 
-        responses[i].ifname = (char*)PPP_TTY_PATH;
+        responses[i].ifname = using_rndis ? (char*)RNDIS_IFACE : (char*)PPP_IFACE;
 
         err = at_tok_nextstr(&line, &out);
         if (err < 0)
@@ -1291,6 +1943,27 @@ static void requestOrSendPDPContextList(RIL_Token *t)
     at_response_free(atResponse);
     atResponse = NULL;
 
+    /* Make sure interface is UP and running. If not, invalidate datacall to
+       force Android to reconnect - This will happen when resuming from suspend, as pppd
+       has probably ended as a consequence of the USB bus being suspended and the terminal
+       disappearing. So, that is why we have this check here. Not only the modem has to
+       report an active connection, also linux has to export an active net interface !*/
+    if (ifc_init() >= 0) {
+        in_addr_t addr;
+        in_addr_t mask;
+        unsigned flags = 0;
+        ifc_get_info( responses[i].ifname, &addr, &mask, &flags);
+        if (!(flags & IFF_UP)) {
+            for (i = 0; i < n; i++) {
+                if (responses[i].active) {
+                    ALOGD("DataCall cid:%d forced to inactive, as associated interface [%s] is DOWN", responses[i].cid, responses[i].ifname );
+                    responses[i].active = 0;
+                }
+            }
+        }
+        ifc_close();
+    }
+
     if (t != NULL)
         RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
                 n * sizeof(RIL_Data_Call_Response_v6));
@@ -1440,13 +2113,12 @@ static struct held_pdu *dequeue_held_pdu(void)
 
 static void enqueue_held_pdu(char type, const char *sms_pdu)
 {
-    struct held_pdu *hpdu = (struct held_pdu *) malloc(sizeof(*hpdu));
+    struct held_pdu *hpdu = (struct held_pdu *) calloc(1, sizeof(*hpdu));
     if (hpdu == NULL) {
         ALOGE("%s() failed to allocate memory!", __func__);
         return;
     }
 
-    memset(hpdu, 0, sizeof(*hpdu));
     hpdu->type = type;
     hpdu->sms_pdu = strdup(sms_pdu);
     if (NULL == hpdu->sms_pdu) {
@@ -1454,9 +2126,9 @@ static void enqueue_held_pdu(char type, const char *sms_pdu)
         return;
     }
 
-    if (s_held_pdus == NULL)
+    if (s_held_pdus == NULL) {
        s_held_pdus = hpdu;
-    else {
+    else {
         struct held_pdu *p = s_held_pdus;
         while (p->next != NULL)
             p = p->next;
@@ -1514,12 +2186,12 @@ exit:
  * SIM SMS storage area is full, cannot receive
  * more messages until memory freed
  */
-void onNewSmsIndication(void)
+static void onNewSmsIndication(void)
 {
     enqueueRILEvent(isSimSmsStorageFull, NULL, NULL);
 }
 
-void onNewSms(const char *sms_pdu)
+static void onNewSms(const char *sms_pdu)
 {
     pthread_mutex_lock(&s_held_pdus_mutex);
 
@@ -1533,13 +2205,13 @@ void onNewSms(const char *sms_pdu)
     } else {
         s_outstanding_acknowledge = 1;
         RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS,
-                                  sms_pdu, strlen(sms_pdu));
+                sms_pdu, strlen(sms_pdu));
     }
 
     pthread_mutex_unlock(&s_held_pdus_mutex);
 }
 
-void onNewStatusReport(const char *sms_pdu)
+static void onNewStatusReport(const char *sms_pdu)
 {
     char *response = NULL;
     int err;
@@ -1563,13 +2235,13 @@ void onNewStatusReport(const char *sms_pdu)
     } else {
         s_outstanding_acknowledge = 1;
         RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
-                                  response, strlen(response));
+                response, strlen(response));
     }
     free(response);
     pthread_mutex_unlock(&s_held_pdus_mutex);
 }
 
-void onNewBroadcastSms(const char *pdu)
+static void onNewBroadcastSms(const char *pdu)
 {
     char *message = NULL;
     D("%s() Length : %d", __func__, strlen(pdu));
@@ -1602,7 +2274,7 @@ void onNewBroadcastSms(const char *pdu)
     } else {
         s_outstanding_acknowledge = 1;
         RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
-                              message, BSM_LENGTH);
+                message, BSM_LENGTH);
     }
 
     pthread_mutex_unlock(&s_held_pdus_mutex);
@@ -1611,7 +2283,7 @@ error:
     return;
 }
 
-void onNewSmsOnSIM(const char *s)
+static void onNewSmsOnSIM(const char *s)
 {
     char *line;
     char *mem;
@@ -1636,8 +2308,14 @@ void onNewSmsOnSIM(const char *s)
     if (err < 0)
         goto error;
 
+    /* Huawei modems use a 0-based message slot index, but the SIM record is 1-based.
+       We will translate Huawei indices to Record indices, to make the Android RIL
+       able to read SMS stored in SIM using SimIo with the same indices as the Sms
+       delete command and NewSmsOnSim index */
+    index += 1;
+
     RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM,
-                              &index, sizeof(int *));
+            &index, sizeof(int *));
 
 finally:
     free(line);
@@ -1715,9 +2393,9 @@ static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
             smsc[4+length] = '\0';
         }
         at_response_free(atResponse);
+    } else {
+        strcpy(smsc, testSmsc);
     }
-    else
-        strcpy(smsc,testSmsc);
 
     asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
     asprintf(&cmd2, "%s%s", smsc, pdu);
@@ -1754,15 +2432,15 @@ finally:
 
 error:
     switch (at_get_cms_error(aterr)) {
-    case CMS_NO_NETWORK_SERVICE:
-    case CMS_NETWORK_TIMEOUT:
-        ret = RIL_E_SMS_SEND_FAIL_RETRY;
-        break;
-    default:
-        ret = RIL_E_GENERIC_FAILURE;
-        break;
-    }
-    RIL_onRequestComplete(t, ret, NULL, 0);
+        case CMS_NO_NETWORK_SERVICE:
+        case CMS_NETWORK_TIMEOUT:
+            ret = RIL_E_SMS_SEND_FAIL_RETRY;
+            break;
+        default:
+            ret = RIL_E_GENERIC_FAILURE;
+            break;
+    }
+    RIL_onRequestComplete(t, ret, NULL, 0);
     goto finally;
 }
 
@@ -1845,7 +2523,18 @@ static void requestDeleteSmsOnSim(void *data, size_t datalen, RIL_Token t)
 {
     int err;
 
-    err = at_send_command("AT+CMGD=%d", ((int *) data)[0]);
+    /* Huawei modems use a 0-based message slot index, but the SIM record is 1-based.
+       We will translate Huawei indices to Record indices, to make the Android RIL
+       able to read SMS stored in SIM using SimIo with the same indices as the Sms
+       delete command and NewSmsOnSim index */
+    int idx = ((int *) data)[0] - 1;
+    if (idx < 0) {
+        ALOGE("DeleteSmsOnSim: Invalid index! (%d)",idx);
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        return;
+    }
+
+    err = at_send_command("AT+CMGD=%d", idx);
     if (err != AT_NOERROR)
         RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
     else
@@ -1921,20 +2610,20 @@ static void requestSmsStorageFull(void *data, size_t datalen, RIL_Token t)
      * 1. memory was full and been cleaned up, inform modem memory is available now.
      */
     switch (ack) {
-    case 0:
-        /* Android will handle this, no need to inform modem. always return success. */
-        ALOGI("SMS storage full");
-        break;
-
-    case 1:
-        /* Since we are not using +CNMA command. It's fine to return without informing network */
-        ALOGI("Failed to inform network for Message Cleanup. Need cmd : ESMSMEMAVAIL");
-        break;
-
-    default:
-        ALOGE("%s() Invalid parameter", __func__);
-        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-        return;
+        case 0:
+            /* Android will handle this, no need to inform modem. always return success. */
+            ALOGI("SMS storage full");
+            break;
+
+        case 1:
+            /* Since we are not using +CNMA command. It's fine to return without informing network */
+            ALOGI("Failed to inform network for Message Cleanup. Need cmd : ESMSMEMAVAIL");
+            break;
+
+        default:
+            ALOGE("%s() Invalid parameter", __func__);
+            RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+            return;
     }
 
     RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
@@ -1982,7 +2671,7 @@ static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
             unsolResponse = RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT;
 
         RIL_onUnsolicitedResponse(unsolResponse, hpdu->sms_pdu,
-                                  strlen(hpdu->sms_pdu));
+                strlen(hpdu->sms_pdu));
 
         free(hpdu->sms_pdu);
         free(hpdu);
@@ -2262,234 +2951,246 @@ error:
  * This is similar to the TS 27.007 "restricted SIM" operation
  * where it assumes all of the EF selection will be done by the
  * callee.
+ *
+ * Reverse Engineered from Kuawei generic RIL *
  */
 
-
-/* All files listed under ADF_USIM in 3GPP TS 31.102 */
-static const int ef_usim_files[] = {
-    0x6F05, 0x6F06, 0x6F07, 0x6F08, 0x6F09,
-    0x6F2C, 0x6F31, 0x6F32, 0x6F37, 0x6F38,
-    0x6F39, 0x6F3B, 0x6F3C, 0x6F3E, 0x6F3F,
-    0x6F40, 0x6F41, 0x6F42, 0x6F43, 0x6F45,
-    0x6F46, 0x6F47, 0x6F48, 0x6F49, 0x6F4B,
-    0x6F4C, 0x6F4D, 0x6F4E, 0x6F4F, 0x6F50,
-    0x6F55, 0x6F56, 0x6F57, 0x6F58, 0x6F5B,
-    0x6F5C, 0x6F60, 0x6F61, 0x6F62, 0x6F73,
-    0x6F78, 0x6F7B, 0x6F7E, 0x6F80, 0x6F81,
-    0x6F82, 0x6F83, 0x6FAD, 0x6FB1, 0x6FB2,
-    0x6FB3, 0x6FB4, 0x6FB5, 0x6FB6, 0x6FB7,
-    0x6FC3, 0x6FC4, 0x6FC5, 0x6FC6, 0x6FC7,
-    0x6FC8, 0x6FC9, 0x6FCA, 0x6FCB, 0x6FCC,
-    0x6FCD, 0x6FCE, 0x6FCF, 0x6FD0, 0x6FD1,
-    0x6FD2, 0x6FD3, 0x6FD4, 0x6FD5, 0x6FD6,
-    0x6FD7, 0x6FD8, 0x6FD9, 0x6FDA, 0x6FDB,
+typedef struct _tagSW1SW2{
+    unsigned char mask[2];
+    unsigned char sw[2];
+    char *text;
+} SW1SW2;
+
+static const SW1SW2 sim_answ[]=
+{
+      /* Response to commands which are correctly executed */
+      { { 0xff, 0xff }, { 0x90, 0x00 } , "Ok" },
+      { { 0xff, 0x00 }, { 0x9f, 0x00 } , "%d response bytes available" },
+      /* Memory management */
+      { { 0xff, 0x00 }, { 0x92, 0x00 } , "Update successful but after using an internal retry of %d times" },
+      { { 0xff, 0xff }, { 0x92, 0x40 } , "memory problem" },
+      /* Referencing management */
+      { { 0xff, 0xff }, { 0x94, 0x00 } , "no EF selected" },
+      { { 0xff, 0xff }, { 0x94, 0x02 } , "out of range (invalid address)" },
+      { { 0xff, 0xff }, { 0x94, 0x04 } , "file ID or pattern not found" },
+      { { 0xff, 0xff }, { 0x94, 0x08 } , "file is inconsistent with the command" },
+      /* Security management */
+      { { 0xff, 0xff }, { 0x98, 0x02 } , "no CHV initialised" },
+      { { 0xff, 0xff }, { 0x98, 0x04 } , "access condition not fulfilled,authentication failed at least one attempt left" },
+      { { 0xff, 0xff }, { 0x98, 0x08 } , "in contradiction with CHV status" },
+      { { 0xff, 0xff }, { 0x98, 0x10 } , "in contradiction with invalidation stats" },
+      { { 0xff, 0xff }, { 0x98, 0x40 } , "unsuccessful CHV verification,no attempt left. CHV blocked" },
+      { { 0xff, 0xff }, { 0x98, 0x50 } , "increase cannot be performed,Max value reached" },
+
+      { { 0xff, 0x00 }, { 0x61, 0x00 } , "%d response bytes available" },
+
+      { { 0xff, 0xff }, { 0x62, 0x81 } , "returned data may be corrupt" },
+      { { 0xff, 0xff }, { 0x62, 0x82 } , "EOF reached prematurely" },
+      { { 0xff, 0xff }, { 0x62, 0x83 } , "selected file invalid" },
+      { { 0xff, 0xff }, { 0x62, 0x84 } , "FCI not formated" },
+      { { 0xff, 0x00 }, { 0x62, 0x00 } , "nvmem unchanged" },
+
+      { { 0xff, 0x00 }, { 0x63, 0x00 } , "nvmem changed" },
+      { { 0xff, 0x00 }, { 0x63, 0x81 } , "file filled up by last write" },
+      { { 0xff, 0xf0 }, { 0x63, 0xc0 } , "Counter=%1.1X" },
+
+      { { 0xff, 0xff }, { 0x64, 0x00 } , "nvmem unchanged" },
+      { { 0xff, 0x00 }, { 0x64, 0x00 } , "nvmem unchanged - RFU" },
+
+      { { 0xff, 0xff }, { 0x65, 0x00 } , "nvmem changed" },
+      { { 0xff, 0xff }, { 0x65, 0x81 } , "nvmem changed - memory failure" },
+      { { 0xff, 0x00 }, { 0x65, 0x00 } , "nvmem changed - unknown?" },
+
+      { { 0xff, 0x00 }, { 0x66, 0x00 } , "security related %d" },
+
+      { { 0xff, 0xff }, { 0x67, 0x00 } , "wrong length" },
+      { { 0xff, 0x00 }, { 0x67, 0x00 } , "wrong length - %d expected" },
+
+      { { 0xff, 0xff }, { 0x68, 0x81 } , "wrong cla - logical channel not supported" },
+      { { 0xff, 0xff }, { 0x68, 0x82 } , "wrong cla - secure messaging not supported" },
+      { { 0xff, 0x00 }, { 0x68, 0x00 } , "cla not supported" },
+
+      { { 0xff, 0xff }, { 0x69, 0x81 } , "command incompatible with file structure" },
+      { { 0xff, 0xff }, { 0x69, 0x82 } , "security status not satisfied" },
+      { { 0xff, 0xff }, { 0x69, 0x83 } , "authentication method blocked" },
+      { { 0xff, 0xff }, { 0x69, 0x84 } , "referenced data invalid" },
+      { { 0xff, 0xff }, { 0x69, 0x85 } , "conditions of use not satisfied" },
+      { { 0xff, 0xff }, { 0x69, 0x86 } , "command not allowed - no current EF" },
+      { { 0xff, 0xff }, { 0x69, 0x87 } , "expected SM data objects missing" },
+      { { 0xff, 0xff }, { 0x69, 0x88 } , "SM data objects incorrect" },
+      { { 0xff, 0x00 }, { 0x69, 0x00 } , "command not allowed" },
+
+      { { 0xff, 0xff }, { 0x6a, 0x80 } , "P1-P2: incorrect parameters in data field" },
+      { { 0xff, 0xff }, { 0x6a, 0x81 } , "P1-P2: function not supported" },
+      { { 0xff, 0xff }, { 0x6a, 0x82 } , "P1-P2: file not found" },
+      { { 0xff, 0xff }, { 0x6a, 0x83 } , "P1-P2: record not found" },
+      { { 0xff, 0xff }, { 0x6a, 0x84 } , "P1-P2: not enough memory space in file" },
+      { { 0xff, 0xff }, { 0x6a, 0x85 } , "P1-P2: Lc inconsistent with TLV" },
+      { { 0xff, 0xff }, { 0x6a, 0x86 } , "P1-P2 incorrect" },
+      { { 0xff, 0xff }, { 0x6a, 0x87 } , "P1-P2 inconsistent with Lc" },
+      { { 0xff, 0xff }, { 0x6a, 0x88 } , "Referenced data not found" },
+      { { 0xff, 0x00 }, { 0x6a, 0x00 } , "P1-P2 invalid" },
+
+      { { 0xff, 0x00 }, { 0x6b, 0x00 } , "P1-P2 invalid" },
+
+      { { 0xff, 0x00 }, { 0x6c, 0x00 } , "wrong length -  %d expected" },
+
+      { { 0xff, 0x00 }, { 0x6d, 0x00 } , "INS code not supported or invalid" },
+
+      { { 0xff, 0x00 }, { 0x6e, 0x00 } , "CLA %02X not supported" },
+
+      { { 0xff, 0x00 }, { 0x6f, 0x00 } , "no precise diagnosis" },
+
+      { { 0x00, 0x00 }, { 0x00, 0x00 } , "Unknown response" }
 };
 
-static const int ef_telecom_files[] = {
-    0x6F3A, 0x6F3D, 0x6F44, 0x6F4A, 0x6F54,
-};
+/* Interpret and print SIM_IO command result */
+static void print_simansw(unsigned char sw1, unsigned char sw2)
+{
+    unsigned j;
+
+    ALOGD("sw1: 0x%02x, sw2: 0x%02x", sw1, sw2);
+    for (j = 0; j < sizeof(sim_answ)/sizeof(sim_answ[0]); j++) {
+        if ((sw1 & sim_answ[j].mask[0]) == sim_answ[j].sw[0] &&
+                (sw2 & sim_answ[j].mask[1]) == sim_answ[j].sw[1]) {
+            ALOGD(sim_answ[j].text, sw2);
+            return;
+        }
+    }
+
+    ALOGD("Unknown error");
+}
 
-#define PATH_ADF_USIM_DIRECTORY      "3F007FFF"
-#define PATH_ADF_TELECOM_DIRECTORY   "3F007F10"
+static unsigned int hex2int(char dig)
+{
+    if (dig >= '0' && dig <= '9')
+        return dig - '0';
+    if (dig >= 'a' && dig <= 'f')
+        return dig - 'a' + 10;
+    if (dig >= 'A' && dig <= 'F')
+        return dig - 'A' + 10;
+    return 0;
+}
 
-/* RID: A000000087 = 3GPP, PIX: 1002 = 3GPP USIM */
-#define USIM_APPLICATION_ID          "A0000000871002"
+static void hexStringToBytes(unsigned char* b, const char* str)
+{
+    int len = strlen(str);
+    len >>= 1;
+    while (len--) {
+        *b++ = (hex2int(str[0]) << 4) | hex2int(str[1]);
+        str += 2;
+    };
+}
 
-static int sendSimIOCmdICC(const RIL_SIM_IO_v6 *ioargs, ATResponse **atResponse, RIL_SIM_IO_Response *sr)
+static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
 {
+    ATResponse *atResponse = NULL;
+    RIL_SIM_IO_Response sr;
     int err;
-    char *fmt;
-    char *arg6;
-    char *arg7;
+    RIL_SIM_IO_v6 *p_args;
     char *line;
+    char *fmt;
+
+    /* FIXME handle pin2 */
+    memset(&sr, 0, sizeof(sr));
 
-    /* FIXME Handle pin2. */
-    memset(sr, 0, sizeof(*sr));
+    p_args = (RIL_SIM_IO_v6 *)data;
 
-    arg6 = ioargs->data;
-    arg7 = ioargs->path;
+    if (!p_args)
+        goto error;
+
+    if (p_args->path != NULL && (strlen(p_args->path) & 3) != 0)
+        goto error;
 
-    if (arg7 && arg6) {
-        fmt = "AT+CRSM=%d,%d,%d,%d,%d,\"%s\",\"%s\"";
-    } else if (arg7) {
-        fmt = "AT+CRSM=%d,%d,%d,%d,%d,,\"%s\"";
-        arg6 = arg7;
-    } else if (arg6) {
-        fmt = "AT+CRSM=%d,%d,%d,%d,%d,\"%s\"";
+    if (p_args->fileid == 0x4F30) {
+        if (!p_args->data) {
+            fmt = "AT+CRSM=%d,%d,%d,%d,%d,,\"3F007F105F3A\"";
+        } else {
+            fmt = "AT+CRSM=%d,%d,%d,%d,%d,%s,\"3F007F105F3A\"";
+        }
     } else {
-        fmt = "AT+CRSM=%d,%d,%d,%d,%d";
+        if (!p_args->data) {
+            fmt = "AT+CRSM=%d,%d,%d,%d,%d";
+        } else {
+            fmt = "AT+CRSM=%d,%d,%d,%d,%d,%s";
+        }
     }
 
-    err = at_send_command_singleline(fmt, "+CRSM:", atResponse,ioargs->command,
-                 ioargs->fileid, ioargs->p1,
-                 ioargs->p2, ioargs->p3,
-                 arg6, arg7);
+    err = at_send_command_singleline(fmt, "+CRSM:", &atResponse,
+             p_args->command,
+             p_args->fileid, p_args->p1,
+             p_args->p2, p_args->p3,
+             p_args->data);
 
     if (err != AT_NOERROR)
-        return err;
+        goto error;
 
-    line = (*atResponse)->p_intermediates->line;
+    line = atResponse->p_intermediates->line;
 
     err = at_tok_start(&line);
-    if (err < 0)
-        goto finally;
+    if (err < 0) goto error;
 
-    err = at_tok_nextint(&line, &(sr->sw1));
-    if (err < 0)
-        goto finally;
+    err = at_tok_nextint(&line, &(sr.sw1));
+    if (err < 0) goto error;
 
-    err = at_tok_nextint(&line, &(sr->sw2));
-    if (err < 0)
-        goto finally;
+    err = at_tok_nextint(&line, &(sr.sw2));
+    if (err < 0) goto error;
 
     if (at_tok_hasmore(&line)) {
-        err = at_tok_nextstr(&line, &(sr->simResponse));
-        if (err < 0)
-            goto finally;
-    }
-
-finally:
-    return err;
-}
-
-static int convertSimIoFcp(RIL_SIM_IO_Response *sr, char **cvt)
-{
-    int err;
-    /* size_t pos; */
-    size_t fcplen;
-    struct ts_51011_921_resp resp;
-    void *cvt_buf = NULL;
-
-    if (!sr->simResponse || !cvt) {
-        err = -EINVAL;
-        goto error;
-    }
-
-    fcplen = strlen(sr->simResponse);
-    if ((fcplen == 0) || (fcplen & 1)) {
-        err = -EINVAL;
-        goto error;
-    }
-
-    err = fcp_to_ts_51011(sr->simResponse, fcplen, &resp);
-    if (err < 0)
-        goto error;
-
-    cvt_buf = malloc(sizeof(resp) * 2 + 1);
-    if (!cvt_buf) {
-        err = -ENOMEM;
-        goto error;
+        err = at_tok_nextstr(&line, &(sr.simResponse));
+        if (err < 0) goto error;
     }
 
-    err = binaryToString((unsigned char*)(&resp),
-                   sizeof(resp), cvt_buf);
-    if (err < 0)
-        goto error;
-
-    /* cvt_buf ownership is moved to the caller */
-    *cvt = cvt_buf;
-    cvt_buf = NULL;
-
-finally:
-    return err;
-
-error:
-    free(cvt_buf);
-    goto finally;
-}
+    /* Interpret and print results as a debugging aid */
+    print_simansw(sr.sw1,sr.sw2);
 
-/**
- * RIL_REQUEST_SIM_IO
- *
- * Request SIM I/O operation.
- * This is similar to the TS 27.007 "restricted SIM" operation
- * where it assumes all of the EF selection will be done by the
- * callee.
- */
-static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
-{
-    (void) datalen;
-    ATResponse *atResponse = NULL;
-    RIL_SIM_IO_Response sr;
-    int cvt_done = 0;
-    int err;
-    UICC_Type UiccType = getUICCType();
+    /* If dealing with a USIM card ... */
+    if (p_args->command == 0xC0 &&
+        sr.simResponse[0] == '6' &&
+        sr.simResponse[1] == '2' &&
+        sr.simResponse[6] == '0' &&
+        sr.simResponse[7] == '5' &&
+        strlen(sr.simResponse) <= 30 &&
+        getUICCType() != UICC_TYPE_SIM) {
 
-    int pathReplaced = 0;
-    RIL_SIM_IO_v6 ioargsDup;
+        /* Convert it to a format Android understands */
 
-    /*
-     * Android telephony framework does not support USIM cards properly,
-     * send GSM filepath where as active cardtype is USIM.
-     * Android RIL needs to change the file path of files listed under ADF-USIM
-     * if current active cardtype is USIM
-     */
-    memcpy(&ioargsDup, data, sizeof(RIL_SIM_IO_v6));
-    if (UICC_TYPE_USIM == UiccType) {
-        unsigned int i;
-        int err;
-        unsigned int count = sizeof(ef_usim_files) / sizeof(int);
-
-        for (i = 0; i < count; i++) {
-            if (ef_usim_files[i] == ioargsDup.fileid) {
-                err = asprintf(&ioargsDup.path, PATH_ADF_USIM_DIRECTORY);
-                if (err < 0)
-                    goto error;
-                pathReplaced = 1;
-                ALOGD("%s() Path replaced for USIM: %d", __func__, ioargsDup.fileid);
-                break;
-            }
-        }
-        if(!pathReplaced){
-            unsigned int count2 = sizeof(ef_telecom_files) / sizeof(int);
-            for (i = 0; i < count2; i++) {
-                if (ef_telecom_files[i] == ioargsDup.fileid) {
-                    err = asprintf(&ioargsDup.path, PATH_ADF_TELECOM_DIRECTORY);
-                    if (err < 0)
-                        goto error;
-                    pathReplaced = 1;
-                    ALOGD("%s() Path replaced for telecom: %d", __func__, ioargsDup.fileid);
-                    break;
-                }
-            }
-        }
-    }
+        unsigned char buf[15];
+        unsigned int val;
 
-    memset(&sr, 0, sizeof(sr));
+        // Convert to bytes...
+        hexStringToBytes(buf,sr.simResponse);
 
-    err = sendSimIOCmdICC(&ioargsDup, &atResponse, &sr);
+        // Reformat response...
+        sr.simResponse[0x00] = '0';
+        sr.simResponse[0x01] = '0';
+        sr.simResponse[0x02] = '0';
+        sr.simResponse[0x03] = '0';
 
-    if (err < 0)
-        goto error;
+        val = buf[8] * (buf[7] + (buf[6]<<8U));
+        sprintf(&sr.simResponse[0x04],"%04x",val & 0xFFFFU);
 
-    /*
-     * In case the command is GET_RESPONSE and cardtype is 3G SIM
-     * convert to 2G FCP
-     */
-    if (ioargsDup.command == 0xC0 && UiccType != UICC_TYPE_SIM) {
-        err = convertSimIoFcp(&sr, &sr.simResponse);
-        if (err < 0)
-            goto error;
-        cvt_done = 1; /* sr.simResponse needs to be freed */
+        sr.simResponse[0x08] = sr.simResponse[0x16];
+        sr.simResponse[0x09] = sr.simResponse[0x17];
+        sr.simResponse[0x0A] = sr.simResponse[0x18];
+        sr.simResponse[0x0B] = sr.simResponse[0x19];
+        sr.simResponse[0x0D] = '4';
+        sr.simResponse[0x1A] = '0';
+        sr.simResponse[0x1B] = '1';
+        sr.simResponse[0x1C] = sr.simResponse[0x0E];
+        sr.simResponse[0x1D] = sr.simResponse[0x0F];
+        sr.simResponse[0x1E] = 0;
     }
 
     RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
-
-finally:
     at_response_free(atResponse);
-    if (cvt_done)
-        free(sr.simResponse);
-
-    if (pathReplaced)
-        free(ioargsDup.path);
     return;
 
 error:
     RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-    goto finally;
+    at_response_free(atResponse);
 }
 
-
 /*
  * The following list contains values for the structure "RIL_AppStatus" to be
  * sent to Android on a given SIM state. It is indexed by the SIM_Status above.
@@ -2818,6 +3519,7 @@ static void requestQueryFacilityLock(void *data, size_t datalen, RIL_Token t)
     char *facility_string = NULL;
     char *facility_password = NULL;
     char *facility_class = NULL;
+    const char *fmt;
 
     (void) datalen;
 
@@ -2830,7 +3532,16 @@ static void requestQueryFacilityLock(void *data, size_t datalen, RIL_Token t)
     facility_password = ((char **) data)[1];
     facility_class = ((char **) data)[2];
 
-    err = at_send_command_singleline("AT+CLCK=\"%s\",2,%s,%s", "+CLCK:", &atResponse,
+    if (facility_password != NULL && facility_password[0] != 0) {
+        if (facility_class != NULL && facility_class[0] != 0) {
+            fmt = "AT+CLCK=\"%s\",2,%s,%s";
+        } else {
+            fmt = "AT+CLCK=\"%s\",2,%s";
+        }
+    } else {
+        fmt = "AT+CLCK=\"%s\",2";
+    }
+    err = at_send_command_singleline(fmt, "+CLCK:", &atResponse,
             facility_string, facility_password, facility_class);
     if (err != AT_NOERROR)
         goto error;
@@ -2896,48 +3607,48 @@ static void requestSetFacilityLock(void *data, size_t datalen, RIL_Token t)
      * printing NULL with %s will give string "(null)".
      */
     err = at_send_command("AT+CLCK=\"%s\",%d,\"%s\",%s", facility_string,
-            facility_mode, facility_password, facility_class);
+            facility_mode, facility_password ? facility_password : "", facility_class);
 
     if (at_get_error_type(err) == AT_ERROR)
         goto exit;
     if (err != AT_NOERROR) {
         switch (at_get_cme_error(err)) {
-        /* CME ERROR 11: "SIM PIN required" happens when PIN is wrong */
-        case CME_SIM_PIN_REQUIRED:
-            ALOGI("Wrong PIN");
-            errorril = RIL_E_PASSWORD_INCORRECT;
-            break;
-        /*
-         * CME ERROR 12: "SIM PUK required" happens when wrong PIN is used
-         * 3 times in a row
-         */
-        case CME_SIM_PUK_REQUIRED:
-            ALOGI("PIN locked, change PIN with PUK");
-            num_retries = 0;/* PUK required */
-            errorril = RIL_E_PASSWORD_INCORRECT;
-            break;
-        /* CME ERROR 16: "Incorrect password" happens when PIN is wrong */
-        case CME_INCORRECT_PASSWORD:
-            ALOGI("Incorrect password, Facility: %s", facility_string);
-            errorril = RIL_E_PASSWORD_INCORRECT;
-            break;
-        /* CME ERROR 17: "SIM PIN2 required" happens when PIN2 is wrong */
-        case CME_SIM_PIN2_REQUIRED:
-            ALOGI("Wrong PIN2");
-            errorril = RIL_E_PASSWORD_INCORRECT;
-            break;
-        /*
-         * CME ERROR 18: "SIM PUK2 required" happens when wrong PIN2 is used
-         * 3 times in a row
-         */
-        case CME_SIM_PUK2_REQUIRED:
-            ALOGI("PIN2 locked, change PIN2 with PUK2");
-            num_retries = 0;/* PUK2 required */
-            errorril = RIL_E_SIM_PUK2;
-            break;
-        default: /* some other error */
-            num_retries = -1;
-            break;
+            /* CME ERROR 11: "SIM PIN required" happens when PIN is wrong */
+            case CME_SIM_PIN_REQUIRED:
+                ALOGI("Wrong PIN");
+                errorril = RIL_E_PASSWORD_INCORRECT;
+                break;
+                /*
+                 * CME ERROR 12: "SIM PUK required" happens when wrong PIN is used
+                 * 3 times in a row
+                 */
+            case CME_SIM_PUK_REQUIRED:
+                ALOGI("PIN locked, change PIN with PUK");
+                num_retries = 0;/* PUK required */
+                errorril = RIL_E_PASSWORD_INCORRECT;
+                break;
+                /* CME ERROR 16: "Incorrect password" happens when PIN is wrong */
+            case CME_INCORRECT_PASSWORD:
+                ALOGI("Incorrect password, Facility: %s", facility_string);
+                errorril = RIL_E_PASSWORD_INCORRECT;
+                break;
+                /* CME ERROR 17: "SIM PIN2 required" happens when PIN2 is wrong */
+            case CME_SIM_PIN2_REQUIRED:
+                ALOGI("Wrong PIN2");
+                errorril = RIL_E_PASSWORD_INCORRECT;
+                break;
+                /*
+                 * CME ERROR 18: "SIM PUK2 required" happens when wrong PIN2 is used
+                 * 3 times in a row
+                 */
+            case CME_SIM_PUK2_REQUIRED:
+                ALOGI("PIN2 locked, change PIN2 with PUK2");
+                num_retries = 0;/* PUK2 required */
+                errorril = RIL_E_SIM_PUK2;
+                break;
+            default: /* some other error */
+                num_retries = -1;
+                break;
         }
         goto finally;
     }
@@ -2981,7 +3692,7 @@ static void requestEnterSimPin(void *data, size_t datalen, RIL_Token t, int requ
             err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
         }
     } else if (datalen == 3 * sizeof(char *)) {
-            err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
+        err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
     } else {
         goto error;
     }
@@ -2990,25 +3701,30 @@ static void requestEnterSimPin(void *data, size_t datalen, RIL_Token t, int requ
 
     if (cme_err != CME_ERROR_NON_CME && err != AT_NOERROR) {
         switch (cme_err) {
-        case CME_SIM_PIN_REQUIRED:
-        case CME_SIM_PUK_REQUIRED:
-        case CME_INCORRECT_PASSWORD:
-        case CME_SIM_PIN2_REQUIRED:
-        case CME_SIM_PUK2_REQUIRED:
-            num_retries = 1;
-            RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &num_retries, sizeof(int *));
-            break;
-        default:
-            goto error;
+            case CME_SIM_PIN_REQUIRED:
+            case CME_SIM_PUK_REQUIRED:
+            case CME_INCORRECT_PASSWORD:
+            case CME_SIM_PIN2_REQUIRED:
+            case CME_SIM_PUK2_REQUIRED:
+                num_retries = 1;
+                RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &num_retries, sizeof(int *));
+                break;
+            default:
+                goto error;
         }
     } else {
-        /*
-         * Got OK, return success and wait for *EPEV to trigger poll
-         * of SIM state.
-         */
+        /* Got OK, return success. */
 
         num_retries = 1;
         RIL_onRequestComplete(t, RIL_E_SUCCESS, &num_retries, sizeof(int *));
+
+        /* Make sure we get notifications for network registeration
+           of both voice and data now */
+        at_send_command("AT+CREG=2");
+        at_send_command("AT+CGREG=2");
+
+        /* Notify that SIM is ready */
+        setRadioState(RADIO_STATE_SIM_READY);
     }
     return;
 error:
@@ -3124,15 +3840,15 @@ static void pollOperatorSelected(void *params)
        Loop and try again. */
     if (!at_tok_hasmore(&line)) {
         switch (s_registrationDeniedReason) {
-        case IMSI_UNKNOWN_IN_HLR: /* fall through */
-        case ILLEGAL_ME:
-            RIL_onRequestComplete(t, RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0);
-            free(poll_params);
-            break;
-        default:
-            poll_params->loopcount++;
-            enqueueRILEvent(pollOperatorSelected,
-                            poll_params, &TIMEVAL_OPERATOR_SELECT_POLL);
+            case IMSI_UNKNOWN_IN_HLR: /* fall through */
+            case ILLEGAL_ME:
+                RIL_onRequestComplete(t, RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0);
+                free(poll_params);
+                break;
+            default:
+                poll_params->loopcount++;
+                enqueueRILEvent(pollOperatorSelected,
+                        poll_params, &TIMEVAL_OPERATOR_SELECT_POLL);
         }
     } else {
         /* We got operator, throw a success! */
@@ -3514,6 +4230,135 @@ error:
     goto finally;
 }
 
+/**
+ * RIL_REQUEST_SET_BAND_MODE
+ *
+ * Assign a specified band for RF configuration.
+ *
+ * "data" is int *
+ * ((int *)data)[0] is == 0 for "unspecified" (selected by baseband automatically)
+ * ((int *)data)[0] is == 1 for "EURO band"  (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+ * ((int *)data)[0] is == 2 for "US band"    (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+ * ((int *)data)[0] is == 3 for "JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+ * ((int *)data)[0] is == 4 for "AUS band"   (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+ * ((int *)data)[0] is == 5 for "AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+ *
+ * "response" is NULL
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  GENERIC_FAILURE
+ */
+static void requestSetBandMode(void *data, size_t datalen, RIL_Token t)
+{
+    int band,err;
+    const char* strband;
+
+    assert (datalen >= sizeof(int *));
+    band = ((int *)data)[0];
+
+    switch (band) {
+        case 0:
+        default:
+            strband = "3FFFFFFF";
+            break;
+        case 1:
+            strband = "2000000400380";
+            break;
+        case 2:
+            strband = "4A80000";
+            break;
+    }
+
+    /* Set allowed bands */
+    err = at_send_command("AT^SYSCFG=16,3,%s,1,2", strband );
+    if (err != AT_NOERROR)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, sizeof(int));
+    return;
+
+error:
+    ALOGE("ERROR: requestSetBandMode() failed");
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+}
+
+/**
+ * RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
+ *
+ * Query the list of band mode supported by RF.
+ *
+ * "data" is NULL
+ *
+ * "response" is int *
+ * "response" points to an array of int's, the int[0] is the size of array, reset is one for
+ * each available band mode.
+ *
+ *  0 for "unspecified" (selected by baseband automatically)
+ *  1 for "EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+ *  2 for "US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+ *  3 for "JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+ *  4 for "AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+ *  5 for "AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  RADIO_NOT_AVAILABLE
+ *  GENERIC_FAILURE
+ *
+ * See also: RIL_REQUEST_SET_BAND_MODE
+ */
+static void requestQueryAvailableBandMode(void *data, size_t datalen, RIL_Token t)
+{
+    int err = 0;
+    char *line;
+    ATResponse *atResponse = NULL;
+    char *strband;
+    int mode, acqorder, band;
+
+    err = at_send_command_singleline("AT^SYSCFG?", "^SYSCFG:", &atResponse);
+    if (err != AT_NOERROR)
+        goto error;
+
+    line = atResponse->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0)
+        goto error;
+
+    err = at_tok_nextint(&line, &mode);
+    if (err < 0)
+        goto error;
+
+    err = at_tok_nextint(&line, &acqorder);
+    if (err < 0)
+        goto error;
+
+    err = at_tok_nextstr(&line, &strband);
+    if (err < 0)
+        goto error;
+
+    if (strcmp(strband, "2000000400380") == 0)
+        band = 1;
+    else if (strcmp(strband, "4A80000") == 0)
+        band = 2;
+    else
+        band = 0;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &band, sizeof(int));
+
+finally:
+    at_response_free(atResponse);
+    return;
+
+error:
+    ALOGE("%s() Failed to get current band mode", __func__);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    goto finally;
+}
+
 
 /**
  * RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
@@ -3529,28 +4374,19 @@ static void requestSetPreferredNetworkType(void *data, size_t datalen, RIL_Token
     assert (datalen >= sizeof(int *));
     rat = ((int *)data)[0];
 
-    /* Huawei specific
-        AT^SYSCFG=2,1,3FFFFFFF,2,4 for GPRS/EDGE Preferred
-        AT^SYSCFG=2,2,3FFFFFFF,2,4 for 3G Preferred
-        AT^SYSCFG=13,1,3FFFFFFF,2,4 for GPRS/EDGE Only
-        AT^SYSCFG=14,2,3FFFFFFF,2,4 for 3G Only
-
-        The third parameter, 0x3FFFFFFF tells the card to use all bands.
-        A value of 0x400380 here means GSM900/1800/WCDMA2100 only and a
-        value of 0x200000 here means GSM1900 only.
-
-    */
-
     switch (rat) {
-        case PREF_NET_TYPE_GSM_ONLY:  /* GSM only */
-            cmd = "AT^SYSCFG=13,1,3FFFFFFF,2,4"; /* for GPRS/EDGE Only */
+        case PREF_NET_TYPE_GSM_ONLY:        /* GSM only */
+            cmd = "AT^SYSCFG=13,1,40000000,2,4"; /* GSM only */
             break;
-        case PREF_NET_TYPE_GSM_WCDMA: /* WCDMA only */
-            cmd = "AT^SYSCFG=14,2,3FFFFFFF,2,4"; /* for 3G Only */
+        case PREF_NET_TYPE_WCDMA:           /* WCDMA only */
+            cmd = "AT^SYSCFG=14,2,40000000,2,4"; /* WCDMA only */
             break;
-        case PREF_NET_TYPE_GSM_WCDMA_AUTO:
+        case PREF_NET_TYPE_GSM_WCDMA:       /* GSM/WCDMA (WCDMA preferred) */
+            cmd = "AT^SYSCFG=2,2,40000000,2,4";  /* Automatic, prefer WCDMA */
+            break;
+        case PREF_NET_TYPE_GSM_WCDMA_AUTO:  /* GSM/WCDMA (auto mode, according to PRL) */
         default:    /* Dual Mode - WCDMA preferred*/
-            cmd = "AT^SYSCFG=2,2,3FFFFFFF,2,4";  /* for 3G Preferred */
+            cmd = "AT^SYSCFG=2,0,40000000,2,4";  /* for 3G Preferred */
             break;
     }
 
@@ -3582,13 +4418,6 @@ error:
  */
 static void requestGetPreferredNetworkType(RIL_Token t)
 {
-    /*
-    AT^SYSCFG=2,1,3FFFFFFF,1,2 for GPRS/EDGE Preferred
-    AT^SYSCFG=2,2,3FFFFFFF,1,2 for 3G Preferred
-    AT^SYSCFG=13,1,3FFFFFFF,1,2 for GPRS/EDGE Only
-    AT^SYSCFG=14,2,3FFFFFFF,1,2 for 3G Only
-    */
-
     ATResponse *atResponse = NULL;
     int err;
     char *line;
@@ -3614,12 +4443,14 @@ static void requestGetPreferredNetworkType(RIL_Token t)
     if (err < 0) goto error;
 
     /* Based on reported syscfg */
-    if (ret1 == 13) {
+    if (ret1 == 13 && ret2 == 1) {
         response = PREF_NET_TYPE_GSM_ONLY;  /* GSM only */
-    } else if (ret1 == 14) {
-        response = PREF_NET_TYPE_GSM_WCDMA; /* WCDMA only */
+    } else if (ret1 == 14 && ret2 == 2) {
+        response = PREF_NET_TYPE_WCDMA;     /* WCDMA only */
+    } else if (ret1 == 2 && ret2 == 2) {
+        response = PREF_NET_TYPE_GSM_WCDMA; /* GSM or WCDMA */
     } else {
-        response = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* for 3G Preferred */
+        response = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* Auto */
     }
 
     D("requestGetPreferredNetworkType() mode:%d", response);
@@ -3660,25 +4491,33 @@ enum CREG_stat {
  *
  * Request current registration state.
  */
-static void requestRegistrationState(RIL_Token t)
+static void requestRegistrationState(RIL_Token t, int data)
 {
-    int err = 0;
-    const char resp_size = 15;
-    int response[15];
-    char *responseStr[15] = {0};
+    const int resp_size = 15;
+    int response[resp_size];
+    char *responseStr[resp_size];
     ATResponse *cgreg_resp = NULL;
     char *line;
     int commas = 0;
     int skip, cs_status = 0;
     int i;
+    int err;
+    const char *cmd;
+    const char *prefix;
 
     /* Setting default values in case values are not returned by AT command */
-    for (i = 0; i < resp_size; i++)
-        responseStr[i] = NULL;
-
+    memset(responseStr, 0, sizeof(responseStr));
     memset(response, 0, sizeof(response));
 
-    err = at_send_command_singleline("AT+CREG?", "+CREG:", &cgreg_resp);
+    if (data == 0) {
+        cmd = "AT+CREG?";
+        prefix = "+CREG:";
+    } else {
+        cmd = "AT+CGREG?";
+        prefix = "+CGREG:";
+    }
+
+    err = at_send_command_singleline(cmd, prefix, &cgreg_resp);
     if (err != AT_NOERROR)
         goto error;
 
@@ -3716,62 +4555,117 @@ static void requestRegistrationState(RIL_Token t)
         goto error;
 
     switch (commas) {
-    case 0:                    /* +CREG: <stat> */
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0)
-            goto error;
+        case 0:                    /* +CREG: <stat> */
+            err = at_tok_nextint(&line, &response[0]);
+            if (err < 0)
+                goto error;
 
-        response[1] = -1;
-        response[2] = -1;
-        break;
+            response[1] = -1;
+            response[2] = -1;
+            break;
 
-    case 1:                    /* +CREG: <n>, <stat> */
-        err = at_tok_nextint(&line, &skip);
-        if (err < 0)
-            goto error;
+        case 1:                    /* +CREG: <n>, <stat> */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0)
+                goto error;
 
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0)
-            goto error;
+            err = at_tok_nextint(&line, &response[0]);
+            if (err < 0)
+                goto error;
 
-        response[1] = -1;
-        response[2] = -1;
-        if (err < 0)
-            goto error;
-        break;
-    case 2:                    /* +CREG: <stat>, <lac>, <cid> */
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0)
-            goto error;
+            response[1] = -1;
+            response[2] = -1;
+            if (err < 0)
+                goto error;
+            break;
+        case 2:                    /* +CREG: <stat>, <lac>, <cid> */
+            err = at_tok_nextint(&line, &response[0]);
+            if (err < 0)
+                goto error;
 
-        err = at_tok_nexthexint(&line, &response[1]);
-        if (err < 0)
-            goto error;
+            err = at_tok_nexthexint(&line, &response[1]);
+            if (err < 0)
+                goto error;
 
-        err = at_tok_nexthexint(&line, &response[2]);
-        if (err < 0)
-            goto error;
-        break;
-    case 3:                    /* +CREG: <n>, <stat>, <lac>, <cid> */
-    case 4:                    /* +CREG: <n>, <stat>, <lac>, <cid>, <?> */
-        err = at_tok_nextint(&line, &skip);
-        if (err < 0)
-            goto error;
+            err = at_tok_nexthexint(&line, &response[2]);
+            if (err < 0)
+                goto error;
+            break;
+        case 3:                    /* +CREG: <n>, <stat>, <lac>, <cid> */
+        case 4:                    /* +CREG: <n>, <stat>, <lac>, <cid>, <?> */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0)
+                goto error;
 
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0)
-            goto error;
+            err = at_tok_nextint(&line, &response[0]);
+            if (err < 0)
+                goto error;
 
-        err = at_tok_nexthexint(&line, &response[1]);
-        if (err < 0)
-            goto error;
+            err = at_tok_nexthexint(&line, &response[1]);
+            if (err < 0)
+                goto error;
 
-        err = at_tok_nexthexint(&line, &response[2]);
-        if (err < 0)
+            err = at_tok_nexthexint(&line, &response[2]);
+
+            /* Hack for broken +CGREG responses which don't return the network type */
+            ATResponse *p_response_op = NULL;
+            err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response_op);
+            /* We need to get the 4th return param */
+            int commas_op;
+            commas_op = 0;
+            char *p_op, *line_op;
+            line_op = p_response_op->p_intermediates->line;
+
+            for (p_op = line_op ; *p_op != '\0' ;p_op++) {
+                if (*p_op == ',') commas_op++;
+            }
+
+            if (commas_op == 3) {
+                err = at_tok_start(&line_op);
+                err = at_tok_nextint(&line_op, &skip);
+                if (err < 0) goto error;
+                err = at_tok_nextint(&line_op, &skip);
+                if (err < 0) goto error;
+                err = at_tok_nextint(&line_op, &skip);
+                if (err < 0) goto error;
+                err = at_tok_nextint(&line_op, &response[3]);
+                if (err < 0) goto error;
+                /* Now translate to 'Broken Android Speak' - can't follow the GSM spec */
+                switch (response[3]) {
+                    /* GSM/GSM Compact - aka GRPS */
+                    case 0:
+                    case 1:
+                        response[3] = 1;
+                        break;
+
+                        /* EGPRS - aka EDGE */
+                    case 3:
+                        response[3] = 2;
+                        break;
+
+                        /* UTRAN - UMTS aka 3G */
+                    case 2:
+                    case 7:
+                        response[3] = 3;
+                        break;
+
+                        /* UTRAN with HSDPA and/or HSUPA aka Turbo-3G*/
+                    case 4:
+                    case 5:
+                    case 6:
+                        response[3] = 9;
+                        break;
+                }
+            }
+
+            at_response_free(p_response_op);
+            /* End hack */
+
+            if (err < 0)
+                goto error;
+            break;
+        default:
             goto error;
-        break;
-    default:
-        goto error;
     }
 
 
@@ -3781,10 +4675,11 @@ static void requestRegistrationState(RIL_Token t)
         asprintf(&responseStr[1], "%04x", response[1]);
     if (response[2] > 0)
         asprintf(&responseStr[2], "%08x", response[2]);
+    if (response[3] > 0)
+        asprintf(&responseStr[3], "%d", response[3]);
 
-    if (response[0] == CGREG_STAT_REG_HOME_NET ||
-        response[0] == CGREG_STAT_ROAMING)
-        responseStr[3] = (0);
+    if (data == 1)
+    responseStr[5] = (char*) "1";
 
     RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr,
                           resp_size * sizeof(char *));
@@ -3803,171 +4698,6 @@ error:
     goto finally;
 }
 
-
-/**
- * RIL_REQUEST_DATA_REGISTRATION_STATE
- *
- * Request current GPRS registration state.
- */
-static void requestGprsRegistrationState(RIL_Token t)
-{
-    int err = 0;
-    const char resp_size = 6;
-    int response[resp_size];
-    char *responseStr[resp_size];
-    ATResponse *atResponse = NULL;
-    char *line, *p;
-    int commas = 0;
-    int skip, tmp;
-    int count = 3;
-
-    memset(responseStr, 0, sizeof(responseStr));
-    memset(response, 0, sizeof(response));
-    response[1] = -1;
-    response[2] = -1;
-
-    err = at_send_command_singleline("AT+CGREG?", "+CGREG: ", &atResponse);
-    if (err != AT_NOERROR)
-        goto error;
-
-    line = atResponse->p_intermediates->line;
-    err = at_tok_start(&line);
-    if (err < 0)
-        goto error;
-    /*
-     * The solicited version of the +CGREG response is
-     * +CGREG: n, stat, [lac, cid [,<AcT>]]
-     * and the unsolicited version is
-     * +CGREG: stat, [lac, cid [,<AcT>]]
-     * The <n> parameter is basically "is unsolicited creg on?"
-     * which it should always be.
-     *
-     * Now we should normally get the solicited version here,
-     * but the unsolicited version could have snuck in
-     * so we have to handle both.
-     *
-     * Also since the LAC, CID and AcT are only reported when registered,
-     * we can have 1, 2, 3, 4 or 5 arguments here.
-     */
-    /* Count number of commas */
-    p = line;
-    err = at_tok_charcounter(line, ',', &commas);
-    if (err < 0) {
-        ALOGE("%s() at_tok_charcounter failed", __func__);
-        goto error;
-    }
-
-    switch (commas) {
-    case 0:                    /* +CGREG: <stat> */
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0) goto error;
-        break;
-
-    case 1:                    /* +CGREG: <n>, <stat> */
-        err = at_tok_nextint(&line, &skip);
-        if (err < 0) goto error;
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0) goto error;
-        break;
-
-    case 2:                    /* +CGREG: <stat>, <lac>, <cid> */
-        err = at_tok_nextint(&line, &response[0]);
-        if (err < 0) goto error;
-        err = at_tok_nexthexint(&line, &response[1]);
-        if (err < 0) goto error;
-        err = at_tok_nexthexint(&line, &response[2]);
-        if (err < 0) goto error;
-        break;
-
-    case 3:                    /* +CGREG: <n>, <stat>, <lac>, <cid> */
-                               /* +CGREG: <stat>, <lac>, <cid>, <AcT> */
-        err = at_tok_nextint(&line, &tmp);
-        if (err < 0) goto error;
-
-        /* We need to check if the second parameter is <lac> */
-        if (*(line) == '"') {
-            response[0] = tmp; /* <stat> */
-            err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
-            if (err < 0) goto error;
-            err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
-            if (err < 0) goto error;
-            err = at_tok_nextint(&line, &response[3]); /* <AcT> */
-            if (err < 0) goto error;
-            count = 4;
-        } else {
-            err = at_tok_nextint(&line, &response[0]); /* <stat> */
-            if (err < 0) goto error;
-            err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
-            if (err < 0) goto error;
-            err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
-            if (err < 0) goto error;
-        }
-        break;
-
-    case 4:                    /* +CGREG: <n>, <stat>, <lac>, <cid>, <AcT> */
-        err = at_tok_nextint(&line, &skip); /* <n> */
-        if (err < 0) goto error;
-        err = at_tok_nextint(&line, &response[0]); /* <stat> */
-        if (err < 0) goto error;
-        err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
-        if (err < 0) goto error;
-        err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
-        if (err < 0) goto error;
-        err = at_tok_nextint(&line, &response[3]); /* <AcT> */
-        if (err < 0) goto error;
-        count = 4;
-        break;
-
-    default:
-        ALOGE("%s() Invalid input", __func__);
-        goto error;
-    }
-
-    /* Converting to stringlist for Android */
-
-    asprintf(&responseStr[0], "%d", response[0]); /* state */
-
-    if (response[1] >= 0)
-        asprintf(&responseStr[1], "%04x", response[1]); /* LAC */
-    else
-        responseStr[1] = NULL;
-
-    if (response[2] >= 0)
-        asprintf(&responseStr[2], "%08x", response[2]); /* CID */
-    else
-        responseStr[2] = NULL;
-
-    if (response[0] == CGREG_STAT_REG_HOME_NET ||
-        response[0] == CGREG_STAT_ROAMING)
-        asprintf(&responseStr[3], "%d",response[3]);
-    else
-        responseStr[3] = NULL;
-
-    responseStr[5] = (char*) "1";
-
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, resp_size * sizeof(char *));
-
-finally:
-
-    if (responseStr[0])
-        free(responseStr[0]);
-    if (responseStr[1])
-        free(responseStr[1]);
-    if (responseStr[2])
-        free(responseStr[2]);
-    if (responseStr[3])
-        free(responseStr[3]);
-
-    at_response_free(atResponse);
-    return;
-
-error:
-    ALOGE("%s Must never return an error when radio is on", __func__);
-    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-    goto finally;
-}
-
-
 /**
  * RIL_REQUEST_OEM_HOOK_RAW
  *
@@ -4049,17 +4779,40 @@ static void unsolicitedNitzTime(const char * s)
 {
     int err;
     char * response = NULL;
-    char * line = NULL;
-    char * p = NULL;
+    char * dt = NULL;
+    char * tm = NULL;
     char * tz = NULL; /* Timezone */
     static char sNITZtime[64] = {0};
 
-    line = strdup(s);
+    char * line = strdup(s);
 
     /* Higher layers expect a NITZ string in this format:
      *  08/10/28,19:08:37-20,1 (yy/mm/dd,hh:mm:ss(+/-)tz,dst)
      */
+    if (strStartsWith(s,"^NWTIME:")) {
+        /* Network time, as reported by Huawei modems:
+           ^NWTIME: 12/09/22,08:33:59+8,01 */
+
+        /* We got the network time, now assemble the response and send to upper layers */
+        at_tok_start(&line);
+
+        err = at_tok_nextstr(&line, &dt);
+        if (err < 0) goto error;
+
+        err = at_tok_nextstr(&line, &tm);
+        if (err < 0) goto error;
+
+        err = at_tok_nextstr(&line, &tz);
+        if (err < 0) goto error;
+
+        asprintf(&response, "%s,%s,%s", dt ,tm ,tz);
+        RIL_onUnsolicitedResponse(RIL_UNSOL_NITZ_TIME_RECEIVED, response, strlen(response));
+        free(response);
+
+        free(line);
+        return;
 
+    } else
     if (strStartsWith(s,"+CTZV:")){
 
         /* Get Time and Timezone data and store in static variable.
@@ -4098,6 +4851,147 @@ static void unsolicitedNitzTime(const char * s)
 
 error:
     ALOGE("Invalid NITZ line %s", s);
+    free(line);
+}
+
+/* Unsolicited call start status */
+static void unsolicitedCONN(const char * s)
+{
+    int err;
+    int call_id;
+    int type;
+    char * line = strdup(s);
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &call_id);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &type);
+    if (err < 0) goto error;
+
+    ALOGD("Call started: ID:%d, type:%d", call_id, type);
+
+    /* Store last call index */
+    lastCallIdx = call_id;
+
+    free(line);
+    return;
+
+error:
+    ALOGI("Error getting Call Start status");
+    free(line);
+    return;
+}
+
+/* Unsolicited call start status */
+static void unsolicitedORIG(const char * s)
+{
+    int err;
+    int call_id;
+    int type;
+    char * line = strdup(s);
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &call_id);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &type);
+    if (err < 0) goto error;
+
+    ALOGD("Call originated: ID:%d, type:%d", call_id, type);
+
+    /* Store last call index */
+    lastCallIdx = call_id;
+
+    free(line);
+    return;
+
+error:
+    ALOGI("Error getting Call Originated status");
+    free(line);
+    return;
+}
+
+/* Unsolicited call conference status */
+static void unsolicitedCONF(const char * s)
+{
+    int err;
+    int call_id;
+    char * line = strdup(s);
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &call_id);
+    if (err < 0) goto error;
+
+    ALOGD("Call conference started: ID:%d", call_id);
+
+    /* Store last call index */
+    lastCallIdx = call_id;
+
+    free(line);
+    return;
+
+error:
+    ALOGI("Error getting Call Conference Start status");
+    free(line);
+    return;
+}
+
+/* Unsolicited call end status */
+static void unsolicitedCEND(const char * s)
+{
+    int err;
+    int call_id;
+    int duration;
+    int end_status;
+    int cc_cause = CALL_FAIL_NORMAL;
+    char * line = strdup(s);
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &call_id);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &duration);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &end_status);
+    if (err < 0) goto error;
+
+    if (at_tok_hasmore(&line)) { /* not present if error */
+        err = at_tok_nextint(&line, &cc_cause);
+        if (err < 0) goto error;
+    }
+
+    ALOGD("Call ended: ID:%d, duration:%ds status:%d, cccause:%d", call_id, duration, end_status, cc_cause);
+
+    /* Store last call error */
+    lastCallFailCause = cc_cause;
+
+    free(line);
+    return;
+
+error:
+    ALOGI("Error getting Call End status");
+    lastCallFailCause = CALL_FAIL_NORMAL;
+    free(line);
+    return;
+}
+
+
+static void unsolicitedDCONN(const char *s)
+{
+}
+
+static void unsolicitedDEND(const char *s)
+{
 }
 
 static void unsolicitedRSSI(const char * s)
@@ -4105,9 +4999,10 @@ static void unsolicitedRSSI(const char * s)
     int err;
     int rssi;
     RIL_SignalStrength_v6 signalStrength;
-    char * line = NULL;
 
-    line = strdup(s);
+    char * line = strdup(s);
+
+    memset(&signalStrength, 0, sizeof(RIL_SignalStrength_v6));
 
     err = at_tok_start(&line);
     if (err < 0) goto error;
@@ -4115,22 +5010,14 @@ static void unsolicitedRSSI(const char * s)
     err = at_tok_nextint(&line, &rssi);
     if (err < 0) goto error;
 
+    if (rssi == 99) return;
+
     signalStrength.GW_SignalStrength.signalStrength = rssi;
     signalStrength.GW_SignalStrength.bitErrorRate = 99;
-    signalStrength.CDMA_SignalStrength.dbm = 0;
-    signalStrength.CDMA_SignalStrength.ecio = 0;
-    signalStrength.EVDO_SignalStrength.dbm = 0;
-    signalStrength.EVDO_SignalStrength.ecio = 0;
-    signalStrength.EVDO_SignalStrength.signalNoiseRatio = 0;
-    signalStrength.LTE_SignalStrength.signalStrength = 0;
-    signalStrength.LTE_SignalStrength.rsrp = 0;
-    signalStrength.LTE_SignalStrength.rsrq = 0;
-    signalStrength.LTE_SignalStrength.rssnr = 0;
-    signalStrength.LTE_SignalStrength.cqi = 0;
 
     ALOGI("Signal Strength %d", rssi);
 
-    RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &signalStrength, sizeof(signalStrength));
+    RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &signalStrength, sizeof(RIL_SignalStrength_v6));
     free(line);
     return;
 
@@ -4141,18 +5028,181 @@ error:
     return;
 }
 
+/* Get SIM status: 1=valid, all the others are invalid */
+static int getSimState(void)
+{
+    ATResponse *atResponse = NULL;
+    int err;
+    char *line;
+    int status;
+    int srv_status,srv_domain,roam_status,sys_mode,sim_state = -1;
+
+    // Check status.
+    err = at_send_command_singleline("AT^SYSINFO", "^SYSINFO:", &atResponse);
+    if (err != AT_NOERROR)
+        goto error;
+
+    line = atResponse->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &srv_status);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &srv_domain);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &roam_status);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &sys_mode);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &sim_state);
+    if (err < 0) goto error;
+
+
+    ALOGE("Sim State: %d",sim_state);
+    at_response_free(atResponse);
+    return sim_state;
+
+error:
+    ALOGE("Failed to get sim state");
+
+    at_response_free(atResponse);
+    return -1;
+}
+
+static int requestNetworkRegistration()
+{
+    ATResponse *atResponse = NULL;
+    int err;
+    char *line;
+    int srv_status,srv_domain,nr = 0;
+
+    // Check status.
+    err = at_send_command_singleline("AT^SYSINFO", "^SYSINFO:", &atResponse);
+    if (err != AT_NOERROR)
+        goto error;
+
+    line = atResponse->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &srv_status);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &srv_domain);
+    if (err < 0) goto error;
+
+    nr = (srv_status == 2 && (srv_domain == 2 || srv_domain == 3));
+
+    ALOGE("Network registration (PS) : %s", nr ? "Yes" : "No");
+    at_response_free(atResponse);
+    return nr;
+
+error:
+    ALOGE("Failed to get network registration");
+
+    at_response_free(atResponse);
+    return -1;
+}
+
+/* SIM status change */
+static void unsolicitedSimStatus(const char * s)
+{
+    int err;
+    int state;
+    char * line = NULL;
+
+    /*
+    ^SIMST:0 Invalid USIM card state
+    ^SIMST:1 Valid USIM card state
+    ^SIMST:2 Invalid USIM card in case of CS
+    ^SIMST:3 Invalid USIM card in case of PS
+    ^SIMST:4 Invalid USIM card in case of CS or PS
+    ^SIMST:255 Card not present
+    */
+
+    line = strdup(s);
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &state);
+    if (err < 0) goto error;
+
+    ALOGD("SIM state: %d",state);
+
+    free(line);
+    return;
+
+error:
+    ALOGI("Error getting state");
+    free(line);
+    return;
+}
+
+static void unsolicitedSrvStatus(const char * s)
+{
+    int err;
+    int mode;
+    char * line = NULL;
+
+    /*
+    ^SRVST:0 No service
+    ^SRVST:1 Restricted service
+    ^SRVST:2 Valid service
+    ^SRVST:3 Restricted Regional Service
+    ^SRVST:4 Power saving and deep sleep
+    */
+
+    line = strdup(s);
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &mode);
+    if (err < 0) goto error;
+
+    free(line);
+    return;
+
+error:
+    ALOGI("Error getting mode");
+    free(line);
+    return;
+}
+
+
 static void unsolicitedMode(const char * s)
 {
     int err;
-    int mode1;
-    int mode2;
+    int android_mode;
+    int sys_mode;
+    int sys_submode;
     char * line = NULL;
 
     /*
-    ^MODE:3,2 indicates GPRS
-    ^MODE:3,3 indicates EDGE
-    ^MODE:5,4 indicates 3G
-    ^MODE:5,5 indicates HSDPA
+    ^MODE:<sys_mode>,<sys_submode>
+
+    <sys_mode>: System mode. The values are as follows:
+    0    No service.
+    1    AMPS mode (not in use currently)
+    2    CDMA mode (not in use currently)
+    3    GSM/GPRS mode
+    4    HDR mode
+    5    WCDMA mode
+    6    GPS mode
+    <sys_submode>: System sub mode. The values are as follows:
+    0    No service.
+    1    GSM mode
+    2    GPRS mode
+    3    EDEG mode
+    4    WCDMA mode
+    5    HSDPA mode
+    6    HSUPA mode
+    7    HSDPA mode and HSUPA mode
     */
 
     line = strdup(s);
@@ -4160,13 +5210,43 @@ static void unsolicitedMode(const char * s)
     err = at_tok_start(&line);
     if (err < 0) goto error;
 
-    err = at_tok_nextint(&line, &mode1);
+    err = at_tok_nextint(&line, &sys_mode);
     if (err < 0) goto error;
 
-    err = at_tok_nextint(&line, &mode2);
+    err = at_tok_nextint(&line, &sys_submode);
     if (err < 0) goto error;
 
+    switch (sys_submode)
+    {
+        case 0:
+            android_mode = RADIO_TECH_UNKNOWN;
+            break;
+        case 1:
+            android_mode = RADIO_TECH_GSM;
+            break;
+        case 2:
+            android_mode = RADIO_TECH_GPRS;
+            break;
+        case 3:
+            android_mode = RADIO_TECH_EDGE;
+            break;
+        case 4:
+            android_mode = RADIO_TECH_UMTS;
+            break;
+        case 5:
+            android_mode = RADIO_TECH_HSDPA;
+            break;
+        case 6:
+            android_mode = RADIO_TECH_HSUPA;
+            break;
+        case 7:
+            android_mode = RADIO_TECH_HSPA;
+            break;
+    }
+
     free(line);
+
+    RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, &android_mode, sizeof(int *));
     return;
 
 error:
@@ -4194,12 +5274,6 @@ static void requestSignalStrength(RIL_Token t)
 
     memset(&signalStrength, 0, sizeof(RIL_SignalStrength_v6));
 
-    signalStrength.LTE_SignalStrength.signalStrength = 0x7FFFFFFF;
-    signalStrength.LTE_SignalStrength.rsrp = 0x7FFFFFFF;
-    signalStrength.LTE_SignalStrength.rsrq = 0x7FFFFFFF;
-    signalStrength.LTE_SignalStrength.rssnr = 0x7FFFFFFF;
-    signalStrength.LTE_SignalStrength.cqi = 0x7FFFFFFF;
-
     err = at_send_command_singleline("AT+CSQ", "+CSQ:", &atResponse);
     if (err != AT_NOERROR)
         goto error;
@@ -4209,32 +5283,18 @@ static void requestSignalStrength(RIL_Token t)
     err = at_tok_start(&line);
     if (err < 0) goto error;
 
-    err = at_tok_nextint(&line,&rssi);
+    err = at_tok_nextint(&line, &rssi);
     if (err < 0) goto error;
 
-    signalStrength.GW_SignalStrength.signalStrength = rssi;
-
     err = at_tok_nextint(&line, &ber);
-    if (err < 0)
-        goto error;
+    if (err < 0) goto error;
 
+    signalStrength.GW_SignalStrength.signalStrength = rssi;
     signalStrength.GW_SignalStrength.bitErrorRate = ber;
 
-    signalStrength.CDMA_SignalStrength.dbm = 0;
-    signalStrength.CDMA_SignalStrength.ecio = 0;
-    signalStrength.EVDO_SignalStrength.dbm = 0;
-    signalStrength.EVDO_SignalStrength.ecio = 0;
-    signalStrength.EVDO_SignalStrength.signalNoiseRatio = 0;
-    signalStrength.LTE_SignalStrength.signalStrength = 0;
-    signalStrength.LTE_SignalStrength.rsrp = 0;
-    signalStrength.LTE_SignalStrength.rsrq = 0;
-    signalStrength.LTE_SignalStrength.rssnr = 0;
-    signalStrength.LTE_SignalStrength.cqi = 0;
-
     ALOGI("SignalStrength %d BER: %d", rssi, ber);
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, &signalStrength,
-                          sizeof(RIL_SignalStrength_v6));
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &signalStrength, sizeof(RIL_SignalStrength_v6));
 
     at_response_free(atResponse);
     atResponse = NULL;
@@ -4266,9 +5326,9 @@ static void requestOperator(RIL_Token t)
 
     memset(response, 0, sizeof(response));
 
-    err = at_send_command_multiline
-        ("AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", "+COPS:",
-         &atResponse);
+    err = at_send_command_multiline(
+            "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", "+COPS:",
+            &atResponse);
 
     if (err != AT_NOERROR)
         goto error;
@@ -4279,8 +5339,8 @@ static void requestOperator(RIL_Token t)
      * +COPS: 0,2,"310170"
      */
     for (i = 0, cursor = atResponse->p_intermediates;
-         cursor != NULL && i < num_resp_lines;
-         cursor = cursor->p_next, i++) {
+            cursor != NULL && i < num_resp_lines;
+            cursor = cursor->p_next, i++) {
         char *line = cursor->line;
 
         err = at_tok_start(&line);
@@ -4367,8 +5427,7 @@ static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
     if (onOff == 0 && getRadioState() != RADIO_STATE_OFF) {
         char value[PROPERTY_VALUE_MAX];
 
-        /* Switch RF OFF */
-        err = at_send_command("AT^RFSWITCH=0");
+        err = at_send_command("AT+CFUN=0");
         if (err != AT_NOERROR)
             goto error;
 
@@ -4379,12 +5438,9 @@ static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
 
     } else if (onOff > 0 && getRadioState() == RADIO_STATE_OFF) {
 
-        /* Switch RF ON */
-        err = at_send_command("AT^RFSWITCH=1");
-        if (err != AT_NOERROR)
-            goto error;
-
+        err = at_send_command("AT+CFUN=1");
         if (err != AT_NOERROR) {
+
             // Some stacks return an error when there is no SIM,
             // but they really turn the RF portion on
             // So, if we get an error, let's check to see if it
@@ -4401,7 +5457,7 @@ static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
 
     restricted = RIL_RESTRICTED_STATE_NONE;
     RIL_onUnsolicitedResponse(RIL_UNSOL_RESTRICTED_STATE_CHANGED,
-                              &restricted, sizeof(int *));
+            &restricted, sizeof(int *));
 
     return;
 
@@ -4430,7 +5486,31 @@ static void requestGetIMSI(RIL_Token t)
     at_response_free(atResponse);
 }
 
+/**
+ * RIL_REQUEST_GET_IMEI
+ *
+ * Get the device IMEI, which should be 15 decimal digits.
+ */
+static void requestGetIMEI(RIL_Token t)
+{
+    ATResponse *atResponse = NULL;
+    int err;
 
+    /* IMEI */
+    err = at_send_command_numeric("AT+CGSN", &atResponse);
+
+    if (err != AT_NOERROR)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, atResponse->p_intermediates->line, sizeof(char *));
+
+    at_response_free(atResponse);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    at_response_free(atResponse);
+}
 
 /**
  * RIL_REQUEST_GET_IMEISV
@@ -4442,9 +5522,8 @@ static void requestGetIMEISV(RIL_Token t)
     RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"01", sizeof(char *));
 }
 
-
-
-/* RIL_REQUEST_DEVICE_IDENTITY
+/**
+ * RIL_REQUEST_DEVICE_IDENTITY
  *
  * Request the device ESN / MEID / IMEI / IMEISV.
  *
@@ -4509,6 +5588,31 @@ static void requestBasebandVersion(RIL_Token t)
     at_response_free(atResponse);
 }
 
+/**
+ * RIL_REQUEST_STK_SETUP_CALL
+ *
+ */
+static void requestStkSetupCall(void * data, size_t datalen, RIL_Token t)
+{
+    int onOff;
+    int err;
+
+    if (datalen < sizeof(int *)) {
+        ALOGE("%s() bad data length!", __func__);
+        goto error;
+    }
+
+    onOff = ((int *)data)[0];
+    err = at_send_command("AT^CSTC=%d", (onOff)?1:0 );
+    if (err != AT_NOERROR)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
 
 /**
  * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE
@@ -4518,9 +5622,21 @@ static void requestBasebandVersion(RIL_Token t)
  */
 static void requestStkSendTerminalResponse(void * data, size_t datalen, RIL_Token t)
 {
+      int err;
+    const char *ec = (const char *) data;
     (void)datalen;
-    const char *stkResponse = (const char *) data;
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+    err = at_send_command("AT^CSTR=%d,\"%s\"",strlen(ec),ec);
+
+    if (err != AT_NOERROR)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL,0 );
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+
 }
 
 
@@ -4532,9 +5648,20 @@ static void requestStkSendTerminalResponse(void * data, size_t datalen, RIL_Toke
  */
 static void requestStkSendEnvelopeCommand(void * data, size_t datalen, RIL_Token t)
 {
+    int err;
     const char *ec = (const char *) data;
     (void)datalen;
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"ok", sizeof(char *));
+
+    err = at_send_command("AT^CSEN=%d,\"%s\"",strlen(ec),ec);
+
+    if (err != AT_NOERROR)
+        goto error;
+
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0 );
+    return;
+
+error:
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
 }
 
 
@@ -4551,6 +5678,11 @@ static void requestStkGetProfile(RIL_Token t)
 }
 
 
+static void initStackUnsolv()
+{
+    at_send_command("AT^CSMN");
+}
+
 /**
  * RIL_REQUEST_STK_SET_PROFILE
  *
@@ -4581,7 +5713,9 @@ void requestReportStkServiceIsRunning(RIL_Token t)
     RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
 }
 
-
+/**
+ * RIL_REQUEST_DIAL
+ */
 static void requestDial(void *data, size_t datalen, RIL_Token t)
 {
     RIL_Dial *p_dial;
@@ -4600,6 +5734,9 @@ static void requestDial(void *data, size_t datalen, RIL_Token t)
     /* Originate call */
     ret = at_send_command("ATD%s%s;", p_dial->address, clir);
 
+    /* Switch to audio from USB1 */
+    at_send_command("AT^DDSETEX=2");
+
     /* success or failure is ignored by the upper layer here.
        it will call GET_CURRENT_CALLS and determine success that way */
     RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
@@ -4614,6 +5751,11 @@ static void requestHangup(void *data, size_t datalen, RIL_Token t)
 
     p_line = (int *)data;
 
+    /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+       stops streaming audio. If another call is being held, it will be restarted a
+       little bit later by the ccurrent call list callback */
+    stopAudioTunnel(NULL);
+
     // 3GPP 22.030 6.5.5
     // "Releases a specific active call X"
     ret = at_send_command("AT+CHLD=1%d", p_line[0]);
@@ -4625,6 +5767,11 @@ static void requestHangup(void *data, size_t datalen, RIL_Token t)
 
 static void requestHangupWaitingOrBackground(RIL_Token t)
 {
+    /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+       stops streaming audio. If another call is being hold, it will be restarted a
+       little bit later by the ccurrent call list callback */
+    stopAudioTunnel(NULL);
+
     // 3GPP 22.030 6.5.5
     // "Releases all held calls or sets User Determined User Busy
     //  (UDUB) for a waiting call."
@@ -4638,6 +5785,11 @@ static void requestHangupWaitingOrBackground(RIL_Token t)
 
 static void requestHangupForegroundResumeBackground(RIL_Token t)
 {
+    /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+       stops streaming audio. If another call is being hold, it will be restarted a
+       little bit later */
+    stopAudioTunnel(NULL);
+
     // 3GPP 22.030 6.5.5
     // "Releases all active calls (if any exist) and accepts
     //  the other (held or waiting) call."
@@ -4651,6 +5803,11 @@ static void requestHangupForegroundResumeBackground(RIL_Token t)
 
 static void requestSwitchWaitingOrHoldingAndActive(RIL_Token t)
 {
+    /* Just in case, stop the audio tunnel now. We need to stop if before the modem
+       stops streaming audio. If another call is being hold, it will be restarted a
+       little bit later */
+    stopAudioTunnel(NULL);
+
     // 3GPP 22.030 6.5.5
     // "Places all active calls (if any exist) on hold and accepts
     //  the other (held or waiting) call."
@@ -4664,8 +5821,12 @@ static void requestSwitchWaitingOrHoldingAndActive(RIL_Token t)
 
 static void requestAnswer(RIL_Token t)
 {
+    /* Answer call */
     at_send_command("ATA");
 
+    /* Switch to audio from USB1 */
+    at_send_command("AT^DDSETEX=2");
+
     /* success or failure is ignored by the upper layer here.
        it will call GET_CURRENT_CALLS and determine success that way */
     RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
@@ -4712,24 +5873,24 @@ static void requestSeparateConnection(void * data, size_t datalen, RIL_Token t)
     }
 }
 
-
+static int wasMuted = 0;
 static void requestSetMute(void *data, size_t datalen, RIL_Token t)
 {
     int err;
     assert (datalen >= sizeof(int *));
+    int mute = ((int*)data)[0];
 
-    /* mute */
-    err = at_send_command("AT+CMUT=%d", ((int*)data)[0]);
-    if (err != AT_NOERROR)
-        goto error;
+    /* Store mute status */
+    wasMuted = mute;
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
-    return;
+    /* mute - Don't consider it an error if it fails, as we are using a Software loopback for audio data */
+    err = at_send_command("AT+CMUT=%d", mute);
 
-error:
-    ALOGE("ERROR: requestSetMute failed");
-    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    /* Update the audio tunnel mute status */
+    muteAudioTunnel(wasMuted);
 
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    return;
 }
 
 
@@ -4740,8 +5901,8 @@ static void requestGetMute(RIL_Token t)
     int response[1];
     char *line;
 
+    /* If we fail, return a cached version of it */
     err = at_send_command_singleline("AT+CMUT?", "+CMUT:", &atResponse);
-
     if (err != AT_NOERROR)
         goto error;
 
@@ -4759,8 +5920,10 @@ static void requestGetMute(RIL_Token t)
     return;
 
 error:
-    ALOGE("ERROR: requestGetMute failed");
-    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    ALOGE("ERROR: requestGetMute failed - Returned cached result");
+
+    response[0] = wasMuted;
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(char*));
     at_response_free(atResponse);
 }
 
@@ -4770,7 +5933,14 @@ static void requestDTMF(void * data, size_t datalen, RIL_Token t)
     int err = 0;
     char c = ((char *)data)[0];
 
-    err = at_send_command("AT+VTS=%c", (int)c);
+    /* Start DTMF generation for 250ms */
+    err = at_send_command("AT^DTMF=%d,%c", lastCallIdx, (int)c); /* 1=call idx */
+
+    /* If failed, try the older method */
+    if (err != AT_NOERROR) {
+        err = at_send_command("AT+VTS=%c", (int)c);
+    }
+
     if (err != AT_NOERROR) {
         RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
     } else {
@@ -4798,7 +5968,6 @@ error:
 
 }
 
-
 static void requestDtmfStart(void *data, size_t datalen, RIL_Token t)
 {
     int err;
@@ -4808,8 +5977,14 @@ static void requestDtmfStart(void *data, size_t datalen, RIL_Token t)
 
     c = ((char *)data)[0];
 
-    /* Start DTMF generation fro 250ms */
-    err = at_send_command("AT^DTMF=0,%c", (int)c);
+    /* Start DTMF generation for 250ms */
+    err = at_send_command("AT^DTMF=%d,%c", lastCallIdx, (int)c); /* 1=call idx */
+
+    /* If failed, try the older method */
+    if (err != AT_NOERROR) {
+        err = at_send_command("AT+VTS=%c", (int)c);
+    }
+
     if (err != AT_NOERROR)
         goto error;
 
@@ -4822,46 +5997,99 @@ error:
 
 }
 
+/* decodes USSDs. Sometimes, they arrive as GSM8, sometimes they arrive as HEX encoded GSM7... */
+static bytes_t decodeUSSD(const char* message)
+{
+    bytes_t utf8 = NULL;
+
+    /* Could be in Hex or in GSM8 ... - Check it - Some modems return HEX
+       encoded GSM7, others return GSM8... */
+    int pos = 0;
+    int ishex = 1;
+    while (1) {
+        unsigned char c = message[pos];
+        if (!c) break;
+        if (!((c >= '0' && c <= '9') || ( c >= 'A' && c <= 'F' ))) {
+            ishex = 0;
+            break;
+        }
+        pos++;
+    };
+
+    /* Not hex encoded. Just convert to UTF-8 from GSM8 */
+    if (!ishex) {
+
+        /* Convert GSM8 to UTF8 */
+        int gsmbytes = strlen(message);
+        int utf8bytes = utf8_from_gsm8((cbytes_t)message,gsmbytes,NULL);
+        utf8 = malloc( utf8bytes + 1);
+        utf8_from_gsm8((cbytes_t)message,gsmbytes,utf8);
+        utf8[utf8bytes]= '\0';
+
+    } else {
+
+        int gsmseptets;
+        int utf8bytes;
+
+        /* Convert HEX to GSM7 */
+        int hexlen = strlen(message);
+        int binlen = (hexlen + 1) >> 1;
+        bytes_t bytes = malloc(binlen + 1);
+        gsm_hex_to_bytes((cbytes_t)message,hexlen,bytes);
+        bytes[binlen] = 0;
+
+        /* And then, GSM7 to UTF8 */
+        gsmseptets = (binlen * 8) / 7; // Round DOWN
+        utf8bytes = utf8_from_gsm7(bytes, 0, gsmseptets, NULL);
+        utf8 = malloc(utf8bytes + 1);
+        utf8_from_gsm7(bytes, 0, gsmseptets, utf8);
+        utf8[utf8bytes] = 0;
+        free(bytes);
+    }
+
+    return utf8;
+}
+
 static void unsolicitedUSSD(const char *s)
 {
     char *line, *linestart;
-    int typeCode, count, err, len;
+    int typeCode, count, err;
     char *message;
-    char *outputmessage;
     char *responseStr[2] = {0,0};
 
     D("unsolicitedUSSD %s", s);
 
-    linestart=line=strdup(s);
+    linestart = line = strdup(s);
+
     err = at_tok_start(&line);
     if (err < 0) goto error;
 
     err = at_tok_nextint(&line, &typeCode);
     if (err < 0) goto error;
 
+    if (typeCode < 0 || typeCode > 5) goto error;
+
     if (at_tok_hasmore(&line)) {
+
         err = at_tok_nextstr(&line, &message);
         if(err < 0) goto error;
 
-        outputmessage = (char*) malloc(strlen(message)*2+1);
-        gsm_hex_to_bytes((cbytes_t)message,strlen(message),(bytes_t)outputmessage);
-
-        responseStr[1] = (char*) malloc(strlen(outputmessage)*2+1);
-
-        len = utf8_from_gsm8((cbytes_t)outputmessage,strlen(outputmessage),(bytes_t)responseStr[1]);
-
-        responseStr[1][strlen(message)/2]='\0';
-        free(outputmessage);
+        /* Decode message */
+        responseStr[1] = (char*) decodeUSSD(message);
 
         count = 2;
+
     } else {
-        responseStr[1]=NULL;
+
+        responseStr[1] = NULL;
         count = 1;
     }
-    free(linestart);
+
     asprintf(&responseStr[0], "%d", typeCode);
 
-    RIL_onUnsolicitedResponse (RIL_UNSOL_ON_USSD, responseStr, count*sizeof(char*));
+    RIL_onUnsolicitedResponse(RIL_UNSOL_ON_USSD, responseStr, count*sizeof(char*));
+
+    free(linestart);
     if (responseStr[0])
         free(responseStr[0]);
     if (responseStr[1])
@@ -5103,23 +6331,84 @@ static void requestSetCLIR(void *data, size_t datalen, RIL_Token t)
 static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
 {
     int err = 0;
-    int len;
-    cbytes_t ussdRequest;
-    bytes_t temp;
-    char *newUSSDRequest;
-    ussdRequest = (cbytes_t)(data);
-
-    temp = (bytes_t) malloc(strlen((char *)ussdRequest)*sizeof(char)+1);
-    len = utf8_to_gsm8(ussdRequest,strlen((char *)ussdRequest),temp);
-    newUSSDRequest = (char*) malloc(2*len*sizeof(char)+1);
-    gsm_hex_from_bytes(newUSSDRequest,temp, len);
-    newUSSDRequest[2*len]='\0';
-    free(temp);
-
-    err = at_send_command("AT+CUSD=1,\"%s\",15", newUSSDRequest);
-    free(newUSSDRequest);
-    if (err != AT_NOERROR)
-        goto error;
+    cbytes_t ussdRequest = (cbytes_t)(data);
+
+    /*
+     * ussdRequest should be checked for invalid characters that can be used to
+     * send invalid AT commands. However Android have complete check of
+     * ussd strings before they are sent to the RIL.
+     *
+     * AT+CUSD=[<n>[,<str>[,<dcs>]]]
+     * <n> = 0,1,2 Dissable, Enable, Cancel
+     * <str> = CUSD string in UTF8
+     * <dcs> = Cell Brodcast Data Coding Scheme:
+     *   0000 German
+     *   0001 English
+     *   0010 Italian
+     *   0011 French
+     *   0100 Spanish
+     *   0101 Dutch
+     *   0110 Swedish
+     *   0111 Danish
+     *   1000 Portuguese
+     *   1001 Finnish
+     *   1010 Norwegian
+     *   1011 Greek
+     *   1100 Turkish
+     *   1101..1110 Reserved for European languages
+     *   1111 Language unspecified
+     *
+     * According to Android ril.h , CUSD messages are always sent as utf8,
+     * but the dcs field does not have an entry for this.
+     * The nearest "most correct" would be 15 = unspecified,
+     * not adding the dcs would result in the default "0" meaning German,
+     * and some networks are not happy with this.
+     *
+     * Huawei modems, depending on firmware version, seem to accept GSM8 or
+     *  a HEX encoded GSM7 request. Try GSM8; if it fails, try GSM7 encoded in HEX
+     */
+
+    /* Convert to GSM8 from UTF8 */
+    int utf8len = strlen((const char*)ussdRequest);
+    int gsmbytes = utf8_to_gsm8(ussdRequest, utf8len, NULL);
+    bytes_t gsm8 = malloc(gsmbytes + 1);
+    utf8_to_gsm8(ussdRequest, utf8len, gsm8);
+    gsm8[gsmbytes] = 0;
+
+    /* Try to send it as GSM8 */
+    err = at_send_command("AT+CUSD=1,%s,15", gsm8);
+
+    /* Some modems like the string to be between quotes ... Retry if error */
+    if (err != AT_NOERROR) {
+        err = at_send_command("AT+CUSD=1,\"%s\",15", gsm8);
+    }
+    free(gsm8);
+
+    /* If modem did not accept the USSD, retry it but using HEX encoded GSM7 */
+    if (err != AT_NOERROR) {
+        char* hex = NULL;
+
+        /* Convert to GSM7 */
+        int gsmseptets = utf8_to_gsm7(ussdRequest, utf8len, NULL, 0);
+        int gsmbytes = ((gsmseptets * 7) + 7) / 8; // Round UP, to be able to transmit incomplete septets
+        bytes_t gsm7 = malloc(gsmbytes + 1);
+        utf8_to_gsm7(ussdRequest, utf8len, gsm7, 0);
+        gsm7[gsmbytes] = 0;
+
+        /* And then encode to HEX */
+        hex = malloc(2*gsmbytes+1);
+        gsm_hex_from_bytes(hex, gsm7, gsmbytes);
+        hex[2*gsmbytes]='\0';
+
+        /* Retry to send the command */
+        ALOGD("utf8len: %d, gsmseptets: %d, gsmbytes:%d", utf8len, gsmseptets, gsmbytes);
+        err = at_send_command("AT+CUSD=1,\"%s\",15", hex);
+        free(gsm7);
+        free(hex);
+
+        if (err != AT_NOERROR)
+            goto error;
+    }
 
     RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
     return;
@@ -5191,11 +6480,9 @@ static void requestResetRadio(RIL_Token t)
 
     /* Reset MS */
     err = at_send_command("AT+CFUN=6");
-    if (err != AT_NOERROR)
-        goto error;
 
     /* Go online */
-    err = at_send_command("AT^RFSWITCH=1");
+    err = at_send_command("AT^RFSWITCH=1");  /* ignore error. If unsupported, the next line will enable RF */
     err = at_send_command("AT+CFUN=1");
     if (err != AT_NOERROR)
         goto error;
@@ -5237,22 +6524,17 @@ static void requestSetLocationUpdates(void *data, size_t datalen, RIL_Token t)
 {
     int err = 0;
     int updates = 0;
-    ATResponse *atResponse = NULL;
 
     updates = ((int *)data)[0] == 1? 2 : 1;
 
-    err = at_send_command_singleline("AT+CREG=%d","+CLIP:",&atResponse, updates);
+    err = at_send_command("AT+CREG=%d", updates);
     if (err != AT_NOERROR)
         goto error;
 
-    at_response_free(atResponse);
-
-    //Always return success for CDMA (for now)
     RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
     return;
 
 error:
-    at_response_free(atResponse);
     RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
 }
 
@@ -5268,6 +6550,16 @@ static void requestLastFailCause(RIL_Token t)
     if(err != AT_NOERROR)
         goto error;
 
+    /*
+    CALL_FAIL_NORMAL = 16,
+    CALL_FAIL_BUSY = 17,
+    CALL_FAIL_CONGESTION = 34,
+    CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
+    CALL_FAIL_CALL_BARRED = 240,
+    CALL_FAIL_FDN_BLOCKED = 241,
+    CALL_FAIL_ERROR_UNSPECIFIED = 0xffff
+    */
+
     line = atResponse->p_intermediates->line;
     err = at_tok_start(&line);
     if(err < 0) goto error;
@@ -5275,17 +6567,19 @@ static void requestLastFailCause(RIL_Token t)
     err = at_tok_nextstr(&line, &tmp);
     if(err < 0) goto error;
 
-    err = at_tok_nextint(&line, &response);
-    if(err < 0) goto error;
+    if (at_tok_hasmore(&line)) {
+        err = at_tok_nextint(&line, &response);
+        if(err < 0) goto error;
+    }
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
-    at_response_free(atResponse);
-    return;
+    ALOGD("Textual last call fail cause: %s [%d]", tmp, response);
 
 error:
-    at_response_free(atResponse);
-    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
 
+    /* Send the last call fail cause */
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &lastCallFailCause, sizeof(int));
+    at_response_free(atResponse);
+    return;
 }
 
 /*
@@ -5448,30 +6742,6 @@ static void onSIMReady(void *p)
     /* Check if ME is ready to set preferred message storage */
     checkMessageStorageReady(NULL);
 
-    /* Select message service */
-    at_send_command("AT+CSMS=0");
-
-    /*
-     * Always send SMS messages directly to the TE
-     *
-     * mode = 1 // discard when link is reserved (link should never be
-     *             reserved)
-     * mt = 2   // most messages routed to TE
-     * bm = 2   // new cell BM's routed to TE
-     * ds = 1   // Status reports routed to TE
-     * bfr = 1  // flush buffer
-     */
-    at_send_command("AT+CNMI=1,2,2,1,1");
-
-    /* Select cell broadcast messages: Do not accept messages */
-    at_send_command("AT+CSCB=1");
-
-    /* Enable automatic timezone update */
-    at_send_command("AT+CTZU=1");
-
-    /* Enable timezone change reporting */
-    at_send_command("AT+CTZR=1");
-
     /* Subscribe to network registration events.
      *  n = 2 - Enable network registration and location information
      *          unsolicited result code +CREG: <stat>[,<lac>,<ci>]
@@ -5482,23 +6752,58 @@ static void onSIMReady(void *p)
         at_send_command("AT+CREG=1");
     }
 
+    /* Enable proactive network registration notifications */
+    at_send_command("AT+CGREG=2");
+
+    /* Extended Cellular result codes enabled */
+    at_send_command("AT+CRC=1");
+
+    /* Calling line identification enabled */
+    at_send_command("AT+CLIP=1");
+
+    /* Call waiting enabled */
+    at_send_command("AT+CCWA=1");
+
+    /* Alternating voice/data off */
+    at_send_command("AT+CMOD=0");
+
+    /*  +CSSU unsolicited supp service notifications */
+    at_send_command("AT+CSSN=0,1");
+
+    /*  Connected line identification On*/
+    at_send_command("AT+COLP=1");
+
+    /*
+     * Ensure that the modem is using GSM character set and not IRA,
+     * otherwise weirdness with umlauts and other non-ASCII characters
+     * can result
+     */
+    at_send_command("AT+CSCS=\"GSM\"");
+
+    /*  USSD unsolicited */
+    at_send_command("AT+CUSD=1");
+
     /* Configure Short Message (SMS) Format
      *  mode = 0 - PDU mode.
      */
     at_send_command("AT+CMGF=0");
 
-    /* Enable unsolicited RSSI reporting */
-    at_send_command("AT^CURC=1");
-
-    /* Enable GPRS reporting */
-    at_send_command("AT+CGEREP=1,0");
+    /* Disable boot messages */
+    at_send_command("AT^BOOT=0,0");
 
+    /* And flow messages */
+    at_send_command("AT^DSFLOWRPT=0");
 
     /* Select SMS type */
-    at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
-}
+    at_send_command_singleline("AT+CSMS=0", "+CSMS:", NULL);
+
+    /* Always send SMS messages directly to the TE */
+    at_send_command("AT+CNMI=2,1,2,2,0");
 
+    /* Enable unsolicited RSSI reporting */
+    at_send_command("AT^CURC=1");
 
+}
 
 static void requestNotSupported(RIL_Token t, int request)
 {
@@ -5519,7 +6824,6 @@ static void processRequest (int request, void *data, size_t datalen, RIL_Token t
      * GENERIC_FAILURE if we're not in SIM_STATE_READY.
      */
     RIL_RadioState radio_state = getRadioState();
-D("%s() %s", __func__, radioStateToString(radio_state));
 
     if (radio_state != RADIO_STATE_SIM_READY &&
             (request == RIL_REQUEST_WRITE_SMS_TO_SIM ||
@@ -5585,11 +6889,11 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             /* Trigger a rehash of network values, just to be sure. */
             if (((int *)data)[0] == 1)
                 RIL_onUnsolicitedResponse(
-                                   RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
-                                   NULL, 0);
+                        RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
+                        NULL, 0);
             break;
 
-        /* Data Call Requests */
+            /* Data Call Requests */
         case RIL_REQUEST_SETUP_DATA_CALL:
             requestSetupDefaultPDP(data, datalen, t);
             break;
@@ -5603,7 +6907,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestPDPContextList(t);
             break;
 
-        /* SMS Requests */
+            /* SMS Requests */
         case RIL_REQUEST_SEND_SMS:
             requestSendSMS(data, datalen, t);
             break;
@@ -5638,7 +6942,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestGSMSMSBroadcastActivation(data, datalen, t);
             break;
 
-        /* SIM Handling Requests */
+            /* SIM Handling Requests */
         case RIL_REQUEST_SIM_IO:
             requestSIM_IO(data, datalen, t);
             break;
@@ -5664,7 +6968,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestSetFacilityLock(data, datalen, t);
             break;
 
-        /* Network Requests */
+            /* Network Requests */
         case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
             requestEnterSimPin(data, datalen, t, request);
             break;
@@ -5686,14 +6990,14 @@ D("%s() %s", __func__, radioStateToString(radio_state));
         case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
             requestGetPreferredNetworkType(t);
             break;
-        case RIL_REQUEST_VOICE_REGISTRATION_STATE:
-            requestRegistrationState(t);
-            break;
         case RIL_REQUEST_DATA_REGISTRATION_STATE:
-            requestGprsRegistrationState(t);
+            requestRegistrationState(t, 1);
+            break;
+        case RIL_REQUEST_VOICE_REGISTRATION_STATE:
+            requestRegistrationState(t, 0);
             break;
 
-        /* OEM */
+            /* OEM */
         case RIL_REQUEST_OEM_HOOK_RAW:
             // echo back data
             requestOEMHookRaw(data, datalen, t);
@@ -5702,7 +7006,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestOEMHookStrings(data, datalen, t);
             break;
 
-        /* Misc */
+            /* Misc */
         case RIL_REQUEST_SIGNAL_STRENGTH:
             requestSignalStrength(t);
             break;
@@ -5716,7 +7020,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestGetIMSI(t);
             break;
         case RIL_REQUEST_GET_IMEI:
-            requestGetIMEISV(t);
+            requestGetIMEI(t);
             break;
         case RIL_REQUEST_GET_IMEISV:
             requestGetIMEISV(t);
@@ -5728,7 +7032,15 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestBasebandVersion(t);
             break;
 
-        /* SIM Application Toolkit */
+            /* Band control */
+        case RIL_REQUEST_SET_BAND_MODE:
+            requestSetBandMode(data, datalen, t);
+            break;
+        case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
+            requestQueryAvailableBandMode(data, datalen, t);
+            break;
+
+            /* SIM Application Toolkit */
         case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
             requestStkSendTerminalResponse(data, datalen, t);
             break;
@@ -5745,7 +7057,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
             requestReportStkServiceIsRunning(t);
             break;
 
-        /* Misc ops */
+            /* Misc ops */
         case RIL_REQUEST_DIAL:
             requestDial(data, datalen, t);
             break;
@@ -5862,7 +7174,7 @@ D("%s() %s", __func__, radioStateToString(radio_state));
 
         default:
             ALOGW("FIXME: Unsupported request logged: %s",
-                 requestToString(request));
+                    requestToString(request));
             requestNotSupported(t, request);
             break;
     }
@@ -5892,8 +7204,7 @@ static void onRequest(int request, void *data, size_t datalen, RIL_Token t)
     RequestQueue *q = &s_requestQueue;
     int err;
 
-    r = (RILRequest *) malloc(sizeof(RILRequest));
-    memset(r, 0, sizeof(RILRequest));
+    r = (RILRequest *) calloc(1, sizeof(RILRequest));
 
     /* Formulate a RILRequest and put it in the queue. */
     r->request = request;
@@ -5986,90 +7297,40 @@ static void sendTime(void *p)
     at_send_command("AT+CCLK=\"%s%c%02d\"", str, tz[0], tzi);
 }
 
-
+/**
+ * Initialize everything
+ */
 static char initializeCommon(void)
 {
     int err = 0;
     unsigned int i;
     static const char* const initcmd[] = {
 
-        /* Reset the MS*/
-        "AT+CFUN=6",
-
-        /*  atchannel is tolerant of echo but it must */
-        /*  reset and have verbose result codes */
-        "ATZV1",
-
         /*  echo off */
         "ATE0",
 
-        /*  No auto-answer */
-        "ATS0=0",
+        /*  Send verbose results */
+        "ATQ0V1",
 
         /*  No auto-answer */
-        "AT%AUTOANSWER=0",
-
-        /*  send results */
-        "ATQ0",
-
-        /*  check for busy, don't check for dialone */
-        "ATX3",
-
-        /*  set DCD depending on service */
-        "AT&C1",
-
-        /*  set DTR according to service */
-        "AT&D1",
+        "ATS0=0",
 
         /*  Extended errors without textual decriptions */
         "AT+CMEE=1",
 
-        /*  detailed rings, unknown */
-        "AT+CRC=1;+CR=1",
-
-        /*  caller id = yes */
-        "AT+CLIP=1",
-
-        /*  don't hide outgoing callerID */
-        "AT+CLIR=0",
-
-        /*  Call Waiting notifications */
-        "AT+CCWA=1",
-
-        /*  No connected line identification */
-        "AT+COLP=0",
-
-        /*  USSD unsolicited */
-        "AT+CUSD=1",
-
-        /*  SMS PDU mode */
-        "AT+CMGF=0",
-
-        //"AT+GTKC=2",
-
-        /*  +CSSU unsolicited supp service notifications */
-        "AT+CSSN=0,1",
-
-        /*  HEX character set */
-        //"AT+CSCS=\"HEX\"",
-        "AT+CSCS=\"IRA\"",
-
-        /*  Modem mode */
-        "AT+FCLASS=0",
-
-        "AT+CNMI=1,2,2,2,0",
-        //"AT+CPPP=1",
+        /* Enable RF */
+        "AT^RFSWITCH=1"
+    };
 
+    D("%s()", __func__);
 
-        "AT"
-    };
+    setRadioState(RADIO_STATE_OFF);
 
     if (at_handshake() < 0) {
         LOG_FATAL("Handshake failed!");
         return 1;
     }
 
-
     for (i=0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
         err = at_send_command(initcmd[i]);
         if (err != AT_NOERROR) {
@@ -6077,63 +7338,9 @@ static char initializeCommon(void)
         }
     }
 
-    /* Send the current time of the OS to the module */
-    sendTime(NULL);
-
-    return 0;
-}
-
-/**
- * Initialize everything
- */
-static char initializeChannel(void)
-{
-    int err = 0;
-    unsigned int i;
-    static const char* const initcmd[] = {
-
-        /* Configure Packet Domain Network Registration Status events
-         *    2 = Enable network registration and location information
-         *        unsolicited result code
-         */
-
-        /*  Alternating voice/data off */
-        "AT+CMOD=0",
+    /* TE-MS handshake function */
+    //"AT^HS=0,0",
 
-        /*  Not muted */
-        "AT+CMUT=0",
-
-        /*  Network registration events */
-        "AT+CREG=2",
-
-        /*  GPRS registration events */
-        "AT+CGREG=2",
-
-        "AT+CGEQREQ=1,4,0,0,0,0,2,0,\"0E0\",\"0E0\",3,0,0",
-
-        /* Enable unsolicited reports */
-        "AT^CURC=1",
-
-        /* Enable GPRS reporting */
-        "AT+CGEREP=1,0",
-
-        /* for 3G Preferred */
-        "AT^SYSCFG=2,2,3FFFFFFF,1,2",
-
-        /* Disable RF */
-        "AT^RFSWITCH=0"
-    };
-
-    D("%s()", __func__);
-
-    setRadioState(RADIO_STATE_OFF);
-
-    for (i=0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
-        err = at_send_command(initcmd[i]);
-        if (err != AT_NOERROR) {
-            ALOGE("Failed sending command '%s'",initcmd[i]);
-        }
-    }
 
     /* Assume radio is off on error. */
     if (isRadioOn() > 0)
@@ -6154,28 +7361,75 @@ static void onUnsolicited (const char *s, const char *sms_pdu)
     if (getRadioState() == RADIO_STATE_UNAVAILABLE)
         return;
 
+    /* Timezone */
     if (strStartsWith(s, "%CTZV:")
             || strStartsWith(s,"+CTZV:")
             || strStartsWith(s,"+CTZDST:")
-            || strStartsWith(s,"+HTCCTZV:")) {
+            || strStartsWith(s,"+HTCCTZV:")
+            || strStartsWith(s,"^NWTIME:")
+            ) {
         unsolicitedNitzTime(s);
+
+    /* Call status/start/end indicator */
     } else if (strStartsWith(s,"+CRING:")
             || strStartsWith(s,"RING")
+            || strStartsWith(s,"+CLIP")
             || strStartsWith(s,"NO CARRIER")
             || strStartsWith(s,"+CCWA")
+            || strStartsWith(s,"^ORIG:")
+            || strStartsWith(s,"^CONF:")
+            || strStartsWith(s,"^CONN:")
+            || strStartsWith(s,"^CEND:")
           ) {
-        RIL_onUnsolicitedResponse (
+
+        /* Start/stop audio tunnel if needed when a successful connection is done */
+        if (   strStartsWith(s,"^ORIG:")) {
+            enqueueRILEvent(startAudioTunnel, NULL, NULL);
+            unsolicitedORIG(s);
+        } else
+        if (   strStartsWith(s,"^CONF:")) {
+            enqueueRILEvent(startAudioTunnel, NULL, NULL);
+            unsolicitedCONF(s);
+        } else
+        if (   strStartsWith(s,"^CONN:")) {
+            enqueueRILEvent(startAudioTunnel, NULL, NULL);
+            unsolicitedCONN(s);
+        } else
+        if (strStartsWith(s,"^CEND:")) {
+            /* This is the only fast way to detect when call was hang by the callee */
+            enqueueRILEvent(stopAudioTunnel, NULL, NULL);
+            unsolicitedCEND(s);
+        }
+
+        RIL_onUnsolicitedResponse(
+                RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
+                NULL, 0);
+        enqueueRILEvent(onDataCallListChanged, NULL, NULL);
+
+    /* Data call status/start/end */
+    } else if (strStartsWith(s,"^DCONN:")
+            || strStartsWith(s,"^DEND:")) {
+
+        RIL_onUnsolicitedResponse(
                 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
                 NULL, 0);
         enqueueRILEvent(onDataCallListChanged, NULL, NULL);
-    } else if (strStartsWith(s,"^RSSI:") ||
-               strStartsWith(s,"%RSSI:")) {
+
+    } else if (strStartsWith(s,"^COMM:")) {
+
+
+    } else if (strStartsWith(s,"^RSSI:")
+            || strStartsWith(s,"%RSSI:")) {
         unsolicitedRSSI(s);
     } else if (strStartsWith(s,"^MODE:")) {
         unsolicitedMode(s);
+    } else if (strStartsWith(s,"^SRVST:")) {
+        unsolicitedSrvStatus(s);
+    } else if (strStartsWith(s,"^SIMST:")) {
+        unsolicitedSimStatus(s);
     } else if (strStartsWith(s,"+CREG:")
             || strStartsWith(s,"+CGREG:")) {
-        RIL_onUnsolicitedResponse (
+        RIL_onUnsolicitedResponse(
                 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
                 NULL, 0);
         enqueueRILEvent(onDataCallListChanged, NULL, NULL);
@@ -6183,7 +7437,8 @@ static void onUnsolicited (const char *s, const char *sms_pdu)
         onNewSms(sms_pdu);
     } else if (strStartsWith(s, "+CBM:")) {
         onNewBroadcastSms(sms_pdu);
-    } else if (strStartsWith(s, "+CMTI:")) {
+    } else if (strStartsWith(s, "+CMTI:")
+            || strStartsWith(s, "+CDSI:")) {
         onNewSmsOnSIM(s);
     } else if (strStartsWith(s, "+CDS:")) {
         onNewStatusReport(sms_pdu);
@@ -6196,8 +7451,9 @@ static void onUnsolicited (const char *s, const char *sms_pdu)
         enqueueRILEvent(onDataCallListChanged, NULL, NULL);
     } else if (strStartsWith(s, "+CUSD:")) {
         unsolicitedUSSD(s);
-    } else if (strStartsWith(s, "+CIEV: 7") ||
-               strStartsWith(s, "Received SMS:")) {
+    } else if (strStartsWith(s, "+CIEV: 7")
+            || strStartsWith(s, "Received SMS:")
+            || strStartsWith(s, "^SMMEMFULL") ) {
         onNewSmsIndication();
     }
 }
@@ -6210,16 +7466,16 @@ static void signalCloseQueues(void)
         RequestQueue *q = s_requestQueues[i];
         if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
             ALOGE("%s() failed to take queue mutex: %s",
-                __func__, strerror(err));
+                    __func__, strerror(err));
 
         q->closed = 1;
         if ((err = pthread_cond_signal(&q->cond)) != 0)
             ALOGE("%s() failed to broadcast queue update: %s",
-                __func__, strerror(err));
+                    __func__, strerror(err));
 
         if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
             ALOGE("%s() failed to take queue mutex: %s", __func__,
-                 strerror(err));
+                    strerror(err));
     }
 }
 
@@ -6251,7 +7507,7 @@ static void onATTimeout()
 static void usage(char *s)
 {
 #ifdef RIL_SHLIB
-    fprintf(stderr, "htcgeneric-ril requires: -p <tcp port> or -d /dev/tty_device\n");
+    fprintf(stderr, "generic-ril requires: -p <tcp port> or -d /dev/tty_device\n");
 #else
     fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device] [-v /dev/tty_device]\n", s);
     exit(-1);
@@ -6318,8 +7574,8 @@ static void *queueRunner(void *param)
 
             if (fd < 0) {
                 ALOGE("%s() Failed to open AT channel %s (%s), retrying in %d.",
-                    __func__, queueArgs->device_path,
-                    strerror(errno), TIMEOUT_SEARCH_FOR_TTY);
+                        __func__, queueArgs->device_path,
+                        strerror(errno), TIMEOUT_SEARCH_FOR_TTY);
                 sleep(TIMEOUT_SEARCH_FOR_TTY);
                 /* Never returns. */
             }
@@ -6339,18 +7595,12 @@ static void *queueRunner(void *param)
         q = &s_requestQueue;
 
         if (initializeCommon()) {
-            ALOGE("%s() Failed to initialize channel!", __func__);
+            ALOGE("%s() Failed to initialize common", __func__);
             at_close();
             continue;
         }
 
         q->closed = 0;
-        if (initializeChannel()) {
-            ALOGE("%s() Failed to initialize channel!", __func__);
-            at_close();
-            continue;
-        }
-
         at_make_default_channel();
 
         ALOGE("%s() Looping the requestQueue!", __func__);
@@ -6362,9 +7612,9 @@ static void *queueRunner(void *param)
 
             memset(&ts, 0, sizeof(ts));
 
-        if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
-            ALOGE("%s() failed to take queue mutex: %s!",
-                __func__, strerror(err));
+            if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
+                ALOGE("%s() failed to take queue mutex: %s!",
+                        __func__, strerror(err));
 
             if (q->closed != 0) {
                 ALOGW("%s() AT Channel error, attempting to recover..", __func__);
@@ -6374,10 +7624,10 @@ static void *queueRunner(void *param)
             }
 
             while (q->closed == 0 && q->requestList == NULL &&
-                q->eventList == NULL) {
+                    q->eventList == NULL) {
                 if ((err = pthread_cond_wait(&q->cond, &q->queueMutex)) != 0)
                     ALOGE("%s() failed broadcast queue cond: %s!",
-                        __func__, strerror(err));
+                            __func__, strerror(err));
             }
 
             /* eventList is prioritized, smallest abstime first. */
@@ -6386,13 +7636,13 @@ static void *queueRunner(void *param)
                 err = pthread_cond_timedwait(&q->cond, &q->queueMutex, &q->eventList->abstime);
                 if (err && err != ETIMEDOUT)
                     ALOGE("%s() timedwait returned unexpected error: %s",
-                __func__, strerror(err));
+                            __func__, strerror(err));
             }
 
             if (q->closed != 0) {
                 if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
                     ALOGE("%s(): Failed to release queue mutex: %s!",
-                        __func__, strerror(err));
+                            __func__, strerror(err));
                 continue; /* Catch the closed bit at the top of the loop. */
             }
 
@@ -6402,7 +7652,7 @@ static void *queueRunner(void *param)
             clock_gettime(CLOCK_MONOTONIC, &ts);
 
             if (q->eventList != NULL &&
-                timespec_cmp(q->eventList->abstime, ts, < )) {
+                    timespec_cmp(q->eventList->abstime, ts, < )) {
                 e = q->eventList;
                 q->eventList = e->next;
             }
@@ -6414,7 +7664,7 @@ static void *queueRunner(void *param)
 
             if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
                 ALOGE("%s(): Failed to release queue mutex: %s!",
-                    __func__, strerror(err));
+                        __func__, strerror(err));
 
             if (e) {
                 e->eventCallback(e->param);
@@ -6441,10 +7691,31 @@ const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc,
     int opt;
     int port = -1;
     char *loophost = NULL;
-    const char *device_path = NULL;
+    const char *ctrl_path = NULL;
     struct queueArgs *queueArgs;
     pthread_attr_t attr;
 
+#if 0
+    /* Logcat test */
+    char local_ip[64];
+    char dns1[64];
+    char dns2[64];
+    char gw[64];
+    struct timeval from;
+    int rr;
+    gettimeofday(&from,NULL);
+    rr = get_pppd_info(&from,local_ip, dns1, dns2, gw);
+    ALOGD("result: %d",rr);
+#endif
+
+#if 0
+    char * m = decodeUSSD("D9775D0E6286E7749050FEBECFD3EE33685A9ECFD36F37283D07BDCD201868297449CBED70DA9D769F414679B90C2287E96190FDCDAEB7CBA0F41C849BCD60B41C68297401");
+    ALOGD("Decoded msg: '%s'",m);
+    free(m);
+#endif
+
+    memset(&sAudioChannel, 0, sizeof(sAudioChannel));
+
     s_rilenv = env;
 
     /* By default, use USB1 as audio channel */
@@ -6452,7 +7723,7 @@ const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc,
 
     D("%s() entering...", __func__);
 
-    while (-1 != (opt = getopt(argc, argv, "z:p:d:v:"))) {
+    while (-1 != (opt = getopt(argc, argv, "z:n:i:p:d:v:"))) {
         switch (opt) {
             case 'z':
                 loophost = optarg;
@@ -6469,8 +7740,8 @@ const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc,
                 break;
 
             case 'd':
-                device_path = optarg;
-                D("%s() Opening tty device %s", __func__, device_path);
+                ctrl_path = optarg;
+                D("%s() Opening tty device %s", __func__, ctrl_path);
                 break;
 
             case 'v':
@@ -6478,21 +7749,30 @@ const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc,
                 D("%s() Opening voice tty device %s", __func__, sAudioDevice);
                 break;
 
+            case 'n':
+                rndis_iface_dev = optarg;
+                D("%s() Using network interface %s as primary data channel.", __func__, rndis_iface_dev);
+                break;
+
+            case 'i':
+                ppp_iface_dev = optarg;
+                D("%s() Using ppp interface %s as primary data channel.", __func__, ppp_iface_dev);
+                break;
+
             default:
                 usage(argv[0]);
                 return NULL;
         }
     }
 
-    if (port < 0 && device_path == NULL) {
+    if (port < 0 && ctrl_path == NULL) {
         usage(argv[0]);
         return NULL;
     }
 
-    queueArgs = (struct queueArgs*) malloc(sizeof(struct queueArgs));
-    memset(queueArgs, 0, sizeof(struct queueArgs));
+    queueArgs = (struct queueArgs*) calloc(1, sizeof(struct queueArgs));
 
-    queueArgs->device_path = device_path;
+    queueArgs->device_path = ctrl_path;
     queueArgs->port = port;
     queueArgs->loophost = loophost;
 
@@ -6510,15 +7790,17 @@ int main (int argc, char **argv)
     int opt;
     int port = -1;
     char *loophost = NULL;
-    const char *device_path = NULL;
+    const char *ctrl_path = NULL;
     struct queueArgs *queueArgs;
 
+    memset(&sAudioChannel, 0, sizeof(sAudioChannel));
+
     /* By default, use USB1 as audio channel */
     strcpy(sAudioDevice,"/dev/ttyUSB1");
 
     D("%s() entering...", __func__);
 
-    while (-1 != (opt = getopt(argc, argv, "z:p:d:v:"))) {
+    while (-1 != (opt = getopt(argc, argv, "z:n:i:p:d:v:"))) {
         switch (opt) {
             case 'z':
                 loophost = optarg;
@@ -6535,8 +7817,8 @@ int main (int argc, char **argv)
                 break;
 
             case 'd':
-                device_path = optarg;
-                D("%s() Opening tty device %s", __func__, device_path);
+                ctrl_path = optarg;
+                D("%s() Opening tty device %s", __func__, ctrl_path);
                 break;
 
             case 'v':
@@ -6544,21 +7826,30 @@ int main (int argc, char **argv)
                 D("%s() Opening voice tty device %s", __func__, sAudioDevice);
                 break;
 
+            case 'n':
+                rndis_iface_dev = optarg;
+                D("%s() Using network interface %s as primary data channel.", __func__, rndis_iface_dev);
+                break;
+
+            case 'i':
+                ppp_iface_dev = optarg;
+                D("%s() Using ppp interface %s as primary data channel.", __func__, ppp_iface_dev);
+                break;
+
             default:
                 usage(argv[0]);
                 return 0;
         }
     }
 
-    if (port < 0 && device_path == NULL) {
+    if (port < 0 && ctrl_path == NULL) {
         usage(argv[0]);
         return 0;
     }
 
-    queueArgs = (struct queueArgs*) malloc(sizeof(struct queueArgs));
-    memset(queueArgs, 0, sizeof(struct queueArgs));
+    queueArgs = (struct queueArgs*) calloc(1, sizeof(struct queueArgs));
 
-    queueArgs->device_path = device_path;
+    queueArgs->device_path = ctrl_path;
     queueArgs->port = port;
     queueArgs->loophost = loophost;
 
index 6a67223..cddeb77 100644 (file)
@@ -78,9 +78,9 @@ char *getFirstElementValue(const char* document,
                    to be used when document contains many tags with same name. */
                 if (remainingDocument != NULL)
                     *remainingDocument = end + strlen(elementEndTag);
+            }
         }
     }
-    }
     return value;
 }
 
diff --git a/huaweigeneric-ril/net-utils.c b/huaweigeneric-ril/net-utils.c
new file mode 100644 (file)
index 0000000..d88f555
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/route.h>
+#include <linux/wireless.h>
+
+#define LOG_TAG "mbm-netutils"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+static int ifc_ctl_sock = -1;
+
+static const char *ipaddr_to_string(in_addr_t addr)
+{
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
+}
+
+int ifc_init(void)
+{
+    if (ifc_ctl_sock == -1) {
+    ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (ifc_ctl_sock < 0)
+        ALOGE("%s() socket() failed: %s", __func__, strerror(errno));
+    }
+    return ifc_ctl_sock < 0 ? -1 : 0;
+}
+
+void ifc_close(void)
+{
+    if (ifc_ctl_sock != -1) {
+        (void) close(ifc_ctl_sock);
+        ifc_ctl_sock = -1;
+    }
+}
+
+static void ifc_init_ifr(const char *name, struct ifreq *ifr)
+{
+    memset(ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr->ifr_name, name, IFNAMSIZ);
+    ifr->ifr_name[IFNAMSIZ - 1] = 0;
+}
+
+static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
+{
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    if (ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0)
+    return -1;
+    ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
+    return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
+}
+
+int ifc_up(const char *name)
+{
+    return ifc_set_flags(name, IFF_UP | IFF_NOARP, 0);
+}
+
+int ifc_down(const char *name)
+{
+    return ifc_set_flags(name, 0, IFF_UP);
+}
+
+static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
+{
+    struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+    sin->sin_addr.s_addr = addr;
+}
+
+int ifc_set_addr(const char *name, in_addr_t addr)
+{
+    struct ifreq ifr;
+
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, addr);
+
+    return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
+}
+
+int ifc_set_mask(const char *name, in_addr_t mask)
+{
+    struct ifreq ifr;
+
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, mask);
+
+    return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
+}
+
+int ifc_configure(const char *ifname,
+        in_addr_t address,
+        in_addr_t gateway)
+{
+    in_addr_t netmask = ~0;
+    (void) gateway;
+
+    ifc_init();
+
+    if (ifc_up(ifname)) {
+        ALOGE("%s() Failed to turn on interface %s: %s", __func__,
+                ifname,
+                strerror(errno));
+        ifc_close();
+        return -1;
+    }
+    if (ifc_set_addr(ifname, address)) {
+        ALOGE("%s() Failed to set ipaddr %s: %s", __func__,
+                ipaddr_to_string(address), strerror(errno));
+        ifc_down(ifname);
+        ifc_close();
+        return -1;
+    }
+    if (ifc_set_mask(ifname, netmask)) {
+        ALOGE("%s() failed to set netmask %s: %s", __func__,
+                ipaddr_to_string(netmask), strerror(errno));
+        ifc_down(ifname);
+        ifc_close();
+        return -1;
+    }
+
+    ifc_close();
+
+    return 0;
+}
+
+int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
+{
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    if (addr != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
+            *addr = 0;
+        } else {
+            *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+
+    if (mask != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
+            *mask = 0;
+        } else {
+            *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+
+    if (flags != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
+            *flags = 0;
+        } else {
+            *flags = ifr.ifr_flags;
+        }
+    }
+
+    return 0;
+}
diff --git a/huaweigeneric-ril/net-utils.h b/huaweigeneric-ril/net-utils.h
new file mode 100644 (file)
index 0000000..4a5d69e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MBM_NET_UTILS_H
+#define MBM_NET_UTILS_H 1
+
+#include <arpa/inet.h>
+
+int ifc_init(void);
+void ifc_close(void);
+int ifc_up(const char *name);
+int ifc_down(const char *name);
+int ifc_set_addr(const char *name, in_addr_t addr);
+int ifc_set_mask(const char *name, in_addr_t mask);
+int ifc_add_host_route(const char *name);
+int ifc_configure(const char *ifname,
+        in_addr_t address,
+        in_addr_t gateway);
+int ifc_get_info(const char *name, in_addr_t *addr,
+        in_addr_t *mask, unsigned *flags);
+
+#endif
index 4bd9263..1fc4c76 100644 (file)
@@ -183,10 +183,7 @@ static void *dispatchString(void *data, size_t datalen)
     (void) data; (void) datalen;
     assert(datalen == sizeof(char *));
 
-    if (data)
-        return strdup((char *) data);
-
-    return NULL;
+    return data ? strdup((char *) data) : NULL;
 }
 
 static void *dispatchStrings(void *data, size_t datalen)
@@ -199,11 +196,9 @@ static void *dispatchStrings(void *data, size_t datalen)
     assert((datalen % sizeof(char *)) == 0);
 
     ret = malloc(strCount * sizeof(char *));
-    memset(ret, 0, sizeof(char *) * strCount);
 
     for (i = 0; i < strCount; i++) {
-        if (a[i])
-            ret[i] = strdup(a[i]);
+        ret[i] = a[i] ? strdup(a[i]) : 0;
     }
 
     return (void *) ret;
@@ -211,20 +206,19 @@ static void *dispatchStrings(void *data, size_t datalen)
 
 static void *dispatchGsmBrSmsCnf(void *data, size_t datalen)
 {
-    RIL_GSM_BroadcastSmsConfigInfo **a =
-        (RIL_GSM_BroadcastSmsConfigInfo **) data;
+    RIL_GSM_BroadcastSmsConfigInfo **a;
     int count;
     void **ret;
     int i;
 
+    a = (RIL_GSM_BroadcastSmsConfigInfo **) data;
     count = datalen / sizeof(RIL_GSM_BroadcastSmsConfigInfo *);
 
     ret = malloc(count * sizeof(RIL_GSM_BroadcastSmsConfigInfo *));
-    memset(ret, 0, sizeof(*ret));
 
     for (i = 0; i < count; i++) {
-        if (a[i])
-            ret[i] = dispatchRaw(a[i], sizeof(RIL_GSM_BroadcastSmsConfigInfo));
+        ret[i] = a[i] ? dispatchRaw(a[i],
+                sizeof(RIL_GSM_BroadcastSmsConfigInfo)) : 0;
     }
 
     return ret;
@@ -248,10 +242,10 @@ static void freeDial(void *data)
 {
     RIL_Dial *d = data;
 
-    if (d->address)
+    if (d) {
         free(d->address);
-
-    free(d);
+        free(d);
+    }
 }
 
 static void freeStrings(void *data, size_t datalen)
index aebe05a..4ce17db 100644 (file)
@@ -18,8 +18,7 @@
 
 int hex2int(char c)
 {
-    if (c>'9') return c-'A'+10;
-    return c-'0';
+    return (c>'9') ? c-'A'+10 : c-'0';
 }
 
 int getbit(char *s,int b)
@@ -28,8 +27,7 @@ int getbit(char *s,int b)
     int bit=b%4;
 
     int data=hex2int(s[byte]);
-    if (data&(1<<(3-bit))) return 1;
-        else return 0;
+    return (data&(1<<(3-bit))) ? 1 : 0;
 }
 
 const char hextable[17]="0123456789ABCDEF";
@@ -64,13 +62,12 @@ const char decode_table[17]=".1234567890*#...";
 
 void decode_number(char *msg, int length, char *no)
 {
-
     int ndigits=getbits(msg,2,8);
-    int j,digit;
+    int j;
 
     for (j=0;j<ndigits;j++)
-        *no++=decode_table[getbits(msg,10+j*4,4)];
-    *no=0;
+        *no++ = decode_table[getbits(msg,10+j*4,4)];
+    *no = 0;
 }
 
 int encode_digit(int d)
@@ -85,7 +82,6 @@ int encode_digit(int d)
 int encode_number(char *msg, char *no)
 {
     unsigned int i;
-    int digit;
 
     setbits(msg, 0, 2, 0);
     setbits(msg, 2, 8, strlen(no));
@@ -102,8 +98,8 @@ void get_code_and_length(char *msg, int *code, int *length)
 
 void decode_bearer_data(char *msg, int length, char *message, int *is_vm)
 {
-    int i=0,j;
-    int code,sublength;
+    int i = 0, j;
+    int code, sublength;
 
     while (i<length) {
         get_code_and_length(msg+i*2,&code,&sublength);
@@ -140,32 +136,32 @@ void decode_bearer_data(char *msg, int length, char *message, int *is_vm)
 
 int encode_bearer_data(char *msg, char *data)
 {
-    int msgid=0;
+    int msgid = 0;
     unsigned int i;
-        int b;
-    char *start=msg;
+    int b;
+    char *start = msg;
 
     for (i=0;i<strlen(data);i++)
-        msgid+=data[i];
+        msgid += data[i];
 
     setbits(msg,0,8,0); // message id
     setbits(msg,8,8,3); // 3 bytes
     setbits(msg,16,4,2); // 2 means send
     setbits(msg,20,16,msgid); // use message sum for id
-    msg+=10;
+    msg += 10;
     setbits(msg,0,8,01); // user data
     setbits(msg,16,5,02); // set encoding
     setbits(msg,21,8,strlen(data)); // length
-    b=29;
+    b = 29;
     for (i=0;i<strlen(data);i++) {
         setbits(msg,b,7,data[i]);
-        b=b+7;
+        b = b+7;
     }
     setbits(msg,8,8,(b+7)/8-2);
-    msg=msg+2*((b+7)/8);
+    msg = msg+2*((b+7)/8);
     setbits(msg,0,24,0x80100);
     setbits(msg,24,24,0x0D0100);
-    msg=msg+12;
+    msg = msg+12;
     return (msg-start)/2;
 }
 
@@ -242,7 +238,8 @@ char **cdma_to_gsmpdu(char *msg)
         smsaddr.toa = 0xd0;
     }
     sms_timestamp_now(&smstime);
-    SmsPDU *pdu=smspdu_create_deliver_utf8((const unsigned char *)message,strlen(message),&smsaddr,&smstime);
+    SmsPDU *pdu = smspdu_create_deliver_utf8(
+            (const unsigned char *)message, strlen(message), &smsaddr, &smstime);
     //hexpdu=malloc(512);
     char *s=hexpdu;
     while (*pdu) {
@@ -260,26 +257,28 @@ char **cdma_to_gsmpdu(char *msg)
 char *gsm_to_cdmapdu(char *msg)
 {
     char to[256];
-    char message[256];
+    unsigned char message[256];
     static char hexpdu[512];
     SmsAddressRec smsaddr;
-    sms_address_from_str(&smsaddr,"000000",6);
+    int length;
+
+    sms_address_from_str(&smsaddr, "000000", 6);
 
-    SmsPDU pdu=smspdu_create_from_hex( msg, strlen(msg) );
-    if (smspdu_get_receiver_address(pdu,&smsaddr)<0) {
+    SmsPDU pdu = smspdu_create_from_hex(msg, strlen(msg));
+    if (smspdu_get_receiver_address(pdu, &smsaddr) < 0) {
         ALOGE("Error: no receiver address");
-        smspdu_get_sender_address(pdu,&smsaddr);
+        smspdu_get_sender_address(pdu, &smsaddr);
     }
-    sms_address_to_str(&smsaddr,to,256);
+    sms_address_to_str(&smsaddr, to, 256);
     if (to[0]=='+') { // convert + to 00 otherwise international sms doesn't work
-        memmove(to+1,to,255);
+        memmove(to+1, to, 255);
         to[0]='0';
         to[1]='0';
     }
-    int length=smspdu_get_text_message(pdu, message, 256);
-    message[length]=0;
+    length = smspdu_get_text_message(pdu, message, 256);
+    message[length] = 0;
     smspdu_free(pdu);
-    ALOGD("GSM Message:%s To:%s\n",message,to);
-    encode_cdma_sms(hexpdu,to,message);
+    ALOGD("GSM Message:%s To:%s\n", message, to);
+    encode_cdma_sms(hexpdu, to, (char *)message);
     return hexpdu;
 }
index 76bf6fb..b8dfbad 100644 (file)
@@ -165,14 +165,14 @@ gsm_rope_add_timestamp( GsmRope  rope, const SmsTimeStampRec*  ts )
 int
 sms_address_to_str( SmsAddress  address, char*  str, int  strlen )
 {
-    bytes_t      data = address->data;
-    if(address->toa == 0x91)
-        *str++='+';
     int i;
     char c;
+    bytes_t data = address->data;
+    if (address->toa == 0x91)
+        *str++='+';
     for (i=0;i<address->len;i++) {
         c=data[i/2];
-        if(i&1) c=c>>4;
+        if (i&1) c=c>>4;
         *str++='0'+(c&15);
     }
     *str=0;
@@ -206,8 +206,8 @@ sms_address_from_str( SmsAddress  address, const char*  src, int  srclen )
     while (src < end) {
         int  c = *src++ - '0';
 
-        if ( (unsigned)c >= 10 ||
-              data >= address->data + sizeof(address->data) )
+        if ((unsigned)c >= 10 ||
+                data >= address->data + sizeof(address->data))
             goto Fail;
 
         data[0] |= c << shift;
@@ -231,7 +231,7 @@ Fail:
 int
 sms_address_from_bytes( SmsAddress  address, const unsigned char*  buf, int  buflen )
 {
-    int   len = sizeof(address->data), num_digits;
+    unsigned int len = sizeof(address->data), num_digits;
 
     if (buflen < 2)
         return -1;
@@ -357,8 +357,8 @@ sms_get_sc_address( cbytes_t   *pcur,
     int       result = -1;
 
     if (cur < end) {
-        int  len = cur[0];
-        int  dlen, adjust = 0;
+        unsigned int  len = cur[0];
+        unsigned int  dlen, adjust = 0;
 
         cur += 1;
 
@@ -438,7 +438,7 @@ sms_get_address( cbytes_t   *pcur,
 {
     cbytes_t  cur    = *pcur;
     int       result = -1;
-    int       len, dlen;
+    unsigned int len, dlen;
 
     if (cur >= end)
         goto Exit;
@@ -683,8 +683,7 @@ sms_get_text_utf8( cbytes_t        *pcur,
     len = *cur++;
 
     /* skip user data header if any */
-    if ( hasUDH )
-    {
+    if ( hasUDH ) {
         int  hlen;
 
         if (cur >= end)
@@ -709,11 +708,10 @@ sms_get_text_utf8( cbytes_t        *pcur,
     if (coding == SMS_CODING_SCHEME_GSM7) {
         int  count = utf8_from_gsm7( cur, 0, len, NULL );
 
-        if (rope != NULL)
-        {
+        if (rope != NULL) {
             bytes_t  dst = gsm_rope_reserve( rope, count );
-        if(hasUDH && dst)
-        *dst++=(*cur++)>>1;
+            if(hasUDH && dst)
+                *dst++=(*cur++)>>1;
             if (dst != NULL)
                 utf8_from_gsm7( cur, 0, len, dst );
         }
@@ -721,8 +719,7 @@ sms_get_text_utf8( cbytes_t        *pcur,
     } else if (coding == SMS_CODING_SCHEME_UCS2) {
         int  count = ucs2_to_utf8( cur, len/2, NULL );
 
-        if (rope != NULL)
-        {
+        if (rope != NULL) {
             bytes_t  dst = gsm_rope_reserve( rope, count );
             if (dst != NULL)
                 ucs2_to_utf8( cur, len/2, dst );
@@ -1065,7 +1062,7 @@ smspdu_create_from_hex( const char*  hex, int  hexlen )
         goto Exit;
     }
 
-    gsm_hex_to_bytes( hex, hexlen, p->base );
+    gsm_hex_to_bytes((cbytes_t) hex, hexlen, p->base );
     p->end = p->base + (hexlen+1)/2;
 
     data = p->base;