huawei: Setup CSCS on both ports
[platform/upstream/ofono.git] / plugins / huawei.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <gatchat.h>
32 #include <gattty.h>
33
34 #define OFONO_API_SUBJECT_TO_CHANGE
35 #include <ofono/plugin.h>
36 #include <ofono/modem.h>
37 #include <ofono/devinfo.h>
38 #include <ofono/netreg.h>
39 #include <ofono/sim.h>
40 #include <ofono/cbs.h>
41 #include <ofono/sms.h>
42 #include <ofono/ussd.h>
43 #include <ofono/gprs.h>
44 #include <ofono/gprs-context.h>
45 #include <ofono/audio-settings.h>
46 #include <ofono/radio-settings.h>
47 #include <ofono/voicecall.h>
48 #include <ofono/call-forwarding.h>
49 #include <ofono/call-settings.h>
50 #include <ofono/call-barring.h>
51 #include <ofono/phonebook.h>
52 #include <ofono/message-waiting.h>
53 #include <ofono/cdma-netreg.h>
54 #include <ofono/cdma-connman.h>
55 #include <ofono/log.h>
56
57 #include <drivers/atmodem/atutil.h>
58 #include <drivers/atmodem/vendor.h>
59
60 static const char *none_prefix[] = { NULL };
61 static const char *gcap_prefix[] = { "+GCAP:", NULL };
62 static const char *rfswitch_prefix[] = { "^RFSWITCH:", NULL };
63 static const char *sysinfo_prefix[] = { "^SYSINFO:", NULL };
64 static const char *ussdmode_prefix[] = { "^USSDMODE:", NULL };
65 static const char *dialmode_prefix[] = { "^DIALMODE:", NULL };
66 static const char *cvoice_prefix[] = { "^CVOICE:", NULL };
67
68 enum {
69         SIM_STATE_INVALID_OR_LOCKED =   0,
70         SIM_STATE_VALID =               1,
71         SIM_STATE_INVALID_CS =          2,
72         SIM_STATE_INVALID_PS =          3,
73         SIM_STATE_INVALID_PS_AND_CS =   4,
74         SIM_STATE_ROMSIM =              240,
75         SIM_STATE_NOT_EXISTENT =        255,
76 };
77
78 struct huawei_data {
79         GAtChat *modem;
80         GAtChat *pcui;
81         gboolean have_sim;
82         int sim_state;
83         guint sysinfo_poll_source;
84         guint sysinfo_poll_count;
85         struct cb_data *online_cbd;
86         const char *offline_command;
87         gboolean have_voice;
88         gboolean have_gsm;
89         gboolean have_cdma;
90 };
91
92 static int huawei_probe(struct ofono_modem *modem)
93 {
94         struct huawei_data *data;
95
96         DBG("%p", modem);
97
98         data = g_try_new0(struct huawei_data, 1);
99         if (data == NULL)
100                 return -ENOMEM;
101
102         ofono_modem_set_data(modem, data);
103
104         return 0;
105 }
106
107 static void huawei_remove(struct ofono_modem *modem)
108 {
109         struct huawei_data *data = ofono_modem_get_data(modem);
110
111         DBG("%p", modem);
112
113         ofono_modem_set_data(modem, NULL);
114
115         /* Cleanup after potential enable polling */
116         if (data->sysinfo_poll_source > 0)
117                 g_source_remove(data->sysinfo_poll_source);
118
119         /* Cleanup after hot-unplug */
120         g_at_chat_unref(data->pcui);
121
122         g_free(data);
123 }
124
125 static void huawei_debug(const char *str, void *user_data)
126 {
127         const char *prefix = user_data;
128
129         ofono_info("%s%s", prefix, str);
130 }
131
132 static void ussdmode_query_cb(gboolean ok, GAtResult *result,
133                                                 gpointer user_data)
134 {
135         struct huawei_data *data = user_data;
136         GAtResultIter iter;
137         gint ussdmode;
138
139         if (!ok)
140                 return;
141
142         g_at_result_iter_init(&iter, result);
143
144         if (!g_at_result_iter_next(&iter, "^USSDMODE:"))
145                 return;
146
147         if (!g_at_result_iter_next_number(&iter, &ussdmode))
148                 return;
149
150         if (ussdmode == 0)
151                 return;
152
153         /* Set USSD mode to text mode */
154         g_at_chat_send(data->pcui, "AT^USSDMODE=0", none_prefix,
155                                                 NULL, NULL, NULL);
156 }
157
158 static void ussdmode_support_cb(gboolean ok, GAtResult *result,
159                                                 gpointer user_data)
160 {
161         struct huawei_data *data = user_data;
162         GAtResultIter iter;
163
164         if (!ok)
165                 return;
166
167         g_at_result_iter_init(&iter, result);
168
169         if (!g_at_result_iter_next(&iter, "^USSDMODE:"))
170                 return;
171
172         /* Query current USSD mode */
173         g_at_chat_send(data->pcui, "AT^USSDMODE?", ussdmode_prefix,
174                                         ussdmode_query_cb, data, NULL);
175 }
176
177 static void dialmode_query_cb(gboolean ok, GAtResult *result,
178                                                 gpointer user_data)
179 {
180         //struct huawei_data *data = user_data;
181         GAtResultIter iter;
182
183         if (!ok)
184                 return;
185
186         g_at_result_iter_init(&iter, result);
187
188         if (!g_at_result_iter_next(&iter, "^DIALMODE:"))
189                 return;
190 }
191
192 static void dialmode_support_cb(gboolean ok, GAtResult *result,
193                                                 gpointer user_data)
194 {
195         struct huawei_data *data = user_data;
196         GAtResultIter iter;
197
198         if (!ok)
199                 return;
200
201         g_at_result_iter_init(&iter, result);
202
203         if (!g_at_result_iter_next(&iter, "^DIALMODE:"))
204                 return;
205
206         /* Query current NDIS mode */
207         g_at_chat_send(data->pcui, "AT^DIALMODE?", dialmode_prefix,
208                                         dialmode_query_cb, data, NULL);
209 }
210
211 static void cvoice_query_cb(gboolean ok, GAtResult *result,
212                                                 gpointer user_data)
213 {
214         struct ofono_modem *modem = user_data;
215         struct huawei_data *data = ofono_modem_get_data(modem);
216         GAtResultIter iter;
217         gint mode, rate, bits, period;
218
219         if (!ok)
220                 return;
221
222         g_at_result_iter_init(&iter, result);
223
224         if (!g_at_result_iter_next(&iter, "^CVOICE:"))
225                 return;
226
227         if (!g_at_result_iter_next_number(&iter, &mode))
228                 return;
229
230         if (!g_at_result_iter_next_number(&iter, &rate))
231                 return;
232
233         if (!g_at_result_iter_next_number(&iter, &bits))
234                 return;
235
236         if (!g_at_result_iter_next_number(&iter, &period))
237                 return;
238
239         data->have_voice = TRUE;
240
241         ofono_info("Voice channel: %d Hz, %d bits, %dms period",
242                                                 rate, bits, period);
243
244         /* Check available voice ports */
245         g_at_chat_send(data->pcui, "AT^DDSETEX=?", none_prefix,
246                                                 NULL, NULL, NULL);
247 }
248
249 static void cvoice_support_cb(gboolean ok, GAtResult *result,
250                                                 gpointer user_data)
251 {
252         struct ofono_modem *modem = user_data;
253         struct huawei_data *data = ofono_modem_get_data(modem);
254         GAtResultIter iter;
255
256         if (!ok)
257                 return;
258
259         g_at_result_iter_init(&iter, result);
260
261         if (!g_at_result_iter_next(&iter, "^CVOICE:"))
262                 return;
263
264         /* Query current voice setting */
265         g_at_chat_send(data->pcui, "AT^CVOICE?", cvoice_prefix,
266                                         cvoice_query_cb, modem, NULL);
267 }
268
269 static void simst_notify(GAtResult *result, gpointer user_data)
270 {
271         struct ofono_modem *modem = user_data;
272         struct huawei_data *data = ofono_modem_get_data(modem);
273         GAtResultIter iter;
274         int sim_state;
275
276         g_at_result_iter_init(&iter, result);
277
278         if (!g_at_result_iter_next(&iter, "^SIMST:"))
279                 return;
280
281         if (!g_at_result_iter_next_number(&iter, &sim_state))
282                 return;
283
284         DBG("%d -> %d", data->sim_state, sim_state);
285
286         data->sim_state = sim_state;
287 }
288
289 static gboolean parse_sysinfo_result(GAtResult *result, int *srv_status,
290                                         int *srv_domain, int *sim_state)
291 {
292         GAtResultIter iter;
293
294         g_at_result_iter_init(&iter, result);
295
296         if (!g_at_result_iter_next(&iter, "^SYSINFO:"))
297                 return FALSE;
298
299         if (!g_at_result_iter_next_number(&iter, srv_status))
300                 return FALSE;
301
302         if (!g_at_result_iter_next_number(&iter, srv_domain))
303                 return FALSE;
304
305         if (!g_at_result_iter_skip_next(&iter))
306                 return FALSE;
307
308         if (!g_at_result_iter_skip_next(&iter))
309                 return FALSE;
310
311         if (!g_at_result_iter_next_number(&iter, sim_state))
312                 return FALSE;
313
314         return TRUE;
315 }
316
317 static void shutdown_device(struct huawei_data *data)
318 {
319         g_at_chat_cancel_all(data->modem);
320         g_at_chat_unregister_all(data->modem);
321
322         g_at_chat_unref(data->modem);
323         data->modem = NULL;
324
325         g_at_chat_cancel_all(data->pcui);
326         g_at_chat_unregister_all(data->pcui);
327
328         g_at_chat_unref(data->pcui);
329         data->pcui = NULL;
330 }
331
332 static void cfun_offline(gboolean ok, GAtResult *result, gpointer user_data)
333 {
334         struct ofono_modem *modem = user_data;
335         struct huawei_data *data = ofono_modem_get_data(modem);
336
337         DBG("");
338
339         if (!ok) {
340                 shutdown_device(data);
341                 ofono_modem_set_powered(modem, FALSE);
342                 return;
343         }
344
345         ofono_modem_set_powered(modem, TRUE);
346 }
347
348 static gboolean sysinfo_enable_check(gpointer user_data);
349
350 static void sysinfo_enable_cb(gboolean ok, GAtResult *result,
351                                                 gpointer user_data)
352 {
353         struct ofono_modem *modem = user_data;
354         struct huawei_data *data = ofono_modem_get_data(modem);
355         int srv_status, srv_domain, sim_state;
356
357         if (!ok)
358                 goto failure;
359
360         if (parse_sysinfo_result(result, &srv_status, &srv_domain,
361                                                 &sim_state) == FALSE)
362                 goto failure;
363
364         DBG("%d -> %d", data->sim_state, sim_state);
365
366         data->sim_state = sim_state;
367
368         if (sim_state == SIM_STATE_NOT_EXISTENT) {
369                 data->sysinfo_poll_count++;
370
371                 if (data->sysinfo_poll_count > 5)
372                         goto failure;
373
374                 data->sysinfo_poll_source = g_timeout_add_seconds(1,
375                                                 sysinfo_enable_check, modem);
376                 return;
377         }
378
379         data->have_sim = TRUE;
380
381         /* Switch data carrier detect signal off */
382         g_at_chat_send(data->modem, "AT&C0", NULL, NULL, NULL, NULL);
383         g_at_chat_send(data->pcui, "AT&C0", NULL, NULL, NULL, NULL);
384
385         /* Query current device settings */
386         g_at_chat_send(data->pcui, "AT^U2DIAG?", none_prefix,
387                                                 NULL, NULL, NULL);
388
389         /* Query current port settings */
390         g_at_chat_send(data->pcui, "AT^GETPORTMODE", none_prefix,
391                                                 NULL, NULL, NULL);
392
393         /* Check USSD mode support */
394         g_at_chat_send(data->pcui, "AT^USSDMODE=?", ussdmode_prefix,
395                                         ussdmode_support_cb, data, NULL);
396
397         /* Check NDIS mode support */
398         g_at_chat_send(data->pcui, "AT^DIALMODE=?", dialmode_prefix,
399                                         dialmode_support_cb, data, NULL);
400
401         /* Check for voice support */
402         g_at_chat_send(data->pcui, "AT^CVOICE=?", cvoice_prefix,
403                                         cvoice_support_cb, modem, NULL);
404
405         if (g_at_chat_send(data->pcui, data->offline_command, none_prefix,
406                                         cfun_offline, modem, NULL) > 0)
407                 return;
408
409 failure:
410         shutdown_device(data);
411         ofono_modem_set_powered(modem, FALSE);
412 }
413
414 static gboolean sysinfo_enable_check(gpointer user_data)
415 {
416         struct ofono_modem *modem = user_data;
417         struct huawei_data *data = ofono_modem_get_data(modem);
418
419         data->sysinfo_poll_source = 0;
420
421         g_at_chat_send(data->pcui, "AT^SYSINFO", sysinfo_prefix,
422                                         sysinfo_enable_cb, modem, NULL);
423
424         return FALSE;
425 }
426
427 static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
428 {
429         struct ofono_modem *modem = user_data;
430         struct huawei_data *data = ofono_modem_get_data(modem);
431
432         DBG("");
433
434         if (!ok) {
435                 shutdown_device(data);
436                 ofono_modem_set_powered(modem, FALSE);
437                 return;
438         }
439
440         /* Follow sim state changes */
441         g_at_chat_register(data->pcui, "^SIMST:", simst_notify,
442                                                 FALSE, modem, NULL);
443
444         data->sysinfo_poll_count = 0;
445
446         sysinfo_enable_check(modem);
447 }
448
449 static void rfswitch_support(gboolean ok, GAtResult *result, gpointer user_data)
450 {
451         struct ofono_modem *modem = user_data;
452         struct huawei_data *data = ofono_modem_get_data(modem);
453
454         if (data->have_gsm == FALSE && data->have_cdma == TRUE) {
455                 data->offline_command = "AT+CFUN=5";
456                 goto done;
457         }
458
459         if (!ok)
460                 data->offline_command = "AT+CFUN=5";
461         else
462                 data->offline_command = "AT+CFUN=7";
463
464 done:
465         g_at_chat_send(data->pcui, "AT+CFUN=1", none_prefix,
466                                         cfun_enable, modem, NULL);
467 }
468
469 static void gcap_support(gboolean ok, GAtResult *result, gpointer user_data)
470 {
471         struct ofono_modem *modem = user_data;
472         struct huawei_data *data = ofono_modem_get_data(modem);
473         GAtResultIter iter;
474         const char *gcap;
475
476         if (!ok)
477                 goto done;
478
479         g_at_result_iter_init(&iter, result);
480
481         if (!g_at_result_iter_next(&iter, "+GCAP:"))
482                 goto done;
483
484         while (g_at_result_iter_next_unquoted_string(&iter, &gcap)) {
485                 if (*gcap == '\0')
486                         break;
487
488                 if (!strcmp(gcap, "+CGSM"))
489                         data->have_gsm = TRUE;
490                 else if (!strcmp(gcap, "+CIS707-A"))
491                         data->have_cdma = TRUE;
492         }
493
494 done:
495         g_at_chat_send(data->pcui, "AT^RFSWITCH=?", rfswitch_prefix,
496                                         rfswitch_support, modem, NULL);
497 }
498
499 static GAtChat *open_device(struct ofono_modem *modem,
500                                 const char *key, char *debug)
501 {
502         const char *device;
503         GIOChannel *channel;
504         GAtSyntax *syntax;
505         GAtChat *chat;
506
507         device = ofono_modem_get_string(modem, key);
508         if (device == NULL)
509                 return NULL;
510
511         DBG("%s %s", key, device);
512
513         channel = g_at_tty_open(device, NULL);
514         if (channel == NULL)
515                 return NULL;
516
517         syntax = g_at_syntax_new_gsm_permissive();
518         chat = g_at_chat_new(channel, syntax);
519         g_at_syntax_unref(syntax);
520
521         g_io_channel_unref(channel);
522
523         if (chat == NULL)
524                 return NULL;
525
526         g_at_chat_add_terminator(chat, "COMMAND NOT SUPPORT", -1, FALSE);
527         g_at_chat_add_terminator(chat, "TOO MANY PARAMETERS", -1, FALSE);
528
529         if (getenv("OFONO_AT_DEBUG"))
530                 g_at_chat_set_debug(chat, huawei_debug, debug);
531
532         return chat;
533 }
534
535 static int huawei_enable(struct ofono_modem *modem)
536 {
537         struct huawei_data *data = ofono_modem_get_data(modem);
538
539         DBG("%p", modem);
540
541         data->modem = open_device(modem, "Modem", "Modem: ");
542         if (data->modem == NULL)
543                 return -EINVAL;
544
545         data->pcui = open_device(modem, "Pcui", "PCUI: ");
546         if (data->pcui == NULL) {
547                 g_at_chat_unref(data->modem);
548                 data->modem = NULL;
549                 return -EIO;
550         }
551
552         g_at_chat_set_slave(data->modem, data->pcui);
553
554         g_at_chat_send(data->modem, "ATE0 +CMEE=1", NULL, NULL, NULL, NULL);
555         g_at_chat_send(data->pcui, "ATE0 +CMEE=1", NULL, NULL, NULL, NULL);
556
557         /*
558          * Ensure that the modem is using GSM character set and not IRA,
559          * otherwise weirdness with umlauts and other non-ASCII characters
560          * can result
561          */
562         g_at_chat_send(data->modem, "AT+CSCS=\"GSM\"", none_prefix,
563                                                         NULL, NULL, NULL);
564         g_at_chat_send(data->pcui, "AT+CSCS=\"GSM\"", none_prefix,
565                                                         NULL, NULL, NULL);
566
567         data->sim_state = SIM_STATE_NOT_EXISTENT;
568
569         /* Check for GSM capabilities */
570         g_at_chat_send(data->pcui, "ATI", gcap_prefix,
571                                         gcap_support, modem, NULL);
572
573         return -EINPROGRESS;
574 }
575
576 static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
577 {
578         struct ofono_modem *modem = user_data;
579         struct huawei_data *data = ofono_modem_get_data(modem);
580
581         DBG("");
582
583         g_at_chat_unref(data->pcui);
584         data->pcui = NULL;
585
586         if (ok)
587                 ofono_modem_set_powered(modem, FALSE);
588 }
589
590 static int huawei_disable(struct ofono_modem *modem)
591 {
592         struct huawei_data *data = ofono_modem_get_data(modem);
593
594         DBG("%p", modem);
595
596         g_at_chat_cancel_all(data->modem);
597         g_at_chat_unregister_all(data->modem);
598
599         g_at_chat_unref(data->modem);
600         data->modem = NULL;
601
602         g_at_chat_cancel_all(data->pcui);
603         g_at_chat_unregister_all(data->pcui);
604
605         /* Cleanup potential online enable polling */
606         if (data->sysinfo_poll_source > 0) {
607                 g_source_remove(data->sysinfo_poll_source);
608                 data->sysinfo_poll_source = 0;
609
610                 g_free(data->online_cbd);
611                 data->online_cbd = NULL;
612         }
613
614         g_at_chat_send(data->pcui, "AT+CFUN=0", none_prefix,
615                                         cfun_disable, modem, NULL);
616
617         return -EINPROGRESS;
618 }
619
620 static gboolean sysinfo_online_check(gpointer user_data);
621
622 static void sysinfo_online_cb(gboolean ok, GAtResult *result,
623                                                 gpointer user_data)
624 {
625         struct huawei_data *data = user_data;
626         ofono_modem_online_cb_t cb = data->online_cbd->cb;
627         int srv_status, srv_domain, sim_state;
628
629         if (!ok)
630                 goto failure;
631
632         if (parse_sysinfo_result(result, &srv_status, &srv_domain,
633                                                         &sim_state) == FALSE)
634                 goto failure;
635
636         DBG("%d -> %d", data->sim_state, sim_state);
637
638         data->sim_state = sim_state;
639
640         /* Valid service status and at minimum PS domain */
641         if (srv_status > 0 && srv_domain > 1) {
642                 CALLBACK_WITH_SUCCESS(cb, data->online_cbd->data);
643                 goto done;
644         }
645
646         switch (sim_state) {
647         case SIM_STATE_VALID:
648         case SIM_STATE_INVALID_CS:
649         case SIM_STATE_INVALID_PS:
650         case SIM_STATE_INVALID_PS_AND_CS:
651         case SIM_STATE_ROMSIM:
652                 CALLBACK_WITH_SUCCESS(cb, data->online_cbd->data);
653                 goto done;
654         }
655
656         data->sysinfo_poll_count++;
657
658         if (data->sysinfo_poll_count > 15)
659                 goto failure;
660
661         data->sysinfo_poll_source = g_timeout_add_seconds(2,
662                                                 sysinfo_online_check, data);
663         return;
664
665 failure:
666         CALLBACK_WITH_FAILURE(cb, data->online_cbd->data);
667
668 done:
669         g_free(data->online_cbd);
670         data->online_cbd = NULL;
671 }
672
673 static gboolean sysinfo_online_check(gpointer user_data)
674 {
675         struct huawei_data *data = user_data;
676
677         data->sysinfo_poll_source = 0;
678
679         g_at_chat_send(data->pcui, "AT^SYSINFO", sysinfo_prefix,
680                                         sysinfo_online_cb, data, NULL);
681
682         return FALSE;
683 }
684
685 static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
686 {
687         struct ofono_modem *modem = user_data;
688         struct huawei_data *data = ofono_modem_get_data(modem);
689
690         if (!ok) {
691                 ofono_modem_online_cb_t cb = data->online_cbd->cb;
692
693                 CALLBACK_WITH_FAILURE(cb, data->online_cbd->data);
694
695                 g_free(data->online_cbd);
696                 data->online_cbd = NULL;
697                 return;
698         }
699
700         data->sysinfo_poll_count = 0;
701
702         sysinfo_online_check(data);
703 }
704
705 static void set_offline_cb(gboolean ok, GAtResult *result, gpointer user_data)
706 {
707         struct cb_data *cbd = user_data;
708         ofono_modem_online_cb_t cb = cbd->cb;
709         struct ofono_error error;
710
711         decode_at_error(&error, g_at_result_final_response(result));
712         cb(&error, cbd->data);
713 }
714
715 static void huawei_set_online(struct ofono_modem *modem, ofono_bool_t online,
716                                 ofono_modem_online_cb_t cb, void *user_data)
717 {
718         struct huawei_data *data = ofono_modem_get_data(modem);
719
720         DBG("modem %p %s", modem, online ? "online" : "offline");
721
722         if (online == TRUE) {
723                 data->online_cbd = cb_data_new(cb, user_data);
724
725                 if (g_at_chat_send(data->pcui, "AT+CFUN=1", none_prefix,
726                                         set_online_cb, modem, NULL) > 0)
727                         return;
728
729                 g_free(data->online_cbd);
730                 data->online_cbd = NULL;
731         } else {
732                 struct cb_data *cbd = cb_data_new(cb, user_data);
733
734                 if (g_at_chat_send(data->pcui, data->offline_command,
735                                 none_prefix, set_offline_cb, cbd, g_free) > 0)
736                         return;
737
738                 g_free(cbd);
739         }
740
741         CALLBACK_WITH_FAILURE(cb, user_data);
742 }
743
744 static void huawei_pre_sim(struct ofono_modem *modem)
745 {
746         struct huawei_data *data = ofono_modem_get_data(modem);
747
748         DBG("%p", modem);
749
750         if (data->have_gsm == TRUE) {
751                 struct ofono_sim *sim;
752
753                 ofono_devinfo_create(modem, 0, "atmodem", data->pcui);
754                 sim = ofono_sim_create(modem, OFONO_VENDOR_HUAWEI,
755                                                 "atmodem", data->pcui);
756
757                 if (sim && data->have_sim == TRUE)
758                         ofono_sim_inserted_notify(sim, TRUE);
759         } else if (data->have_cdma == TRUE) {
760                 ofono_devinfo_create(modem, 0, "cdmamodem", data->pcui);
761         }
762 }
763
764 static void huawei_post_sim(struct ofono_modem *modem)
765 {
766         struct huawei_data *data = ofono_modem_get_data(modem);
767
768         DBG("%p", modem);
769
770         if (data->have_voice == TRUE) {
771                 ofono_voicecall_create(modem, 0, "huaweimodem", data->pcui);
772                 ofono_audio_settings_create(modem, 0,
773                                                 "huaweimodem", data->pcui);
774         }
775
776         if (data->have_gsm == TRUE) {
777                 struct ofono_gprs *gprs;
778                 struct ofono_gprs_context *gc;
779
780                 ofono_phonebook_create(modem, 0, "atmodem", data->pcui);
781                 ofono_radio_settings_create(modem, 0,
782                                                 "huaweimodem", data->pcui);
783
784                 ofono_sms_create(modem, OFONO_VENDOR_HUAWEI,
785                                                 "atmodem", data->pcui);
786
787                 gprs = ofono_gprs_create(modem, OFONO_VENDOR_HUAWEI,
788                                                 "atmodem", data->pcui);
789                 gc = ofono_gprs_context_create(modem, 0,
790                                                 "atmodem", data->modem);
791
792                 if (gprs && gc)
793                         ofono_gprs_add_context(gprs, gc);
794         }
795 }
796
797 static void huawei_post_online(struct ofono_modem *modem)
798 {
799         struct huawei_data *data = ofono_modem_get_data(modem);
800
801         DBG("%p", modem);
802
803         if (data->have_gsm == TRUE) {
804                 ofono_netreg_create(modem, OFONO_VENDOR_HUAWEI,
805                                                 "atmodem", data->pcui);
806
807                 ofono_cbs_create(modem, OFONO_VENDOR_QUALCOMM_MSM,
808                                                 "atmodem", data->pcui);
809                 ofono_ussd_create(modem, OFONO_VENDOR_QUALCOMM_MSM,
810                                                 "atmodem", data->pcui);
811         } else if (data->have_cdma == TRUE) {
812                 ofono_cdma_netreg_create(modem, 0, "huaweimodem", data->pcui);
813
814                 ofono_cdma_connman_create(modem, OFONO_VENDOR_HUAWEI,
815                                                 "cdmamodem", data->modem);
816         }
817
818         if (data->have_voice == TRUE) {
819                 struct ofono_message_waiting *mw;
820
821                 ofono_call_forwarding_create(modem, 0, "atmodem", data->pcui);
822                 ofono_call_settings_create(modem, 0, "atmodem", data->pcui);
823                 ofono_call_barring_create(modem, 0, "atmodem", data->pcui);
824
825                 mw = ofono_message_waiting_create(modem);
826                 if (mw)
827                         ofono_message_waiting_register(mw);
828         }
829 }
830
831 static struct ofono_modem_driver huawei_driver = {
832         .name           = "huawei",
833         .probe          = huawei_probe,
834         .remove         = huawei_remove,
835         .enable         = huawei_enable,
836         .disable        = huawei_disable,
837         .set_online     = huawei_set_online,
838         .pre_sim        = huawei_pre_sim,
839         .post_sim       = huawei_post_sim,
840         .post_online    = huawei_post_online,
841 };
842
843 static int huawei_init(void)
844 {
845         return ofono_modem_driver_register(&huawei_driver);
846 }
847
848 static void huawei_exit(void)
849 {
850         ofono_modem_driver_unregister(&huawei_driver);
851 }
852
853 OFONO_PLUGIN_DEFINE(huawei, "HUAWEI Mobile modem driver", VERSION,
854                 OFONO_PLUGIN_PRIORITY_DEFAULT, huawei_init, huawei_exit)