Hi Philip, > +static void sim_state_cb(gboolean present, gpointer user_data) > +{ > + struct ofono_modem *modem = user_data; > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + DBG("present %d", present); > + > + at_util_sim_state_query_free(data->sim_state_query); > + data->sim_state_query = NULL; > + > + data->have_sim = present; > + > + ofono_modem_set_powered(modem, TRUE); > + > + /* Enable +CME error reporting and turn off the radio. */ > + g_at_chat_send(data->aux, "AT+CMEE=1", NULL, NULL, NULL, NULL); > + g_at_chat_send(data->aux, "AT+CFUN=4", NULL, NULL, NULL, NULL); Please use none_prefix here since it is already defined. > +} > + > +static void cfun_query(gboolean ok, GAtResult *result, gpointer user_data) > +{ > + struct ofono_modem *modem = user_data; > + struct quectel_data *data = ofono_modem_get_data(modem); > + GAtResultIter iter; > + int status; > + > + DBG("ok %d", ok); > + > + if (!ok) > + return; > + > + g_at_result_iter_init(&iter, result); > + > + if (g_at_result_iter_next(&iter, "+CFUN:") == FALSE) > + return; > + > + g_at_result_iter_next_number(&iter, &status); > + > + /* > + * When coming out of reset or transitioning out of CFUN=0, the modem > + * firmware will respond to most commands with ERROR until some amount > + * of time (which varies with temperature) passes. Empirical evidence > + * suggests that the firmware will report an unsolicited +CPIN: > + * indication when it is ready to be useful. > + * > + * Specific issues: > + * > + * o The modem firmware powers up in CFUN=1 but responds to > + * AT+CFUN=4 with ERROR until it has sent an unsolicited > + * +CPIN: indication. > + * > + * o In CFUN=0 or after toggling the modem's reset line, the > + * modem firmware will respond to AT+CPIN? queries with > + * +CME ERROR: 10 ("SIM not inserted", regardless of whether > + * a SIM is actually inserted), again until it has sent an > + * unsolicited +CPIN: indication. > + * > + * Work around these features by temporarily disabling +CME error > + * reporting and transitioning to CFUN=4 only after polling the > + * AT+CPIN? status. > + */ So why not query CFUN, register to unsolicited CPIN notifications and query CPIN. If that fails, then in theory CPIN will come in unsolicited. Beats polling. > + > + if (status != 1) { > + g_at_chat_send(data->aux, "AT+CMEE=0", NULL, NULL, > + NULL, NULL); Might want to use a prefix here as well > + g_at_chat_send(data->aux, "AT+CFUN=1", none_prefix, > + cfun_enable, modem, NULL); Should you be using CFUN=4 here? > + return; > + } > + > + cfun_enable(TRUE, NULL, modem); > +} > + > +static int quectel_enable(struct ofono_modem *modem) > +{ > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + DBG("%p", modem); > + > + data->modem = open_device(modem, "Modem", "Modem: "); > + if (data->modem == NULL) > + return -EINVAL; > + > + data->aux = open_device(modem, "Aux", "Aux: "); > + if (data->aux == NULL) { > + g_at_chat_unref(data->modem); > + data->modem = NULL; > + return -EIO; > + } > + g_at_chat_set_slave(data->modem, data->aux); > + > + g_at_chat_send(data->modem, "ATE0 &C0", NULL, NULL, NULL, NULL); > + g_at_chat_send(data->aux, "ATE0 &C0", NULL, NULL, NULL, NULL); > + prefixes here > + g_at_chat_send(data->aux, "AT+CFUN?", cfun_prefix, > + cfun_query, modem, NULL); > + > + return -EINPROGRESS; > +} > + > +static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data) > +{ > + struct ofono_modem *modem = user_data; > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + DBG(""); > + > + g_at_chat_unref(data->aux); > + data->aux = NULL; > + > + if (ok) > + ofono_modem_set_powered(modem, FALSE); > +} > + > +static int quectel_disable(struct ofono_modem *modem) > +{ > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + DBG("%p", modem); > + > + g_at_chat_cancel_all(data->modem); > + g_at_chat_unregister_all(data->modem); > + > + g_at_chat_unref(data->modem); > + data->modem = NULL; > + > + g_at_chat_cancel_all(data->aux); > + g_at_chat_unregister_all(data->aux); > + > + g_at_chat_send(data->aux, "AT+CFUN=0", cfun_prefix, That should probably be none_prefix if the modem follows standards. > + cfun_disable, modem, NULL); > + > + return -EINPROGRESS; > +} > + > +static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data) > +{ > + struct cb_data *cbd = user_data; > + ofono_modem_online_cb_t cb = cbd->cb; > + struct ofono_error error; > + > + decode_at_error(&error, g_at_result_final_response(result)); > + cb(&error, cbd->data); > +} > + > +static void quectel_set_online(struct ofono_modem *modem, ofono_bool_t online, > + ofono_modem_online_cb_t cb, void *user_data) > +{ > + struct quectel_data *data = ofono_modem_get_data(modem); > + struct cb_data *cbd = cb_data_new(cb, user_data); > + char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4"; > + > + DBG("modem %p %s", modem, online ? "online" : "offline"); > + > + if (g_at_chat_send(data->aux, command, cfun_prefix, set_online_cb, > + cbd, g_free) > 0) > + return; > + > + CALLBACK_WITH_FAILURE(cb, cbd->data); > + > + g_free(cbd); > +} > + > +static void quectel_pre_sim(struct ofono_modem *modem) > +{ > + struct quectel_data *data = ofono_modem_get_data(modem); > + struct ofono_sim *sim; > + > + DBG("%p", modem); > + > + ofono_devinfo_create(modem, OFONO_VENDOR_QUECTEL, "atmodem", > + data->aux); We don't specify VENDOR flags if the atom driver uses default behavior. That way it is easy to tell where non-standard behavior occurs for a particular modem. So just use 0 here. > + sim = ofono_sim_create(modem, OFONO_VENDOR_QUECTEL, "atmodem", > + data->aux); > + > + if (sim && data->have_sim == TRUE) > + ofono_sim_inserted_notify(sim, TRUE); > +} > + > +static void quectel_post_sim(struct ofono_modem *modem) > +{ > + struct quectel_data *data = ofono_modem_get_data(modem); > + struct ofono_gprs *gprs; > + struct ofono_gprs_context *gc; > + > + DBG("%p", modem); > + > + gprs = ofono_gprs_create(modem, OFONO_VENDOR_QUECTEL, "atmodem", > + data->aux); > + gc = ofono_gprs_context_create(modem, OFONO_VENDOR_QUECTEL, "atmodem", > + data->modem); Same as above > + > + if (gprs && gc) > + ofono_gprs_add_context(gprs, gc); > +} > + > +static void quectel_post_online(struct ofono_modem *modem) > +{ > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + ofono_netreg_create(modem, OFONO_VENDOR_QUECTEL, "atmodem", > + data->aux); And here > +} > + Regards, -Denis