4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Junhwan An <jh48.an@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
34 #include <user_request.h>
36 #include <core_object.h>
40 #define SERVER_INIT_WAIT_TIMEOUT 500
42 #define DEVICE_NAME_LEN_MAX 16
43 #define DEVICE_NAME_PREFIX "pdp"
45 #define BUF_LEN_MAX 512
47 #define CORE_OBJECT_NAME_MAX 16
49 #define MODEM_PLUGIN_NAME "atmodem-plugin.so"
51 #define BIT_SIZE(type) (sizeof(type) * 8)
53 #define COPY_MASK(type) ((0xffffffff) >> (32 - BIT_SIZE(type)))
55 #define MASK(width, offset, data) \
56 (((width) == BIT_SIZE(data)) ? (data) : \
57 ((((COPY_MASK(data) << (BIT_SIZE(data) - ((width) % BIT_SIZE(data)))) & COPY_MASK(data)) >> (offset)) & (data))) \
60 #define MASK_AND_SHIFT(width, offset, shift, data) \
61 ((((signed) (shift)) < 0) ? \
62 MASK((width), (offset), (data)) << -(shift) : \
63 MASK((width), (offset), (data)) >> (((signed) (shift)))) \
67 guint watch_id_vdpram;
77 char co_name[CORE_OBJECT_NAME_MAX];
80 static char __util_unpackb(const char *src, int pos, int len)
88 rshift = MAX(8 - (pos + len), 0);
91 result = MASK_AND_SHIFT(len, pos, rshift, (unsigned char)*src);
93 result = MASK(8 - pos, pos, (unsigned char)*src);
97 if (len > 0) result = (result << len) | (*src >> (8 - len)); /* if any bits left */
103 static char __util_convert_byte_hexchar(char val)
108 hex_char = (char) (val + '0');
109 else if (val >= 10 && val <= 15)
110 hex_char = (char) (val - 10 + 'A');
117 static gboolean __util_byte_to_hex(const char *byte_pdu, char *hex_pdu, int num_bytes)
123 for (i = 0; i < num_bytes * 2; i++) {
124 nibble = __util_unpackb(byte_pdu, buf_pos, 4);
126 hex_pdu[i] = __util_convert_byte_hexchar(nibble);
132 static TcoreModem *__get_modem(TcorePlugin *modem_iface_plugin)
134 PluginData *user_data;
136 if (modem_iface_plugin == NULL)
139 user_data = tcore_plugin_ref_user_data(modem_iface_plugin);
140 if (user_data == NULL)
143 /* 'modem' corresponding to Modem Interface plug-in */
144 return user_data->modem;
147 static guint __vmodem_reencode_mt_sms(gchar *mt_sms, guint mt_sms_len)
149 #define VMODEM_CR 0x0D
150 #define VMODEM_LF 0x0A
151 #define VMODEM_COLON 0x3A
153 gchar sms_buf[BUF_LEN_MAX] = {0, };
154 guint sca_len, pdu_len, tpdu_len;
155 gushort tpdu_len_ptr = 0;
156 gchar tpdu_len_str[8] = {0};
157 guint i, local_index = 0;
159 if (mt_sms_len > (BUF_LEN_MAX - 2))
160 mt_sms_len = BUF_LEN_MAX - 2;
162 for (i = 0; i < mt_sms_len; i++) {
163 if ((mt_sms[i] == VMODEM_CR)
164 && (mt_sms[i+1] == VMODEM_LF)) {
165 sms_buf[i] = mt_sms[i];
167 sms_buf[i] = mt_sms[i];
170 } else if (mt_sms[i] == VMODEM_COLON) {
171 tpdu_len_ptr = i + 1;
175 sms_buf[i] = mt_sms[i];
178 dbg("SCA length: [%d] TPDU length offset: [%d]", sca_len, tpdu_len_ptr);
180 pdu_len = (mt_sms_len-i);
181 tpdu_len = pdu_len - (sca_len+1);
182 dbg("PDU length: [%d] Actual TPDU Length: [%d]", pdu_len, tpdu_len);
184 if (pdu_len >= 100 && tpdu_len < 100) {
186 * Move back complete buffer by a Byte (to fill up the
187 * void created by hundreds place).
190 sms_buf[i-3] = VMODEM_CR;
191 sms_buf[i-2] = VMODEM_LF;
193 __util_byte_to_hex(&mt_sms[i], &sms_buf[i - 1], pdu_len);
194 i += (2*pdu_len - 1);
197 __util_byte_to_hex(&mt_sms[i], &sms_buf[i], pdu_len);
201 /* Update actual TPDU length */
202 snprintf(tpdu_len_str, 8, "%d", tpdu_len);
203 switch (strlen(tpdu_len_str)) {
204 case 4: /* 100s place */
205 dbg("1000s : [%d]", tpdu_len_str[local_index]);
207 sms_buf[tpdu_len_ptr] = tpdu_len_str[local_index];
211 case 3: /* 100s place */
212 dbg("100s : [%d]", tpdu_len_str[local_index]);
214 sms_buf[tpdu_len_ptr] = tpdu_len_str[local_index];
218 case 2: /* 10s place */
219 dbg("10s : [%d]", tpdu_len_str[local_index]);
221 sms_buf[tpdu_len_ptr] = tpdu_len_str[local_index];
225 case 1: /* 1s place */
226 dbg("1s : [%d]", tpdu_len_str[local_index]);
228 sms_buf[tpdu_len_ptr] = tpdu_len_str[local_index];
232 dbg("Unsupported length: [%d]", strlen(tpdu_len_str));
237 * Greater than (BUF_LEN_MAX - 2),
238 * restrict the length to ( BUF_LEN_MAX - 2).
240 * This is to accomadate <CR> & <LF>.
242 if (i > (BUF_LEN_MAX - 2))
245 /* Append <CR> & <LF> */
246 sms_buf[i++] = VMODEM_CR;
247 sms_buf[i++] = VMODEM_LF;
248 dbg("MT SMS: [%s]", sms_buf);
250 tcore_util_hex_dump(" ", (int)i, sms_buf);
255 * 'data_len' is not accessed hence it need not be updated.
257 g_strlcpy(mt_sms, sms_buf, i+1);
258 dbg("Encoded MT SMS: [%d][%s]", i, mt_sms);
263 static guint __register_gio_watch(TcoreHal *h, int fd, void *callback)
265 GIOChannel *channel = NULL;
268 dbg("Register to Watch list - fd: [%d]", fd);
270 if ((fd < 0) || (callback == NULL))
273 channel = g_io_channel_unix_new(fd);
274 source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
275 g_io_channel_unref(channel);
281 static void __deregister_gio_watch(guint watch_id)
283 dbg("Deregister Watch ID: [%d]", watch_id);
286 g_source_remove(watch_id);
289 static gboolean __load_modem_plugin(gpointer data)
293 struct custom_data *user_data;
295 unsigned int slot_count = 1;
305 plugin = tcore_hal_ref_plugin(hal);
306 modem = __get_modem(plugin);
308 /* Load Modem Plug-in */
309 if (tcore_server_load_modem_plugin(tcore_plugin_ref_server(plugin),
310 modem, MODEM_PLUGIN_NAME) == TCORE_RETURN_FAILURE) {
311 err("Load Modem Plug-in - [FAIL]");
315 dbg("Load Modem Plug-in - [SUCCESS]");
318 tcore_server_send_notification(tcore_plugin_ref_server(plugin),
319 NULL, TNOTI_SERVER_ADDED_MODEM_PLUGIN_COMPLETED,
320 sizeof(slot_count), &slot_count);
322 /* To stop the cycle need to return FALSE */
326 user_data = tcore_hal_ref_user_data(hal);
327 if (user_data == NULL)
330 /* Deregister from Watch list */
331 __deregister_gio_watch(user_data->watch_id_vdpram);
336 /* Close VDPRAM device */
337 vdpram_close(user_data->vdpram_fd);
339 /* Free custom data */
345 static TReturn _modem_power(TcoreHal *hal, gboolean enable)
347 struct custom_data *user_data;
349 user_data = tcore_hal_ref_user_data(hal);
350 if (user_data == NULL) {
351 err(" User data is NULL");
352 return TCORE_RETURN_FAILURE;
355 if (enable == TRUE) { /* POWER ON */
356 if (FALSE == vdpram_poweron(user_data->vdpram_fd)) {
357 err(" Power ON - [FAIL]");
358 return TCORE_RETURN_FAILURE;
361 /* Set Power State - ON */
362 tcore_hal_set_power_state(hal, TRUE);
363 } else { /* POWER OFF */
364 if (vdpram_poweroff(user_data->vdpram_fd) == FALSE) {
365 err(" Power OFF - [FAIL]");
366 return TCORE_RETURN_FAILURE;
369 /* Set Power state - OFF */
370 tcore_hal_set_power_state(hal, FALSE);
373 return TCORE_RETURN_SUCCESS;
376 static gboolean on_recv_vdpram_message(GIOChannel *channel,
377 GIOCondition condition, gpointer data)
379 TcoreHal *hal = data;
380 struct custom_data *custom;
381 char buf[BUF_LEN_MAX];
385 custom = tcore_hal_ref_user_data(hal);
386 memset(buf, 0x0, BUF_LEN_MAX);
388 /* Read from Device */
389 n = vdpram_tty_read(custom->vdpram_fd, buf, BUF_LEN_MAX);
391 err(" Read error - Data received: [%d]", n);
394 dbg(" DPRAM Receive - Data length: [%d]", n);
396 msg("\n---------- [RECV] Length of received data: [%d] ----------\n", n);
398 /* Emit receive callback */
399 tcore_hal_emit_recv_callback(hal, n, buf);
402 * This is to ensure that the received MT SMS (+CMT:) is
403 * encoded according to 3GPP standard
405 if (buf[0] == 0x2B && buf[1] == 0x43 && buf[2] == 0x4D
406 && buf[3] == 0x54 && buf[4] == 0x3A) {
407 dbg("Received - [MT SMS]");
408 n = __vmodem_reencode_mt_sms((gchar *)buf, n);
409 } else if (buf[0] == 0x25) {
410 dbg("Replaced % --> +");
414 /* Dispatch received data to response handler */
415 dbg("Invoking tcore_hal_dispatch_response_data()");
416 ret = tcore_hal_dispatch_response_data(hal, 0, n, buf);
417 msg("\n---------- [RECV FINISH] Receive processing: [%d] ----------\n", ret);
422 static TReturn hal_power(TcoreHal *hal, gboolean flag)
424 return _modem_power(hal, flag);
427 static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data)
430 struct custom_data *user_data;
432 if (tcore_hal_get_power_state(hal) == FALSE) {
433 err(" HAL Power state - OFF");
434 return TCORE_RETURN_FAILURE;
437 user_data = tcore_hal_ref_user_data(hal);
438 if (user_data == NULL) {
439 err(" User data is NULL");
440 return TCORE_RETURN_FAILURE;
443 ret = vdpram_tty_write(user_data->vdpram_fd, data, data_len);
445 err(" Write failed");
446 return TCORE_RETURN_FAILURE;
448 dbg("vdpram_tty_write success ret=%d (fd=%d, len=%d)",
449 ret, user_data->vdpram_fd, data_len);
450 return TCORE_RETURN_SUCCESS;
454 static TReturn hal_setup_netif(CoreObject *co,
455 TcoreHalSetupNetifCallback func, void *user_data,
456 unsigned int cid, gboolean enable)
458 char ifname[DEVICE_NAME_LEN_MAX];
462 const char *control = NULL;
465 err(" Context ID: [%d]", cid);
466 return TCORE_RETURN_EINVAL;
469 if (enable == TRUE) {
470 dbg(" ACTIVATE - Context ID: [%d]", cid);
471 control = "/sys/class/net/svnet0/pdp/activate";
473 dbg(" DEACTIVATE - Context ID: [%d]", cid);
474 control = "/sys/class/net/svnet0/pdp/deactivate";
477 fd = open(control, O_WRONLY);
479 err(" Failed to Open interface: [%s]", control);
481 /* Invoke callback function */
483 func(co, -1, NULL, user_data);
485 return TCORE_RETURN_FAILURE;
488 /* Context ID needs to be written to the Device */
489 snprintf(buf, sizeof(buf), "%d", cid);
490 size = write(fd, buf, strlen(buf));
491 dbg(" SIZE [%d]", size);
497 snprintf(ifname, DEVICE_NAME_LEN_MAX, "%s%d", DEVICE_NAME_PREFIX, (cid - 1));
498 dbg(" Interface Name: [%s]", ifname);
500 /* Invoke callback function */
502 func(co, 0, ifname, user_data);
504 return TCORE_RETURN_SUCCESS;
508 static struct tcore_hal_operations hal_ops = {
511 .setup_netif = hal_setup_netif,
514 static gboolean on_load()
521 static gboolean on_init(TcorePlugin *plugin)
524 PluginData *user_data;
525 struct custom_data *data;
529 if (plugin == NULL) {
530 err(" PLug-in is NULL");
534 /* User Data for Modem Interface Plug-in */
535 user_data = g_try_new0(PluginData, 1);
536 if (user_data == NULL) {
537 err(" Failed to allocate memory for Plugin data");
541 /* Register to Server */
542 user_data->modem = tcore_server_register_modem(tcore_plugin_ref_server(plugin), plugin);
543 if (user_data->modem == NULL) {
544 err(" Registration Failed");
548 dbg(" Registered from Server");
551 data = g_try_new0(struct custom_data, 1);
553 err(" Failed to allocate memory for Custom data");
555 /* Unregister from Server */
556 tcore_server_unregister_modem(tcore_plugin_ref_server(plugin), user_data->modem);
558 /* Free Plugin data */
567 data->vdpram_fd = vdpram_open();
568 if (data->vdpram_fd < 0) {
569 /* Fre custom data */
572 /* Unregister from Server */
573 tcore_server_unregister_modem(tcore_plugin_ref_server(plugin), user_data->modem);
575 /* Free Plugin data */
581 * Create and initialize HAL
583 hal = tcore_hal_new(plugin, "vmodem", &hal_ops, TCORE_HAL_MODE_AT);
585 /* Close VDPRAM device */
586 vdpram_close(data->vdpram_fd);
588 /* Fre custom data */
591 /* Unregister from Server */
592 tcore_server_unregister_modem(tcore_plugin_ref_server(plugin), user_data->modem);
594 /* Fre Plugin data */
599 user_data->hal = hal;
601 /* Link custom data to HAL user data */
602 tcore_hal_link_user_data(hal, data);
604 /* Set HAL as Modem Interface Plug-in's User data */
605 tcore_plugin_link_user_data(plugin, user_data);
607 /* Register to Watch list */
608 data->watch_id_vdpram = __register_gio_watch(hal,
609 data->vdpram_fd, on_recv_vdpram_message);
610 dbg(" fd: [%d] Watch ID: [%d]",
611 data->vdpram_fd, data->watch_id_vdpram);
613 /* Power ON VDPRAM device */
614 if (_modem_power(hal, TRUE) == TCORE_RETURN_SUCCESS) {
615 dbg(" Power ON - [SUCCESS]");
617 err(" Power ON - [FAIL]");
621 /* Check CP Power ON */
622 g_timeout_add_full(G_PRIORITY_HIGH, SERVER_INIT_WAIT_TIMEOUT, __load_modem_plugin, hal, 0);
624 dbg("[VMMODEM] Exit");
628 /* Deregister from Watch list */
629 __deregister_gio_watch(data->watch_id_vdpram);
634 /* Close VDPRAM device */
635 vdpram_close(data->vdpram_fd);
637 /* Free custom data */
640 /* Unregister from Server */
641 tcore_server_unregister_modem(tcore_plugin_ref_server(plugin), user_data->modem);
649 static void on_unload(TcorePlugin *plugin)
652 struct custom_data *data;
653 PluginData *user_data;
660 user_data = tcore_plugin_ref_user_data(plugin);
661 if (user_data == NULL)
664 hal = user_data->hal;
666 /* Unload Modem Plug-in */
667 #if 0 /* TODO - Open the code below */
668 tcore_server_unload_modem_plugin(tcore_plugin_ref_server(plugin), plugin);
670 data = tcore_hal_ref_user_data(hal);
674 /* Deregister from Watch list */
675 __deregister_gio_watch(data->watch_id_vdpram);
676 dbg(" Deregistered Watch ID");
682 /* Close VDPRAM device */
683 vdpram_close(data->vdpram_fd);
684 dbg(" Closed VDPRAM device");
686 /* Free custom data */
689 tcore_server_unregister_modem(tcore_plugin_ref_server(plugin), user_data->modem);
690 dbg(" Unregistered from Server");
692 dbg(" Unloaded MODEM");
696 /* VMODEM Descriptor Structure */
697 EXPORT_API struct tcore_plugin_define_desc plugin_define_desc = {
699 .priority = TCORE_PLUGIN_PRIORITY_HIGH,