3 * tel-plugin-mfld-blackbay
5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
25 #include <sys/ioctl.h>
29 #include <netinet/in.h>
30 #include <linux/if_ether.h>
31 #include <linux/gsmmux.h>
39 #include <core_object.h>
42 #include <user_request.h>
48 #include "util_mfld_blackbay.h"
50 #define DEVICE_IFX "/dev/ttyIFX0"
53 #define NUM_DATA_DLC 2
54 #define BUF_LEN_MAX 512
65 gboolean rawip_enabled;
67 TcoreHal *hal[NUM_DLC];
68 TcoreHal *data_hal[NUM_DATA_DLC];
72 /* Virtual ttys for KERNEL mux */
73 static const char *dlc_nodes[NUM_DLC] =
74 { "/dev/gsmtty1", "/dev/gsmtty2",
75 "/dev/gsmtty3", "/dev/gsmtty4",
76 "/dev/gsmtty6", "/dev/gsmtty7",
79 static TReturn hal_power(TcoreHal *hal, gboolean flag);
80 static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data);
81 static TReturn hal_setup_netif(CoreObject *co, TcoreHalSetupNetifCallback func,
82 void *user_data, unsigned int cid,
85 static struct tcore_hal_operations hops = {
88 .setup_netif = hal_setup_netif,
91 static TReturn prepare_and_send_at_request(CoreObject *co, TcoreHal *hal,
93 const char *at_cmd_prefix,
94 enum tcore_at_command_type at_cmd_type,
95 TcorePendingResponseCallback resp_cb,
98 TcorePending *pending;
101 /* Create Pending Request */
102 pending = tcore_pending_new(co, 0);
103 if (pending == NULL) {
104 err("Memory failure, pending is NULL");
105 return TCORE_RETURN_ENOMEM;
108 /* Create AT-Command Request */
109 req = tcore_at_request_new(at_cmd, at_cmd_prefix, at_cmd_type);
111 err("Memory failure, request is NULL");
112 tcore_pending_free(pending);
113 return TCORE_RETURN_ENOMEM;
116 dbg("AT Command: %s, Prefix(if any):%s, AT-Command length: %d",
117 req->cmd, req->prefix, strlen(req->cmd));
119 tcore_pending_set_request_data(pending, 0, req);
120 tcore_pending_set_response_callback(pending, resp_cb, resp_cb_data);
122 return tcore_hal_send_request(hal, pending);
125 static gboolean on_recv_tty_message(GIOChannel *channel,
126 GIOCondition condition, gpointer data)
128 TcoreHal *hal = data;
129 char read_buffer[BUF_LEN_MAX];
132 if (condition & G_IO_NVAL)
135 bytes_read = channel_read(channel, read_buffer, BUF_LEN_MAX);
136 if (bytes_read == 0) {
137 err("channel_read error.");
141 dbg("bytes_read = %d", bytes_read);
142 tcore_hal_emit_recv_callback(hal, bytes_read, read_buffer);
144 tcore_hal_dispatch_response_data(hal, 0, bytes_read, read_buffer);
149 static gboolean setup_channel(GIOChannel *io)
153 if (g_io_channel_set_encoding(io, NULL, NULL) != G_IO_STATUS_NORMAL)
156 g_io_channel_set_buffered(io, FALSE);
157 io_flags = g_io_channel_get_flags(io);
158 io_flags |= (G_IO_FLAG_NONBLOCK & G_IO_FLAG_SET_MASK);
160 if (g_io_channel_set_flags(io, io_flags, NULL) != G_IO_STATUS_NORMAL)
163 g_io_channel_set_close_on_unref(io, TRUE);
168 static void set_termio(int fd)
170 struct termios newtio;
172 /* Switch TTY to raw mode */
173 memset(&newtio, 0, sizeof(newtio));
177 newtio.c_cflag |= CLOCAL;
179 tcflush(fd, TCIFLUSH);
180 tcsetattr(fd, TCSANOW, &newtio);
183 static int open_device(const char *tty)
187 fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
196 static GIOChannel *tty_open(const char *tty)
201 fd = open_device(tty);
207 channel = g_io_channel_unix_new(fd);
208 if (channel == NULL) {
213 setup_channel(channel);
218 static guint register_gio_watch(GIOChannel *channel, void *callback,
223 if (channel == NULL || callback == NULL)
226 source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
231 /* This table contains information of which HAL <--> CoreObject Type */
232 static void mapping_table_insert_hals(TcorePlugin *pg, TcoreHal **hal)
234 struct custom_data *cdata = tcore_hal_ref_user_data(hal[4]);
238 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_MODEM, hal[0]);
239 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_CALL, hal[0]);
240 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_SIM, hal[1]);
241 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_SAT, hal[1]);
242 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_SAP, hal[1]);
243 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_PHONEBOOK, hal[1]);
244 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_SMS, hal[2]);
245 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_NETWORK, hal[3]);
246 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_SS, hal[3]);
247 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_PS, hal[4]);
248 tcore_server_add_cp_mapping_tbl_entry(pg, CORE_OBJECT_TYPE_GPS, hal[4]);
250 cdata->data_hal[0] = hal[5];
251 cdata->data_hal[1] = hal[6];
256 static void remove_custom_data(TcoreHal *hal_log)
258 struct custom_data *cdata = tcore_hal_ref_user_data(hal_log);
263 if (cdata->watch_id > 0) {
264 g_source_remove(cdata->watch_id);
268 g_io_channel_unref(cdata->channel);
272 static void remove_logical_hals(TcoreHal *hal_phy)
274 struct custom_data *cdata = tcore_hal_ref_user_data(hal_phy);
279 for (i = 0; i < NUM_DLC; i++) {
280 if (cdata->hal[i] == NULL)
283 /* Remove mapping table entries based on hal */
284 tcore_server_remove_cp_mapping_tbl_entry(cdata->plugin,
287 remove_custom_data(cdata->hal[i]);
288 tcore_hal_free(cdata->hal[i]);
294 static gboolean dlc_ready_check(gpointer user_data)
296 TcoreHal *h = user_data;
297 struct custom_data *cdata = tcore_hal_ref_user_data(h);
306 err("Cannot retrieve Custom DATA from physical HAL\n"
307 "Cannot proceed with dlc ready check");
310 cdata->dlc_poll_count++;
312 if (stat(dlc_nodes[0], &st) < 0) {
313 /* only possible error is ENOENT */
314 if (cdata->dlc_poll_count > 6)
320 fd = g_io_channel_unix_get_fd(cdata->channel);
323 for (i = 0; i < NUM_DLC; i++) {
324 TcoreHal *hal = NULL;
325 struct custom_data *hal_data;
326 char channel_id_name[16];
328 hal_data = g_try_new0(struct custom_data, 1);
330 hal_data->channel = tty_open(dlc_nodes[i]);
332 if (hal_data->channel == NULL) {
333 err("Failed to open tty port - [%s]", strerror(errno));
337 dbg("Virtual tty port opened successfully. channel:%p,"
338 "path:%s", hal_data->channel, dlc_nodes[i]);
340 snprintf(channel_id_name, sizeof(channel_id_name),
342 hal = tcore_hal_new(cdata->plugin, channel_id_name, &hops,
344 hal_data->watch_id = register_gio_watch(hal_data->channel,
348 dbg("hal=%p %s=%p watch_id=%d ", hal, channel_id_name,
349 hal_data->channel, hal_data->watch_id);
351 g_io_channel_unref(hal_data->channel);
353 tcore_hal_set_power_state(hal, TRUE);
355 tcore_hal_link_user_data(hal, hal_data);
360 /* Map Core Object to corresponding logical HAL */
361 mapping_table_insert_hals(cdata->plugin, cdata->hal);
363 server = tcore_plugin_ref_server(tcore_hal_ref_plugin(h));
364 if (tcore_server_load_modem_plugin(server, cdata->plugin,
365 "imc-plugin.so") != TCORE_RETURN_SUCCESS)
366 err("Failed to load Vendor plugin IMC");
369 cdata->dlc_poll_src = 0;
374 static int setup_mux(TcoreHal *h)
376 struct gsm_config cfg;
377 int ldisc = N_GSM0710;
379 struct custom_data *data;
382 dbg("Function Enter");
384 data = tcore_hal_ref_user_data(h);
386 err("Cannot retrieve Custom DATA from physical HAL");
387 return TCORE_RETURN_FAILURE;
390 fd = g_io_channel_unix_get_fd(data->channel);
392 err("fd not available\n");
396 ret = ioctl(fd, TIOCSETD, &ldisc);
398 err("Set ioctl failed [%s]\n", strerror(errno));
402 ret = ioctl(fd, TIOCGETD, &ldisc);
404 err("Get ioctl failed [%s]\n", strerror(errno));
408 if (ldisc != N_GSM0710) {
409 err("Unable to set line discipline\n");
414 memset(&cfg, 0, sizeof(struct gsm_config));
416 ret = ioctl(fd, GSMIOC_GETCONF, &cfg);
418 err("Get config ioctl failed [%s]\n", strerror(errno));
422 cfg.encapsulation = 0; /* encoding -- set to basic */
423 cfg.initiator = 1; /* we are starting side */
424 cfg.mru = 32768; /* In specification 3GPP TS 27.010, 5.7.2 */
425 cfg.mtu = 32768; /* In specification 3GPP TS 27.010, 5.7.2 */
427 ret = ioctl(fd, GSMIOC_SETCONF, &cfg);
429 err("Set config ioctl failed [%s]\n", strerror(errno));
433 data->dlc_poll_count = 0;
434 data->dlc_poll_src = g_timeout_add_full(G_PRIORITY_HIGH, 250,dlc_ready_check, h, 0);
436 return TCORE_RETURN_SUCCESS;
439 static void on_response_setupmux(TcorePending *p, int data_len,
440 const void *data, void *user_data)
442 TcoreHal *hal = user_data;
443 struct custom_data *cdata = tcore_hal_ref_user_data(hal);
448 err("Cannot retrieve Custom DATA from physical HAL");
453 * We don't need to exchange data on physical HAL, multiplexer
454 * channels will be used by core objects
456 if (cdata->watch_id > 0) {
457 g_source_remove(cdata->watch_id);
461 /* Setup KERNEL CMUX */
462 if (setup_mux(hal) != TCORE_RETURN_SUCCESS)
463 err("Failed to initialize CMUX");
468 static void on_response_poweron(TcorePending *p, int data_len,
469 const void *data, void *user_data)
471 const TcoreATResponse *resp = data;
472 TcoreHal *hal = user_data;
474 if (resp->success == 0) {
479 /* Disable UART for power saving */
480 prepare_and_send_at_request(NULL, hal, "AT+XPOW=0,0,0",
481 NULL, TCORE_AT_NO_RESULT, NULL, hal);
483 dbg("Proceed with mux initialization");
485 tcore_cmux_init(hal, 0, on_response_setupmux, hal);
490 if (tcore_hal_set_power(hal, TRUE) != TCORE_RETURN_SUCCESS)
491 err("Failed to power ON the modem");
494 static TReturn hal_power(TcoreHal *hal, gboolean flag)
496 struct custom_data *cdata = tcore_hal_ref_user_data(hal);
502 err("Cannot retrieve Custom DATA from physical HAL");
503 return TCORE_RETURN_FAILURE;
506 server = tcore_plugin_ref_server(cdata->plugin);
507 tcore_hal_set_power_state(hal, flag);
510 tcore_server_register_modem(server, cdata->plugin);
512 return prepare_and_send_at_request(NULL, hal,
514 "+CPAS", TCORE_AT_SINGLELINE,
515 on_response_poweron, hal);
517 remove_logical_hals(hal);
519 tcore_server_unregister_modem(server, cdata->plugin);
521 dbg("Phone Power Off success.");
524 return TCORE_RETURN_SUCCESS;
528 static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data)
530 size_t bytes_written;
531 struct custom_data *cdata;
533 if (tcore_hal_get_power_state(hal) == FALSE)
534 return TCORE_RETURN_FAILURE;
536 cdata = tcore_hal_ref_user_data(hal);
538 err("Cannot retrive custom data for hal %s",
539 tcore_hal_get_name(hal));
540 return TCORE_RETURN_FAILURE;
543 bytes_written = channel_write(cdata->channel, data, data_len);
544 if (bytes_written != data_len) {
545 err("channel_write failed");
547 return TCORE_RETURN_FAILURE;
550 dbg("channel_write success (channel=%p, len=%d)", cdata->channel, bytes_written);
552 return TCORE_RETURN_SUCCESS;
555 static const char *setup_rawip(GIOChannel *channel)
557 struct gsm_netconfig netconfig;
560 char ifname[IFNAMSIZ];
565 memset(&netconfig, 0, sizeof(struct gsm_netconfig));
567 netconfig.adaption = 3;
568 netconfig.protocol = htons(ETH_P_IP);
570 fd = g_io_channel_unix_get_fd(channel);
574 index = ioctl(fd, GSMIOC_ENABLE_NET, &netconfig);
576 err("Set ioctl to create network failed [%s]\n", strerror(errno));
580 dbg("Net interface index: %d", index);
582 interface = if_indextoname(index, ifname);
583 if (interface == NULL) {
584 err("Interface index %d error %s", index, strerror(errno));
588 dbg("Interface name: %s", interface);
593 static void on_response_setup_pdp(TcorePending *p, int data_len, const void *data, void *user_data)
595 TcoreHal *hal = user_data;
596 const TcoreATResponse *resp = data;
597 struct custom_data *cdata = tcore_hal_ref_user_data(hal);
598 CoreObject *co = tcore_pending_ref_core_object(p);
599 TcoreHalSetupNetifCallback func = (TcoreHalSetupNetifCallback)cdata->cb;
600 const char *interface = NULL;
604 if (resp->success == 0) {
607 func(co, -1, interface, cdata->cb_data);
614 interface = setup_rawip(cdata->channel);
615 cdata->rawip_enabled = TRUE;
618 func(co, 0, interface, cdata->cb_data);
621 static gboolean disable_pdp_context(gpointer user_data)
623 TcoreHal *hal = user_data;
624 struct custom_data *cdata = tcore_hal_ref_user_data(hal);
625 TcoreHalSetupNetifCallback func;
628 func = (TcoreHalSetupNetifCallback)cdata->cb;
630 fd = g_io_channel_unix_get_fd(cdata->channel);
631 if (ioctl(fd, GSMIOC_DISABLE_NET, NULL) < 0) {
632 err("Set ioctl to disable network interface failed [%s]",
635 func(cdata->co, -1, NULL, cdata->cb_data);
640 cdata->rawip_enabled = FALSE;
643 func(cdata->co, 0, NULL, cdata->cb_data);
648 static TReturn hal_setup_netif(CoreObject *co, TcoreHalSetupNetifCallback func,
649 void *user_data, unsigned int cid,
652 TcoreHal *hal = tcore_object_get_hal(co);
655 struct custom_data *cdata = tcore_hal_ref_user_data(hal);
661 err("No custom data on PS HAL");
662 return TCORE_RETURN_FAILURE;
666 data_hal = cdata->data_hal[0];
668 data_hal = cdata->data_hal[1];
670 err("Invalid CID %d", cid);
671 return TCORE_RETURN_EINVAL;
674 if (data_hal == NULL) {
675 err("Fail to get channel data");
676 return TCORE_RETURN_FAILURE;
679 cdata = tcore_hal_ref_user_data(data_hal);
681 err("No custom data on DATA HAL");
682 return TCORE_RETURN_FAILURE;
685 if ((enable == FALSE) && (cdata->rawip_enabled == FALSE)) {
686 err("PDP context %d already disabled", cid);
687 return TCORE_RETURN_SUCCESS;
690 cdata->cb = (void *)func;
691 cdata->cb_data = user_data;
693 if (enable == FALSE) {
695 g_idle_add(disable_pdp_context, data_hal);
696 return TCORE_RETURN_SUCCESS;
699 cmd_str = g_strdup_printf("AT+CGDATA=\"M-RAW_IP\",%d", cid);
701 ret = prepare_and_send_at_request(co, data_hal, cmd_str, NULL,
703 on_response_setup_pdp, data_hal);
710 static gboolean on_load()
717 static gboolean on_init(TcorePlugin *plugin)
720 struct custom_data *data;
728 data = g_try_new0(struct custom_data, 1);
730 err("Memory failure");
734 data->plugin = plugin;
736 data->channel = tty_open(DEVICE_IFX);
737 if (data->channel == NULL) {
738 err("Failed to open tty port - [%s]", strerror(errno));
743 dbg("tty port (%s) opened successfully", DEVICE_IFX);
746 hal = tcore_hal_new(plugin, "mfld-blackbay", &hops, TCORE_HAL_MODE_AT);
748 err("Failed to create HAL");
753 data->watch_id = register_gio_watch(data->channel,
754 on_recv_tty_message, hal);
755 if (data->watch_id == 0){
756 err("Failed to register gio watch ");
759 g_io_channel_unref(data->channel);
763 tcore_hal_link_user_data(hal, data);
765 dbg("HAL is mfld-blackbay: channel = %p, watch_id=%d ", data->channel, data->watch_id);
767 if (tcore_hal_set_power(hal, TRUE) != TCORE_RETURN_SUCCESS) {
768 err("Failed to power ON the modem");
775 static void on_unload(TcorePlugin *plugin)
778 struct custom_data *cdata;
783 hal = tcore_plugin_ref_user_data(plugin);
787 cdata = tcore_hal_ref_user_data(hal);
791 g_io_channel_unref(cdata->channel);
794 tcore_hal_set_power(hal, FALSE);
800 struct tcore_plugin_define_desc plugin_define_desc =
802 .name = "mfld_blackbay",
803 .priority = TCORE_PLUGIN_PRIORITY_HIGH,