s_sim: add support of "AT+XPINCNT=<n>"
[platform/core/telephony/tel-plugin-imc.git] / src / s_modem.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Harish Bishnoi <hbishnoi@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <glib.h>
27
28 #include <tcore.h>
29 #include <hal.h>
30 #include <core_object.h>
31 #include <plugin.h>
32 #include <user_request.h>
33 #include <queue.h>
34 #include <co_modem.h>
35 #include <storage.h>
36 #include <server.h>
37 #include <at.h>
38 #include <mux.h>
39
40 #include "s_common.h"
41 #include "s_modem.h"
42
43
44 #define ID_RESERVED_AT 0x0229
45
46 #define MAX_VERSION_LEN 32
47 #define TAPI_MISC_ME_SN_LEN_MAX             32
48 #define TAPI_MISC_PRODUCT_CODE_LEN_MAX      32
49 #define TAPI_MISC_MODEL_ID_LEN_MAX          17
50 #define TAPI_MISC_PRL_ERI_VER_LEN_MAX       17
51
52 #define CPAS_RES_READY          0
53 #define CPAS_RES_UNAVAIL            1
54 #define CPAS_RES_UNKNOWN            2
55 #define CPAS_RES_RINGING            3
56 #define CPAS_RES_CALL_PROGRESS  4
57 #define CPAS_RES_ASLEEP           5
58 #define AT_VER_LEN 20
59
60
61 enum cp_state {
62         CP_STATE_OFFLINE,
63         CP_STATE_CRASH_RESET,
64         CP_STATE_CRASH_EXIT,
65         CP_STATE_BOOTING,
66         CP_STATE_ONLINE,
67         CP_STATE_NV_REBUILDING,
68         CP_STATE_LOADER_DONE,
69 };
70
71 typedef enum {
72         TAPI_MISC_ME_IMEI = 0x00, /**< 0x00: IMEI, GSM/UMTS device */
73         TAPI_MISC_ME_ESN = 0x01, /**< 0x01: ESN(Electronic Serial Number), It`s essentially run out. CDMA device */
74         TAPI_MISC_ME_MEID = 0x02, /**< 0x02: MEID, This value can have hexa decimal digits. CDMA device */
75         TAPI_MISC_ME_MAX = 0xff /**< 0xff: reserved */
76 } TelMiscSNIndexType_t;
77
78 typedef struct {
79         TelMiscSNIndexType_t sn_index; /**< serial number index */
80         int sn_len; /**< Length */
81         unsigned char szNumber[TAPI_MISC_ME_SN_LEN_MAX]; /**< Number */
82 } TelMiscSNInformation;
83
84 /**
85  * Mobile Equipment Version Information
86  */
87 typedef struct {
88         unsigned char ver_mask; /**< version mask  - 0x01:SW_ver, 0x02:HW_ver, 0x04:RF_CAL_date, 0x08:Product_code, 0x10:Model_ID, 0x20:PRL, 0x04:ERI, 0xff:all */
89         unsigned char szSwVersion[MAX_VERSION_LEN]; /**< Software version, null termination */
90         unsigned char szHwVersion[MAX_VERSION_LEN]; /**< Hardware version, null termination */
91         unsigned char szRfCalDate[MAX_VERSION_LEN]; /**< Calculation Date, null termination */
92         unsigned char szProductCode[TAPI_MISC_PRODUCT_CODE_LEN_MAX]; /**< product code, null termination */
93         unsigned char szModelId[TAPI_MISC_MODEL_ID_LEN_MAX]; /**< model id (only for CDMA), null termination */
94         unsigned char prl_nam_num; /**< number of PRL NAM fields */
95         unsigned char szPrlVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< prl version (only for CDMA), null termination */
96         unsigned char eri_nam_num; /**< number of PRL NAM fields */
97         unsigned char szEriVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< eri version (only for CDMA), null termination */
98 } TelMiscVersionInformation;
99
100
101 static void prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback);
102 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data);
103 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data);
104 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data);
105
106 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
107 {
108         dbg("on_confirmation_modem_message_send - msg out from queue.\n");
109
110         if (result == FALSE) {
111                 /* Fail */
112                 dbg("SEND FAIL");
113         } else {
114                 dbg("SEND OK");
115         }
116 }
117
118 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data)
119 {
120         const TcoreATResponse *resp = data;
121
122         if (resp->success > 0) {
123                 dbg("RESPONSE OK proactive command enabled");
124         } else {
125                 dbg("RESPONSE NOK proactive command disabled");
126         }
127 }
128
129 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data)
130 {
131         const TcoreATResponse *resp = data;
132
133         if (resp->success > 0) {
134                 dbg("registration attempt OK");
135         } else {
136                 dbg("registration attempt failed");
137         }
138 }
139
140 void prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback)
141 {
142         TcoreATRequest *req = NULL;
143         TcoreHal *hal = NULL;
144         TcorePending *pending = NULL;
145         TReturn ret;
146
147         hal = tcore_object_get_hal(co);
148         dbg("hal: %p", hal);
149
150         pending = tcore_pending_new(co, 0);
151         if (!pending)
152                 dbg("Pending is NULL");
153         req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
154
155         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
156
157         tcore_pending_set_request_data(pending, 0, req);
158         tcore_pending_set_response_callback(pending, callback, NULL);
159         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
160         ret = tcore_hal_send_request(hal, pending);
161 }
162
163 static void on_response_power_off(TcorePending *p, int data_len, const void *data, void *user_data)
164 {
165         CoreObject *o = 0;
166         TcoreHal *h = 0;
167
168         o = tcore_pending_ref_core_object(p);
169         h = tcore_object_get_hal(o);
170
171         dbg("modem power off");
172
173         tcore_hal_set_power_state(h, FALSE);
174 }
175
176 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
177 {
178         CoreObject *o = NULL;
179         UserRequest *ur = NULL;
180         const TcoreATResponse *ATresp = data;
181         GSList *tokens = NULL;
182         const char *line = NULL;
183         struct tresp_modem_set_flightmode res = {0};
184         int response = 0;
185         struct tnoti_modem_flight_mode modem_flight_mode = {0};
186         const struct treq_modem_set_flightmode *req_data = NULL;
187
188         o = tcore_pending_ref_core_object(p);
189
190         if (ATresp->success > 0) {
191                 dbg("RESPONSE OK - flight mode operation finished");
192                 res.result = TCORE_RETURN_SUCCESS;
193         } else {
194                 dbg("RESPONSE NOK");
195                 line = (const char *) ATresp->final_response;
196                 tokens = tcore_at_tok_new(line);
197
198                 if (g_slist_length(tokens) < 1) {
199                         dbg("err cause not specified or string corrupted");
200                         res.result = TCORE_RETURN_3GPP_ERROR;
201                 } else {
202                         response = atoi(g_slist_nth_data(tokens, 0));
203                         /* TODO: CMEE error mapping is required. */
204                         res.result = TCORE_RETURN_3GPP_ERROR;
205                 }
206         }
207
208         ur = tcore_pending_ref_user_request(p);
209         if (NULL == ur) {
210                 dbg("No user request. Internal request created during boot-up sequence");
211
212                 if (ATresp->success > 0) {
213                         modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
214                         dbg("sucess case - Sending Flight Mode Notification (%d) to Telephony Server", modem_flight_mode.enable);
215
216                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
217                                                                                    sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
218                 }
219         } else {
220                 dbg("Sending response for Flight mode operation");
221
222                 req_data = tcore_user_request_ref_data(ur, NULL);
223
224                 if (TCORE_RETURN_SUCCESS == res.result) {
225                         if (TRUE == req_data->enable)
226                                 res.result = 1;
227                         else
228                                 res.result = 2;
229                 } else {
230                         res.result = 3;
231                 }
232
233                 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
234
235                 if (req_data->enable == 0) {
236                         dbg("Flight mode is disabled, trigger COPS to register on network");
237                         /* Trigger Network registration (for the moment automatic) */
238                         prepare_and_send_pending_request(o, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
239                 }
240         }
241
242         tcore_at_tok_free(tokens);
243 }
244
245 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
246 {
247         const TcoreATResponse *resp = data;
248         TcorePlugin *plugin = NULL;
249         struct tresp_modem_get_imei res;
250         TelMiscSNInformation *imei_property = NULL;
251         UserRequest *ur = NULL;
252         GSList *tokens = NULL;
253         const char *line;
254         int response = 0;
255
256         memset(&res, 0, sizeof(struct tresp_modem_get_imei));
257
258         if (resp->success > 0) {
259                 dbg("RESPONSE OK");
260                 if (resp->lines) {
261                         line = (const char *) resp->lines->data;
262                         tokens = tcore_at_tok_new(line);
263                         if (g_slist_length(tokens) != 1) {
264                                 msg("invalid message");
265                                 goto OUT;
266                         }
267                 }
268                 res.result = TCORE_RETURN_SUCCESS;
269                 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
270
271                 dbg("imei = [%s]", res.imei);
272
273                 plugin = tcore_pending_ref_plugin(p);
274                 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
275                 if (imei_property) {
276                         imei_property->sn_index = TAPI_MISC_ME_IMEI;
277                         imei_property->sn_len = strlen(res.imei);
278                         memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
279                 }
280         } else {
281                 dbg("RESPONSE NOK");
282                 if (resp->lines) {
283                         line = (const char *) resp->lines->data;
284                         tokens = tcore_at_tok_new(line);
285                 }
286
287
288                 if (g_slist_length(tokens) < 1) {
289                         dbg("err cause not specified or string corrupted");
290                         res.result = TCORE_RETURN_3GPP_ERROR;
291                 } else {
292                         response = atoi(g_slist_nth_data(tokens, 0));
293                         /* TODO: CMEE error mapping is required. */
294                         res.result = TCORE_RETURN_3GPP_ERROR;
295                 }
296         }
297
298         ur = tcore_pending_ref_user_request(p);
299         tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI, sizeof(struct tresp_modem_get_imei), &res);
300
301 OUT:
302         if (tokens != NULL)
303                 tcore_at_tok_free(tokens);
304
305         return;
306 }
307
308 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
309 {
310         const TcoreATResponse *resp = data;
311         TcorePlugin *plugin = NULL;
312         struct tresp_modem_get_version res = {0};
313         TelMiscVersionInformation *vi_property = NULL;
314         TelMiscVersionInformation *vi = NULL;
315         UserRequest *ur = NULL;
316         GSList *tokens = NULL;
317         const char *line = NULL;
318         char *swver = NULL;
319         char *hwver = NULL;
320         char *caldate = NULL;
321         char *pcode = NULL;
322         char *id = NULL;
323
324         int response = 0;
325
326         if (resp->success > 0) {
327                 dbg("RESPONSE OK");
328                 if (resp->lines) {
329                         line = (const char *) resp->lines->data;
330                         tokens = tcore_at_tok_new(line);
331                         if (g_slist_length(tokens) == 1) {
332                                 swver = g_slist_nth_data(tokens, 0);
333                                 dbg("version: sw=[%s]", swver);
334                         } else if (g_slist_length(tokens) == 5) {
335                                 swver = g_slist_nth_data(tokens, 0);
336                                 hwver = g_slist_nth_data(tokens, 1);
337                                 caldate = g_slist_nth_data(tokens, 2);
338                                 pcode = g_slist_nth_data(tokens, 3);
339                                 id = g_slist_nth_data(tokens, 4);
340
341                                 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]", swver, hwver, caldate, pcode, id);
342                         } else {
343                                 msg("invalid message");
344                                 goto OUT;
345                         }
346                 }
347
348                 vi = calloc(sizeof(TelMiscVersionInformation), 1);
349                 if (NULL != swver)
350                         memcpy(vi->szSwVersion, swver, strlen(swver));
351                 if (NULL != hwver)
352                         memcpy(vi->szHwVersion, hwver, strlen(hwver));
353                 if (NULL != caldate)
354                         memcpy(vi->szRfCalDate, caldate, strlen(caldate));
355                 if (NULL != pcode)
356                         memcpy(vi->szProductCode, pcode, strlen(pcode));
357                 if (NULL != id)
358                         memcpy(vi->szModelId, id, strlen(id));
359
360                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
361
362                 if (NULL != swver)
363                         snprintf(res.software, (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN), "%s", swver);
364                 if (NULL != hwver)
365                         snprintf(res.hardware, (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN), "%s", hwver);
366
367                 plugin = tcore_pending_ref_plugin(p);
368                 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
369                 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
370                 free(vi);
371         } else {
372                 dbg("RESPONSE NOK");
373                 if (resp->lines) {
374                         line = (const char *) resp->lines->data;
375                         tokens = tcore_at_tok_new(line);
376                 }
377
378                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
379
380
381                 if (g_slist_length(tokens) < 1) {
382                         dbg("err cause not specified or string corrupted");
383                         res.result = TCORE_RETURN_3GPP_ERROR;
384                 } else {
385                         response = atoi(g_slist_nth_data(tokens, 0));
386                         /* TODO: CMEE error mapping is required. */
387                         res.result = TCORE_RETURN_3GPP_ERROR;
388                 }
389         }
390
391         ur = tcore_pending_ref_user_request(p);
392         tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION, sizeof(struct tresp_modem_get_version), &res);
393
394 OUT:
395         if (tokens != NULL)
396                 tcore_at_tok_free(tokens);
397
398         return;
399 }
400
401 static enum tcore_hook_return on_hook_sim_status(Server *s, CoreObject *source, enum tcore_notification_command command,
402                                                                                            unsigned int data_len, void *data, void *user_data)
403 {
404         const struct tnoti_sim_status *sim = data;
405         CoreObject *co_sat;
406         CoreObject *co_network;
407         TcorePlugin *plugin = tcore_object_ref_plugin(source);
408
409         co_sat = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAT);
410         co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK);
411
412         if (sim->sim_status == SIM_STATUS_INIT_COMPLETED) {
413                 dbg("SIM ready for attach");
414                 dbg("Enable STK and Fetching of proactive Commands");
415                 prepare_and_send_pending_request(co_sat, "AT+CFUN=6", NULL, TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
416                 prepare_and_send_pending_request(co_network, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, on_response_network_registration);
417         }
418
419         return TCORE_HOOK_RETURN_CONTINUE;
420 }
421
422 gboolean modem_power_on(TcorePlugin *p)
423 {
424         CoreObject *co_modem = NULL;
425         struct treq_modem_set_flightmode flight_mode_set = {0};
426         struct tnoti_modem_power modem_power = {0};
427         TcoreHal *h = NULL;
428         Storage *strg = NULL;
429
430         co_modem = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_MODEM);
431
432         strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf");
433         flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
434
435         h = tcore_object_get_hal(co_modem);
436         tcore_hal_set_power_state(h, TRUE);
437
438         /* Set Flight mode as per AP settings */
439         if (flight_mode_set.enable) { /* Radio Off */
440                 prepare_and_send_pending_request(co_modem, "AT+CFUN=4", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
441                 tcore_modem_set_flight_mode_state(co_modem, TRUE);
442         } else { /* Radio On */
443                 prepare_and_send_pending_request(co_modem, "AT+CFUN=1", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
444                 tcore_modem_set_flight_mode_state(co_modem, FALSE);
445         }
446
447         /* Get IMEI */
448         prepare_and_send_pending_request(co_modem, "AT+CGSN", NULL, TCORE_AT_NUMERIC, on_response_imei);
449
450         /* Get Version Number  */
451         prepare_and_send_pending_request(co_modem, "AT+CGMR", NULL, TCORE_AT_SINGLELINE, on_response_version);
452
453         tcore_modem_set_powered(co_modem, TRUE);
454
455         modem_power.state = MODEM_STATE_ONLINE;
456
457         tcore_server_send_notification(tcore_plugin_ref_server(p), co_modem, TNOTI_MODEM_POWER,
458                                                                    sizeof(struct tnoti_modem_power), &modem_power);
459
460         return TRUE;
461 }
462
463 static TReturn power_off(CoreObject *o, UserRequest *ur)
464 {
465         TcoreHal *hal = NULL;
466         TcoreATRequest *req = NULL;
467         TcorePending *pending = NULL;
468
469         hal = tcore_object_get_hal(o);
470         pending = tcore_pending_new(o, 0);
471
472         req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
473
474         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
475
476         tcore_pending_set_request_data(pending, 0, req);
477         tcore_pending_set_response_callback(pending, on_response_power_off, hal);
478         tcore_pending_link_user_request(pending, ur);
479         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
480
481         tcore_hal_send_request(hal, pending);
482
483         return TCORE_RETURN_SUCCESS;
484 }
485
486 static TReturn get_imei(CoreObject *o, UserRequest *ur)
487 {
488         TcoreHal *hal;
489         TcoreATRequest *req;
490         TcorePending *pending = NULL;
491
492         hal = tcore_object_get_hal(o);
493         if (FALSE == tcore_hal_get_power_state(hal)) {
494                 dbg("cp not ready/n");
495                 return TCORE_RETURN_ENOSYS;
496         }
497         pending = tcore_pending_new(o, 0);
498
499         req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
500
501         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
502
503         tcore_pending_set_request_data(pending, 0, req);
504         tcore_pending_set_response_callback(pending, on_response_imei, hal);
505         tcore_pending_link_user_request(pending, ur);
506         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
507
508         tcore_hal_send_request(hal, pending);
509
510         return TCORE_RETURN_SUCCESS;
511 }
512
513
514 static TReturn get_version(CoreObject *o, UserRequest *ur)
515 {
516         TcoreHal *hal;
517         TcoreATRequest *req;
518         TcorePending *pending = NULL;
519
520         hal = tcore_object_get_hal(o);
521         if (FALSE == tcore_hal_get_power_state(hal)) {
522                 dbg("cp not ready/n");
523                 return TCORE_RETURN_ENOSYS;
524         }
525         pending = tcore_pending_new(o, 0);
526
527         req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
528
529         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
530
531         tcore_pending_set_request_data(pending, 0, req);
532         tcore_pending_set_response_callback(pending, on_response_version, hal);
533         tcore_pending_link_user_request(pending, ur);
534         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
535
536         tcore_hal_send_request(hal, pending);
537
538         return TCORE_RETURN_SUCCESS;
539 }
540
541 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
542 {
543         TcoreHal *hal = NULL;
544         TcoreATRequest *req = NULL;
545         TcorePending *pending = NULL;
546         const struct treq_modem_set_flightmode *req_data = NULL;
547         char *cmd_str = NULL;
548
549         hal = tcore_object_get_hal(o);
550         if (FALSE == tcore_hal_get_power_state(hal)) {
551                 dbg("cp not ready/n");
552                 return TCORE_RETURN_ENOSYS;
553         }
554         pending = tcore_pending_new(o, 0);
555
556         req_data = tcore_user_request_ref_data(ur, NULL);
557
558         if (req_data->enable) {
559                 dbg("Flight mode on/n");
560                 cmd_str = g_strdup("AT+CFUN=4");
561         } else {
562                 dbg("Flight mode off/n");
563                 cmd_str = g_strdup("AT+CFUN=1");
564         }
565
566         req = tcore_at_request_new((const char *) cmd_str, NULL, TCORE_AT_NO_RESULT);
567
568         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
569
570         tcore_pending_set_request_data(pending, 0, req);
571         tcore_pending_set_response_callback(pending, on_response_set_flight_mode, hal);
572         tcore_pending_link_user_request(pending, ur);
573         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
574
575         tcore_hal_send_request(hal, pending);
576
577         return TCORE_RETURN_SUCCESS;
578 }
579
580
581 static struct tcore_modem_operations modem_ops = {
582         .power_on = NULL,
583         .power_off = power_off,
584         .power_reset = NULL,
585         .set_flight_mode = set_flight_mode,
586         .get_imei = get_imei,
587         .get_version = get_version,
588         .get_sn = NULL,
589         .dun_pin_ctrl = NULL,
590 };
591
592 gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem)
593 {
594         TelMiscVersionInformation *vi_property;
595         TelMiscSNInformation *imei_property;
596         TelMiscSNInformation *sn_property;
597
598         dbg("Enter");
599
600         tcore_modem_override_ops(co_modem, &modem_ops);
601
602         vi_property = g_try_new0(TelMiscVersionInformation, 1);
603         tcore_plugin_link_property(cp, "VERSION", vi_property);
604
605         imei_property = g_try_new0(TelMiscSNInformation, 1);
606         tcore_plugin_link_property(cp, "IMEI", imei_property);
607
608         sn_property = g_try_new0(TelMiscSNInformation, 1);
609         tcore_plugin_link_property(cp, "SN", sn_property);
610
611         tcore_server_add_notification_hook(tcore_plugin_ref_server(cp), TNOTI_SIM_STATUS, on_hook_sim_status, co_modem);
612
613         dbg("Exit");
614
615         return TRUE;
616 }
617
618 void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem)
619 {
620         TelMiscVersionInformation *vi_property;
621         TelMiscSNInformation *imei_property;
622         TelMiscSNInformation *sn_property;
623         TcorePlugin *plugin = tcore_object_ref_plugin(co_modem);
624
625         vi_property = tcore_plugin_ref_property(plugin, "VERSION");
626         g_free(vi_property);
627
628         imei_property = tcore_plugin_ref_property(plugin, "IMEI");
629         g_free(imei_property);
630
631         sn_property = tcore_plugin_ref_property(plugin, "SN");
632         g_free(sn_property);
633
634         dbg("Exit");
635 }