diff --git a/plugins/sim900.c b/plugins/sim900.c index b55991b9..de2a6f7a 100644 --- a/plugins/sim900.c +++ b/plugins/sim900.c @@ -25,10 +25,10 @@ #include #include - #include #include #include +#include #define OFONO_API_SUBJECT_TO_CHANGE #include @@ -44,13 +44,27 @@ #include #include #include - +#include #include +#define NUM_DLC 5 + +#define SETUP_DLC 0 +#define VOICE_DLC 1 +#define NETREG_DLC 2 +#define SMS_DLC 3 +#define GPRS_DLC 4 + +static char *dlc_prefixes[NUM_DLC] = { "Voice: ", "Net: ", "SMS: ", + "GPRS: " , "Setup: "}; + static const char *none_prefix[] = { NULL }; struct sim900_data { - GAtChat *modem; + GIOChannel *device; + GAtMux *mux; + GAtChat * dlcs[NUM_DLC]; + guint frame_size; }; static int sim900_probe(struct ofono_modem *modem) @@ -76,8 +90,6 @@ static void sim900_remove(struct ofono_modem *modem) ofono_modem_set_data(modem, NULL); - g_at_chat_unref(data->modem); - g_free(data); } @@ -89,8 +101,9 @@ static void sim900_debug(const char *str, void *user_data) } static GAtChat *open_device(struct ofono_modem *modem, - const char *key, char *debug) + const char *key, char *debug) { + struct sim900_data *data = ofono_modem_get_data(modem); const char *device; GAtSyntax *syntax; GIOChannel *channel; @@ -121,10 +134,32 @@ static GAtChat *open_device(struct ofono_modem *modem, if (channel == NULL) return NULL; + data->device = channel; syntax = g_at_syntax_new_gsm_permissive(); chat = g_at_chat_new(channel, syntax); g_at_syntax_unref(syntax); + if (chat == NULL) + return NULL; + + if (getenv("OFONO_AT_DEBUG")) + g_at_chat_set_debug(chat, sim900_debug, debug); + + return chat; +} + +static GAtChat *create_chat(GIOChannel *channel, struct ofono_modem *modem, + char *debug) +{ + GAtSyntax *syntax; + GAtChat *chat; + + if (channel == NULL) + return NULL; + + syntax = g_at_syntax_new_gsmv1(); + chat = g_at_chat_new(channel, syntax); + g_at_syntax_unref(syntax); g_io_channel_unref(channel); if (chat == NULL) @@ -136,6 +171,96 @@ static GAtChat *open_device(struct ofono_modem *modem, return chat; } +static void shutdown_device(struct sim900_data *data) +{ + int i, fd; + + DBG(""); + + for (i = 0; i < NUM_DLC; i++) { + if (data->dlcs[i] == NULL) + continue; + + g_at_chat_unref(data->dlcs[i]); + data->dlcs[i] = NULL; + } + + if (data->mux) { + g_at_mux_shutdown(data->mux); + g_at_mux_unref(data->mux); + data->mux = NULL; + goto done; + } + +done: + g_io_channel_unref(data->device); + data->device = NULL; +} + +static void setup_internal_mux(struct ofono_modem *modem) +{ + struct sim900_data *data = ofono_modem_get_data(modem); + int i; + + DBG(""); + + data->frame_size = 128; + + data->mux = g_at_mux_new_gsm0710_basic(data->device, + data->frame_size); + if (data->mux == NULL) + goto error; + + if (getenv("OFONO_MUX_DEBUG")) + g_at_mux_set_debug(data->mux, sim900_debug, "MUX: "); + + if (!g_at_mux_start(data->mux)) { + g_at_mux_shutdown(data->mux); + g_at_mux_unref(data->mux); + goto error; + } + + for (i = 0; i < NUM_DLC; i++) { + GIOChannel *channel = g_at_mux_create_channel(data->mux); + + data->dlcs[i] = create_chat(channel, modem, dlc_prefixes[i]); + if (data->dlcs[i] == NULL) { + ofono_error("Failed to create channel"); + goto error; + } + } + + ofono_modem_set_powered(modem, TRUE); + + return; + +error: + shutdown_device(data); + ofono_modem_set_powered(modem, FALSE); +} + +static void mux_setup_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct sim900_data *data = ofono_modem_get_data(modem); + + DBG(""); + + g_at_chat_unref(data->dlcs[SETUP_DLC]); + data->dlcs[SETUP_DLC] = NULL; + + if (!ok) + goto error; + + setup_internal_mux(modem); + + return; + +error: + shutdown_device(data); + ofono_modem_set_powered(modem, FALSE); +} + static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_modem *modem = user_data; @@ -144,11 +269,15 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data) DBG(""); if (!ok) { - g_at_chat_unref(data->modem); - data->modem = NULL; + g_at_chat_unref(data->dlcs[SETUP_DLC]); + data->dlcs[SETUP_DLC] = NULL; + ofono_modem_set_powered(modem, FALSE); + return; } - ofono_modem_set_powered(modem, ok); + g_at_chat_send(data->dlcs[SETUP_DLC], + "AT+CMUX=0,0,5,128,10,3,30,10,2", NULL, + mux_setup_cb, modem, NULL); } static int sim900_enable(struct ofono_modem *modem) @@ -157,25 +286,22 @@ static int sim900_enable(struct ofono_modem *modem) DBG("%p", modem); - data->modem = open_device(modem, "Device", "Device: "); - if (data->modem == NULL) { - DBG("return -EINVAL"); + data->dlcs[SETUP_DLC] = open_device(modem, "Device", "Setup: "); + if (data->dlcs[SETUP_DLC] == NULL) return -EINVAL; - } - g_at_chat_send(data->modem, "ATE0", NULL, NULL, NULL, NULL); + g_at_chat_send(data->dlcs[SETUP_DLC], "ATE0", NULL, NULL, NULL, NULL); /* For obtain correct sms service number */ - g_at_chat_send(data->modem, "AT+CSCS=\"GSM\"", NULL, + g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CSCS=\"GSM\"", NULL, NULL, NULL, NULL); - g_at_chat_send(data->modem, "AT+CFUN=1", none_prefix, + g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=1", none_prefix, cfun_enable, modem, NULL); return -EINPROGRESS; } - static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data) { struct ofono_modem *modem = user_data; @@ -183,8 +309,11 @@ static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data) DBG(""); - g_at_chat_unref(data->modem); - data->modem = NULL; + g_at_mux_shutdown(data->mux); + g_at_mux_unref(data->mux); + + g_at_chat_unref(data->dlcs[SETUP_DLC]); + data->dlcs[SETUP_DLC] = NULL; if (ok) ofono_modem_set_powered(modem, FALSE); @@ -196,12 +325,11 @@ static int sim900_disable(struct ofono_modem *modem) DBG("%p", modem); - g_at_chat_cancel_all(data->modem); - g_at_chat_unregister_all(data->modem); - - g_at_chat_send(data->modem, "AT+CFUN=4", none_prefix, + g_at_chat_send(data->dlcs[SETUP_DLC], "AT+CFUN=4", none_prefix, cfun_disable, modem, NULL); + shutdown_device(data); + return -EINPROGRESS; } @@ -212,9 +340,9 @@ static void sim900_pre_sim(struct ofono_modem *modem) DBG("%p", modem); - ofono_devinfo_create(modem, 0, "atmodem", data->modem); + ofono_devinfo_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]); sim = ofono_sim_create(modem, OFONO_VENDOR_SIMCOM, "atmodem", - data->modem); + data->dlcs[VOICE_DLC]); if (sim) ofono_sim_inserted_notify(sim, TRUE); @@ -223,12 +351,23 @@ static void sim900_pre_sim(struct ofono_modem *modem) static void sim900_post_sim(struct ofono_modem *modem) { struct sim900_data *data = ofono_modem_get_data(modem); + struct ofono_gprs *gprs; + struct ofono_gprs_context *gc; DBG("%p", modem); - ofono_phonebook_create(modem, 0, "atmodem", data->modem); + ofono_phonebook_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]); ofono_sms_create(modem, OFONO_VENDOR_SIMCOM, "atmodem", - data->modem); + data->dlcs[SMS_DLC]); + + gprs = ofono_gprs_create(modem, 0, "atmodem", data->dlcs[GPRS_DLC]); + if (gprs == NULL) + return; + + gc = ofono_gprs_context_create(modem, OFONO_VENDOR_SIMCOM, + "atmodem", data->dlcs[GPRS_DLC]); + if (gc) + ofono_gprs_add_context(gprs, gc); } static void sim900_post_online(struct ofono_modem *modem) @@ -237,9 +376,11 @@ static void sim900_post_online(struct ofono_modem *modem) DBG("%p", modem); - ofono_netreg_create(modem, OFONO_VENDOR_SIMCOM, "atmodem", data->modem); - ofono_ussd_create(modem, 0, "atmodem", data->modem); - ofono_voicecall_create(modem, 0, "atmodem", data->modem); + ofono_netreg_create(modem, OFONO_VENDOR_SIMCOM, + "atmodem", data->dlcs[NETREG_DLC]); + ofono_ussd_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]); + ofono_voicecall_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]); + ofono_call_volume_create(modem, 0, "atmodem", data->dlcs[VOICE_DLC]); } static struct ofono_modem_driver sim900_driver = {