diff --git a/ofono/AUTHORS b/ofono/AUTHORS index 63a55e892..b6102deee 100644 --- a/ofono/AUTHORS +++ b/ofono/AUTHORS @@ -130,3 +130,8 @@ Joey Hewitt Richard Röjfors Philippe De Swert Gabriel Lucas +Mariem Cherif +Bassem Boubaker +Bob Ham +Varun Gargi +Florent Beillonnet diff --git a/ofono/ChangeLog b/ofono/ChangeLog index 9cf608625..2ed56d526 100644 --- a/ofono/ChangeLog +++ b/ofono/ChangeLog @@ -1,3 +1,16 @@ +ver 1.24: + Fix issue with property changed signals and CDMA networks. + Fix issue with handling SIM filesystem and SIM removal. + Fix issue with handling PIN state and incorrect codes. + Fix issue with handling of parsing AID type. + Fix issue with SIM detection and QMI devices. + Fix issue with PIN handling and QMI devices. + Fix issue with USSD handling and QMI devices. + Fix issue with handling USSD TERMINATED response. + Fix issue with handling USSD reset and STK REFRESH. + Add support for detecting Gemalto ALS3 modems. + Add support for SIMCom based SIM7100E modems. + ver 1.23: Fix issue with handling SIM AID sessions. Add support for QMI LTE bearer handling. diff --git a/ofono/Makefile.am b/ofono/Makefile.am index 798cd380e..7dbabdfcc 100644 --- a/ofono/Makefile.am +++ b/ofono/Makefile.am @@ -573,6 +573,12 @@ builtin_sources += plugins/samsung.c builtin_modules += sim900 builtin_sources += plugins/sim900.c +builtin_modules += sim7100 +builtin_sources += plugins/sim7100.c + +builtin_modules += connman +builtin_sources += plugins/connman.c + builtin_modules += telit builtin_sources += plugins/telit.c diff --git a/ofono/configure.ac b/ofono/configure.ac index aa55bc008..fb56202e6 100644 --- a/ofono/configure.ac +++ b/ofono/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(ofono, 1.23) +AC_INIT(ofono, 1.24) AM_INIT_AUTOMAKE([foreign subdir-objects color-tests]) AC_CONFIG_HEADERS(config.h) diff --git a/ofono/drivers/atmodem/cbs.c b/ofono/drivers/atmodem/cbs.c index 3c491be0a..0a76ba255 100644 --- a/ofono/drivers/atmodem/cbs.c +++ b/ofono/drivers/atmodem/cbs.c @@ -48,6 +48,51 @@ struct cbs_data { unsigned int vendor; }; +static void at_xmm_etw_sec_notify(GAtResult *result, gpointer user_data) +{ + struct ofono_cbs *cbs = user_data; + const char *hexpdu; + int pdulen; + GAtResultIter iter; + unsigned char pdu[88]; + long hexpdulen; + + DBG(""); + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+XETWSECWARN:")) + return; + + if (!g_at_result_iter_next_number(&iter, &pdulen)) + return; + + if (pdulen != 88) { + ofono_error("Got a CBM message with invalid PDU size!"); + return; + } + + hexpdu = g_at_result_pdu(result); + if (hexpdu == NULL) { + ofono_error("Got a CBM, but no PDU. Are we in text mode?"); + return; + } + + DBG("Got new Cell Broadcast via XETWSECWARN: %s, %d", hexpdu, pdulen); + + if (decode_hex_own_buf(hexpdu, -1, &hexpdulen, 0, pdu) == NULL) { + ofono_error("Unable to hex-decode the PDU"); + return; + } + + if (hexpdulen != pdulen) { + ofono_error("hexpdu length not equal to reported pdu length"); + return; + } + + ofono_cbs_notify(cbs, pdu, pdulen); +} + static void at_cbm_notify(GAtResult *result, gpointer user_data) { struct ofono_cbs *cbs = user_data; @@ -124,6 +169,10 @@ static void at_cbs_set_topics(struct ofono_cbs *cbs, const char *topics, g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix, NULL, NULL, NULL); break; + case OFONO_VENDOR_XMM: + g_at_chat_send(data->chat, "AT+XETWNTFYSTART=2", none_prefix, + NULL, NULL, NULL); + break; default: break; } @@ -151,6 +200,10 @@ static void at_cbs_clear_topics(struct ofono_cbs *cbs, DBG(""); + if (data->vendor == OFONO_VENDOR_XMM) + g_at_chat_send(data->chat, "AT+XETWNTFYSTOP=2", none_prefix, + NULL, NULL, NULL); + if (g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix, at_cscb_set_cb, cbd, g_free) > 0) return; @@ -175,6 +228,10 @@ static void at_cbs_register(gboolean ok, GAtResult *result, gpointer user) */ g_at_chat_register(data->chat, "+CBM:", at_cbm_notify, TRUE, cbs, NULL); + if (data->vendor == OFONO_VENDOR_XMM) + g_at_chat_register(data->chat, "+XETWSECWARN:", + at_xmm_etw_sec_notify, TRUE, cbs, NULL); + ofono_cbs_register(cbs); } @@ -223,6 +280,13 @@ static int at_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor, ofono_cbs_set_data(cbs, data); + if (vendor == OFONO_VENDOR_XMM) { + g_at_chat_send(data->chat, "AT+XCMAS=1", cscb_prefix, + NULL, NULL, NULL); + g_at_chat_send(data->chat, "AT+XETWCFG=1,1,0,0; ", none_prefix, + NULL, NULL, NULL); + } + g_at_chat_send(data->chat, "AT+CSCB=?", cscb_prefix, at_cscb_support_cb, cbs, NULL); diff --git a/ofono/drivers/atmodem/lte.c b/ofono/drivers/atmodem/lte.c index 61a4cd2bd..efa4e5fe2 100644 --- a/ofono/drivers/atmodem/lte.c +++ b/ofono/drivers/atmodem/lte.c @@ -91,7 +91,7 @@ static gboolean lte_delayed_register(gpointer user_data) return FALSE; } -static int at_lte_probe(struct ofono_lte *lte, void *data) +static int at_lte_probe(struct ofono_lte *lte, unsigned int vendor, void *data) { GAtChat *chat = data; struct lte_driver_data *ldd; diff --git a/ofono/drivers/atmodem/network-registration.c b/ofono/drivers/atmodem/network-registration.c index a5e2af3dc..0854cd12b 100644 --- a/ofono/drivers/atmodem/network-registration.c +++ b/ofono/drivers/atmodem/network-registration.c @@ -48,6 +48,7 @@ static const char *cops_prefix[] = { "+COPS:", NULL }; static const char *csq_prefix[] = { "+CSQ:", NULL }; static const char *cind_prefix[] = { "+CIND:", NULL }; static const char *cmer_prefix[] = { "+CMER:", NULL }; +static const char *smoni_prefix[] = { "^SMONI:", NULL }; static const char *zpas_prefix[] = { "+ZPAS:", NULL }; static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL }; @@ -178,6 +179,31 @@ static int option_parse_tech(GAtResult *result) return tech; } +static int cinterion_parse_tech(GAtResult *result) +{ + int tech = -1; + GAtResultIter iter; + const char *technology; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "^SMONI: ")) + return tech; + + if (!g_at_result_iter_next_unquoted_string(&iter, &technology)) + return tech; + + if (strcmp(technology, "2G") == 0) { + tech = ACCESS_TECHNOLOGY_GSM_EGPRS; + } else if (strcmp(technology, "3G") == 0) { + tech = ACCESS_TECHNOLOGY_UTRAN; + } else if (strcmp(technology, "4G") == 0) { + tech = ACCESS_TECHNOLOGY_EUTRAN; + } + + return tech; +} + static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; @@ -205,6 +231,18 @@ static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data) cb(&error, status, lac, ci, tech, cbd->data); } +static void cinterion_query_tech_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct tech_query *tq = user_data; + int tech; + + tech = cinterion_parse_tech(result); + + ofono_netreg_status_notify(tq->netreg, + tq->status, tq->lac, tq->ci, tech); +} + static void zte_tech_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; @@ -1518,6 +1556,12 @@ static void creg_notify(GAtResult *result, gpointer user_data) option_query_tech_cb, tq, g_free) > 0) return; break; + case OFONO_VENDOR_CINTERION: + if (g_at_chat_send(nd->chat, "AT^SMONI", + smoni_prefix, + cinterion_query_tech_cb, tq, g_free) > 0) + return; + break; } g_free(tq); diff --git a/ofono/drivers/atmodem/sim.c b/ofono/drivers/atmodem/sim.c index ab75b32af..10dc80092 100644 --- a/ofono/drivers/atmodem/sim.c +++ b/ofono/drivers/atmodem/sim.c @@ -1359,12 +1359,12 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk, char buf[64]; int ret; - cbd->user = sd; + cbd->user = sim; snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd); ret = g_at_chat_send(sd->chat, buf, none_prefix, - at_pin_send_cb, cbd, NULL); + at_pin_send_cb, cbd, g_free); memset(buf, 0, sizeof(buf)); diff --git a/ofono/drivers/atmodem/voicecall.c b/ofono/drivers/atmodem/voicecall.c index e4c59c267..aa56f1ee7 100644 --- a/ofono/drivers/atmodem/voicecall.c +++ b/ofono/drivers/atmodem/voicecall.c @@ -1120,6 +1120,7 @@ static int at_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor, switch (vd->vendor) { case OFONO_VENDOR_QUALCOMM_MSM: + case OFONO_VENDOR_SIMCOM: g_at_chat_send(vd->chat, "AT+COLP=0", NULL, NULL, NULL, NULL); break; default: diff --git a/ofono/drivers/qmimodem/devinfo.c b/ofono/drivers/qmimodem/devinfo.c index 0d66c5381..f50286578 100644 --- a/ofono/drivers/qmimodem/devinfo.c +++ b/ofono/drivers/qmimodem/devinfo.c @@ -129,6 +129,7 @@ static void get_ids_cb(struct qmi_result *result, void *user_data) 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); diff --git a/ofono/drivers/qmimodem/lte.c b/ofono/drivers/qmimodem/lte.c index 9a1492899..841e77517 100644 --- a/ofono/drivers/qmimodem/lte.c +++ b/ofono/drivers/qmimodem/lte.c @@ -212,7 +212,8 @@ static void create_wds_cb(struct qmi_service *service, void *user_data) ofono_lte_register(lte); } -static int qmimodem_lte_probe(struct ofono_lte *lte, void *data) +static int qmimodem_lte_probe(struct ofono_lte *lte, + unsigned int vendor, void *data) { struct qmi_device *device = data; struct lte_data *ldd; diff --git a/ofono/drivers/qmimodem/qmi.c b/ofono/drivers/qmimodem/qmi.c index 257afd0d7..19ec13038 100644 --- a/ofono/drivers/qmimodem/qmi.c +++ b/ofono/drivers/qmimodem/qmi.c @@ -47,6 +47,13 @@ struct discovery { qmi_destroy_func_t destroy; }; +struct qmi_version { + uint8_t type; + uint16_t major; + uint16_t minor; + const char *name; +}; + struct qmi_device { int ref_count; int fd; @@ -80,7 +87,6 @@ struct qmi_device { struct qmi_service { int ref_count; struct qmi_device *device; - bool shared; uint8_t type; uint16_t major; uint16_t minor; @@ -161,25 +167,25 @@ void qmi_free(void *ptr) static struct qmi_request *__request_alloc(uint8_t service, uint8_t client, uint16_t message, - uint16_t headroom, const void *data, + const void *data, uint16_t length, qmi_message_func_t func, - void *user_data, void **head) + void *user_data) { struct qmi_request *req; struct qmi_mux_hdr *hdr; struct qmi_message_hdr *msg; + uint16_t headroom; - req = g_try_new0(struct qmi_request, 1); - if (!req) - return NULL; + req = g_new0(struct qmi_request, 1); + + if (service == QMI_SERVICE_CONTROL) + headroom = QMI_CONTROL_HDR_SIZE; + else + headroom = QMI_SERVICE_HDR_SIZE; req->len = QMI_MUX_HDR_SIZE + headroom + QMI_MESSAGE_HDR_SIZE + length; - req->buf = g_try_malloc(req->len); - if (!req->buf) { - g_free(req); - return NULL; - } + req->buf = g_malloc(req->len); req->client = client; @@ -203,8 +209,6 @@ static struct qmi_request *__request_alloc(uint8_t service, req->callback = func; req->user_data = user_data; - *head = req->buf + QMI_MUX_HDR_SIZE; - return req; } @@ -256,9 +260,6 @@ static gboolean __service_compare_shared(gpointer key, gpointer value, struct qmi_service *service = value; uint8_t type = GPOINTER_TO_UINT(user_data); - if (!service->shared) - return FALSE; - if (service->type == type) return TRUE; @@ -695,14 +696,37 @@ static void wakeup_writer(struct qmi_device *device) can_write_data, device, write_watch_destroy); } -static void __request_submit(struct qmi_device *device, - struct qmi_request *req, uint16_t transaction) +static uint16_t __request_submit(struct qmi_device *device, + struct qmi_request *req) { - req->tid = transaction; + struct qmi_mux_hdr *mux; + + mux = req->buf; + + if (mux->service == QMI_SERVICE_CONTROL) { + struct qmi_control_hdr *hdr; + + hdr = req->buf + QMI_MUX_HDR_SIZE; + hdr->type = 0x00; + hdr->transaction = device->next_control_tid++; + if (device->next_control_tid == 0) + device->next_control_tid = 1; + req->tid = hdr->transaction; + } else { + struct qmi_service_hdr *hdr; + hdr = req->buf + QMI_MUX_HDR_SIZE; + hdr->type = 0x00; + hdr->transaction = device->next_service_tid++; + if (device->next_service_tid < 256) + device->next_service_tid = 256; + req->tid = hdr->transaction; + } g_queue_push_tail(device->req_queue, req); wakeup_writer(device); + + return req->tid; } static void service_notify(gpointer key, gpointer value, gpointer user_data) @@ -961,6 +985,9 @@ struct qmi_device *qmi_device_new(int fd) device->service_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, service_destroy); + device->next_control_tid = 1; + device->next_service_tid = 256; + return device; } @@ -1078,6 +1105,41 @@ static const void *tlv_get(const void *data, uint16_t size, return NULL; } +bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type, + uint16_t *major, uint16_t *minor) +{ + struct qmi_version *info; + int i; + + for (i = 0, info = device->version_list; + i < device->version_count; + i++, info++) { + if (info->type == type) { + *major = info->major; + *minor = info->minor; + return true; + } + } + + return false; +} + +bool qmi_device_has_service(struct qmi_device *device, uint8_t type) +{ + struct qmi_version *info; + int i; + + for (i = 0, info = device->version_list; + i < device->version_count; + i++, info++) { + if (info->type == type) { + return true; + } + } + + return false; +} + struct discover_data { struct discovery super; struct qmi_device *device; @@ -1177,7 +1239,7 @@ static void discover_callback(uint16_t message, uint16_t length, device->version_count = count; if (data->func) - data->func(count, list, data->user_data); + data->func(data->user_data); __qmi_device_discovery_complete(data->device, &data->super); } @@ -1213,8 +1275,7 @@ static gboolean discover_reply(gpointer user_data) } if (data->func) - data->func(device->version_count, - device->version_list, data->user_data); + data->func(data->user_data); __qmi_device_discovery_complete(data->device, &data->super); __request_free(req, NULL); @@ -1227,7 +1288,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func, { struct discover_data *data; struct qmi_request *req; - struct qmi_control_hdr *hdr; + uint8_t tid; if (!device) return false; @@ -1251,21 +1312,12 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func, } req = __request_alloc(QMI_SERVICE_CONTROL, 0x00, - QMI_CTL_GET_VERSION_INFO, QMI_CONTROL_HDR_SIZE, - NULL, 0, discover_callback, data, (void **) &hdr); - if (!req) { - g_free(data); - return false; - } - - if (device->next_control_tid < 1) - device->next_control_tid = 1; + QMI_CTL_GET_VERSION_INFO, + NULL, 0, discover_callback, data); - hdr->type = 0x00; - hdr->transaction = device->next_control_tid++; - data->tid = hdr->transaction; + tid = __request_submit(device, req); - __request_submit(device, req, hdr->transaction); + data->tid = tid; data->timeout = g_timeout_add_seconds(5, discover_reply, data); __qmi_device_discovery_started(device, &data->super); @@ -1279,24 +1331,13 @@ static void release_client(struct qmi_device *device, { unsigned char release_req[] = { 0x01, 0x02, 0x00, type, client_id }; struct qmi_request *req; - struct qmi_control_hdr *hdr; req = __request_alloc(QMI_SERVICE_CONTROL, 0x00, - QMI_CTL_RELEASE_CLIENT_ID, QMI_CONTROL_HDR_SIZE, + QMI_CTL_RELEASE_CLIENT_ID, release_req, sizeof(release_req), - func, user_data, (void **) &hdr); - if (!req) { - func(0x0000, 0x0000, NULL, user_data); - return; - } + func, user_data); - if (device->next_control_tid < 1) - device->next_control_tid = 1; - - hdr->type = 0x00; - hdr->transaction = device->next_control_tid++; - - __request_submit(device, req, hdr->transaction); + __request_submit(device, req); } static void shutdown_destroy(gpointer user_data) @@ -1374,7 +1415,6 @@ bool qmi_device_sync(struct qmi_device *device, qmi_sync_func_t func, void *user_data) { struct qmi_request *req; - struct qmi_control_hdr *hdr; struct sync_data *func_data; if (!device) @@ -1387,17 +1427,11 @@ bool qmi_device_sync(struct qmi_device *device, func_data->user_data = user_data; req = __request_alloc(QMI_SERVICE_CONTROL, 0x00, - QMI_CTL_SYNC, QMI_CONTROL_HDR_SIZE, + QMI_CTL_SYNC, NULL, 0, - qmi_device_sync_callback, func_data, (void **) &hdr); - - if (device->next_control_tid < 1) - device->next_control_tid = 1; + qmi_device_sync_callback, func_data); - hdr->type = 0x00; - hdr->transaction = device->next_control_tid++; - - __request_submit(device, req, hdr->transaction); + __request_submit(device, req); return true; } @@ -1898,7 +1932,6 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type, struct service_create_data { struct discovery super; struct qmi_device *device; - bool shared; uint8_t type; uint16_t major; uint16_t minor; @@ -1969,7 +2002,6 @@ static void service_create_callback(uint16_t message, uint16_t length, service->ref_count = 1; service->device = data->device; - service->shared = data->shared; service->type = data->type; service->major = data->major; @@ -1992,100 +2024,52 @@ static void service_create_callback(uint16_t message, uint16_t length, __qmi_device_discovery_complete(data->device, &data->super); } -static void service_create_discover(uint8_t count, - const struct qmi_version *list, void *user_data) -{ - struct service_create_data *data = user_data; - struct qmi_device *device = data->device; - struct qmi_request *req; - struct qmi_control_hdr *hdr; - unsigned char client_req[] = { 0x01, 0x01, 0x00, data->type }; - unsigned int i; - - __debug_device(device, "service create [type=%d]", data->type); - - for (i = 0; i < count; i++) { - if (list[i].type == data->type) { - data->major = list[i].major; - data->minor = list[i].minor; - break; - } - } - - req = __request_alloc(QMI_SERVICE_CONTROL, 0x00, - QMI_CTL_GET_CLIENT_ID, QMI_CONTROL_HDR_SIZE, - client_req, sizeof(client_req), - service_create_callback, data, (void **) &hdr); - if (!req) { - if (data->timeout > 0) - g_source_remove(data->timeout); - - data->timeout = g_timeout_add_seconds(0, - service_create_reply, data); - __qmi_device_discovery_started(device, &data->super); - return; - } - - if (device->next_control_tid < 1) - device->next_control_tid = 1; - - hdr->type = 0x00; - hdr->transaction = device->next_control_tid++; - - __request_submit(device, req, hdr->transaction); -} - -static bool service_create(struct qmi_device *device, bool shared, +static bool service_create(struct qmi_device *device, uint8_t type, qmi_create_func_t func, void *user_data, qmi_destroy_func_t destroy) { struct service_create_data *data; + unsigned char client_req[] = { 0x01, 0x01, 0x00, type }; + struct qmi_request *req; + int i; data = g_try_new0(struct service_create_data, 1); if (!data) return false; + if (!device->version_list) + return false; + data->super.destroy = service_create_data_free; data->device = device; - data->shared = shared; data->type = type; data->func = func; data->user_data = user_data; data->destroy = destroy; - if (device->version_list) { - service_create_discover(device->version_count, - device->version_list, data); - goto done; - } + __debug_device(device, "service create [type=%d]", type); - if (qmi_device_discover(device, service_create_discover, data, NULL)) - goto done; + for (i = 0; i < device->version_count; i++) { + if (device->version_list[i].type == data->type) { + data->major = device->version_list[i].major; + data->minor = device->version_list[i].minor; + break; + } + } - g_free(data); + req = __request_alloc(QMI_SERVICE_CONTROL, 0x00, + QMI_CTL_GET_CLIENT_ID, + client_req, sizeof(client_req), + service_create_callback, data); - return false; + __request_submit(device, req); -done: data->timeout = g_timeout_add_seconds(8, service_create_reply, data); __qmi_device_discovery_started(device, &data->super); return true; } -bool qmi_service_create(struct qmi_device *device, - uint8_t type, qmi_create_func_t func, - void *user_data, qmi_destroy_func_t destroy) -{ - if (!device || !func) - return false; - - if (type == QMI_SERVICE_CONTROL) - return false; - - return service_create(device, false, type, func, user_data, destroy); -} - struct service_create_shared_data { struct discovery super; struct qmi_service *service; @@ -2161,7 +2145,15 @@ bool qmi_service_create_shared(struct qmi_device *device, return 0; } - return service_create(device, true, type, func, user_data, destroy); + return service_create(device, type, func, user_data, destroy); +} + +bool qmi_service_create(struct qmi_device *device, + uint8_t type, qmi_create_func_t func, + void *user_data, qmi_destroy_func_t destroy) +{ + return qmi_service_create_shared(device, type, func, + user_data, destroy); } static void service_release_callback(uint16_t message, uint16_t length, @@ -2238,8 +2230,6 @@ bool qmi_service_get_version(struct qmi_service *service, } struct service_send_data { - struct qmi_service *service; - struct qmi_param *param; qmi_result_func_t func; void *user_data; qmi_destroy_func_t destroy; @@ -2250,8 +2240,6 @@ static void service_send_free(struct service_send_data *data) if (data->destroy) data->destroy(data->user_data); - qmi_param_free(data->param); - g_free(data); } @@ -2292,7 +2280,7 @@ uint16_t qmi_service_send(struct qmi_service *service, struct qmi_device *device; struct service_send_data *data; struct qmi_request *req; - struct qmi_service_hdr *hdr; + uint16_t tid; if (!service) return 0; @@ -2308,31 +2296,21 @@ uint16_t qmi_service_send(struct qmi_service *service, if (!data) return 0; - data->service = service; - data->param = param; data->func = func; data->user_data = user_data; data->destroy = destroy; req = __request_alloc(service->type, service->client_id, - message, QMI_SERVICE_HDR_SIZE, - data->param ? data->param->data : NULL, - data->param ? data->param->length : 0, - service_send_callback, data, (void **) &hdr); - if (!req) { - g_free(data); - return 0; - } - - if (device->next_service_tid < 256) - device->next_service_tid = 256; + message, + param ? param->data : NULL, + param ? param->length : 0, + service_send_callback, data); - hdr->type = 0x00; - hdr->transaction = device->next_service_tid++; + qmi_param_free(param); - __request_submit(device, req, hdr->transaction); + tid = __request_submit(device, req); - return hdr->transaction; + return tid; } bool qmi_service_cancel(struct qmi_service *service, uint16_t id) diff --git a/ofono/drivers/qmimodem/qmi.h b/ofono/drivers/qmimodem/qmi.h index e18010459..2665c4412 100644 --- a/ofono/drivers/qmimodem/qmi.h +++ b/ofono/drivers/qmimodem/qmi.h @@ -61,13 +61,6 @@ enum qmi_device_expected_data_format { QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP, }; -struct qmi_version { - uint8_t type; - uint16_t major; - uint16_t minor; - const char *name; -}; - void qmi_free(void *ptr); typedef void (*qmi_destroy_func_t)(void *user_data); @@ -78,8 +71,7 @@ struct qmi_device; typedef void (*qmi_debug_func_t)(const char *str, void *user_data); typedef void (*qmi_sync_func_t)(void *user_data); typedef void (*qmi_shutdown_func_t)(void *user_data); -typedef void (*qmi_discover_func_t)(uint8_t count, - const struct qmi_version *list, void *user_data); +typedef void (*qmi_discover_func_t)(void *user_data); struct qmi_device *qmi_device_new(int fd); @@ -96,6 +88,10 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func, bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func, void *user_data, qmi_destroy_func_t destroy); +bool qmi_device_has_service(struct qmi_device *device, uint8_t type); +bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type, + uint16_t *major, uint16_t *minor); + bool qmi_device_sync(struct qmi_device *device, qmi_sync_func_t func, void *user_data); bool qmi_device_is_sync_supported(struct qmi_device *device); diff --git a/ofono/drivers/qmimodem/sim.c b/ofono/drivers/qmimodem/sim.c index 71c7e04ec..1ac506869 100644 --- a/ofono/drivers/qmimodem/sim.c +++ b/ofono/drivers/qmimodem/sim.c @@ -493,8 +493,15 @@ static bool get_card_status(const struct qmi_uim_slot_info *slot, case 0x03: /* PUK1 or PUK for UPIN is required */ sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK; break; + case 0x00: /* Unknown */ + case 0x01: /* Detected */ case 0x04: /* Personalization state must be checked. */ - /* This is temporary, we could retry and get another result */ + case 0x05: /* PIN1 blocked */ + case 0x06: /* Illegal */ + /* + * This could be temporary, we should retry and + * expect another result + */ sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID; need_retry = true; break; @@ -557,7 +564,7 @@ static enum get_card_status_result handle_get_card_status_result( index = GUINT16_FROM_LE(status->index_gw_pri); - if ((index & 0xff) == i && (index >> 8) == n) { + if ((index & 0xff) == n && (index >> 8) == i) { if (get_card_status(slot, info1, info2, sim_stat)) res = GET_CARD_STATUS_RESULT_TEMP_ERROR; @@ -595,20 +602,32 @@ static void query_passwd_state_cb(struct qmi_result *result, struct sim_status sim_stat; enum get_card_status_result res; struct cb_data *retry_cbd; + unsigned int i; + + for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++) + sim_stat.retries[i] = -1; res = handle_get_card_status_result(result, &sim_stat); switch (res) { case GET_CARD_STATUS_RESULT_OK: DBG("passwd state %d", sim_stat.passwd_state); data->retry_count = 0; - CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data); + if (sim_stat.passwd_state == OFONO_SIM_PASSWORD_INVALID) { + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + ofono_sim_inserted_notify(sim, FALSE); + } else + CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, + cbd->data); break; case GET_CARD_STATUS_RESULT_TEMP_ERROR: data->retry_count++; if (data->retry_count > MAX_RETRY_COUNT) { - DBG("Failed after %d attempts", data->retry_count); + DBG("Failed after %d attempts. Card state:%d", + data->retry_count, + sim_stat.card_state); data->retry_count = 0; CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + ofono_sim_inserted_notify(sim, FALSE); } else { DBG("Retry command"); retry_cbd = cb_data_new(cb, cbd->data); @@ -622,6 +641,7 @@ static void query_passwd_state_cb(struct qmi_result *result, DBG("Command failed"); data->retry_count = 0; CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + ofono_sim_inserted_notify(sim, FALSE); break; } } @@ -650,9 +670,13 @@ static void query_pin_retries_cb(struct qmi_result *result, void *user_data) struct cb_data *cbd = user_data; ofono_sim_pin_retries_cb_t cb = cbd->cb; struct sim_status sim_stat; + unsigned int i; DBG(""); + for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++) + sim_stat.retries[i] = -1; + if (handle_get_card_status_result(result, &sim_stat) != GET_CARD_STATUS_RESULT_OK) { CALLBACK_WITH_FAILURE(cb, NULL, cbd->data); diff --git a/ofono/drivers/qmimodem/ussd.c b/ofono/drivers/qmimodem/ussd.c index c7b0b3455..174e354d1 100644 --- a/ofono/drivers/qmimodem/ussd.c +++ b/ofono/drivers/qmimodem/ussd.c @@ -251,6 +251,7 @@ static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs, qmi_ussd->dcs = QMI_USSD_DCS_ASCII; qmi_ussd->length = len; memcpy(qmi_ussd->data, utf8, utf8_len); + g_free(utf8); param = qmi_param_new(); if (param == NULL) @@ -265,7 +266,6 @@ static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs, qmi_param_free(param); error: - g_free(utf8); g_free(cbd); CALLBACK_WITH_FAILURE(cb, data); } diff --git a/ofono/drivers/rilmodem/call-forwarding.c b/ofono/drivers/rilmodem/call-forwarding.c index 1fcedb3eb..4aff4d339 100644 --- a/ofono/drivers/rilmodem/call-forwarding.c +++ b/ofono/drivers/rilmodem/call-forwarding.c @@ -38,6 +38,8 @@ #include #include "common.h" +#pragma GCC diagnostic ignored "-Wrestrict" + #include "gril.h" #include "rilmodem.h" diff --git a/ofono/drivers/rilmodem/lte.c b/ofono/drivers/rilmodem/lte.c index d196be8a9..1302a5628 100644 --- a/ofono/drivers/rilmodem/lte.c +++ b/ofono/drivers/rilmodem/lte.c @@ -108,7 +108,8 @@ static gboolean lte_delayed_register(gpointer user_data) return FALSE; } -static int ril_lte_probe(struct ofono_lte *lte, void *user_data) +static int ril_lte_probe(struct ofono_lte *lte, + unsigned int vendor, void *user_data) { GRil *ril = user_data; struct ril_lte_data *ld; diff --git a/ofono/drivers/rilmodem/network-registration.c b/ofono/drivers/rilmodem/network-registration.c index 8ba4dbb2d..809b3bc82 100644 --- a/ofono/drivers/rilmodem/network-registration.c +++ b/ofono/drivers/rilmodem/network-registration.c @@ -37,6 +37,8 @@ #include #include +#pragma GCC diagnostic ignored "-Wrestrict" + #include #include "common.h" diff --git a/ofono/drivers/ubloxmodem/lte.c b/ofono/drivers/ubloxmodem/lte.c index cb2469a89..e9cb82b06 100644 --- a/ofono/drivers/ubloxmodem/lte.c +++ b/ofono/drivers/ubloxmodem/lte.c @@ -91,7 +91,8 @@ static gboolean lte_delayed_register(gpointer user_data) return FALSE; } -static int ublox_lte_probe(struct ofono_lte *lte, void *data) +static int ublox_lte_probe(struct ofono_lte *lte, + unsigned int vendor, void *data) { GAtChat *chat = data; struct lte_driver_data *ldd; diff --git a/ofono/gatchat/gatmux.c b/ofono/gatchat/gatmux.c index d492edb5c..9660006b0 100644 --- a/ofono/gatchat/gatmux.c +++ b/ofono/gatchat/gatmux.c @@ -30,6 +30,9 @@ #include #include +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wcast-function-type" + #include #include "ringbuffer.h" diff --git a/ofono/include/lte.h b/ofono/include/lte.h index f3ff4053d..ef84ab99d 100644 --- a/ofono/include/lte.h +++ b/ofono/include/lte.h @@ -38,7 +38,7 @@ typedef void (*ofono_lte_cb_t)(const struct ofono_error *error, void *data); struct ofono_lte_driver { const char *name; - int (*probe)(struct ofono_lte *lte, void *data); + int (*probe)(struct ofono_lte *lte, unsigned int vendor, void *data); void (*remove)(struct ofono_lte *lte); void (*set_default_attach_info)(const struct ofono_lte *lte, const struct ofono_lte_default_attach_info *info, @@ -50,6 +50,7 @@ int ofono_lte_driver_register(const struct ofono_lte_driver *d); void ofono_lte_driver_unregister(const struct ofono_lte_driver *d); struct ofono_lte *ofono_lte_create(struct ofono_modem *modem, + unsigned int vendor, const char *driver, void *data); void ofono_lte_register(struct ofono_lte *lte); diff --git a/ofono/plugins/gemalto.c b/ofono/plugins/gemalto.c index 3739d7bb2..b7734124c 100644 --- a/ofono/plugins/gemalto.c +++ b/ofono/plugins/gemalto.c @@ -53,6 +53,11 @@ #define HARDWARE_MONITOR_INTERFACE OFONO_SERVICE ".cinterion.HardwareMonitor" +/* Supported gemalto's modem */ +#define GEMALTO_MODEL_PHS8P "0053" +/* ALS3, PLS8-E, and PLS8-X family */ +#define GEMALTO_MODEL_ALS3_PLS8x "0061" + static const char *none_prefix[] = { NULL }; static const char *sctm_prefix[] = { "^SCTM:", NULL }; static const char *sbv_prefix[] = { "^SBV:", NULL }; @@ -70,6 +75,8 @@ struct gemalto_data { gboolean have_sim; struct at_util_sim_state_query *sim_state_query; struct gemalto_hardware_monitor *hm; + guint modem_ready_id; + guint trial_cmd_id; }; static int gemalto_probe(struct ofono_modem *modem) @@ -107,10 +114,26 @@ static GAtChat *open_device(const char *device) GAtSyntax *syntax; GIOChannel *channel; GAtChat *chat; + GHashTable *options; + + options = g_hash_table_new(g_str_hash, g_str_equal); + if (options == NULL) + return NULL; + + g_hash_table_insert(options, "Baud", "115200"); + g_hash_table_insert(options, "StopBits", "1"); + g_hash_table_insert(options, "DataBits", "8"); + g_hash_table_insert(options, "Parity", "none"); + g_hash_table_insert(options, "XonXoff", "off"); + g_hash_table_insert(options, "RtsCts", "on"); + g_hash_table_insert(options, "Local", "on"); + g_hash_table_insert(options, "Read", "on"); DBG("Opening device %s", device); - channel = g_at_tty_open(device, NULL); + channel = g_at_tty_open(device, options); + g_hash_table_destroy(options); + if (channel == NULL) return NULL; @@ -125,6 +148,72 @@ static GAtChat *open_device(const char *device) return chat; } +static void sim_ready_cb(gboolean present, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct gemalto_data *data = ofono_modem_get_data(modem); + struct ofono_sim *sim = data->sim; + + at_util_sim_state_query_free(data->sim_state_query); + data->sim_state_query = NULL; + + DBG("sim present: %d", present); + + ofono_sim_inserted_notify(sim, present); +} + +static void gemalto_ciev_notify(GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct gemalto_data *data = ofono_modem_get_data(modem); + struct ofono_sim *sim = data->sim; + + const char *sim_status = "simstatus"; + const char *ind_str; + int status; + GAtResultIter iter; + + g_at_result_iter_init(&iter, result); + + /* Example: +CIEV: simstatus, */ + if (!g_at_result_iter_next(&iter, "+CIEV:")) + return; + + if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str)) + return; + + if (!g_str_equal(sim_status, ind_str)) + return; + + if (!g_at_result_iter_next_number(&iter, &status)) + return; + + DBG("sim status %d", status); + + switch (status) { + /* SIM is removed from the holder */ + case 0: + ofono_sim_inserted_notify(sim, FALSE); + break; + + /* SIM is inserted inside the holder */ + case 1: + /* The SIM won't be ready yet */ + data->sim_state_query = at_util_sim_state_query_new(data->app, + 1, 20, sim_ready_cb, modem, + NULL); + break; + + /* USIM initialization completed. UE has finished reading USIM data. */ + case 5: + ofono_sim_initialized_notify(sim); + break; + + default: + break; + } +} + static void sim_state_cb(gboolean present, gpointer user_data) { struct ofono_modem *modem = user_data; @@ -135,6 +224,13 @@ static void sim_state_cb(gboolean present, gpointer user_data) data->have_sim = present; ofono_modem_set_powered(modem, TRUE); + + /* Register for specific sim status reports */ + g_at_chat_register(data->app, "+CIEV:", + gemalto_ciev_notify, FALSE, modem, NULL); + + g_at_chat_send(data->app, "AT^SIND=\"simstatus\",1", none_prefix, + NULL, NULL, NULL); } static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data) @@ -300,29 +396,24 @@ static int gemalto_hardware_monitor_enable(struct ofono_modem *modem) return 0; } -static int gemalto_enable(struct ofono_modem *modem) +static void gemalto_initialize(struct ofono_modem *modem) { struct gemalto_data *data = ofono_modem_get_data(modem); - const char *app, *mdm; + const char *mdm; - DBG("%p", modem); + DBG(""); - app = ofono_modem_get_string(modem, "Application"); mdm = ofono_modem_get_string(modem, "Modem"); - if (app == NULL || mdm == NULL) - return -EINVAL; + if (mdm == NULL) + return; /* Open devices */ - data->app = open_device(app); - if (data->app == NULL) - return -EINVAL; - data->mdm = open_device(mdm); if (data->mdm == NULL) { g_at_chat_unref(data->app); data->app = NULL; - return -EINVAL; + return; } if (getenv("OFONO_AT_DEBUG")) { @@ -340,6 +431,67 @@ static int gemalto_enable(struct ofono_modem *modem) cfun_enable, modem, NULL); gemalto_hardware_monitor_enable(modem); +} + +static void gemalto_modem_ready(GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct gemalto_data *data = ofono_modem_get_data(modem); + const char *app = ofono_modem_get_string(modem, "Application"); + + DBG(""); + + /* + * As the modem wasn't ready to handle AT commands when we opened + * it, we have to close and reopen the device app. + */ + data->modem_ready_id = 0; + data->trial_cmd_id = 0; + + g_at_chat_unref(data->app); + + data->app = open_device(app); + if (data->app == NULL) { + ofono_modem_set_powered(modem, FALSE); + } else { + gemalto_initialize(modem); + } +} + +static void gemalto_at_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct gemalto_data *data = ofono_modem_get_data(modem); + + g_at_chat_unregister(data->app, data->modem_ready_id); + data->modem_ready_id = 0; + + gemalto_initialize(modem); +} + +static int gemalto_enable(struct ofono_modem *modem) +{ + struct gemalto_data *data = ofono_modem_get_data(modem); + const char *app, *mdm; + + DBG("%p", modem); + + app = ofono_modem_get_string(modem, "Application"); + mdm = ofono_modem_get_string(modem, "Modem"); + + if (app == NULL || mdm == NULL) + return -EINVAL; + + /* Open devices */ + data->app = open_device(app); + if (data->app == NULL) + return -EINVAL; + + /* Try the AT command. If it doesn't work, wait for ^SYSSTART */ + data->modem_ready_id = g_at_chat_register(data->app, "^SYSSTART", + gemalto_modem_ready, FALSE, modem, NULL); + data->trial_cmd_id = g_at_chat_send(data->app, "ATE0 AT", + none_prefix, gemalto_at_cb, modem, NULL); return -EINPROGRESS; } @@ -414,17 +566,16 @@ static void gemalto_set_online(struct ofono_modem *modem, ofono_bool_t online, static void gemalto_pre_sim(struct ofono_modem *modem) { struct gemalto_data *data = ofono_modem_get_data(modem); - struct ofono_sim *sim; DBG("%p", modem); ofono_devinfo_create(modem, 0, "atmodem", data->app); ofono_location_reporting_create(modem, 0, "gemaltomodem", data->app); - sim = ofono_sim_create(modem, OFONO_VENDOR_CINTERION, "atmodem", + data->sim = ofono_sim_create(modem, OFONO_VENDOR_CINTERION, "atmodem", data->app); - if (sim && data->have_sim == TRUE) - ofono_sim_inserted_notify(sim, TRUE); + if (data->sim && data->have_sim == TRUE) + ofono_sim_inserted_notify(data->sim, TRUE); } static void gemalto_post_sim(struct ofono_modem *modem) @@ -432,6 +583,7 @@ static void gemalto_post_sim(struct ofono_modem *modem) struct gemalto_data *data = ofono_modem_get_data(modem); struct ofono_gprs *gprs; struct ofono_gprs_context *gc; + const char *model = ofono_modem_get_string(modem, "Model"); DBG("%p", modem); @@ -444,6 +596,10 @@ static void gemalto_post_sim(struct ofono_modem *modem) if (gprs && gc) ofono_gprs_add_context(gprs, gc); + + if (!g_strcmp0(model, GEMALTO_MODEL_ALS3_PLS8x)) + ofono_lte_create(modem, OFONO_VENDOR_CINTERION, + "atmodem", data->app); } static void gemalto_post_online(struct ofono_modem *modem) diff --git a/ofono/plugins/gobi.c b/ofono/plugins/gobi.c index e7cf15986..852189130 100644 --- a/ofono/plugins/gobi.c +++ b/ofono/plugins/gobi.c @@ -264,56 +264,38 @@ static void create_shared_dms(void *user_data) create_dms_cb, modem, NULL); } -static void discover_cb(uint8_t count, const struct qmi_version *list, - void *user_data) +static void discover_cb(void *user_data) { struct ofono_modem *modem = user_data; struct gobi_data *data = ofono_modem_get_data(modem); - uint8_t i; + uint16_t major, minor; DBG(""); - for (i = 0; i < count; i++) { - DBG("%s %d.%d - %d", list[i].name, list[i].major, list[i].minor, - list[i].type); - - switch (list[i].type) { - case QMI_SERVICE_DMS: - data->features |= GOBI_DMS; - break; - case QMI_SERVICE_NAS: - data->features |= GOBI_NAS; - break; - case QMI_SERVICE_WMS: - data->features |= GOBI_WMS; - break; - case QMI_SERVICE_WDS: - data->features |= GOBI_WDS; - break; - case QMI_SERVICE_WDA: - data->features |= GOBI_WDA; - break; - case QMI_SERVICE_PDS: - data->features |= GOBI_PDS; - break; - case QMI_SERVICE_PBM: - data->features |= GOBI_PBM; - break; - case QMI_SERVICE_UIM: - data->features |= GOBI_UIM; - break; - case QMI_SERVICE_CAT: - data->features |= GOBI_CAT; - break; - case QMI_SERVICE_CAT_OLD: - if (list[i].major > 0) - data->features |= GOBI_CAT_OLD; - break; - case QMI_SERVICE_VOICE: + if (qmi_device_has_service(data->device, QMI_SERVICE_DMS)) + data->features |= GOBI_DMS; + if (qmi_device_has_service(data->device, QMI_SERVICE_NAS)) + data->features |= GOBI_NAS; + if (qmi_device_has_service(data->device, QMI_SERVICE_WMS)) + data->features |= GOBI_WMS; + if (qmi_device_has_service(data->device, QMI_SERVICE_WDS)) + data->features |= GOBI_WDS; + if (qmi_device_has_service(data->device, QMI_SERVICE_WDA)) + data->features |= GOBI_WDA; + if (qmi_device_has_service(data->device, QMI_SERVICE_PDS)) + data->features |= GOBI_PDS; + if (qmi_device_has_service(data->device, QMI_SERVICE_PBM)) + data->features |= GOBI_PBM; + if (qmi_device_has_service(data->device, QMI_SERVICE_UIM)) + data->features |= GOBI_UIM; + if (qmi_device_has_service(data->device, QMI_SERVICE_CAT)) + data->features |= GOBI_CAT; + if (qmi_device_get_service_version(data->device, + QMI_SERVICE_CAT_OLD, &major, &minor)) + if (major > 0) + data->features |= GOBI_CAT_OLD; + if (qmi_device_has_service(data->device, QMI_SERVICE_VOICE)) data->features |= GOBI_VOICE; - break; - } - } if (!(data->features & GOBI_DMS)) { if (++data->discover_attempts < 3) { @@ -484,7 +466,7 @@ static void gobi_post_sim(struct ofono_modem *modem) DBG("%p", modem); - ofono_lte_create(modem, "qmimodem", data->device); + ofono_lte_create(modem, 0, "qmimodem", data->device); if (data->features & GOBI_CAT) ofono_stk_create(modem, 0, "qmimodem", data->device); diff --git a/ofono/plugins/mbim.c b/ofono/plugins/mbim.c index 87bb0233e..b54846fec 100644 --- a/ofono/plugins/mbim.c +++ b/ofono/plugins/mbim.c @@ -422,6 +422,8 @@ static struct ofono_modem_driver mbim_driver = { static int mbim_init(void) { + l_debug("------------------->Foobar"); + return ofono_modem_driver_register(&mbim_driver); } diff --git a/ofono/plugins/ril_intel.c b/ofono/plugins/ril_intel.c index 9cda8da9d..382fe9cad 100644 --- a/ofono/plugins/ril_intel.c +++ b/ofono/plugins/ril_intel.c @@ -458,7 +458,7 @@ static void ril_post_sim(struct ofono_modem *modem) } if (ofono_modem_get_boolean(modem, MODEM_PROP_LTE_CAPABLE)) - ofono_lte_create(modem, "rilmodem", rd->ril); + ofono_lte_create(modem, 0, "rilmodem", rd->ril); ofono_stk_create(modem, 0, "rilmodem", rd->ril); } diff --git a/ofono/plugins/sim7100.c b/ofono/plugins/sim7100.c new file mode 100644 index 000000000..7c7e46d12 --- /dev/null +++ b/ofono/plugins/sim7100.c @@ -0,0 +1,273 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2009 Collabora Ltd. All rights reserved. + * Copyright 2018 Purism SPC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + * This file was originally copied from g1.c and + * modified by Bob Ham + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#define OFONO_API_SUBJECT_TO_CHANGE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct sim7100_data { + GAtChat *at; + GAtChat *ppp; +}; + +static void sim7100_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + ofono_info("%s%s", prefix, str); +} + +/* Detect hardware, and initialize if found */ +static int sim7100_probe(struct ofono_modem *modem) +{ + struct sim7100_data *data; + + DBG(""); + + data = g_try_new0(struct sim7100_data, 1); + if (data == NULL) + return -ENOMEM; + + ofono_modem_set_data(modem, data); + + return 0; +} + +static void sim7100_remove(struct ofono_modem *modem) +{ + struct sim7100_data *data = ofono_modem_get_data(modem); + + DBG(""); + + if (!data) + return; + + if (data->at) + g_at_chat_unref(data->at); + + if (data->ppp) + g_at_chat_unref(data->ppp); + + ofono_modem_set_data(modem, NULL); + g_free (data); +} + +static void cfun_set_on_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + + DBG(""); + + if (ok) + ofono_modem_set_powered(modem, TRUE); +} + +static int open_device(struct ofono_modem *modem, const char *devkey, + GAtChat **chatp) +{ + GIOChannel *channel; + GAtSyntax *syntax; + GAtChat *chat; + const char *device; + + DBG("devkey=%s", devkey); + + device = ofono_modem_get_string(modem, devkey); + if (device == NULL) + return -EINVAL; + + channel = g_at_tty_open(device, NULL); + if (channel == NULL) + return -EIO; + + syntax = g_at_syntax_new_gsm_permissive(); + chat = g_at_chat_new(channel, syntax); + g_at_syntax_unref(syntax); + g_io_channel_unref(channel); + + if (chat == NULL) + return -EIO; + + if (getenv("OFONO_AT_DEBUG")) + g_at_chat_set_debug(chat, sim7100_debug, ""); + + *chatp = chat; + return 0; +} + +static int sim7100_enable(struct ofono_modem *modem) +{ + struct sim7100_data *data = ofono_modem_get_data(modem); + int err; + + DBG(""); + + err = open_device(modem, "AT", &data->at); + if (err < 0) + return err; + + err = open_device(modem, "PPP", &data->ppp); + if (err < 0) + return err; + + /* ensure modem is in a known state; verbose on, echo/quiet off */ + g_at_chat_send(data->at, "ATE0Q0V1", NULL, NULL, NULL, NULL); + + /* power up modem */ + g_at_chat_send(data->at, "AT+CFUN=1", NULL, cfun_set_on_cb, + modem, NULL); + + return 0; +} + +static void cfun_set_off_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct sim7100_data *data = ofono_modem_get_data(modem); + + DBG(""); + + g_at_chat_unref(data->ppp); + g_at_chat_unref(data->at); + data->at = data->ppp = NULL; + + if (ok) + ofono_modem_set_powered(modem, FALSE); +} + +static int sim7100_disable(struct ofono_modem *modem) +{ + struct sim7100_data *data = ofono_modem_get_data(modem); + + DBG(""); + + /* power down modem */ + g_at_chat_cancel_all(data->ppp); + g_at_chat_cancel_all(data->at); + g_at_chat_unregister_all(data->ppp); + g_at_chat_unregister_all(data->at); + g_at_chat_send(data->at, "AT+CFUN=0", NULL, cfun_set_off_cb, + modem, NULL); + + return -EINPROGRESS; +} + +static void sim7100_pre_sim(struct ofono_modem *modem) +{ + struct sim7100_data *data = ofono_modem_get_data(modem); + struct ofono_sim *sim; + + DBG(""); + + ofono_devinfo_create(modem, 0, "atmodem", data->at); + sim = ofono_sim_create(modem, 0, "atmodem", data->at); + ofono_voicecall_create(modem, OFONO_VENDOR_SIMCOM, "atmodem", data->at); + + if (sim) + ofono_sim_inserted_notify(sim, TRUE); +} + +static void sim7100_post_sim(struct ofono_modem *modem) +{ + struct sim7100_data *data = ofono_modem_get_data(modem); + struct ofono_message_waiting *mw; + struct ofono_gprs *gprs = NULL; + struct ofono_gprs_context *gc = NULL; + + DBG(""); + + ofono_ussd_create(modem, 0, "atmodem", data->at); + ofono_call_forwarding_create(modem, 0, "atmodem", data->at); + ofono_call_settings_create(modem, 0, "atmodem", data->at); + ofono_netreg_create(modem, 0, "atmodem", data->at); + ofono_call_meter_create(modem, 0, "atmodem", data->at); + ofono_call_barring_create(modem, 0, "atmodem", data->at); + ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem", data->at); + ofono_phonebook_create(modem, 0, "atmodem", data->at); + + gprs = ofono_gprs_create(modem, 0, "atmodem", data->at); + gc = ofono_gprs_context_create(modem, 0, "atmodem", data->ppp); + + if (gprs && gc) + ofono_gprs_add_context(gprs, gc); + + mw = ofono_message_waiting_create(modem); + if (mw) + ofono_message_waiting_register(mw); +} + +static struct ofono_modem_driver sim7100_driver = { + .name = "sim7100", + .probe = sim7100_probe, + .remove = sim7100_remove, + .enable = sim7100_enable, + .disable = sim7100_disable, + .pre_sim = sim7100_pre_sim, + .post_sim = sim7100_post_sim, +}; + +static int sim7100_init(void) +{ + return ofono_modem_driver_register(&sim7100_driver); +} + +static void sim7100_exit(void) +{ + ofono_modem_driver_unregister(&sim7100_driver); +} + +OFONO_PLUGIN_DEFINE(sim7100, "SIMCom SIM7100E modem driver", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, sim7100_init, sim7100_exit) diff --git a/ofono/plugins/ublox.c b/ofono/plugins/ublox.c index 5611ef5c7..cfcdd3f2e 100644 --- a/ofono/plugins/ublox.c +++ b/ofono/plugins/ublox.c @@ -319,7 +319,7 @@ static void ublox_post_sim(struct ofono_modem *modem) --ncontexts; } - ofono_lte_create(modem, "ubloxmodem", data->aux); + ofono_lte_create(modem, 0, "ubloxmodem", data->aux); } static void ublox_post_online(struct ofono_modem *modem) diff --git a/ofono/plugins/udevng.c b/ofono/plugins/udevng.c index 89aec8e0e..7d6d5b34a 100644 --- a/ofono/plugins/udevng.c +++ b/ofono/plugins/udevng.c @@ -710,7 +710,7 @@ static gboolean setup_telitqmi(struct modem_info *modem) return TRUE; } -static gboolean setup_simcom(struct modem_info *modem) +static gboolean setup_sim900(struct modem_info *modem) { const char *mdm = NULL, *aux = NULL, *gps = NULL, *diag = NULL; GSList *list; @@ -1132,6 +1132,7 @@ static gboolean setup_gemalto(struct modem_info* modem) DBG("%s %s %s %s %s", info->devnode, info->interface, info->number, info->label, info->subsystem); + /* PHS8-P */ if (g_strcmp0(info->interface, "255/255/255") == 0) { if (g_strcmp0(info->number, "01") == 0) gps = info->devnode; @@ -1144,6 +1145,20 @@ static gboolean setup_gemalto(struct modem_info* modem) else if (g_strcmp0(info->subsystem, "usbmisc") == 0) qmi = info->devnode; } + + /* Cinterion ALS3, PLS8-E, PLS8-X */ + if (g_strcmp0(info->interface, "2/2/1") == 0) { + if (g_strcmp0(info->number, "00") == 0) + mdm = info->devnode; + else if (g_strcmp0(info->number, "02") == 0) + app = info->devnode; + else if (g_strcmp0(info->number, "04") == 0) + gps = info->devnode; + } + if (g_strcmp0(info->interface, "2/6/0") == 0) { + if (g_strcmp0(info->subsystem, "net") == 0) + net = info->devnode; + } } DBG("application=%s gps=%s modem=%s network=%s qmi=%s", @@ -1156,6 +1171,7 @@ static gboolean setup_gemalto(struct modem_info* modem) ofono_modem_set_string(modem->modem, "GPS", gps); ofono_modem_set_string(modem->modem, "Modem", mdm); ofono_modem_set_string(modem->modem, "Device", qmi); + ofono_modem_set_string(modem->modem, "Model", modem->model); ofono_modem_set_string(modem->modem, "NetworkInterface", net); return TRUE; @@ -1196,6 +1212,54 @@ static gboolean setup_xmm7xxx(struct modem_info *modem) return TRUE; } +static gboolean setup_sim7100(struct modem_info *modem) +{ + const char *at = NULL, *ppp = NULL, *gps = NULL, *diag = NULL, *audio = NULL; + GSList *list; + + DBG("%s", modem->syspath); + + for (list = modem->devices; list; list = list->next) { + struct device_info *info = list->data; + + DBG("%s %s", info->devnode, info->number); + + /* + * Serial port layout: + * 0: QCDM/DIAG + * 1: NMEA + * 2: AT + * 3: AT/PPP + * 4: audio + * + * -- https://www.spinics.net/lists/linux-usb/msg135728.html + */ + if (g_strcmp0(info->number, "00") == 0) + diag = info->devnode; + else if (g_strcmp0(info->number, "01") == 0) + gps = info->devnode; + else if (g_strcmp0(info->number, "02") == 0) + at = info->devnode; + else if (g_strcmp0(info->number, "03") == 0) + ppp = info->devnode; + else if (g_strcmp0(info->number, "04") == 0) + audio = info->devnode; + } + + if (at == NULL) + return FALSE; + + DBG("at=%s ppp=%s gps=%s diag=%s, audio=%s", at, ppp, gps, diag, audio); + + ofono_modem_set_string(modem->modem, "AT", at); + ofono_modem_set_string(modem->modem, "PPP", ppp); + ofono_modem_set_string(modem->modem, "GPS", gps); + ofono_modem_set_string(modem->modem, "Diag", diag); + ofono_modem_set_string(modem->modem, "Audio", audio); + + return TRUE; +} + static struct { const char *name; gboolean (*setup)(struct modem_info *modem); @@ -1215,7 +1279,8 @@ static struct { { "nokia", setup_nokia }, { "telit", setup_telit, "device/interface" }, { "telitqmi", setup_telitqmi }, - { "simcom", setup_simcom }, + { "sim900", setup_sim900 }, + { "sim7100", setup_sim7100 }, { "zte", setup_zte }, { "icera", setup_icera }, { "samsung", setup_samsung }, @@ -1579,7 +1644,8 @@ static struct { { "alcatel", "option", "1bbb", "0017" }, { "novatel", "option", "1410" }, { "zte", "option", "19d2" }, - { "simcom", "option", "05c6", "9000" }, + { "sim900", "option", "05c6", "9000" }, + { "sim7100", "option", "1e0e", "9001" }, { "telit", "usbserial", "1bc7" }, { "telit", "option", "1bc7" }, { "telit", "cdc_acm", "1bc7", "0021" }, @@ -1600,10 +1666,12 @@ static struct { { "gemalto", "option", "1e2d", "0053" }, { "gemalto", "cdc_wdm", "1e2d", "0053" }, { "gemalto", "qmi_wwan", "1e2d", "0053" }, + { "gemalto", "cdc_acm", "1e2d", "0061" }, + { "gemalto", "cdc_ether", "1e2d", "0061" }, { "telit", "cdc_ncm", "1bc7", "0036" }, { "telit", "cdc_acm", "1bc7", "0036" }, - { "xmm7xxx", "cdc_acm", "8087", "0930" }, - { "xmm7xxx", "cdc_ncm", "8087", "0930" }, + { "xmm7xxx", "cdc_acm", "8087" }, + { "xmm7xxx", "cdc_ncm", "8087" }, { } }; @@ -1733,7 +1801,11 @@ static gboolean create_modem(gpointer key, gpointer value, gpointer user_data) if (driver_list[i].setup(modem) == TRUE) { ofono_modem_set_string(modem->modem, "SystemPath", syspath); - ofono_modem_register(modem->modem); + if (ofono_modem_register(modem->modem) < 0) { + DBG("could not register modem '%s'", modem->driver); + return TRUE; + } + return FALSE; } } diff --git a/ofono/plugins/xmm7xxx.c b/ofono/plugins/xmm7xxx.c index 9f0ae8f48..9db87ad18 100644 --- a/ofono/plugins/xmm7xxx.c +++ b/ofono/plugins/xmm7xxx.c @@ -323,7 +323,7 @@ static void xmm7xxx_post_sim(struct ofono_modem *modem) { struct xmm7xxx_data *data = ofono_modem_get_data(modem); - ofono_lte_create(modem, "atmodem", data->chat); + ofono_lte_create(modem, 0, "atmodem", data->chat); ofono_radio_settings_create(modem, 0, "xmm7modem", data->chat); ofono_sim_auth_create(modem); } diff --git a/ofono/src/cdma-netreg.c b/ofono/src/cdma-netreg.c index ba9ee23a6..23616d9a7 100644 --- a/ofono/src/cdma-netreg.c +++ b/ofono/src/cdma-netreg.c @@ -115,6 +115,8 @@ static const GDBusMethodTable cdma_netreg_manager_methods[] = { }; static const GDBusSignalTable cdma_netreg_manager_signals[] = { + { GDBUS_SIGNAL("PropertyChanged", + GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; diff --git a/ofono/src/lte.c b/ofono/src/lte.c index 9b20749c6..a6d26b3cf 100644 --- a/ofono/src/lte.c +++ b/ofono/src/lte.c @@ -244,6 +244,7 @@ static void lte_atom_remove(struct ofono_atom *atom) } struct ofono_lte *ofono_lte_create(struct ofono_modem *modem, + unsigned int vendor, const char *driver, void *data) { struct ofono_lte *lte; @@ -266,7 +267,7 @@ struct ofono_lte *ofono_lte_create(struct ofono_modem *modem, if (g_strcmp0(drv->name, driver)) continue; - if (drv->probe(lte, data) < 0) + if (drv->probe(lte, vendor, data) < 0) continue; lte->driver = drv; diff --git a/ofono/src/sim.c b/ofono/src/sim.c index 4f6f10189..db3a16d9a 100644 --- a/ofono/src/sim.c +++ b/ofono/src/sim.c @@ -960,7 +960,8 @@ static void sim_enter_pin_cb(const struct ofono_error *error, void *data) __ofono_dbus_pending_reply(&sim->pending, reply); - if (sim->initialized) + /* If PIN entry fails, then recheck the PIN type */ + if (sim->initialized || error->type != OFONO_ERROR_TYPE_NO_ERROR) goto recheck; if (sim->pin_type == OFONO_SIM_PASSWORD_SIM_PIN || diff --git a/ofono/unit/test-mbim.c b/ofono/unit/test-mbim.c index a4ac8541f..b27bfb2a5 100644 --- a/ofono/unit/test-mbim.c +++ b/ofono/unit/test-mbim.c @@ -329,7 +329,7 @@ static void parse_device_caps(const void *data) assert(r); assert(device_type == 1); - assert(cellular_class = 1); + assert(cellular_class == 1); assert(voice_class == 1); assert(sim_class == 2); assert(data_class == 0x3f); diff --git a/rpm/ofono.spec b/rpm/ofono.spec index c2d081251..778a8f8b9 100644 --- a/rpm/ofono.spec +++ b/rpm/ofono.spec @@ -1,6 +1,6 @@ Name: ofono Summary: Open Source Telephony -Version: 1.23 +Version: 1.24 Release: 1 License: GPLv2 URL: https://git.sailfishos.org/mer-core/ofono