diff --git a/plugins/quectel.c b/plugins/quectel.c index bddf6a17..eef66ced 100644 --- a/plugins/quectel.c +++ b/plugins/quectel.c @@ -99,6 +99,9 @@ struct quectel_data { int mux_ready_count; int initial_ldisc; struct l_gpio_writer *gpio; + struct l_timeout *init_timeout; + size_t init_count; + guint init_cmd; }; struct dbus_hw { @@ -186,6 +189,7 @@ static void quectel_remove(struct ofono_modem *modem) g_at_chat_unregister(data->aux, data->cpin_ready); ofono_modem_set_data(modem, NULL); + l_timeout_remove(data->init_timeout); l_gpio_writer_free(data->gpio); g_at_chat_unref(data->aux); g_at_chat_unref(data->modem); @@ -867,6 +871,47 @@ static void ate_cb(int ok, GAtResult *result, void *user_data) cmux_cb, modem, NULL); } +static void init_cmd_cb(gboolean ok, GAtResult *result, void *user_data) +{ + struct ofono_modem *modem = user_data; + struct quectel_data *data = ofono_modem_get_data(modem); + const char *rts_cts; + + DBG("%p", modem); + + if (!ok) + return; + + rts_cts = ofono_modem_get_string(modem, "RtsCts"); + + if (strcmp(rts_cts, "on") == 0) + g_at_chat_send(data->uart, "AT+IFC=2,2; E0", none_prefix, + ate_cb, modem, NULL); + else + g_at_chat_send(data->uart, "ATE0", none_prefix, ate_cb, modem, + NULL); + + l_timeout_remove(data->init_timeout); + data->init_timeout = NULL; +} + +static void init_timeout_cb(struct l_timeout *timeout, void *user_data) +{ + struct ofono_modem *modem = user_data; + struct quectel_data *data = ofono_modem_get_data(modem); + + DBG("%p", modem); + + if (data->init_count++ >= 20) { + ofono_error("failed to init modem after 20 attempts"); + close_serial(modem); + return; + } + + g_at_chat_retry(data->uart, data->init_cmd); + l_timeout_modify_ms(timeout, 500); +} + static int open_serial(struct ofono_modem *modem) { struct quectel_data *data = ofono_modem_get_data(modem); @@ -910,18 +955,15 @@ static int open_serial(struct ofono_modem *modem) * a few 'AT' bytes to detect the host UART bitrate, but the RDY is * lost. * - * the wakeup command feature is (mis)used to support all three - * scenarious by sending AT commands until the modem responds with OK, - * at which point the modem is ready. + * Handle all three cases by issuing a plain AT command. The modem + * answers with OK when it is ready. Create a timer to re-issue + * the AT command at regular intervals until the modem answers. */ - g_at_chat_set_wakeup_command(data->uart, "AT\r", 500, 10000); - - if (strcmp(rts_cts, "on") == 0) - g_at_chat_send(data->uart, "AT+IFC=2,2; E0", none_prefix, - ate_cb, modem, NULL); - else - g_at_chat_send(data->uart, "ATE0", none_prefix, ate_cb, modem, - NULL); + data->init_count = 0; + data->init_cmd = g_at_chat_send(data->uart, "AT", none_prefix, + init_cmd_cb, modem, NULL); + data->init_timeout = l_timeout_create_ms(500, init_timeout_cb, modem, + NULL); return -EINPROGRESS; }