From 39f70c29d18a0c677f2269587fc2571c17021a62 Mon Sep 17 00:00:00 2001 From: Sergei Golubtsov Date: Thu, 7 Jan 2021 23:40:17 +0300 Subject: [PATCH] quectel: adding support for the Quectel EC200 USB modem series Support for the Quectel EC200 USB modem series has been added. The model identification AT command has been added as the first step in the communication with a Quectel USB modem. --- plugins/quectel.c | 128 +++++++++++++++++++++++++++++----------------- plugins/udevng.c | 6 ++- 2 files changed, 85 insertions(+), 49 deletions(-) diff --git a/plugins/quectel.c b/plugins/quectel.c index 82fc688d..950f7ce6 100644 --- a/plugins/quectel.c +++ b/plugins/quectel.c @@ -64,7 +64,7 @@ static const char *cpin_prefix[] = { "+CPIN:", NULL }; static const char *cbc_prefix[] = { "+CBC:", NULL }; static const char *qinistat_prefix[] = { "+QINISTAT:", NULL }; static const char *cgmm_prefix[] = { "UC15", "Quectel_M95", "Quectel_MC60", - "EC21", NULL }; + "EC21", "EC200", NULL }; static const char *none_prefix[] = { NULL }; static const uint8_t gsm0710_terminate[] = { @@ -84,6 +84,7 @@ enum quectel_model { QUECTEL_M95, QUECTEL_MC60, QUECTEL_EC21, + QUECTEL_EC200, }; struct quectel_data { @@ -127,6 +128,15 @@ enum quectel_power_event { static const char dbus_hw_interface[] = OFONO_SERVICE ".quectel.Hardware"; +static ofono_bool_t has_serial_connection(struct ofono_modem *modem) +{ + + if (ofono_modem_get_string(modem, "Device")) + return TRUE; + + return FALSE; +} + static void quectel_debug(const char *str, void *user_data) { const char *prefix = user_data; @@ -543,6 +553,7 @@ static void dbus_hw_enable(struct ofono_modem *modem) switch (data->model) { case QUECTEL_UC15: case QUECTEL_EC21: + case QUECTEL_EC200: g_at_chat_register(data->aux, "+QIND", qind_notify, FALSE, hw, NULL); break; @@ -591,6 +602,13 @@ static void qinistat_cb(gboolean ok, GAtResult *result, gpointer user_data) /* UC15 uses a bitmap of 1 + 2 + 4 = 7 */ ready = 7; break; + case QUECTEL_EC200: + /* + * EC200T doesn't indicate that the Phonebook initialization + * is completed (==4) when AT+CFUN=4, that's why 1 + 2 = 3 + */ + ready = 3; + break; case QUECTEL_M95: case QUECTEL_MC60: /* M95 and MC60 uses a counter to 3 */ @@ -807,6 +825,9 @@ static void setup_aux(struct ofono_modem *modem) NULL, NULL, NULL); g_at_chat_send(data->aux, "AT+QURCCFG=\"urcport\",\"uart1\"", none_prefix, NULL, NULL, NULL); + } else if (data->model == QUECTEL_EC200) { + g_at_chat_send(data->aux, "ATE0; &C0; +CMEE=1", none_prefix, + NULL, NULL, NULL); } else g_at_chat_send(data->aux, "ATE0; &C0; +CMEE=1; +QIURC=0", none_prefix, NULL, NULL, NULL); @@ -815,6 +836,59 @@ static void setup_aux(struct ofono_modem *modem) NULL); } +static void cgmm_cb(int ok, GAtResult *result, void *user_data) +{ + struct ofono_modem *modem = user_data; + struct quectel_data *data = ofono_modem_get_data(modem); + const char *model; + + DBG("%p ok %d", modem, ok); + + if (!at_util_parse_attr(result, "", &model)) { + ofono_error("Failed to query modem model"); + close_serial(modem); + return; + } + + if (strcmp(model, "UC15") == 0) { + DBG("%p model UC15", modem); + data->vendor = OFONO_VENDOR_QUECTEL; + data->model = QUECTEL_UC15; + } else if (strcmp(model, "Quectel_M95") == 0) { + DBG("%p model M95", modem); + data->vendor = OFONO_VENDOR_QUECTEL_SERIAL; + data->model = QUECTEL_M95; + } else if (strcmp(model, "Quectel_MC60") == 0) { + DBG("%p model MC60", modem); + data->vendor = OFONO_VENDOR_QUECTEL_SERIAL; + data->model = QUECTEL_MC60; + } else if (strcmp(model, "EC21") == 0) { + DBG("%p model EC21", modem); + data->vendor = OFONO_VENDOR_QUECTEL_EC2X; + data->model = QUECTEL_EC21; + } else if (strstr(model, "EC200")) { + DBG("%p model %s", modem, model); + data->vendor = OFONO_VENDOR_QUECTEL_EC2X; + data->model = QUECTEL_EC200; + } else { + ofono_warn("%p unknown model: '%s'", modem, model); + data->vendor = OFONO_VENDOR_QUECTEL; + data->model = QUECTEL_UNKNOWN; + } + + setup_aux(modem); +} + +static void identify_model(struct ofono_modem *modem) +{ + struct quectel_data *data = ofono_modem_get_data(modem); + + DBG("%p", modem); + + g_at_chat_send(data->aux, "AT+CGMM", cgmm_prefix, cgmm_cb, modem, + NULL); +} + static int open_ttys(struct ofono_modem *modem) { struct quectel_data *data = ofono_modem_get_data(modem); @@ -834,7 +908,7 @@ static int open_ttys(struct ofono_modem *modem) return -EIO; } - setup_aux(modem); + identify_model(modem); return -EINPROGRESS; } @@ -898,7 +972,7 @@ static void cmux_gatmux(struct ofono_modem *modem) return; } - setup_aux(modem); + identify_model(modem); } static void mux_ready_cb(struct l_timeout *timeout, void *user_data) @@ -1031,46 +1105,6 @@ static void cmux_cb(gboolean ok, GAtResult *result, gpointer user_data) close_serial(modem); } -static void cgmm_cb(int ok, GAtResult *result, void *user_data) -{ - struct ofono_modem *modem = user_data; - struct quectel_data *data = ofono_modem_get_data(modem); - const char *model; - - DBG("%p ok %d", modem, ok); - - if (!at_util_parse_attr(result, "", &model)) { - ofono_error("Failed to query modem model"); - close_serial(modem); - return; - } - - if (strcmp(model, "UC15") == 0) { - DBG("%p model UC15", modem); - data->vendor = OFONO_VENDOR_QUECTEL; - data->model = QUECTEL_UC15; - } else if (strcmp(model, "Quectel_M95") == 0) { - DBG("%p model M95", modem); - data->vendor = OFONO_VENDOR_QUECTEL_SERIAL; - data->model = QUECTEL_M95; - } else if (strcmp(model, "Quectel_MC60") == 0) { - DBG("%p model MC60", modem); - data->vendor = OFONO_VENDOR_QUECTEL_SERIAL; - data->model = QUECTEL_MC60; - } else if (strcmp(model, "EC21") == 0) { - DBG("%p model EC21", modem); - data->vendor = OFONO_VENDOR_QUECTEL_EC2X; - data->model = QUECTEL_EC21; - } else { - ofono_warn("%p unknown model: '%s'", modem, model); - data->vendor = OFONO_VENDOR_QUECTEL; - data->model = QUECTEL_UNKNOWN; - } - - g_at_chat_send(data->uart, "AT+CMUX=0,0,5,127,10,3,30,10,2", NULL, - cmux_cb, modem, NULL); -} - static void ate_cb(int ok, GAtResult *result, void *user_data) { struct ofono_modem *modem = user_data; @@ -1078,8 +1112,8 @@ static void ate_cb(int ok, GAtResult *result, void *user_data) DBG("%p", modem); - g_at_chat_send(data->uart, "AT+CGMM", cgmm_prefix, cgmm_cb, modem, - NULL); + g_at_chat_send(data->uart, "AT+CMUX=0,0,5,127,10,3,30,10,2", NULL, + cmux_cb, modem, NULL); } static void init_cmd_cb(gboolean ok, GAtResult *result, void *user_data) @@ -1211,7 +1245,7 @@ static int quectel_enable(struct ofono_modem *modem) { DBG("%p", modem); - if (ofono_modem_get_string(modem, "Device")) + if (has_serial_connection(modem)) return open_serial(modem); else return open_ttys(modem); @@ -1315,7 +1349,7 @@ static void quectel_post_sim(struct ofono_modem *modem) ofono_phonebook_create(modem, data->vendor, "atmodem", data->aux); ofono_call_volume_create(modem, data->vendor, "atmodem", data->aux); - if (data->model == QUECTEL_EC21) { + if (data->model == QUECTEL_EC21 || data->model == QUECTEL_EC200) { ofono_ussd_create(modem, data->vendor, "atmodem", data->aux); ofono_lte_create(modem, data->vendor, "atmodem", data->aux); } diff --git a/plugins/udevng.c b/plugins/udevng.c index 3458fe89..34ac1cc0 100644 --- a/plugins/udevng.c +++ b/plugins/udevng.c @@ -941,10 +941,12 @@ static gboolean setup_quectel_serial(struct modem_info *modem) static gboolean setup_quectel(struct modem_info *modem) { - if (modem->serial) + if (modem->type == MODEM_TYPE_SERIAL) return setup_quectel_serial(modem); - else + else if (modem->type == MODEM_TYPE_USB) return setup_quectel_usb(modem); + else + return FALSE; } static gboolean setup_quectelqmi(struct modem_info *modem)