Hi Denis,
On Sat, Jun 11, 2011 at 7:33 PM, Denis Kenzior <denkenz(a)gmail.com> wrote:
Hi Amit,
On 06/08/2011 04:46 AM, Amit Mendapara wrote:
> The AT commands listed with AT+CLAC matches with MBM supported devices.
> However, the mbm plugin doesn't work for this devices and the
specification is
> also quite different.
The linktop device is most likely another Qualcomm clone, so the closest
driver would be the huawei and not mbm.
The windows driver files have some references to ST-Ericsson and the AT
commands
looks more like as subset of ST-Ericsson commands then Huawei.
I have cross check the listed commands with
http://natisbad.org/E4300/Dell_Wireless_5530_AT_cmd_ref.html and
found lots of AT*E**** commands which are Ericsson extensions.
>
> I have also adopted some fixes from huawei plugin to fix MeeGo bug #14784
>
> Signed-off-by: Amit Mendapara <mendapara.amit(a)gmail.com>
We don't use Signed-off-by, please configure your git accordingly.
Sure, I will remove signed-off next time.
> ---
> plugins/linktop.c | 301
++++++++++++++++++++++++++++++++++++----------------
> 1 files changed, 208 insertions(+), 93 deletions(-)
>
> diff --git a/plugins/linktop.c b/plugins/linktop.c
> index 953f634..26536d8 100644
> --- a/plugins/linktop.c
> +++ b/plugins/linktop.c
> @@ -26,6 +26,7 @@
> #include <stdio.h>
> #include <errno.h>
> #include <stdlib.h>
> +#include <string.h>
>
> #include <glib.h>
> #include <gatchat.h>
> @@ -42,6 +43,7 @@
> #include <ofono/message-waiting.h>
> #include <ofono/netreg.h>
> #include <ofono/sim.h>
> +#include <ofono/stk.h>
This looks fishy, have you actually tested STK on the linktop devices?
If not, then I'd rather leave this part out right now.
I never tested this feature and the test-stk-menu shows empty menu so yes
you can remove this.
> #include <ofono/cbs.h>
> #include <ofono/sms.h>
> #include <ofono/ussd.h>
> @@ -53,16 +55,21 @@
> #include <ofono/radio-settings.h>
Same with radio-settings and voicecall.
I have tested redio-settings and is required to switch to edge to umts.
The device supports voice call but I am unable to test with test-voicecall
script ast it fails with
`Method "GetCalls" with signature "" on interface
"org.ofono.VoiceCallManager" doesn't exist` error.
Looking at windows driver log, the device issues AT*ECAV command
to initiate voice call like this:
AT*ECAV: 1,1,1,,,"1503",129
> #include <ofono/log.h>
>
> -#include <drivers/atmodem/vendor.h>
> #include <drivers/atmodem/atutil.h>
> +#include <drivers/atmodem/vendor.h>
>
> +static const char *cpin_prefix[] = { "+CPIN:", NULL };
> static const char *none_prefix[] = { NULL };
>
> struct linktop_data {
> - GAtChat *modem;
> - GAtChat *control;
> + GAtChat *modem_port;
> + GAtChat *data_port;
> + guint cpin_poll_source;
> + guint cpin_poll_count;
> + gboolean have_sim;
> struct ofono_gprs *gprs;
> struct ofono_gprs_context *gc;
> + guint reopen_source;
> };
>
> static int linktop_probe(struct ofono_modem *modem)
> @@ -86,35 +93,86 @@ static void linktop_remove(struct ofono_modem *modem)
>
> DBG("%p", modem);
>
> + if (data->reopen_source > 0) {
> + g_source_remove(data->reopen_source);
> + data->reopen_source = 0;
> + }
> +
> ofono_modem_set_data(modem, NULL);
>
> - g_at_chat_unref(data->modem);
> - g_at_chat_unref(data->control);
> + g_at_chat_unref(data->data_port);
> + g_at_chat_unref(data->modem_port);
> +
> + if (data->cpin_poll_source > 0)
> + g_source_remove(data->cpin_poll_source);
>
> g_free(data);
> }
>
> static void linktop_debug(const char *str, void *user_data)
> {
> - const char *prefix = user_data;
> + const char *prefix = user_data;
> +
> + ofono_info("%s%s", prefix, str);
> +}
> +
> +static gboolean init_simpin_check(gpointer user_data);
> +
> +static void simpin_check(gboolean ok, GAtResult *result, gpointer
user_data)
> +{
> + struct ofono_modem *modem = user_data;
> + struct linktop_data *data = ofono_modem_get_data(modem);
>
> - ofono_info("%s%s", prefix, str);
> + DBG("");
> +
> + /* Modem returns an error if SIM is not ready. */
> + if (!ok && data->cpin_poll_count++ < 5) {
> + data->cpin_poll_source =
> + g_timeout_add_seconds(1, init_simpin_check, modem);
> + return;
> + }
> +
> + data->cpin_poll_count = 0;
> +
> + /* There is probably no SIM if SIM is not ready after 5 seconds. */
> + data->have_sim = ok;
> +
> + ofono_modem_set_powered(modem, TRUE);
> }
>
> -static GAtChat *open_device(struct ofono_modem *modem,
> - const char *key, char *debug)
> +static gboolean init_simpin_check(gpointer user_data)
> +{
> + struct ofono_modem *modem = user_data;
> + struct linktop_data *data = ofono_modem_get_data(modem);
> +
> + data->cpin_poll_source = 0;
> +
> + g_at_chat_send(data->modem_port, "AT+CPIN?", cpin_prefix,
> + simpin_check, modem, NULL);
> +
> + return FALSE;
> +}
> +
> +static void cfun_enable(gboolean ok, GAtResult *result, gpointer
user_data)
Please name this function cfun_enable_cb, so it is clear that it is in
fact a callback.
Fine, I will do that...
> +{
> + struct ofono_modem *modem = user_data;
> +
> + DBG("");
> +
> + if (!ok) {
> + ofono_modem_set_powered(modem, FALSE);
> + return;
> + }
> +
> + init_simpin_check(modem);
> +}
> +
> +static GAtChat *create_port(const char *device)
> {
> - const char *device;
> GAtSyntax *syntax;
> GIOChannel *channel;
> GAtChat *chat;
>
> - device = ofono_modem_get_string(modem, key);
> - if (device == NULL)
> - return NULL;
> -
> - DBG("%s %s", key, device);
> -
> channel = g_at_tty_open(device, NULL);
> if (channel == NULL)
> return NULL;
> @@ -127,81 +185,116 @@ static GAtChat *open_device(struct ofono_modem
*modem,
> if (chat == NULL)
> return NULL;
>
> - if (getenv("OFONO_AT_DEBUG"))
> - g_at_chat_set_debug(chat, linktop_debug, debug);
> -
> return chat;
> }
>
> -static void linktop_disconnect(gpointer user_data)
> +static void linktop_disconnect(gpointer user_data);
> +
> +static gboolean reopen_callback(gpointer user_data)
> {
> struct ofono_modem *modem = user_data;
> struct linktop_data *data = ofono_modem_get_data(modem);
> + const char *data_dev;
> +
> + data_dev = ofono_modem_get_string(modem, "DataDevice");
> + data->data_port = create_port(data_dev);
> + /* retry once if failed */
> + if (data->data_port == NULL) {
> + if (data->reopen_source > 0)
> + return FALSE;
> +
> + data->reopen_source = g_timeout_add_seconds(1,
> + reopen_callback, modem);
> + ofono_debug("opening data port failed, retrying...");
> + return FALSE;
> + }
>
> - DBG("");
> -
> - if (data->gc)
> - ofono_gprs_context_remove(data->gc);
> -
> - g_at_chat_unref(data->modem);
> - data->modem = NULL;
> -
> - data->modem = open_device(modem, "Modem", "Modem: ");
> - if (data->modem == NULL)
> - return;
> + if (getenv("OFONO_AT_DEBUG"))
> + g_at_chat_set_debug(data->data_port, linktop_debug, "Data:
");
>
> - g_at_chat_set_disconnect_function(data->modem,
> + g_at_chat_set_disconnect_function(data->data_port,
> linktop_disconnect, modem);
>
> ofono_info("Reopened GPRS context channel");
>
> - data->gc = ofono_gprs_context_create(modem, 0, "atmodem",
data->modem);
> -
> - if (data->gprs && data->gc)
> + data->gc = ofono_gprs_context_create(modem, 0,
> + "atmodem", data->data_port);
> + if (data->gprs && data->gc) {
> ofono_gprs_add_context(data->gprs, data->gc);
> + }
These braces are not necessary, please remove them
Fine...
> +
> + data->reopen_source = 0;
> +
> + return FALSE;
> }
>
> -static void cfun_enable(gboolean ok, GAtResult *result, gpointer
user_data)
> +static void linktop_disconnect(gpointer user_data)
> {
> struct ofono_modem *modem = user_data;
> + struct linktop_data *data = ofono_modem_get_data(modem);
>
> - DBG("");
> + DBG("%p, data->gc %p", modem, data->gc);
> +
> + /* gprs_context has been destructed and needs not reopen */
> + if (data->gc == NULL)
> + return
> +
> + ofono_gprs_context_remove(data->gc);
>
> - ofono_modem_set_powered(modem, ok);
> + g_at_chat_unref(data->data_port);
> + data->data_port = NULL;
> +
> + /* Waiting for the +CGEV: ME DEACT might also work */
> + if (data->reopen_source > 0)
> + g_source_remove(data->reopen_source);
> +
> + data->reopen_source = g_timeout_add_seconds(1, reopen_callback,
modem);
> }
>
> static int linktop_enable(struct ofono_modem *modem)
> {
> struct linktop_data *data = ofono_modem_get_data(modem);
> + const char *modem_dev;
> + const char *data_dev;
>
> DBG("%p", modem);
>
> - data->modem = open_device(modem, "Modem", "Modem: ");
> - if (data->modem == NULL)
> - return -EINVAL;
> + modem_dev = ofono_modem_get_string(modem, "ModemDevice");
> + data_dev = ofono_modem_get_string(modem, "DataDevice");
>
> - g_at_chat_set_disconnect_function(data->modem,
> - linktop_disconnect, modem);
> + DBG("%s, %s", modem_dev, data_dev);
> +
> + if (modem_dev == NULL || data_dev == NULL)
> + return -EINVAL;
>
> - data->control = open_device(modem, "Control", "Control:
");
> - if (data->control == NULL) {
> - g_at_chat_unref(data->modem);
> - data->modem = NULL;
> + data->modem_port = create_port(modem_dev);
> + if (data->modem_port == NULL)
> return -EIO;
> - }
>
> - g_at_chat_send(data->control, "ATE0 +CMEE=1", none_prefix,
> - NULL, NULL, NULL);
> + if (getenv("OFONO_AT_DEBUG"))
> + g_at_chat_set_debug(data->modem_port, linktop_debug,
"Modem: ");
> +
> + data->data_port = create_port(data_dev);
> + if (data->data_port == NULL) {
> + g_at_chat_unref(data->modem_port);
> + data->modem_port = NULL;
>
> - g_at_chat_send(data->modem, "AT", none_prefix,
> - NULL, NULL, NULL);
> + return -EIO;
> + }
>
> - g_at_chat_send(data->modem, "AT &F", none_prefix,
> - NULL, NULL, NULL);
> + if (getenv("OFONO_AT_DEBUG"))
> + g_at_chat_set_debug(data->data_port, linktop_debug, "Data:
");
>
> - g_at_chat_send(data->control, "AT+CFUN=4", none_prefix,
> - cfun_enable, modem, NULL);
> + g_at_chat_set_disconnect_function(data->data_port,
> + linktop_disconnect, modem);
>
> + g_at_chat_send(data->modem_port, "AT&F E0 V1 X4 &C1
+CMEE=1", NULL,
> + NULL, NULL, NULL);
> + g_at_chat_send(data->data_port, "AT&F E0 V1 X4 &C1
+CMEE=1", NULL,
> + NULL, NULL, NULL);
> + g_at_chat_send(data->modem_port, "AT+CFUN=4", none_prefix,
> + cfun_enable, modem, NULL);
> +
> return -EINPROGRESS;
> }
>
> @@ -212,8 +305,11 @@ static void cfun_disable(gboolean ok, GAtResult
*result, gpointer user_data)
>
> DBG("");
>
> - g_at_chat_unref(data->control);
> - data->control = NULL;
> + g_at_chat_unref(data->modem_port);
> + data->modem_port = NULL;
> +
> + g_at_chat_unref(data->data_port);
> + data->data_port = NULL;
>
> if (ok)
> ofono_modem_set_powered(modem, FALSE);
> @@ -225,19 +321,17 @@ static int linktop_disable(struct ofono_modem
*modem)
>
> DBG("%p", modem);
>
> - if (data->modem) {
> - g_at_chat_cancel_all(data->modem);
> - g_at_chat_unregister_all(data->modem);
> - g_at_chat_unref(data->modem);
> - data->modem = NULL;
> + if (data->reopen_source > 0) {
> + g_source_remove(data->reopen_source);
> + data->reopen_source = 0;
> }
>
> - if (data->control == NULL)
> + if (data->modem_port == NULL)
> return 0;
>
> - g_at_chat_cancel_all(data->control);
> - g_at_chat_unregister_all(data->control);
> - g_at_chat_send(data->control, "AT+CFUN=4", none_prefix,
> + g_at_chat_cancel_all(data->modem_port);
> + g_at_chat_unregister_all(data->modem_port);
> + g_at_chat_send(data->modem_port, "AT+CFUN=4", NULL,
> cfun_disable, modem, NULL);
>
> return -EINPROGRESS;
> @@ -253,17 +347,37 @@ static void set_online_cb(gboolean ok, GAtResult
*result, gpointer user_data)
> cb(&error, cbd->data);
> }
>
> +static void set_offline_cb(gboolean ok, GAtResult *result, gpointer
user_data)
> +{
> + struct cb_data *cbd = user_data;
> + ofono_modem_online_cb_t cb = cbd->cb;
> + struct ofono_error error;
> +
> + if (ok) {
> + struct linktop_data *data = cbd->user;
> +
> + data->gc = NULL;
> + data->gprs = NULL;
> + }
> +
> + decode_at_error(&error, g_at_result_final_response(result));
> + cb(&error, cbd->data);
> +}
> +
> static void linktop_set_online(struct ofono_modem *modem, ofono_bool_t
online,
> ofono_modem_online_cb_t cb, void
*user_data)
> {
> struct linktop_data *data = ofono_modem_get_data(modem);
> - GAtChat *chat = data->control;
> + GAtChat *chat = data->modem_port;
> struct cb_data *cbd = cb_data_new(cb, user_data);
> char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4";
>
> DBG("modem %p %s", modem, online ? "online" :
"offline");
>
> - if (g_at_chat_send(chat, command, NULL, set_online_cb, cbd,
g_free))
> + cbd->user = data;
> +
> + if (g_at_chat_send(chat, command, NULL,
> + online ? set_online_cb : set_offline_cb,
cbd, g_free))
> return;
>
> g_free(cbd);
> @@ -278,11 +392,11 @@ static void linktop_pre_sim(struct ofono_modem
*modem)
>
> DBG("%p", modem);
>
> - ofono_devinfo_create(modem, 0, "atmodem", data->control);
> - sim = ofono_sim_create(modem, 0, "atmodem", data->control);
> - ofono_voicecall_create(modem, 0, "stemodem", data->control);
> + ofono_devinfo_create(modem, 0, "atmodem", data->modem_port);
> + sim = ofono_sim_create(modem, 0, "atmodem", data->modem_port);
> + ofono_voicecall_create(modem, 0, "stemodem", data->modem_port);
>
> - if (sim)
> + if (data->have_sim && sim)
> ofono_sim_inserted_notify(sim, TRUE);
> }
>
> @@ -292,35 +406,36 @@ static void linktop_post_sim(struct ofono_modem
*modem)
>
> DBG("%p", modem);
>
> - ofono_radio_settings_create(modem, 0, "stemodem",
data->control);
> - ofono_phonebook_create(modem, 0, "atmodem", data->control);
> - ofono_sms_create(modem, 0, "atmodem", data->control);
> + ofono_stk_create(modem, 0, "mbmmodem", data->modem_port);
> + ofono_radio_settings_create(modem, 0, "stemodem",
data->modem_port);
The above two look fishy. Have you tested that they work? Otherwise
lets drop them for now.
As said earlier, radio settings is required and test.
> + ofono_phonebook_create(modem, 0, "atmodem", data->modem_port);
> + ofono_sms_create(modem, 0, "atmodem", data->modem_port);
> }
>
> static void linktop_post_online(struct ofono_modem *modem)
> {
> struct linktop_data *data = ofono_modem_get_data(modem);
> struct ofono_message_waiting *mw;
> - struct ofono_gprs *gprs;
> - struct ofono_gprs_context *gc;
>
> DBG("%p", modem);
>
> - ofono_ussd_create(modem, 0, "atmodem", data->control);
> - ofono_call_forwarding_create(modem, 0, "atmodem",
data->control);
> - ofono_call_settings_create(modem, 0, "atmodem", data->control);
> - ofono_netreg_create(modem, OFONO_VENDOR_MBM, "atmodem",
data->control);
> - ofono_call_meter_create(modem, 0, "atmodem", data->control);
> - ofono_call_barring_create(modem, 0, "atmodem", data->control);
> - ofono_call_volume_create(modem, 0, "atmodem", data->control);
> - ofono_cbs_create(modem, 0, "atmodem", data->control);
> -
> - gprs = ofono_gprs_create(modem, OFONO_VENDOR_MBM,
> - "atmodem", data->control);
> - gc = ofono_gprs_context_create(modem, 0, "atmodem",
data->modem);
> -
> - if (gprs && gc)
> - ofono_gprs_add_context(gprs, gc);
> + ofono_netreg_create(modem, 0, "atmodem", data->modem_port);
> + ofono_cbs_create(modem, 0, "atmodem", data->modem_port);
> + ofono_ussd_create(modem, 0, "atmodem", data->modem_port);
> + ofono_call_forwarding_create(modem, 0, "atmodem",
data->modem_port);
> + ofono_call_settings_create(modem, 0, "atmodem",
data->modem_port);
> + ofono_call_meter_create(modem, 0, "atmodem", data->modem_port);
> + ofono_call_barring_create(modem, 0, "atmodem",
data->modem_port);
> + ofono_call_volume_create(modem, 0, "atmodem", data->modem_port);
> +
This device has voice call features and also supports call forward/barring
and volume
settings but I am unable to test with the test scripts. So I you suggest, I
will remove these
feature for the moment and only enable the features I tested successfully.
I have tested ussd and it's working fine however not sure about cbs...
Here I am attaching few information about the device and the windows driver
log sniffed
with sysinternal's usb monitor tool.
Regards
--
Amit Mendapara