5030e002eed3659d1597fe6e2805ad2f4e2c1a62
[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         data->sim_state = SIM_STATE_NOT_EXISTENT;
558
559         /* Check for GSM capabilities */
560         g_at_chat_send(data->pcui, "ATI", gcap_prefix,
561                                         gcap_support, modem, NULL);
562
563         return -EINPROGRESS;
564 }
565
566 static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
567 {
568         struct ofono_modem *modem = user_data;
569         struct huawei_data *data = ofono_modem_get_data(modem);
570
571         DBG("");
572
573         g_at_chat_unref(data->pcui);
574         data->pcui = NULL;
575
576         if (ok)
577                 ofono_modem_set_powered(modem, FALSE);
578 }
579
580 static int huawei_disable(struct ofono_modem *modem)
581 {
582         struct huawei_data *data = ofono_modem_get_data(modem);
583
584         DBG("%p", modem);
585
586         g_at_chat_cancel_all(data->modem);
587         g_at_chat_unregister_all(data->modem);
588
589         g_at_chat_unref(data->modem);
590         data->modem = NULL;
591
592         g_at_chat_cancel_all(data->pcui);
593         g_at_chat_unregister_all(data->pcui);
594
595         /* Cleanup potential online enable polling */
596         if (data->sysinfo_poll_source > 0) {
597                 g_source_remove(data->sysinfo_poll_source);
598                 data->sysinfo_poll_source = 0;
599
600                 g_free(data->online_cbd);
601                 data->online_cbd = NULL;
602         }
603
604         g_at_chat_send(data->pcui, "AT+CFUN=0", none_prefix,
605                                         cfun_disable, modem, NULL);
606
607         return -EINPROGRESS;
608 }
609
610 static gboolean sysinfo_online_check(gpointer user_data);
611
612 static void sysinfo_online_cb(gboolean ok, GAtResult *result,
613                                                 gpointer user_data)
614 {
615         struct huawei_data *data = user_data;
616         ofono_modem_online_cb_t cb = data->online_cbd->cb;
617         int srv_status, srv_domain, sim_state;
618
619         if (!ok)
620                 goto failure;
621
622         if (parse_sysinfo_result(result, &srv_status, &srv_domain,
623                                                         &sim_state) == FALSE)
624                 goto failure;
625
626         DBG("%d -> %d", data->sim_state, sim_state);
627
628         data->sim_state = sim_state;
629
630         /* Valid service status and at minimum PS domain */
631         if (srv_status > 0 && srv_domain > 1) {
632                 CALLBACK_WITH_SUCCESS(cb, data->online_cbd->data);
633                 goto done;
634         }
635
636         switch (sim_state) {
637         case SIM_STATE_VALID:
638         case SIM_STATE_INVALID_CS:
639         case SIM_STATE_INVALID_PS:
640         case SIM_STATE_INVALID_PS_AND_CS:
641         case SIM_STATE_ROMSIM:
642                 CALLBACK_WITH_SUCCESS(cb, data->online_cbd->data);
643                 goto done;
644         }
645
646         data->sysinfo_poll_count++;
647
648         if (data->sysinfo_poll_count > 15)
649                 goto failure;
650
651         data->sysinfo_poll_source = g_timeout_add_seconds(2,
652                                                 sysinfo_online_check, data);
653         return;
654
655 failure:
656         CALLBACK_WITH_FAILURE(cb, data->online_cbd->data);
657
658 done:
659         g_free(data->online_cbd);
660         data->online_cbd = NULL;
661 }
662
663 static gboolean sysinfo_online_check(gpointer user_data)
664 {
665         struct huawei_data *data = user_data;
666
667         data->sysinfo_poll_source = 0;
668
669         g_at_chat_send(data->pcui, "AT^SYSINFO", sysinfo_prefix,
670                                         sysinfo_online_cb, data, NULL);
671
672         return FALSE;
673 }
674
675 static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
676 {
677         struct ofono_modem *modem = user_data;
678         struct huawei_data *data = ofono_modem_get_data(modem);
679
680         if (!ok) {
681                 ofono_modem_online_cb_t cb = data->online_cbd->cb;
682
683                 CALLBACK_WITH_FAILURE(cb, data->online_cbd->data);
684
685                 g_free(data->online_cbd);
686                 data->online_cbd = NULL;
687                 return;
688         }
689
690         data->sysinfo_poll_count = 0;
691
692         sysinfo_online_check(data);
693 }
694
695 static void set_offline_cb(gboolean ok, GAtResult *result, gpointer user_data)
696 {
697         struct cb_data *cbd = user_data;
698         ofono_modem_online_cb_t cb = cbd->cb;
699         struct ofono_error error;
700
701         decode_at_error(&error, g_at_result_final_response(result));
702         cb(&error, cbd->data);
703 }
704
705 static void huawei_set_online(struct ofono_modem *modem, ofono_bool_t online,
706                                 ofono_modem_online_cb_t cb, void *user_data)
707 {
708         struct huawei_data *data = ofono_modem_get_data(modem);
709
710         DBG("modem %p %s", modem, online ? "online" : "offline");
711
712         if (online == TRUE) {
713                 data->online_cbd = cb_data_new(cb, user_data);
714
715                 if (g_at_chat_send(data->pcui, "AT+CFUN=1", none_prefix,
716                                         set_online_cb, modem, NULL) > 0)
717                         return;
718
719                 g_free(data->online_cbd);
720                 data->online_cbd = NULL;
721         } else {
722                 struct cb_data *cbd = cb_data_new(cb, user_data);
723
724                 if (g_at_chat_send(data->pcui, data->offline_command,
725                                 none_prefix, set_offline_cb, cbd, g_free) > 0)
726                         return;
727
728                 g_free(cbd);
729         }
730
731         CALLBACK_WITH_FAILURE(cb, user_data);
732 }
733
734 static void huawei_pre_sim(struct ofono_modem *modem)
735 {
736         struct huawei_data *data = ofono_modem_get_data(modem);
737
738         DBG("%p", modem);
739
740         if (data->have_gsm == TRUE) {
741                 struct ofono_sim *sim;
742
743                 ofono_devinfo_create(modem, 0, "atmodem", data->pcui);
744                 sim = ofono_sim_create(modem, OFONO_VENDOR_HUAWEI,
745                                                 "atmodem", data->pcui);
746
747                 if (sim && data->have_sim == TRUE)
748                         ofono_sim_inserted_notify(sim, TRUE);
749         } else if (data->have_cdma == TRUE) {
750                 ofono_devinfo_create(modem, 0, "cdmamodem", data->pcui);
751         }
752 }
753
754 static void huawei_post_sim(struct ofono_modem *modem)
755 {
756         struct huawei_data *data = ofono_modem_get_data(modem);
757
758         DBG("%p", modem);
759
760         if (data->have_voice == TRUE) {
761                 ofono_voicecall_create(modem, 0, "huaweimodem", data->pcui);
762                 ofono_audio_settings_create(modem, 0,
763                                                 "huaweimodem", data->pcui);
764         }
765
766         if (data->have_gsm == TRUE) {
767                 struct ofono_gprs *gprs;
768                 struct ofono_gprs_context *gc;
769
770                 ofono_phonebook_create(modem, 0, "atmodem", data->pcui);
771                 ofono_radio_settings_create(modem, 0,
772                                                 "huaweimodem", data->pcui);
773
774                 ofono_sms_create(modem, OFONO_VENDOR_HUAWEI,
775                                                 "atmodem", data->pcui);
776
777                 gprs = ofono_gprs_create(modem, OFONO_VENDOR_HUAWEI,
778                                                 "atmodem", data->pcui);
779                 gc = ofono_gprs_context_create(modem, 0,
780                                                 "atmodem", data->modem);
781
782                 if (gprs && gc)
783                         ofono_gprs_add_context(gprs, gc);
784         }
785 }
786
787 static void huawei_post_online(struct ofono_modem *modem)
788 {
789         struct huawei_data *data = ofono_modem_get_data(modem);
790
791         DBG("%p", modem);
792
793         if (data->have_gsm == TRUE) {
794                 ofono_netreg_create(modem, OFONO_VENDOR_HUAWEI,
795                                                 "atmodem", data->pcui);
796
797                 ofono_cbs_create(modem, OFONO_VENDOR_QUALCOMM_MSM,
798                                                 "atmodem", data->pcui);
799                 ofono_ussd_create(modem, OFONO_VENDOR_QUALCOMM_MSM,
800                                                 "atmodem", data->pcui);
801         } else if (data->have_cdma == TRUE) {
802                 ofono_cdma_netreg_create(modem, 0, "huaweimodem", data->pcui);
803
804                 ofono_cdma_connman_create(modem, OFONO_VENDOR_HUAWEI,
805                                                 "cdmamodem", data->modem);
806         }
807
808         if (data->have_voice == TRUE) {
809                 struct ofono_message_waiting *mw;
810
811                 ofono_call_forwarding_create(modem, 0, "atmodem", data->pcui);
812                 ofono_call_settings_create(modem, 0, "atmodem", data->pcui);
813                 ofono_call_barring_create(modem, 0, "atmodem", data->pcui);
814
815                 mw = ofono_message_waiting_create(modem);
816                 if (mw)
817                         ofono_message_waiting_register(mw);
818         }
819 }
820
821 static struct ofono_modem_driver huawei_driver = {
822         .name           = "huawei",
823         .probe          = huawei_probe,
824         .remove         = huawei_remove,
825         .enable         = huawei_enable,
826         .disable        = huawei_disable,
827         .set_online     = huawei_set_online,
828         .pre_sim        = huawei_pre_sim,
829         .post_sim       = huawei_post_sim,
830         .post_online    = huawei_post_online,
831 };
832
833 static int huawei_init(void)
834 {
835         return ofono_modem_driver_register(&huawei_driver);
836 }
837
838 static void huawei_exit(void)
839 {
840         ofono_modem_driver_unregister(&huawei_driver);
841 }
842
843 OFONO_PLUGIN_DEFINE(huawei, "HUAWEI Mobile modem driver", VERSION,
844                 OFONO_PLUGIN_PRIORITY_DEFAULT, huawei_init, huawei_exit)