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.
This commit is contained in:
Sergei Golubtsov 2021-01-07 23:40:17 +03:00 committed by Denis Kenzior
parent 0be380fb9d
commit 39f70c29d1
2 changed files with 85 additions and 49 deletions

View File

@ -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);
}

View File

@ -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)