Enhance trace level
[framework/telephony/tel-plugin-mfld-blackbay.git] / src / desc_mfld_blackbay.c
1 /*
2 *
3 *  tel-plugin-mfld-blackbay
4 *
5 * Copyright (C) 2013  Intel Corporation. All rights reserved.
6 *
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
10 *
11 *     http://www.apache.org/licenses/LICENSE-2.0
12 *
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.
18 *
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <sys/ioctl.h>
26 #include <termios.h>
27 #include <sys/stat.h>
28 #include <net/if.h>
29 #include <netinet/in.h>
30 #include <linux/if_ether.h>
31 #include <linux/gsmmux.h>
32 #include <fcntl.h>
33
34 #include <glib.h>
35
36 #include <tcore.h>
37 #include <server.h>
38 #include <plugin.h>
39 #include <core_object.h>
40
41
42 #include <user_request.h>
43 #include <hal.h>
44 #include <mux.h>
45 #include <at.h>
46 #include <queue.h>
47
48 #include "util_mfld_blackbay.h"
49
50 #define DEVICE_IFX "/dev/ttyIFX0"
51 #define N_GSM0710 21
52 #define NUM_DLC  7
53 #define NUM_DATA_DLC  2
54 #define BUF_LEN_MAX 512
55
56 struct custom_data {
57         TcorePlugin *plugin;
58         GIOChannel *channel;
59         guint watch_id;
60         CoreObject *co;
61         void *cb;
62         void *cb_data;
63         guint dlc_poll_count;
64         guint dlc_poll_src;
65         gboolean rawip_enabled;
66         union {
67                 TcoreHal *hal[NUM_DLC];
68                 TcoreHal *data_hal[NUM_DATA_DLC];
69         };
70 };
71
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",
77                                         "/dev/gsmtty8" };
78
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,
83                                 gboolean enable);
84
85 static struct tcore_hal_operations hops = {
86         .power = hal_power,
87         .send = hal_send,
88         .setup_netif = hal_setup_netif,
89 };
90
91 static TReturn prepare_and_send_at_request(CoreObject *co, TcoreHal *hal,
92                                         const char *at_cmd,
93                                         const char *at_cmd_prefix,
94                                         enum tcore_at_command_type at_cmd_type,
95                                         TcorePendingResponseCallback resp_cb,
96                                         void *resp_cb_data)
97 {
98         TcorePending *pending;
99         TcoreATRequest *req;
100
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;
106         }
107
108         /* Create AT-Command Request */
109         req = tcore_at_request_new(at_cmd, at_cmd_prefix, at_cmd_type);
110         if (req == NULL) {
111                 err("Memory failure, request is NULL");
112                 tcore_pending_free(pending);
113                 return TCORE_RETURN_ENOMEM;
114         }
115
116         dbg("AT Command: %s, Prefix(if any):%s, AT-Command length: %d",
117                 req->cmd, req->prefix, strlen(req->cmd));
118
119         tcore_pending_set_request_data(pending, 0, req);
120         tcore_pending_set_response_callback(pending, resp_cb, resp_cb_data);
121
122         return tcore_hal_send_request(hal, pending);
123 }
124
125 static gboolean on_recv_tty_message(GIOChannel *channel,
126                                         GIOCondition condition, gpointer data)
127 {
128         TcoreHal *hal = data;
129         char read_buffer[BUF_LEN_MAX];
130         size_t bytes_read;
131
132         if (condition & G_IO_NVAL)
133                 return FALSE;
134
135         bytes_read = channel_read(channel, read_buffer, BUF_LEN_MAX);
136         if (bytes_read == 0) {
137                 err("channel_read error.");
138                 return FALSE;
139         }
140
141         dbg("bytes_read = %d", bytes_read);
142         tcore_hal_emit_recv_callback(hal, bytes_read, read_buffer);
143
144         tcore_hal_dispatch_response_data(hal, 0, bytes_read, read_buffer);
145
146         return TRUE;
147 }
148
149 static gboolean setup_channel(GIOChannel *io)
150 {
151         GIOFlags io_flags;
152
153         if (g_io_channel_set_encoding(io, NULL, NULL) != G_IO_STATUS_NORMAL)
154                 return FALSE;
155
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);
159
160         if (g_io_channel_set_flags(io, io_flags, NULL) != G_IO_STATUS_NORMAL)
161                         return FALSE;
162
163         g_io_channel_set_close_on_unref(io, TRUE);
164
165         return TRUE;
166 }
167
168 static void set_termio(int fd)
169 {
170         struct termios newtio;
171
172         /* Switch TTY to raw mode */
173         memset(&newtio, 0, sizeof(newtio));
174         cfmakeraw(&newtio);
175
176         /* Line is local */
177         newtio.c_cflag |= CLOCAL;
178
179         tcflush(fd, TCIFLUSH);
180         tcsetattr(fd, TCSANOW, &newtio);
181 }
182
183 static int open_device(const char *tty)
184 {
185         int fd;
186
187         fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
188         if (fd < 0)
189                 return -1;
190
191         set_termio(fd);
192
193         return fd;
194 }
195
196 static GIOChannel *tty_open(const char *tty)
197 {
198         GIOChannel *channel;
199         int fd;
200
201         fd = open_device(tty);
202         if (fd < 0)
203                 return NULL;
204
205         dbg("fd =%d ", fd);
206
207         channel = g_io_channel_unix_new(fd);
208         if (channel == NULL) {
209                 close(fd);
210                 return NULL;
211         }
212
213         setup_channel(channel);
214
215         return channel;
216 }
217
218 static guint register_gio_watch(GIOChannel *channel, void *callback,
219                                         TcoreHal *h)
220 {
221         guint source;
222
223         if (channel == NULL || callback == NULL)
224                 return 0;
225
226         source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
227
228         return source;
229 }
230
231 /* This table contains information of which HAL <--> CoreObject Type */
232 static void mapping_table_insert_hals(TcorePlugin *pg, TcoreHal **hal)
233 {
234         struct custom_data *cdata = tcore_hal_ref_user_data(hal[4]);
235
236         dbg("Entry");
237
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]);
249
250         cdata->data_hal[0] = hal[5];
251         cdata->data_hal[1] = hal[6];
252
253         dbg("Exit");
254 }
255
256 static void remove_custom_data(TcoreHal *hal_log)
257 {
258         struct custom_data *cdata = tcore_hal_ref_user_data(hal_log);
259
260         if (cdata == NULL)
261                 return;
262
263         if (cdata->watch_id > 0) {
264                 g_source_remove(cdata->watch_id);
265                 cdata->watch_id = 0;
266         }
267
268         g_io_channel_unref(cdata->channel);
269         g_free(cdata);
270 }
271
272 static void remove_logical_hals(TcoreHal *hal_phy)
273 {
274         struct custom_data *cdata = tcore_hal_ref_user_data(hal_phy);
275         int i;
276
277         dbg("Entry");
278
279         for (i = 0; i < NUM_DLC; i++) {
280                 if (cdata->hal[i] == NULL)
281                         continue;
282
283                 /* Remove mapping table entries based on hal */
284                 tcore_server_remove_cp_mapping_tbl_entry(cdata->plugin,
285                                                                 cdata->hal[i]);
286
287                 remove_custom_data(cdata->hal[i]);
288                 tcore_hal_free(cdata->hal[i]);
289         }
290
291         dbg("Exit");
292 }
293
294 static gboolean dlc_ready_check(gpointer user_data)
295 {
296         TcoreHal *h = user_data;
297         struct custom_data *cdata = tcore_hal_ref_user_data(h);
298         struct stat st;
299         Server *server;
300         int i;
301         gint fd;
302
303         dbg("Entry");
304
305         if (cdata == NULL) {
306                 err("Cannot retrieve Custom DATA from physical HAL\n"
307                         "Cannot proceed with dlc ready check");
308                 return FALSE;
309         }
310         cdata->dlc_poll_count++;
311
312         if (stat(dlc_nodes[0], &st) < 0) {
313                 /* only possible error is ENOENT */
314                 if (cdata->dlc_poll_count > 6)
315                         goto error;
316
317                 return TRUE;
318         }
319
320         fd = g_io_channel_unix_get_fd(cdata->channel);
321         set_termio(fd);
322
323         for (i = 0; i < NUM_DLC; i++) {
324                 TcoreHal *hal = NULL;
325                 struct custom_data *hal_data;
326                 char channel_id_name[16];
327
328                 hal_data = g_try_new0(struct custom_data, 1);
329
330                 hal_data->channel = tty_open(dlc_nodes[i]);
331
332                 if (hal_data->channel == NULL) {
333                         err("Failed to open tty port - [%s]", strerror(errno));
334
335                         goto error;
336                 } else
337                         dbg("Virtual tty port opened successfully. channel:%p,"
338                                 "path:%s", hal_data->channel, dlc_nodes[i]);
339
340                 snprintf(channel_id_name, sizeof(channel_id_name),
341                                 "channel_%d", i);
342                 hal = tcore_hal_new(cdata->plugin, channel_id_name, &hops,
343                                         TCORE_HAL_MODE_AT);
344                 hal_data->watch_id = register_gio_watch(hal_data->channel,
345                                                         on_recv_tty_message,
346                                                         hal);
347
348                 dbg("hal=%p %s=%p watch_id=%d ", hal, channel_id_name,
349                         hal_data->channel, hal_data->watch_id);
350
351                 g_io_channel_unref(hal_data->channel);
352
353                 tcore_hal_set_power_state(hal, TRUE);
354
355                 tcore_hal_link_user_data(hal, hal_data);
356
357                 cdata->hal[i] = hal;
358         }
359
360         /* Map Core Object to corresponding logical HAL */
361         mapping_table_insert_hals(cdata->plugin, cdata->hal);
362
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");
367
368 error:
369         cdata->dlc_poll_src = 0;
370
371         return FALSE;
372 }
373
374 static int setup_mux(TcoreHal *h)
375 {
376         struct gsm_config cfg;
377         int ldisc = N_GSM0710;
378         int ret = 0;
379         struct custom_data *data;
380         gint fd;
381
382         dbg("Function Enter");
383
384         data = tcore_hal_ref_user_data(h);
385         if (!data) {
386                 err("Cannot retrieve Custom DATA from physical HAL");
387                 return TCORE_RETURN_FAILURE;
388         }
389
390         fd = g_io_channel_unix_get_fd(data->channel);
391         if (fd < 0){
392                 err("fd not available\n");
393                 return -1;
394         }
395
396         ret = ioctl(fd, TIOCSETD, &ldisc);
397         if (ret < 0) {
398                 err("Set ioctl failed [%s]\n", strerror(errno));
399                 return -1;
400         }
401
402         ret = ioctl(fd, TIOCGETD, &ldisc);
403         if (ret < 0) {
404                 err("Get ioctl failed [%s]\n", strerror(errno));
405                 return -1;
406         }
407
408         if (ldisc != N_GSM0710) {
409                 err("Unable to set line discipline\n");
410                 return -1;
411         }
412
413         /* configure mux */
414         memset(&cfg, 0, sizeof(struct gsm_config));
415
416         ret = ioctl(fd, GSMIOC_GETCONF, &cfg);
417         if (ret < 0) {
418                 err("Get config ioctl failed [%s]\n", strerror(errno));
419                 return -1;
420         }
421
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 */
426
427         ret = ioctl(fd, GSMIOC_SETCONF, &cfg);
428         if (ret < 0) {
429                 err("Set config ioctl failed [%s]\n", strerror(errno));
430                 return -1;
431         }
432
433         data->dlc_poll_count = 0;
434         data->dlc_poll_src = g_timeout_add_full(G_PRIORITY_HIGH, 250,dlc_ready_check, h, 0);
435
436         return TCORE_RETURN_SUCCESS;
437 }
438
439 static void on_response_setupmux(TcorePending *p, int data_len,
440                                         const void *data, void *user_data)
441 {
442         TcoreHal *hal = user_data;
443         struct custom_data *cdata = tcore_hal_ref_user_data(hal);
444
445         dbg("Entry");
446
447         if (cdata == NULL) {
448                 err("Cannot retrieve Custom DATA from physical HAL");
449                 return;
450         }
451
452         /*
453          * We don't need to exchange data on physical HAL, multiplexer
454          * channels will be used by core objects
455          */
456         if (cdata->watch_id > 0) {
457                 g_source_remove(cdata->watch_id);
458                 cdata->watch_id = 0;
459         }
460
461         /* Setup KERNEL CMUX */
462         if (setup_mux(hal) != TCORE_RETURN_SUCCESS)
463                 err("Failed to initialize CMUX");
464
465         dbg("Exit");
466 }
467
468 static void on_response_poweron(TcorePending *p, int data_len,
469                                         const void *data, void *user_data)
470 {
471         const TcoreATResponse *resp = data;
472         TcoreHal *hal = user_data;
473
474         if (resp->success == 0) {
475                 dbg("RESPONSE NOK");
476                 goto retry;
477         }
478
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);
482
483         dbg("Proceed with mux initialization");
484
485         tcore_cmux_init(hal, 0, on_response_setupmux, hal);
486
487         return;
488
489 retry:
490         if (tcore_hal_set_power(hal, TRUE) != TCORE_RETURN_SUCCESS)
491                 err("Failed to power ON the modem");
492 }
493
494 static TReturn hal_power(TcoreHal *hal, gboolean flag)
495 {
496         struct custom_data *cdata = tcore_hal_ref_user_data(hal);
497         Server *server;
498
499         dbg("Entry");
500
501         if (cdata == NULL) {
502                 err("Cannot retrieve Custom DATA from physical HAL");
503                 return TCORE_RETURN_FAILURE;
504         }
505
506         server = tcore_plugin_ref_server(cdata->plugin);
507         tcore_hal_set_power_state(hal, flag);
508
509         if (flag == TRUE) {
510                 tcore_server_register_modem(server, cdata->plugin);
511
512                 return prepare_and_send_at_request(NULL, hal,
513                                                 "AT+CPAS",
514                                                 "+CPAS", TCORE_AT_SINGLELINE,
515                                                 on_response_poweron, hal);
516         } else {
517                 remove_logical_hals(hal);
518
519                 tcore_server_unregister_modem(server, cdata->plugin);
520
521                 dbg("Phone Power Off success.");
522         }
523
524         return TCORE_RETURN_SUCCESS;
525 }
526
527
528 static TReturn hal_send(TcoreHal *hal, unsigned int data_len, void *data)
529 {
530         size_t bytes_written;
531         struct custom_data *cdata;
532
533         if (tcore_hal_get_power_state(hal) == FALSE)
534                 return TCORE_RETURN_FAILURE;
535
536         cdata = tcore_hal_ref_user_data(hal);
537         if (cdata == NULL) {
538                 err("Cannot retrive custom data for hal %s",
539                                 tcore_hal_get_name(hal));
540                 return TCORE_RETURN_FAILURE;
541         }
542
543         bytes_written = channel_write(cdata->channel, data, data_len);
544         if (bytes_written != data_len) {
545                 err("channel_write failed");
546
547                 return TCORE_RETURN_FAILURE;
548         }
549
550         dbg("channel_write success (channel=%p, len=%d)", cdata->channel, bytes_written);
551
552         return TCORE_RETURN_SUCCESS;
553 }
554
555 static const char *setup_rawip(GIOChannel *channel)
556 {
557         struct gsm_netconfig netconfig;
558         int index;
559         char *interface;
560         char ifname[IFNAMSIZ];
561         int fd;
562
563         dbg("Entry");
564
565         memset(&netconfig, 0, sizeof(struct gsm_netconfig));
566
567         netconfig.adaption = 3;
568         netconfig.protocol = htons(ETH_P_IP);
569
570         fd = g_io_channel_unix_get_fd(channel);
571         if (fd < 0)
572                 return NULL;
573
574         index = ioctl(fd, GSMIOC_ENABLE_NET, &netconfig);
575         if (index < 0) {
576                 err("Set ioctl to create network failed [%s]\n", strerror(errno));
577                 return NULL;
578         }
579
580         dbg("Net interface index: %d", index);
581
582         interface = if_indextoname(index, ifname);
583         if (interface == NULL) {
584                 err("Interface index %d error %s", index, strerror(errno));
585                 return NULL;
586         }
587
588         dbg("Interface name: %s", interface);
589
590         return interface;
591 }
592
593 static void on_response_setup_pdp(TcorePending *p, int data_len, const void *data, void *user_data)
594 {
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;
601
602         dbg("Entry");
603
604         if (resp->success == 0) {
605                 dbg("Response NOk");
606                 if (func != NULL)
607                         func(co, -1, interface, cdata->cb_data);
608
609                 return;
610         }
611
612         dbg("Response Ok");
613
614         interface = setup_rawip(cdata->channel);
615         cdata->rawip_enabled = TRUE;
616
617         if (func != NULL)
618                 func(co, 0, interface, cdata->cb_data);
619 }
620
621 static gboolean disable_pdp_context(gpointer user_data)
622 {
623         TcoreHal *hal = user_data;
624         struct custom_data *cdata = tcore_hal_ref_user_data(hal);
625         TcoreHalSetupNetifCallback func;
626         gint fd;
627
628         func = (TcoreHalSetupNetifCallback)cdata->cb;
629
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]",
633                         strerror(errno));
634                 if (func != NULL)
635                         func(cdata->co, -1, NULL, cdata->cb_data);
636
637                 return FALSE;
638         }
639
640         cdata->rawip_enabled = FALSE;
641
642         if (func != NULL)
643                 func(cdata->co, 0, NULL, cdata->cb_data);
644
645         return FALSE;
646 }
647
648 static TReturn hal_setup_netif(CoreObject *co, TcoreHalSetupNetifCallback func,
649                                 void *user_data, unsigned int cid,
650                                 gboolean enable)
651 {
652         TcoreHal *hal = tcore_object_get_hal(co);
653         TcoreHal *data_hal;
654         char *cmd_str;
655         struct custom_data *cdata = tcore_hal_ref_user_data(hal);
656         TReturn ret;
657
658         dbg("Entry");
659
660         if (cdata == NULL) {
661                 err("No custom data on PS HAL");
662                 return TCORE_RETURN_FAILURE;
663         }
664
665         if (cid == 1)
666                 data_hal =  cdata->data_hal[0];
667         else if (cid == 2)
668                 data_hal = cdata->data_hal[1];
669         else {
670                 err("Invalid CID %d", cid);
671                 return TCORE_RETURN_EINVAL;
672         }
673
674         if (data_hal == NULL) {
675                 err("Fail to get channel data");
676                 return TCORE_RETURN_FAILURE;
677         }
678
679         cdata = tcore_hal_ref_user_data(data_hal);
680         if (cdata == NULL) {
681                 err("No custom data on DATA HAL");
682                 return TCORE_RETURN_FAILURE;
683         }
684
685         if ((enable == FALSE) && (cdata->rawip_enabled == FALSE)) {
686                 err("PDP context %d already disabled", cid);
687                 return TCORE_RETURN_SUCCESS;
688         }
689
690         cdata->cb = (void *)func;
691         cdata->cb_data = user_data;
692
693         if (enable == FALSE) {
694                 cdata->co = co;
695                 g_idle_add(disable_pdp_context, data_hal);
696                 return TCORE_RETURN_SUCCESS;
697         }
698
699         cmd_str = g_strdup_printf("AT+CGDATA=\"M-RAW_IP\",%d", cid);
700
701         ret = prepare_and_send_at_request(co, data_hal, cmd_str, NULL,
702                                                 TCORE_AT_NO_RESULT,
703                                                 on_response_setup_pdp, data_hal);
704
705         g_free(cmd_str);
706
707         return ret;
708 }
709
710 static gboolean on_load()
711 {
712         dbg("I'm load!");
713
714         return TRUE;
715 }
716
717 static gboolean on_init(TcorePlugin *plugin)
718 {
719         TcoreHal *hal;
720         struct custom_data *data;
721
722         if (!plugin)
723                 return FALSE;
724
725         dbg("I'm init!");
726
727         /* Phonet init */
728         data = g_try_new0(struct custom_data, 1);
729         if (data == NULL) {
730                 err("Memory failure");
731                 return FALSE;
732         }
733
734         data->plugin = plugin;
735
736         data->channel = tty_open(DEVICE_IFX);
737         if (data->channel == NULL) {
738                 err("Failed to open tty port - [%s]", strerror(errno));
739                 g_free(data);
740                 return FALSE;
741         }
742
743         dbg("tty port (%s) opened successfully", DEVICE_IFX);
744
745         /* HAL init */
746         hal = tcore_hal_new(plugin, "mfld-blackbay", &hops, TCORE_HAL_MODE_AT);
747         if (hal == NULL){
748                 err("Failed to create HAL");
749                 g_free(data);
750                 return FALSE;
751         }
752
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 ");
757                 g_free(data);
758                 tcore_hal_free(hal);
759                 g_io_channel_unref(data->channel);
760                 return FALSE;
761         }
762
763         tcore_hal_link_user_data(hal, data);
764
765         dbg("HAL is mfld-blackbay: channel = %p, watch_id=%d ", data->channel, data->watch_id);
766
767         if (tcore_hal_set_power(hal, TRUE) != TCORE_RETURN_SUCCESS) {
768                 err("Failed to power ON the modem");
769                 return FALSE;
770         }
771
772         return TRUE;
773 }
774
775 static void on_unload(TcorePlugin *plugin)
776 {
777         TcoreHal *hal;
778         struct custom_data *cdata;
779
780         if (!plugin)
781                 return;
782
783         hal = tcore_plugin_ref_user_data(plugin);
784         if (hal == NULL)
785                 return;
786
787         cdata = tcore_hal_ref_user_data(hal);
788         if (cdata == NULL)
789                 return;
790
791         g_io_channel_unref(cdata->channel);
792         g_free(cdata);
793
794         tcore_hal_set_power(hal, FALSE);
795         tcore_hal_free(hal);
796
797         dbg("I'm unload");
798 }
799
800 struct tcore_plugin_define_desc plugin_define_desc =
801 {
802         .name = "mfld_blackbay",
803         .priority = TCORE_PLUGIN_PRIORITY_HIGH,
804         .version = 1,
805         .load = on_load,
806         .init = on_init,
807         .unload = on_unload
808 };