Add support of the MUX kernel (enabled by default)
authorPhilippe Nunes <philippe.nunes@linux.intel.com>
Tue, 23 Oct 2012 16:43:31 +0000 (18:43 +0200)
committerAuke Kok <auke-jan.h.kok@intel.com>
Fri, 8 Feb 2013 20:25:55 +0000 (12:25 -0800)
To switch back to the MUX handled by libtcore, just remove the
definition KERNEL_MUX in the spec file.

CMakeLists.txt
packaging/tel-plugin-imc-pr3.spec
src/desc_imc_kernel_mux_pr3.c [new file with mode: 0644]

index b442ea6..bf4e847 100644 (file)
@@ -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})
index 36e9830..30d19c1 100644 (file)
@@ -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 (file)
index 0000000..33c479d
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include <tcore.h>
+#include <plugin.h>
+#include <core_object.h>
+
+
+#include <user_request.h>
+#include <hal.h>
+#include <mux.h>
+#include <at.h>
+#include <queue.h>
+
+#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
+};