Hi Philip, > + > +static void verify_enable(gboolean ok, GAtResult *result, gpointer user_data) > +{ > + struct ofono_modem *modem = user_data; > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + if (ok) { > + ofono_modem_set_powered(modem, TRUE); > + g_at_chat_send(data->modem, "AT&C0", NULL, NULL, NULL, NULL); > + g_at_chat_send(data->aux, "AT&C0", NULL, NULL, NULL, NULL); Why do you do send AT&C0 here? Can it be done earlier? Any reason for checking that CFUN succeeded? If so, then it might be a good idea to document that in comments / commit description. What if it failed? Are you relying on the core timeout mechanisms? > + } > +} > + > +static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data) > +{ > + struct ofono_modem *modem = user_data; > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + DBG("ok %d (tried %d times)", (int)ok, data->enable_tries); This cast seems unnecessary > + > + if (!ok) { > + if (data->enable_tries > MAX_RETRIES) { > + g_at_chat_unref(data->aux); > + data->aux = NULL; > + g_at_chat_unref(data->modem); > + data->modem = NULL; > + ofono_modem_set_powered(modem, FALSE); > + DBG("modem won't enable - giving up"); > + } > + goto retry; Is the timer still running in case MAX_RETRIES is reached? In general we prefer using single-shot timers and re-starting them if the command fails. Certain commands might take several seconds to return on some hardware. > + } > + > + g_at_chat_send(data->aux, "AT+CPIN?", NULL, verify_enable, > + modem, NULL); Using prefixes is a good idea, otherwise any unsolicited notifications will be missed. git show 35feae07e50f89ea3c42566c765f501ec768bd44 for an example of what might happen. > +retry: > + data->enable_tries++; > +} > + > +static gboolean quectel_start(gpointer user_data) > +{ > + struct ofono_modem *modem = user_data; > + struct quectel_data *data = ofono_modem_get_data(modem); > + > + if (ofono_modem_get_powered(modem) == FALSE) { > + g_at_chat_send(data->aux, "AT+CFUN=1", NULL, cfun_enable, > + modem, NULL); > + return TRUE; > + } > + > + data->enable_timer = 0; > + > + return FALSE; > +} > + > +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 +CMEE=1", NULL, NULL, NULL, NULL); > + g_at_chat_send(data->aux, "ATE0 +CMEE=1", NULL, NULL, NULL, NULL); > + > + /* Give the modem a bit more time to power up completely. */ > + data->enable_tries = 0; > + data->enable_timer = g_timeout_add_seconds(RESET_DELAY, > + quectel_start, modem); Is this delay always necessary? enable() is called in other situations besides a hot-plugging... > + > + 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); > + > + /* Prevent a race with cfun_start() retries. */ > + if (data->enable_timer) > + g_source_remove(data->enable_timer); > + > + 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", NULL, > + cfun_disable, modem, NULL); What behavior does this modem exhibit when using CFUN=0? Many devices jump off the USB bus when this is sent. Hence why most drivers use CFUN=4. > + > + return -EINPROGRESS; > +} > + Regards, -Denis