qmimodem: return all serial numbers

Some modems, eg. Quectel EC25E, return the ESN, IMEI, and MEID even
though they support only one network type in a region. Current serial
number query gives precedence to the ESN if it exists, and does not
consider the IMEI and MEID.

Add a check of the supported radio interfaces in deciding which
serial number to return. If radio interfaces are 3GPP based, then
return the IMEI, else return the ESN. If neither exist, return MEID
if available, else fail.
This commit is contained in:
Tom Nguyen 2019-04-12 11:52:26 -04:00 committed by Denis Kenzior
parent 05aaab72ae
commit 0ddb7c6e2f
1 changed files with 75 additions and 13 deletions

View File

@ -36,6 +36,7 @@
struct devinfo_data {
struct qmi_service *dms;
bool device_is_3gpp;
};
static void string_cb(struct qmi_result *result, void *user_data)
@ -116,7 +117,12 @@ static void qmi_query_revision(struct ofono_devinfo *devinfo,
static void get_ids_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
struct ofono_devinfo *devinfo = cbd->user;
struct devinfo_data *data = ofono_devinfo_get_data(devinfo);
ofono_devinfo_query_cb_t cb = cbd->cb;
char *esn;
char *imei;
char *meid;
char *str;
DBG("");
@ -126,20 +132,28 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
return;
}
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
/* Telit qmi modems return a "0" string when ESN is not available. */
if (!str || strcmp(str, "0") == 0) {
qmi_free(str);
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
if (!str) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
return;
}
}
esn = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
imei = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
meid = qmi_result_get_string(result, QMI_DMS_RESULT_MEID);
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
str = NULL;
qmi_free(str);
if (data->device_is_3gpp && imei && strcmp(imei, "0"))
str = imei;
else if (esn && strcmp(esn, "0"))
str = esn;
if (str == NULL && meid && strcmp(meid, "0"))
str = meid;
if (str)
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
else
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
qmi_free(esn);
qmi_free(imei);
qmi_free(meid);
}
static void qmi_query_serial(struct ofono_devinfo *devinfo,
@ -150,6 +164,8 @@ static void qmi_query_serial(struct ofono_devinfo *devinfo,
DBG("");
cbd->user = devinfo;
if (qmi_service_send(data->dms, QMI_DMS_GET_IDS, NULL,
get_ids_cb, cbd, g_free) > 0)
return;
@ -159,6 +175,51 @@ static void qmi_query_serial(struct ofono_devinfo *devinfo,
g_free(cbd);
}
static void get_caps_cb(struct qmi_result *result, void *user_data)
{
struct ofono_devinfo *devinfo = user_data;
struct devinfo_data *data = ofono_devinfo_get_data(devinfo);
const struct qmi_dms_device_caps *caps;
uint8_t i;
DBG("");
if (qmi_result_set_error(result, NULL))
goto error;
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, NULL);
if (caps == NULL)
goto error;
data->device_is_3gpp = false;
for (i = 0; i < caps->radio_if_count; i++) {
switch (caps->radio_if[i]) {
case QMI_DMS_RADIO_IF_GSM:
case QMI_DMS_RADIO_IF_UMTS:
case QMI_DMS_RADIO_IF_LTE:
data->device_is_3gpp = true;
break;
}
}
error:
ofono_devinfo_register(devinfo);
}
static void qmi_query_caps(struct ofono_devinfo *devinfo)
{
struct devinfo_data *data = ofono_devinfo_get_data(devinfo);
DBG("");
if (qmi_service_send(data->dms, QMI_DMS_GET_CAPS, NULL,
get_caps_cb, devinfo, NULL) > 0)
return;
ofono_devinfo_register(devinfo);
}
static void create_dms_cb(struct qmi_service *service, void *user_data)
{
struct ofono_devinfo *devinfo = user_data;
@ -173,8 +234,9 @@ static void create_dms_cb(struct qmi_service *service, void *user_data)
}
data->dms = qmi_service_ref(service);
data->device_is_3gpp = false;
ofono_devinfo_register(devinfo);
qmi_query_caps(devinfo);
}
static int qmi_devinfo_probe(struct ofono_devinfo *devinfo,