48f6961fbbc5ace76dcde4bbcb3134641c795ef0
[framework/telephony/tel-plugin-imcmodem.git] / src / desc-imcmodem.c
1 /*
2  * tel-plugin-imcmodem
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Kyoungyoup Park <gynaru.park@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 <string.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include <sys/utsname.h>
28
29 #include <glib.h>
30
31 #include <tcore.h>
32 #include <server.h>
33 #include <plugin.h>
34 #include <storage.h>
35 #include <user_request.h>
36 #include <hal.h>
37
38 #include "vnet.h"
39
40 struct vnet_channel {
41         int fd;
42         guint watch_id;
43         gboolean on;
44 };
45
46 struct custom_data {
47         struct vnet_channel ipc0;
48 };
49
50 typedef gboolean(*cb_func)(GIOChannel *channel, GIOCondition condition, gpointer data);
51
52 static gboolean on_recv_ipc_message(GIOChannel *channel, GIOCondition condition, gpointer data);
53
54 static guint register_gio_watch(TcoreHal *p, int fd, void *callback);
55
56 static TReturn hal_power(TcoreHal *h, gboolean flag);
57
58 static void hex_dump(char *pad, int size, const void *data)
59 {
60         char buf[255] = {0, };
61         char hex[4] = {0, };
62         int i;
63         unsigned char *p;
64
65         if (size <= 0) {
66                 msg("%sno data", pad);
67                 return;
68         }
69
70         p = (unsigned char *)data;
71
72         snprintf(buf, 255, "%s%04X: ", pad, 0);
73         for (i = 0; i<size; i++) {
74                 snprintf(hex, 4, "%02X ", p[i]);
75                 strcat(buf, hex);
76
77                 if ((i + 1) % 8 == 0) {
78                         if ((i + 1) % 16 == 0) {
79                                 msg("%s", buf);
80                                 memset(buf, 0, 255);
81                                 snprintf(buf, 255, "%s%04X: ", pad, i + 1);
82                         }
83                         else {
84                                 strcat(buf, "  ");
85                         }
86                 }
87         }
88
89         msg("%s", buf);
90 }
91
92 static void print_dump(unsigned short data_len, void *data)
93 {
94         if(!data)
95                 return;
96
97         msg("");
98         msg("  \tlen=%d\t%s", data_len, (char *)data);
99         hex_dump("        ", data_len, data);
100
101         msg("");
102 }
103
104 static gboolean _ipc0_init( TcoreHal *h, struct vnet_channel *ch, cb_func recv_message )
105 {
106         if ( !ch->fd ) {
107                 g_source_remove( ch->watch_id );
108                 close( ch->fd );
109         }
110
111         ch->fd = vnet_ipc0_open();
112         if ( ch->fd < 0 ) {
113                 dbg("[ error ] vnet_ipc0_open()");
114                 return FALSE;
115         }
116
117         ch->watch_id = register_gio_watch(h, ch->fd, recv_message);
118
119         ch->on = TRUE;
120
121         return ch->on;
122 }
123
124 static void _ipc0_deinit( struct vnet_channel *ch )
125 {
126         g_source_remove( ch->watch_id );
127         close( ch->fd );
128
129         ch->watch_id = 0;
130         ch->fd = 0;
131         ch->on = FALSE;
132 }
133
134
135 static gboolean _silent_reset( TcoreHal *h )
136 {
137         dbg("[ error ] cp crash : strat silent reset");
138         tcore_hal_set_power_state(h, FALSE);
139
140         dbg("[ error ] do nothing.");
141 #if 0 // this is not applicable code, now silent reset is not guaranteed ( 2012, 04, 19 )
142
143         vnet_start_cp_reset();
144
145         if ( !hal_power( h, TRUE ) ) {
146                 dbg("[ check ] cp crash : silent reset done");
147                 return TRUE;
148         }
149
150 #endif
151
152         return FALSE;
153 }
154
155 static gboolean _do_exception_operation( TcoreHal *h, int fd, GIOCondition con )
156 {
157         int state = -1;
158         struct custom_data *user_data = tcore_hal_ref_user_data( h );
159
160         dbg("entrance");
161
162         switch ( con ) {
163         case G_IO_HUP: {
164                 state = vnet_get_cp_state( fd );
165                 if ( state < 0 ) {
166                         dbg("[ error ] vnet_get_cp_state()");
167                         break;
168                 }
169
170                 switch ( (enum vnet_cp_state)state ) {
171                         case VNET_CP_STATE_CRASH_EXIT: {
172                                 dbg("[ error ] cp crash : strat ramdump");
173                                 _ipc0_deinit( &user_data->ipc0 );
174                                 vnet_start_cp_ramdump();
175
176                                 state = VNET_CP_STATE_CRASH_RESET;
177
178
179                         } break;
180
181                         case VNET_CP_STATE_CRASH_RESET: {
182
183                                 _ipc0_deinit( &user_data->ipc0 );
184
185                                 if (tcore_hal_get_power_state( h ))  {
186
187                                         state = VNET_CP_STATE_CRASH_RESET;
188
189                                          if ( !_silent_reset( h ) ) {
190                                                  dbg("[ error ] _silent_reset()");
191                                                  break;
192                                          }
193                                 }
194
195                                 /*
196                                 * if current hal power state is FALSE, 'cp_reset' mean normal power off
197                                 * ( it's because of kernel concept )
198                                 */
199                                 state = VNET_CP_STATE_OFFLINE;
200
201                         } break;
202
203                         default:
204                                 dbg("useless state, state : (0x%x)", state);
205                                 return TRUE;
206                 }
207
208         } break;
209
210         case G_IO_IN:
211         case G_IO_OUT:
212         case G_IO_PRI:
213         case G_IO_ERR:
214         case G_IO_NVAL:
215                 dbg("[ error ] unknown problem, con : (0x%x)", con);
216                 break;
217
218         }
219
220         tcore_hal_emit_recv_callback(h, sizeof(int), &state);
221
222         dbg("done");
223
224         return TRUE;
225 }
226
227 static gboolean _power_on( gpointer data )
228 {
229         struct custom_data *user_data = 0;
230         TcoreHal *h = (TcoreHal*)data;
231         gboolean ret = 0;
232         static int count = 0;
233
234         user_data = tcore_hal_ref_user_data(h);
235         if (!user_data) {
236                 dbg("[ error ] tcore_hal_ref_user_data()");
237                 return TRUE;
238         }
239
240         count++;
241
242         ret = _ipc0_init( h, &user_data->ipc0, on_recv_ipc_message );
243         if ( !ret ) {
244                 dbg("[ error ] _ipc0_init()");
245
246                 if ( count > 20 ) {
247                         dbg("[ error ] _ipc0_init() timeout");
248                         return FALSE;
249                 }
250
251                 return TRUE;
252         }
253
254         tcore_hal_set_power_state(h, TRUE);
255
256         return FALSE;
257 }
258
259 static TReturn hal_power(TcoreHal *h, gboolean flag)
260 {
261         if (flag == FALSE) {
262                 /* power off not support */
263                 return TCORE_RETURN_FAILURE;
264         }
265
266         g_timeout_add_full( G_PRIORITY_HIGH, 500, _power_on, h, 0 );
267
268         return TCORE_RETURN_SUCCESS;
269 }
270
271 static TReturn hal_send(TcoreHal *h, unsigned int data_len, void *data)
272 {
273         int ret;
274         struct custom_data *user_data;
275
276         if (tcore_hal_get_power_state(h) == FALSE)
277                 return TCORE_RETURN_FAILURE;
278
279         user_data = tcore_hal_ref_user_data(h);
280         if (!user_data)
281                 return TCORE_RETURN_FAILURE;
282
283         dbg("write (fd=%d, len=%d)", user_data->ipc0.fd, data_len);
284
285         ret = write( user_data->ipc0.fd, (guchar *) data, data_len );
286         if (ret < 0)
287                 return TCORE_RETURN_FAILURE;
288
289         return TCORE_RETURN_SUCCESS;;
290 }
291
292 static struct tcore_hal_operations hops =
293 {
294         .power = hal_power,
295         .send = hal_send,
296 };
297
298 static gboolean on_recv_ipc_message(GIOChannel *channel, GIOCondition condition, gpointer data)
299 {
300         TcoreHal *h = data;
301         struct custom_data *custom;
302
303         #define BUF_LEN_MAX 4096
304         char buf[BUF_LEN_MAX];
305         int n = 0;
306
307         custom = tcore_hal_ref_user_data(h);
308
309         if ( condition != G_IO_IN ) {
310                 dbg("[ error ] svnet has a problem");
311                 return _do_exception_operation( h, custom->ipc0.fd, condition );
312         }
313
314         memset(buf, 0, BUF_LEN_MAX);
315
316         n = read(custom->ipc0.fd, (guchar *) buf, BUF_LEN_MAX);
317         if (n < 0) {
318                 err("read error. return_valute = %d", n);
319                 return TRUE;
320         }
321
322         msg("--[RECV]-------------------------");
323         dbg("recv (len = %d)", n);
324
325         tcore_hal_emit_recv_callback(h, n, buf);
326         msg("--[RECV FINISH]------------------\n");
327
328         /* Notice: Mode of any HAL is TCORE_HAL_MODE_AT as default. */
329         tcore_hal_dispatch_response_data(h, 0, n, buf);
330
331         return TRUE;
332 }
333
334 static guint register_gio_watch(TcoreHal *h, int fd, void *callback)
335 {
336         GIOChannel *channel = NULL;
337         guint source;
338
339         if (fd < 0 || !callback)
340                 return 0;
341
342         channel = g_io_channel_unix_new(fd);
343         source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, (GIOFunc) callback, h);
344         g_io_channel_unref(channel);
345         channel = NULL;
346
347         return source;
348 }
349
350 static gboolean on_load()
351 {
352         struct utsname u;
353         char *vnet_models[] = { "SMDK4410", "SMDK4212", "SLP_PQ", "SLP_PQ_LTE", "SLP_NAPLES", "REDWOOD", "TRATS", NULL };
354         int i = 0;
355
356         memset(&u, 0, sizeof(struct utsname));
357         uname(&u);
358
359         dbg("u.nodename: [%s]", u.nodename);
360
361         for (i = 0; vnet_models[i]; i++ ) {
362                 if (!g_strcmp0(u.nodename, vnet_models[i])) {
363                         return TRUE;
364                 }
365         }
366
367         /*
368          * Not supported model
369          *  - unload this plugin.
370          */
371
372         return FALSE;
373 }
374
375 static gboolean on_init(TcorePlugin *p)
376 {
377         TcoreHal *h;
378         struct custom_data *data;
379
380         if (!p)
381                 return FALSE;
382
383         dbg("i'm init!");
384
385         data = calloc(sizeof(struct custom_data), 1);
386         memset(data, 0, sizeof(struct custom_data));
387
388         
389         /*
390          * HAL init
391          */
392         h = tcore_hal_new(p, "6262", &hops, TCORE_HAL_MODE_AT);
393
394         tcore_hal_set_power_state(h, FALSE);
395         tcore_hal_link_user_data(h, data);
396
397         return TRUE;
398 }
399
400 static void on_unload(TcorePlugin *p)
401 {
402         if (!p)
403                 return;
404
405         dbg("i'm unload");
406 }
407
408 struct tcore_plugin_define_desc plugin_define_desc =
409 {
410         .name = "imcmodem",
411         .priority = TCORE_PLUGIN_PRIORITY_HIGH,
412         .version = 1,
413         .load = on_load,
414         .init = on_init,
415         .unload = on_unload
416 };