From: Philippe Nunes Date: Tue, 23 Oct 2012 16:43:31 +0000 (+0200) Subject: Add support of the MUX kernel (enabled by default) X-Git-Tag: accepted/tizen_2.0/20130305.215309~10 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6a554d41538cc7d70ea260ff6acadcef3f934228;p=adaptation%2Fintel_mfld%2Ftel-plugin-mfld-blackbay.git Add support of the MUX kernel (enabled by default) To switch back to the MUX handled by libtcore, just remove the definition KERNEL_MUX in the spec file. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index b442ea6..bf4e847 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,13 +27,23 @@ ADD_DEFINITIONS("-DTCORE_LOG_TAG=\"IMC-PR3\"") MESSAGE(${CMAKE_C_FLAGS}) MESSAGE(${CMAKE_EXE_LINKER_FLAGS}) -SET(SRCS - src/desc_imc_pr3.c - src/util_imc.c - src/pr3_audio.c -) - - +IF( ${KERNEL_MUX} EQUAL 1 ) + MESSAGE( "KERNEL MUX is enabled" ) + SET(SRCS + src/desc_imc_kernel_mux_pr3.c + src/util_imc.c + src/pr3_audio.c + ) +ELSE( ${KERNEL_MUX} EQUAL 1 ) + MESSAGE( "KERNEL MUX is disabled" ) + SET(SRCS + src/desc_imc_pr3.c + src/util_imc.c + src/pr3_audio.c + ) +ENDIF( ${KERNEL_MUX} EQUAL 1 ) + +MESSAGE( "SOURCES: ${SRCS}" ) # library build ADD_LIBRARY(imc-pr3-plugin SHARED ${SRCS}) diff --git a/packaging/tel-plugin-imc-pr3.spec b/packaging/tel-plugin-imc-pr3.spec index 36e9830..30d19c1 100644 --- a/packaging/tel-plugin-imc-pr3.spec +++ b/packaging/tel-plugin-imc-pr3.spec @@ -20,7 +20,7 @@ PR3 plateform telephony plugin %setup -q %build -cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DKERNEL_MUX=1 make %{?jobs:-j%jobs} %post diff --git a/src/desc_imc_kernel_mux_pr3.c b/src/desc_imc_kernel_mux_pr3.c new file mode 100644 index 0000000..33c479d --- /dev/null +++ b/src/desc_imc_kernel_mux_pr3.c @@ -0,0 +1,733 @@ +/* + * + * tel-plugin-imc-pr3 + * + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#include +#include +#include +#include +#include + +#include "util_imc.h" +#include "pr3_audio.h" + +#define DEVICE_IFX "/dev/ttyIFX0" +#define N_GSM0710 21 +#define NUM_DLC 7 +#define BUF_LEN_MAX 512 + +#define CHANNEL_MODEM 0 +#define CHANNEL_CALL 0 +#define CHANNEL_SIM 1 +#define CHANNEL_SMS 2 +#define CHANNEL_NETWORK 3 +#define CHANNEL_PS 4 +#define CHANNEL_SAT 1 +#define CHANNEL_SS 3 +#define CHANNEL_DATA_1 5 +#define CHANNEL_DATA_2 6 +#define CHANNEL_NONE -1 + +struct custom_data { + GIOChannel *channel; + guint watch_id; + void *cb; + void *cb_data; + guint dlc_poll_count; + guint dlc_poll_src; + gboolean rawip_enabled; +}; + +struct gsm_config { + unsigned int adaption; + unsigned int encapsulation; + unsigned int initiator; + unsigned int t1; + unsigned int t2; + unsigned int t3; + unsigned int n2; + unsigned int mru; + unsigned int mtu; + unsigned int k; + unsigned int i; + unsigned int clocal; + unsigned int unused[7]; /* Padding for expansion without breaking stuff */ +}; + +#define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config) +#define GSMIOC_SETCONF _IOW('G', 1, struct gsm_config) + +struct gsm_netconfig { + unsigned int adaption; /* Adaption to use in network mode */ + unsigned short protocol; /* Protocol to use - only ETH_P_IP supported */ + unsigned short unused2; + char if_name[IFNAMSIZ]; /* interface name format string */ + __u8 unused[28]; /* For future use */ +}; + +#define GSMIOC_ENABLE_NET _IOW('G', 2, struct gsm_netconfig) +#define GSMIOC_DISABLE_NET _IO('G', 3) + +/* Virtual ttys for the mux */ +static const char *dlc_nodes[NUM_DLC] = { "/dev/gsmtty1", "/dev/gsmtty2", + "/dev/gsmtty3", "/dev/gsmtty4", + "/dev/gsmtty6", "/dev/gsmtty7", + "/dev/gsmtty8" }; + +/* CMUX structure */ +typedef struct cmux { + TcoreHal *hal[NUM_DLC]; + int channel_nb; +} MUX; + +/* Global pointer MUX Object pointer */ +MUX *g_mux_obj_ptr = NULL; + +static TReturn hal_power(TcoreHal *hal, gboolean flag, + TcoreHalPowerCallBack func, void *user_data); +static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data); +static TReturn hal_link_object_channel(CoreObject *object); +static TReturn hal_setup_pdp(CoreObject *co, TcoreHalSetupPDPCallBack func, + void *user_data, unsigned int cid); + +static struct tcore_hal_operations hops = +{ + .power = hal_power, + .send = hal_send, + .set_sound_path = pr3_audio_set_sound_path, + .link_object_channel = hal_link_object_channel, + .setup_pdp = hal_setup_pdp, +}; + +static gboolean on_recv_tty_message(GIOChannel *channel, GIOCondition condition, gpointer data) +{ + TcoreHal *hal = data; + char read_buffer[BUF_LEN_MAX]; + size_t bytes_read; + + if (condition & G_IO_NVAL) + return FALSE; + + bytes_read = channel_read(channel, read_buffer, BUF_LEN_MAX); + if (bytes_read == 0) { + err("channel_read error."); + return FALSE; + } + + dbg("bytes_read = %d", bytes_read); + tcore_hal_emit_recv_callback(hal, bytes_read, read_buffer); + + tcore_hal_dispatch_response_data(hal, 0, bytes_read, read_buffer); + + return TRUE; +} + + +static TcoreHal *get_object_hal(const char *obj_name) +{ + if (strcmp(obj_name, "modem") == 0) + return g_mux_obj_ptr->hal[CHANNEL_MODEM]; + else if (strcmp(obj_name, "call") == 0) + return g_mux_obj_ptr->hal[CHANNEL_CALL]; + else if (strcmp(obj_name, "sim") == 0) + return g_mux_obj_ptr->hal[CHANNEL_SIM]; + else if (strcmp(obj_name, "umts_sms") == 0) + return g_mux_obj_ptr->hal[CHANNEL_SMS]; + else if (strcmp(obj_name, "umts_network") == 0) + return g_mux_obj_ptr->hal[CHANNEL_NETWORK]; + else if (strcmp(obj_name, "umts_ps") == 0) + return g_mux_obj_ptr->hal[CHANNEL_PS]; + else if (strcmp(obj_name, "sat") == 0) + return g_mux_obj_ptr->hal[CHANNEL_SAT]; + else if (strcmp(obj_name, "ss") == 0) + return g_mux_obj_ptr->hal[CHANNEL_SS]; + + return NULL; +} + +static gboolean setup_channel(GIOChannel *io) +{ + GIOFlags io_flags; + + if (g_io_channel_set_encoding(io, NULL, NULL) != G_IO_STATUS_NORMAL) + return FALSE; + + g_io_channel_set_buffered(io, FALSE); + io_flags = g_io_channel_get_flags(io); + io_flags |= (G_IO_FLAG_NONBLOCK & G_IO_FLAG_SET_MASK); + + if (g_io_channel_set_flags(io, io_flags, NULL) != G_IO_STATUS_NORMAL) + return FALSE; + + g_io_channel_set_close_on_unref(io, TRUE); + + return TRUE; +} + +static void set_termio(int fd) +{ + struct termios newtio; + + /* Switch TTY to raw mode */ + memset(&newtio, 0, sizeof(newtio)); + cfmakeraw(&newtio); + + /* Line is local */ + newtio.c_cflag |= CLOCAL; + + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &newtio); +} + +static int open_device(const char *tty) +{ + int fd; + + fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + return -1; + + set_termio(fd); + + return fd; +} + +static GIOChannel *tty_open(const char *tty) +{ + GIOChannel *channel; + int fd; + + fd = open_device(tty); + if (fd < 0) + return NULL; + + dbg("fd =%d ", fd); + + channel = g_io_channel_unix_new(fd); + if (channel == NULL) { + close(fd); + return NULL; + } + + setup_channel(channel); + + return channel; +} + +static guint register_gio_watch(GIOChannel *channel, void *callback, TcoreHal *h) +{ + guint source; + + if (channel == NULL || !callback) + return 0; + + source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h); + + return source; +} + +static gboolean dlc_ready_check(gpointer user_data) +{ + TcoreHal *h = user_data; + struct custom_data *cdata = tcore_hal_ref_user_data(h); + struct stat st; + TcoreHalPowerCallBack func = (TcoreHalPowerCallBack)cdata->cb; + int i; + gint fd; + + dbg("Entry"); + + cdata->dlc_poll_count++; + + if (stat(dlc_nodes[0], &st) < 0) { + /* only possible error is ENOENT */ + if (cdata->dlc_poll_count > 6) + goto error; + + return TRUE; + } + + fd = g_io_channel_unix_get_fd(cdata->channel); + set_termio(fd); + + /* Allocating memory for mux */ + g_mux_obj_ptr = (MUX *) g_new0(struct cmux, 1); + if (!g_mux_obj_ptr) { + err("Failed to allocate memory"); + goto error; + } + + for (i = 0; i < NUM_DLC; i++) { + TcoreHal *hal = NULL; + struct custom_data *hal_data; + char channel_id_name[16]; + + hal_data = g_new0(struct custom_data, 1); + + hal_data->channel = tty_open(dlc_nodes[i]); + + if (hal_data->channel == NULL) { + err("Failed to open tty port - [%s]", strerror(errno)); + + goto error; + } else + dbg("Virtual tty port opened successfully. channel:%p, path:%s", + hal_data->channel, dlc_nodes[i]); + + snprintf(channel_id_name, sizeof(channel_id_name), "channel_%d", i); + hal = tcore_hal_new(NULL, channel_id_name, &hops, TCORE_HAL_MODE_AT); + hal_data->watch_id = register_gio_watch(hal_data->channel, on_recv_tty_message, hal); + + dbg("hal=%p %s=%p watch_id=%d ", hal, channel_id_name, hal_data->channel, hal_data->watch_id); + + g_io_channel_unref(hal_data->channel); + + // Store CMUX Channel + g_mux_obj_ptr->hal[i] = hal; + g_mux_obj_ptr->channel_nb++; + + // Set Logical HAL Power State to TRUE + tcore_hal_set_power_state(hal, TRUE); + + tcore_hal_link_user_data(hal, hal_data); + } + + cdata->dlc_poll_src = 0; + //tcore_hal_set_power_state(h, TRUE); + func(h, cdata->cb_data); + + return FALSE; + +error: + cdata->dlc_poll_src = 0; + + return FALSE; +} + +static int setup_mux(TcoreHal *h) +{ + struct gsm_config cfg; + int ldisc = N_GSM0710; + int ret = 0; + struct custom_data *data; + gint fd; + + dbg("Function Enter"); + + data = tcore_hal_ref_user_data(h); + if (!data) + return TCORE_RETURN_FAILURE; + + fd = g_io_channel_unix_get_fd(data->channel); + if (fd < 0){ + err("fd not available\n"); + return -1; + } + + ret = ioctl(fd, TIOCSETD, &ldisc); + if (ret < 0) { + err("Set ioctl failed [%s]\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, TIOCGETD, &ldisc); + if (ret < 0) { + err("Get ioctl failed [%s]\n", strerror(errno)); + return -1; + } + + if (ldisc != N_GSM0710) { + err("Unable to set line discipline\n"); + return -1; + } + + /* configure mux */ + memset(&cfg, 0, sizeof(struct gsm_config)); + + ret = ioctl(fd, GSMIOC_GETCONF, &cfg); + if (ret < 0) { + err("Get config ioctl failed [%s]\n", strerror(errno)); + return -1; + } + + cfg.encapsulation = 0; /* encoding -- set to basic */ + cfg.initiator = 1; /* we are starting side */ + cfg.mru = 32768; /* In specification 3GPP TS 27.010, 5.7.2 */ + cfg.mtu = 32768; /* In specification 3GPP TS 27.010, 5.7.2 */ + + ret = ioctl(fd, GSMIOC_SETCONF, &cfg); + if (ret < 0) { + err("Set config ioctl failed [%s]\n", strerror(errno)); + return -1; + } + + data->dlc_poll_count = 0; + data->dlc_poll_src = g_timeout_add_full(G_PRIORITY_HIGH, 250,dlc_ready_check, h, 0); + return EXIT_SUCCESS; + +} + +static void on_response_setupmux(TcorePending *p, int data_len, + const void *data, void *user_data) +{ + TcoreHal *hal = user_data; + struct custom_data *cdata = tcore_hal_ref_user_data(hal); + TReturn ret; + + dbg("Entry"); + + if (cdata->watch_id > 0) { + g_source_remove(cdata->watch_id); + cdata->watch_id = 0; + } + + /* Initialize CMUX */ + ret = setup_mux(hal); + if (TCORE_RETURN_SUCCESS != ret) + err("Failed to initialize CMUX"); + + dbg("Exit"); + + return; +} + +static TReturn hal_power(TcoreHal *hal, gboolean flag, + TcoreHalPowerCallBack func, void *user_data) +{ + struct custom_data *cdata = tcore_hal_ref_user_data(hal); + + dbg("Entry"); + + /* power on */ + if (flag == TRUE) { + TcorePending *pending; + + cdata->cb = (void *)func; + cdata->cb_data = user_data; + + tcore_hal_set_power_state(hal, TRUE); + + pending = tcore_at_pending_new(NULL, "AT+CMUX=0,0,,1509,10,3,30,,", "+CMUX", TCORE_AT_NO_RESULT, on_response_setupmux, hal); + + if (pending == NULL) { + err("Fail to create AT+CMUX pending request"); + + return TCORE_RETURN_FAILURE; + } + + /* Send callback */ + tcore_hal_send_request(hal, pending); + /* power off */ + } else { + int i; + + for (i = 0; i < g_mux_obj_ptr->channel_nb; i++) { + + cdata = tcore_hal_ref_user_data(g_mux_obj_ptr->hal[i]); + + if (cdata->watch_id > 0) + g_source_remove(cdata->watch_id); + + g_io_channel_unref(cdata->channel); + + tcore_hal_free(g_mux_obj_ptr->hal[i]); + free(cdata); + } + + tcore_hal_set_power_state(hal, FALSE); + + /* Free MUX Object */ + free(g_mux_obj_ptr); + g_mux_obj_ptr = NULL; + + dbg("Phone Power Off success."); + } + + return TCORE_RETURN_SUCCESS; +} + + +static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data) +{ + size_t bytes_written; + struct custom_data *cdata; + + if (tcore_hal_get_power_state(hal) == FALSE) + return TCORE_RETURN_FAILURE; + + cdata = tcore_hal_ref_user_data(hal); + if (!cdata) + return TCORE_RETURN_FAILURE; + + bytes_written = channel_write(cdata->channel, data, data_len); + if(bytes_written != data_len) { + err("channel_write failed"); + + return TCORE_RETURN_FAILURE; + } + + dbg("channel_write success (channel=%p, len=%d)", cdata->channel, bytes_written); + + return TCORE_RETURN_SUCCESS; +} + +static TReturn hal_link_object_channel(CoreObject *object) +{ + const char *name = tcore_object_ref_name(object); + TcoreHal *hal; + TReturn ret; + + dbg("Entry"); + + hal = get_object_hal(name); + if (hal == NULL) + return TCORE_RETURN_EINVAL; + + ret = tcore_object_set_hal(object, hal); + + return ret; +} + +static const char *setup_rawip(int fd) +{ + struct gsm_netconfig netconfig; + int index; + char *interface = NULL; + char ifname[IFNAMSIZ]; + + dbg("Entry"); + + memset(&netconfig, 0, sizeof(struct gsm_netconfig)); + + netconfig.adaption = 3; + netconfig.protocol = htons(ETH_P_IP); + + if (fd < 0) + return NULL; + + index = ioctl(fd, GSMIOC_ENABLE_NET, &netconfig); + if (index < 0) { + err("Set ioctl to create network failed [%s]\n", strerror(errno)); + return NULL; + } + + dbg("Net interface index: %d", index); + + interface = if_indextoname(index, ifname); + if (interface == NULL) { + err("Interface index %d error %s", index, strerror(errno)); + return NULL; + } + + dbg("Interface name: %s", interface); + + return interface; +} + +static void on_response_setup_pdp(TcorePending *p, int data_len, const void *data, void *user_data) +{ + TcoreHal *hal = user_data; + const TcoreATResponse *resp = data; + const char *interface = NULL; + struct custom_data *cdata = tcore_hal_ref_user_data(hal); + CoreObject *co = tcore_pending_ref_core_object(p); + TcoreHalSetupPDPCallBack func = (TcoreHalSetupPDPCallBack)cdata->cb; + + dbg("Entry"); + + if (resp->success) { + gint fd; + + dbg("Response Ok"); + + fd = g_io_channel_unix_get_fd(cdata->channel); + + interface = setup_rawip(fd); + + cdata->rawip_enabled = TRUE; + + func(co, interface, cdata->cb_data); + + return; + } + + func(co, NULL, cdata->cb_data); + dbg("Response NOk"); + + return; +} + +static TReturn hal_setup_pdp(CoreObject *co, TcoreHalSetupPDPCallBack func, + void *user_data, unsigned int cid) +{ + TcorePending *pending = NULL; + TcoreHal *hal = NULL; + char *cmd_str = NULL; + struct custom_data *cdata; + + dbg("Entry"); + + if (cid == 1) + hal = g_mux_obj_ptr->hal[CHANNEL_DATA_1]; + else if (cid == 2) + hal = g_mux_obj_ptr->hal[CHANNEL_DATA_2]; + + if (hal == NULL) { + err("Fail to get channel data"); + return TCORE_RETURN_FAILURE; + } + + cdata = tcore_hal_ref_user_data(hal); + + /* + * If data call was previously UP, we need to disable the + * network interface + */ + if (cdata->rawip_enabled == TRUE) { + gint fd; + int ret; + + fd = g_io_channel_unix_get_fd(cdata->channel); + + ret = ioctl(fd, GSMIOC_DISABLE_NET, NULL); + if (ret < 0) { + err("Set ioctl to disable network interface failed [%s]\n", strerror(errno)); + return TCORE_RETURN_FAILURE; + } + + cdata->rawip_enabled = FALSE; + } + + cdata->cb = (void *)func; + cdata->cb_data = user_data; + + cmd_str = g_strdup_printf("AT+CGDATA=\"M-RAW_IP\",%d", cid); + pending = tcore_at_pending_new(co, cmd_str, NULL, TCORE_AT_NO_RESULT, on_response_setup_pdp, hal); + g_free(cmd_str); + + if (pending == NULL) { + err("Fail to create AT+CGDATA pending request"); + + return TCORE_RETURN_FAILURE; + } + + tcore_hal_send_request(hal, pending); + + return TCORE_RETURN_SUCCESS; +} + +static gboolean on_load() +{ + dbg("I'm load!"); + + return TRUE; +} + +static gboolean on_init(TcorePlugin *plugin) +{ + TcoreHal *hal; + struct custom_data *data; + + if (!plugin) + return FALSE; + + dbg("I'm init!"); + + /* Phonet init */ + data = g_new0(struct custom_data, 1); + + data->channel = tty_open(DEVICE_IFX); + if (data->channel == NULL) { + err("Failed to open tty port - [%s]", strerror(errno)); + g_free(data); + return FALSE; + } + + dbg("tty port (%s) opened successfully", DEVICE_IFX); + + /* HAL init */ + hal = tcore_hal_new(plugin, "imc-pr3", &hops, TCORE_HAL_MODE_AT); + if (hal == NULL){ + err("Failed to create HAL"); + g_free(data); + return FALSE; + } + + data->watch_id = register_gio_watch(data->channel, on_recv_tty_message, hal); + + if (data->watch_id == 0){ + err("Failed to register gio watch "); + free(data); + tcore_hal_free(hal); + g_io_channel_unref(data->channel); + return FALSE; + } + + tcore_hal_link_user_data(hal, data); + + dbg("HAL is imc-pr3: channel = %p, watch_id=%d ", data->channel, data->watch_id); + + if (pr3_audio_init() != TRUE) + err("Error in audio initialization") + + return TRUE; +} + +static void on_unload(TcorePlugin *plugin) +{ + if (!plugin) + return; + + if (pr3_audio_unload() != TRUE) + err("Error in audio unload") + + dbg("I'm unload"); +} + +struct tcore_plugin_define_desc plugin_define_desc = +{ + .name = "IMC-PR3", + .priority = TCORE_PLUGIN_PRIORITY_HIGH, + .version = 1, + .load = on_load, + .init = on_init, + .unload = on_unload +};