1/*
2 *  User Mode Init manager - For TI shared transport
3 *
4 *  This program is free software; you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation; either version 2 of the License, or
7 *  (at your option) any later version.
8 *
9 *  This program is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with this program;if not, write to the Free Software
16 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18#include <stdio.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <string.h>
22#include <signal.h>
23#include <sys/ioctl.h>
24#include <termios.h>
25#include <poll.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <sys/stat.h>
29#include <sys/utsname.h>
30#ifdef ANDROID
31#include <private/android_filesystem_config.h>
32#include <cutils/log.h>
33#endif
34
35#ifdef ANDROID
36#include <common/ppoll.h> /* for ppoll */
37#endif
38#include "uim.h"
39
40#ifndef ANDROID
41#define INCLUDE_FM 0
42#endif
43
44/* Maintains the exit state of UIM*/
45static int exiting;
46
47/* UART configuration parameters*/
48int uart_flow_control;
49int cust_baud_rate;
50char uart_dev_name[15];
51unsigned int uart_baud_rate;
52struct termios ti;
53int line_discipline;
54
55/* BD address as string and a pointer to array of hex bytes */
56char uim_bd_address[17];
57bdaddr_t *bd_addr;
58
59/* File descriptor for the UART device*/
60int dev_fd;
61
62/* Maintains the state of N_TI_WL line discipline installation*/
63unsigned char st_state = UNINSTALL_N_TI_WL;
64unsigned char prev_st_state = UNINSTALL_N_TI_WL;
65
66/* from kernel's include/linux/rfkill.h
67 * the header in itself not included because of the
68 * version mismatch of android kernel headers project
69 */
70
71/**
72 * enum rfkill_operation - operation types
73 * @RFKILL_OP_ADD: a device was added
74 * @RFKILL_OP_DEL: a device was removed
75 * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device
76 * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all)
77 */
78enum rfkill_operation {
79    RFKILL_OP_ADD = 0,
80    RFKILL_OP_DEL,
81    RFKILL_OP_CHANGE,
82    RFKILL_OP_CHANGE_ALL,
83};
84
85/**
86 * struct rfkill_event - events for userspace on /dev/rfkill
87 * @idx: index of dev rfkill
88 * @type: type of the rfkill struct
89 * @op: operation code
90 * @hard: hard state (0/1)
91 * @soft: soft state (0/1)
92 *
93 * Structure used for userspace communication on /dev/rfkill,
94 * used for events from the kernel and control to the kernel.
95 */
96#ifdef ANDROID
97struct rfkill_event {
98    __u32 idx;
99    __u8  type;
100    __u8  op;
101    __u8  soft, hard;
102} __packed;
103#else
104struct rfkill_event {
105    uint32_t idx;
106    uint8_t  type;
107    uint8_t  op;
108    uint8_t  soft, hard;
109} __packed;
110#endif /* ANDROID */
111
112/* to read events and filter notifications for us */
113struct rfkill_event rf_event;
114unsigned int   rfkill_idx;
115
116/*****************************************************************************/
117#ifdef UIM_DEBUG
118/*  Function to Read the firmware version
119 *  module into the system. Currently used for
120 *  debugging purpose, whenever the baud rate is changed
121 */
122void read_firmware_version()
123{
124    int index = 0;
125    char resp_buffer[20] = { 0 };
126    unsigned char buffer[] = { 0x01, 0x01, 0x10, 0x00 };
127
128    UIM_START_FUNC();
129    UIM_VER(" wrote %d bytes", (int)write(dev_fd, buffer, 4));
130    UIM_VER(" reading %d bytes", (int)read(dev_fd, resp_buffer, 15));
131
132    for (index = 0; index < 15; index++) {
133        UIM_VER(" %x ", resp_buffer[index]);
134    }
135
136    printf("\n");
137}
138#endif
139
140/*****************************************************************************/
141#ifdef ANDROID                 /* library for android to do insmod/rmmod  */
142
143/* Function to insert the kernel module into the system*/
144static int insmod(const char *filename, const char *args)
145{
146    void *module;
147    unsigned int size;
148    int ret = -1;
149
150    UIM_START_FUNC();
151
152    module = (void *)load_file(filename, &size);
153    if (!module) {
154        return ret;
155    }
156
157    ret = init_module(module, size, args);
158    free(module);
159
160    return ret;
161}
162
163/* Function to remove the kernel module from the system*/
164static int rmmod(const char *modname)
165{
166    int ret = -1;
167    int maxtry = MAX_TRY;
168
169    UIM_START_FUNC();
170
171    /* Retry MAX_TRY number of times in case of
172     * failure
173     */
174    while (maxtry-- > 0) {
175        ret = delete_module(modname, O_NONBLOCK | O_EXCL);
176        if (ret < 0 && errno == EAGAIN) {
177            sleep(1);
178        }
179        else
180            break;
181    }
182
183    /* Failed to remove the module
184    */
185    if (ret != 0) {
186        UIM_ERR("Unable to unload driver module \"%s\": %s",
187                modname, strerror(errno));
188    }
189    return ret;
190}
191#endif /*ANDROID*/
192
193/*****************************************************************************/
194/* Function to read the HCI event from the given file descriptor
195 *
196 * This will parse the response received and returns error
197 * if the required response is not received
198 */
199int read_hci_event(int fd, unsigned char *buf, int size)
200{
201    int remain, rd;
202    int count = 0;
203    int reading = 1;
204    int rd_retry_count = 0;
205    struct timespec tm = {0, 50*1000*1000};
206
207    UIM_START_FUNC();
208
209    UIM_VER(" read_hci_event");
210    if (size <= 0) {
211        return -1;
212    }
213
214    /* The first byte identifies the packet type. For HCI event packets, it
215     * should be 0x04, so we read until we get to the 0x04. */
216    while (reading) {
217        rd = read(fd, buf, 1);
218        if (rd <= 0 && rd_retry_count++ < 4) {
219            nanosleep(&tm, NULL);
220            continue;
221        } else if (rd_retry_count >= 4) {
222            return -1;
223        }
224
225        if (buf[0] == RESP_PREFIX) {
226            break;
227        }
228    }
229    count++;
230
231    /* The next two bytes are the event code and parameter total length. */
232    while (count < 3) {
233        rd = read(fd, buf + count, 3 - count);
234        if (rd <= 0) {
235            return -1;
236        }
237        count += rd;
238    }
239
240    /* Now we read the parameters. */
241    if (buf[2] < (size - 3)) {
242        remain = buf[2];
243    } else {
244        remain = size - 3;
245    }
246
247    while ((count - 3) < remain) {
248        rd = read(fd, buf + count, remain - (count - 3));
249        if (rd <= 0) {
250            return -1;
251        }
252        count += rd;
253    }
254
255    return count;
256}
257
258/* Function to read the Command complete event
259 *
260 * This will read the response for the change speed
261 * command that was sent to configure the UART speed
262 * with the custom baud rate
263 */
264static int read_command_complete(int fd, unsigned short opcode)
265{
266    command_complete_t resp;
267
268    UIM_START_FUNC();
269
270    UIM_VER(" Command complete started");
271    if (read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0) {
272        UIM_ERR(" Invalid response");
273        return -1;
274    }
275
276    /* Response should be an event packet */
277    if (resp.uart_prefix != HCI_EVENT_PKT) {
278        UIM_ERR
279            (" Error in response: not an event packet, but 0x%02x!",
280             resp.uart_prefix);
281        return -1;
282    }
283
284    /* Response should be a command complete event */
285    if (resp.hci_hdr.evt != EVT_CMD_COMPLETE) {
286        /* event must be event-complete */
287        UIM_ERR
288            (" Error in response: not a cmd-complete event,but 0x%02x!",
289             resp.hci_hdr.evt);
290        return -1;
291    }
292
293    if (resp.hci_hdr.plen < 4) {
294        /* plen >= 4 for EVT_CMD_COMPLETE */
295        UIM_ERR(" Error in response: plen is not >= 4, but 0x%02x!",
296                resp.hci_hdr.plen);
297        return -1;
298    }
299
300    if (resp.cmd_complete.opcode != (unsigned short)opcode) {
301        UIM_ERR(" Error in response: opcode is 0x%04x, not 0x%04x!",
302                resp.cmd_complete.opcode, opcode);
303        return -1;
304    }
305
306    UIM_DBG(" Command complete done");
307    return resp.status == 0 ? 0 : -1;
308}
309
310/* Function to set the default baud rate
311 *
312 * The default baud rate of 115200 is set to the UART from the host side
313 * by making a call to this function.This function is also called before
314 * making a call to set the custom baud rate
315 */
316static int set_baud_rate()
317{
318    UIM_START_FUNC();
319
320    tcflush(dev_fd, TCIOFLUSH);
321
322    /* Get the attributes of UART */
323    if (tcgetattr(dev_fd, &ti) < 0) {
324        UIM_ERR(" Can't get port settings");
325        return -1;
326    }
327
328    /* Change the UART attributes before
329     * setting the default baud rate*/
330    cfmakeraw(&ti);
331
332    ti.c_cflag |= 1;
333    ti.c_cflag |= CRTSCTS;
334
335    /* Set the attributes of UART after making
336     * the above changes
337     */
338    tcsetattr(dev_fd, TCSANOW, &ti);
339
340    /* Set the actual default baud rate */
341    cfsetospeed(&ti, B115200);
342    cfsetispeed(&ti, B115200);
343    tcsetattr(dev_fd, TCSANOW, &ti);
344
345    tcflush(dev_fd, TCIOFLUSH);
346    UIM_DBG(" set_baud_rate() done");
347
348    return 0;
349}
350
351/* Function to set the UART custom baud rate.
352 *
353 * The UART baud rate has already been
354 * set to default value 115200 before calling this function.
355 * The baud rate is then changed to custom baud rate by this function*/
356static int set_custom_baud_rate()
357{
358    UIM_START_FUNC();
359
360    struct termios2 ti2;
361
362    UIM_VER(" Changing baud rate to %u, flow control to %u",
363            cust_baud_rate, uart_flow_control);
364
365    /* Flush non-transmitted output data,
366     * non-read input data or both*/
367    tcflush(dev_fd, TCIOFLUSH);
368
369    /*Set the UART flow control */
370    if (uart_flow_control) {
371        ti.c_cflag |= CRTSCTS;
372    } else {
373        ti.c_cflag &= ~CRTSCTS;
374    }
375
376    /*
377     * Set the parameters associated with the UART
378     * The change will occur immediately by using TCSANOW
379     */
380    if (tcsetattr(dev_fd, TCSANOW, &ti) < 0) {
381        UIM_ERR(" Can't set port settings");
382        return -1;
383    }
384
385    tcflush(dev_fd, TCIOFLUSH);
386
387    /*Set the actual baud rate */
388    ioctl(dev_fd, TCGETS2, &ti2);
389    ti2.c_cflag &= ~CBAUD;
390    ti2.c_cflag |= BOTHER;
391    ti2.c_ospeed = cust_baud_rate;
392    ioctl(dev_fd, TCSETS2, &ti2);
393
394    UIM_DBG(" set_custom_baud_rate() done");
395    return 0;
396}
397
398/*
399 * Handling the Signals sent from the Kernel Init Manager.
400 * After receiving the signals, configure the baud rate, flow
401 * control and Install the N_TI_WL line discipline
402 */
403int st_sig_handler(int signo)
404{
405    int ldisc, len;
406    uim_speed_change_cmd cmd;
407
408    uim_bdaddr_change_cmd addr_cmd;
409
410    UIM_START_FUNC();
411
412    /* Raise a signal after when UIM is killed.
413     * This will exit UIM, and remove the inserted kernel
414     * modules
415     */
416    if (signo == SIGINT) {
417        UIM_DBG(" Exiting. . .");
418        exiting = 1;
419        return -1;
420    }
421
422    /* Install the line discipline when the signal is received by UIM.
423     * Whenever the first protocol tries to register with the ST core, the
424     * ST KIM will send a signal SIGUSR2 to the UIM to install the N_TI_WL
425     * line discipline and do the host side UART configurations.
426     *
427     * On failure, ST KIM's line discipline installation times out, and the
428     * relevant protocol register fails
429     */
430    if (st_state == INSTALL_N_TI_WL) {
431        UIM_VER(" signal received, opening %s", uart_dev_name);
432        dev_fd = open(uart_dev_name, O_RDWR);
433        if (dev_fd < 0) {
434            UIM_ERR(" Can't open %s", uart_dev_name);
435            return -1;
436        }
437        /*
438         * Set only the default baud rate.
439         * This will set the baud rate to default 115200
440         */
441        if (set_baud_rate() < 0) {
442            UIM_ERR(" set_baudrate() failed");
443            close(dev_fd);
444            return -1;
445        }
446
447        fcntl(dev_fd, F_SETFL,fcntl(dev_fd, F_GETFL) | O_NONBLOCK);
448        /* Set only thecustom baud rate */
449        if (cust_baud_rate) {
450
451            /* Forming the packet for Change speed command */
452            cmd.uart_prefix = HCI_COMMAND_PKT;
453            cmd.hci_hdr.opcode = HCI_HDR_OPCODE;
454            cmd.hci_hdr.plen = sizeof(unsigned long);
455            cmd.speed = cust_baud_rate;
456
457            /* Writing the change speed command to the UART
458             * This will change the UART speed at the controller
459             * side
460             */
461            UIM_VER(" Setting speed to %d", cust_baud_rate);
462            len = write(dev_fd, &cmd, sizeof(cmd));
463            if (len < 0) {
464                UIM_ERR(" Failed to write speed-set command");
465                close(dev_fd);
466                return -1;
467            }
468
469            /* Read the response for the Change speed command */
470            if (read_command_complete(dev_fd, HCI_HDR_OPCODE) < 0) {
471                close(dev_fd);
472                return -1;
473            }
474
475            UIM_VER(" Speed changed to %d", cust_baud_rate);
476
477            /* Set the actual custom baud rate at the host side */
478            if (set_custom_baud_rate() < 0) {
479                UIM_ERR(" set_custom_baud_rate() failed");
480                close(dev_fd);
481
482                return -1;
483            }
484
485            /* Set the uim BD address */
486            if (uim_bd_address[0] != 0) {
487
488                memset(&addr_cmd, 0, sizeof(addr_cmd));
489                /* Forming the packet for change BD address command*/
490                addr_cmd.uart_prefix = HCI_COMMAND_PKT;
491                addr_cmd.hci_hdr.opcode = WRITE_BD_ADDR_OPCODE;
492                addr_cmd.hci_hdr.plen = sizeof(bdaddr_t);
493                memcpy(&addr_cmd.addr, bd_addr, sizeof(bdaddr_t));
494
495                /* Writing the change BD address command to the UART
496                 * This will change the change BD address  at the controller
497                 * side
498                 */
499                len = write(dev_fd, &addr_cmd, sizeof(addr_cmd));
500                if (len < 0) {
501                    UIM_ERR(" Failed to write BD address command");
502                    close(dev_fd);
503                    return -1;
504                }
505
506                /* Read the response for the change BD address command */
507                if (read_command_complete(dev_fd, WRITE_BD_ADDR_OPCODE) < 0) {
508                    close(dev_fd);
509                    return -1;
510                }
511
512                UIM_VER(" BD address changed to %s", uim_bd_address);
513            }
514#ifdef UIM_DEBUG
515            read_firmware_version();
516#endif
517        }
518
519        /* After the UART speed has been changed, the IOCTL is
520         * is called to set the line discipline to N_TI_WL
521         */
522        ldisc = line_discipline;
523        if (ioctl(dev_fd, TIOCSETD, &ldisc) < 0) {
524            UIM_ERR(" Can't set line discipline");
525            close(dev_fd);
526            return -1;
527        }
528
529        UIM_DBG(" Installed N_TI_WL Line displine");
530    }
531    else {
532        UIM_DBG(" Un-Installed N_TI_WL Line displine");
533        /* UNINSTALL_N_TI_WL - When the Signal is received from KIM */
534        /* closing UART fd */
535        close(dev_fd);
536    }
537    prev_st_state = st_state;
538    return 0;
539}
540int remove_modules()
541{
542    int err = 0;
543
544#ifdef ANDROID
545    UIM_VER(" Removing gps_drv ");
546    if (rmmod("gps_drv") != 0) {
547        UIM_ERR(" Error removing gps_drv module");
548        err = -1;
549    } else {
550        UIM_DBG(" Removed gps_drv module");
551    }
552
553    UIM_VER(" Removing fm_drv ");
554    if (rmmod("fm_drv") != 0) {
555        UIM_ERR(" Error removing fm_drv module");
556        err = -1;
557    } else {
558        UIM_DBG(" Removed fm_drv module");
559    }
560    UIM_DBG(" Removed fm_drv module");
561
562    UIM_VER(" Removing bt_drv ");
563
564    if (rmmod("bt_drv") != 0) {
565        UIM_ERR(" Error removing bt_drv module");
566        err = -1;
567    } else {
568        UIM_DBG(" Removed bt_drv module");
569    }
570    UIM_DBG(" Removed bt_drv module");
571
572    /*Remove the Shared Transport */
573    UIM_VER(" Removing st_drv ");
574
575    if (rmmod("st_drv") != 0) {
576        UIM_ERR(" Error removing st_drv module");
577        err = -1;
578    } else {
579        UIM_DBG(" Removed st_drv module ");
580    }
581    UIM_DBG(" Removed st_drv module ");
582#else
583#if INCLUDE_FM
584    UIM_VER(" Removing fm_drv ");
585    if (system("rmmod fm_drv") != 0) {
586        UIM_ERR(" Error removing fm_drv module");
587        err = -1;
588    } else {
589        UIM_DBG(" Removed fm_drv module");
590    }
591#endif /* INCLUDE_FM */
592    UIM_VER(" Removing bt_drv ");
593    if (system("rmmod bt_drv") != 0) {
594        UIM_ERR(" Error removing bt_drv module");
595        err = -1;
596    } else {
597        UIM_DBG(" Removed bt_drv module");
598    }
599
600    /*Remove the Shared Transport */
601    UIM_VER(" Removing st_drv ");
602
603    if (system("rmmod st_drv") != 0) {
604        UIM_ERR(" Error removing st_drv module");
605        err = -1;
606    } else {
607        UIM_DBG(" Removed st_drv module ");
608    }
609#endif
610    return err;
611}
612
613int change_rfkill_perms(void)
614{
615    int fd, id, sz;
616    char path[64];
617    char buf[16];
618    for (id = 0; id < 50; id++) {
619        snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
620        fd = open(path, O_RDONLY);
621        if (fd < 0) {
622            UIM_DBG("open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
623            continue;
624        }
625        sz = read(fd, &buf, sizeof(buf));
626        close(fd);
627        if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) {
628            UIM_DBG("found bluetooth rfkill entry @ %d\n", id);
629            rfkill_idx = id;
630            break;
631        }
632    }
633    if (id == 50) {
634        return -1;
635    }
636#ifdef ANDROID
637    sprintf(path, "/sys/class/rfkill/rfkill%d/state", id);
638    sz = chown(path, AID_BLUETOOTH, AID_BLUETOOTH);
639    if (sz < 0) {
640        UIM_ERR("change mode failed for %s (%d)\n", path, errno);
641        return -1;
642    }
643#endif /* ANDROID */
644    /*
645     * bluetooth group's user system needs write permission
646     */
647    sz = chmod(path, 0660);
648    if (sz < 0) {
649        UIM_ERR("change mode failed for %s (%d)\n", path, errno);
650        return -1;
651    }
652    UIM_DBG("changed permissions for %s(%d) \n", path, sz);
653    /* end of change_perms */
654
655    return 0;
656}
657
658void *bt_malloc(size_t size)
659{
660    return malloc(size);
661}
662
663/* Function to convert the BD address from ascii to hex value */
664bdaddr_t *strtoba(const char *str)
665{
666    const char *ptr = str;
667    int i;
668
669    uint8_t *ba = bt_malloc(sizeof(bdaddr_t));
670    if (!ba) {
671        return NULL;
672    }
673
674    for (i = 0; i < 6; i++) {
675        ba[i] = (uint8_t) strtol(ptr, NULL, 16);
676        if (i != 5 && !(ptr = strchr(ptr, ':'))) {
677            ptr = ":00:00:00:00:00";
678        }
679        ptr++;
680    }
681
682    return (bdaddr_t *) ba;
683}
684
685/*****************************************************************************/
686int main(int argc, char *argv[])
687{
688    int st_fd,err;
689    struct stat file_stat;
690#ifndef ANDROID        /* used on ubuntu */
691    char *tist_ko_path;
692    struct utsname name;
693#endif
694    struct pollfd   p;
695    sigset_t        sigs;
696
697    UIM_START_FUNC();
698    err = 0;
699
700    /* Parse the user input */
701    if ((argc == 5) || (argc == 6)) {
702        strcpy(uart_dev_name, argv[1]);
703        uart_baud_rate = atoi(argv[2]);
704        uart_flow_control = atoi(argv[3]);
705        line_discipline = atoi(argv[4]);
706
707        /* Depending upon the baud rate value, differentiate
708         * the custom baud rate and default baud rate
709         */
710        switch (uart_baud_rate) {
711            case 115200:
712                UIM_VER(" Baudrate 115200");
713                break;
714            case 9600:
715            case 19200:
716            case 38400:
717            case 57600:
718            case 230400:
719            case 460800:
720            case 500000:
721            case 576000:
722            case 921600:
723            case 1000000:
724            case 1152000:
725            case 1500000:
726            case 2000000:
727            case 2500000:
728            case 3000000:
729            case 3500000:
730            case 3686400:
731            case 4000000:
732                cust_baud_rate = uart_baud_rate;
733                UIM_VER(" Baudrate %d", cust_baud_rate);
734                break;
735            default:
736                UIM_ERR(" Inavalid Baud Rate");
737                break;
738        }
739
740        memset(&uim_bd_address, 0, sizeof(uim_bd_address));
741    } else {
742        UIM_ERR(" Invalid arguements");
743        UIM_ERR(" Usage: uim [Uart device] [Baud rate] [Flow control] [Line discipline] <bd address>");
744        return -1;
745    }
746    if (argc == 6) {
747        /* BD address passed as string in xx:xx:xx:xx:xx:xx format */
748        strcpy(uim_bd_address, argv[5]);
749        bd_addr = strtoba(uim_bd_address);
750    }
751
752
753#ifndef ANDROID
754    if (uname (&name) == -1) {
755        UIM_ERR("cannot get kernel release name");
756        return -1;
757    }
758#else  /* if ANDROID */
759
760    if (0 == lstat("/st_drv.ko", &file_stat)) {
761        if (insmod("/st_drv.ko", "") < 0) {
762            UIM_ERR(" Error inserting st_drv module");
763            return -1;
764        } else {
765            UIM_DBG(" Inserted st_drv module");
766        }
767    } else {
768        if (0 == lstat("/dev/rfkill", &file_stat)) {
769            UIM_DBG("ST built into the kernel ?");
770        } else {
771            UIM_ERR("BT/FM/GPS would be unavailable on system");
772            UIM_ERR(" rfkill device '/dev/rfkill' not found ");
773            return -1;
774        }
775    }
776#endif
777
778#ifndef ANDROID
779    /*-- Insmod of ST driver --*/
780    asprintf(&tist_ko_path,
781            "/lib/modules/%s/kernel/drivers/misc/ti-st/st_drv.ko",name.release);
782    if (0 == lstat(tist_ko_path, &file_stat)) {
783        if (system("insmod /lib/modules/`uname -r`/kernel/drivers/misc/ti-st/st_drv.ko") != 0) {
784            UIM_ERR(" Error inserting st_drv module");
785            free(tist_ko_path);
786            return -1;
787        } else {
788            UIM_DBG(" Inserted st_drv module");
789        }
790    } else {
791        UIM_ERR("ST driver built into the kernel ?");
792    }
793    free(tist_ko_path);
794#endif
795
796    if (change_rfkill_perms() < 0) {
797        /* possible error condition */
798        UIM_ERR("rfkill not enabled in st_drv - BT on from UI might fail\n");
799    }
800
801#ifndef ANDROID
802    /*-- Insmod of BT driver --*/
803    asprintf(&tist_ko_path,
804            "/lib/modules/%s/kernel/drivers/staging/ti-st/bt_drv.ko",name.release);
805    if (0 == lstat(tist_ko_path, &file_stat)) {
806        if (system("insmod /lib/modules/`uname -r`/kernel/drivers/staging/ti-st/bt_drv.ko") != 0) {
807            UIM_ERR(" Error inserting bt_drv module");
808            system("rmmod st_drv");
809            free(tist_ko_path);
810            return -1;
811        } else {
812            UIM_DBG(" Inserted bt_drv module");
813        }
814    } else {
815        UIM_ERR("BT driver built into the kernel ?");
816    }
817    free(tist_ko_path);
818
819#if INCLUDE_FM
820    /*-- Insmod of FM driver --*/
821    asprintf(&tist_ko_path,
822            "/lib/modules/%s/kernel/drivers/staging/ti-st/fm_drv.ko",name.release);
823    if (0 == lstat(tist_ko_path, &file_stat)) {
824        if (system("insmod /lib/modules/`uname -r`/kernel/drivers/staging/ti-st/fm_drv.ko") != 0) {
825            UIM_ERR(" Error inserting fm_drv module");
826            system("rmmod bt_drv");
827            system("rmmod st_drv");
828            free(tist_ko_path);
829            return -1;
830        } else {
831            UIM_DBG(" Inserted fm_drv module");
832        }
833    } else {
834        UIM_ERR("FM driver built into the kernel ?");
835    }
836    free(tist_ko_path);
837#endif /* INCLUDE_FM */
838#else  /* if ANDROID */
839    if (0 == lstat("/bt_drv.ko", &file_stat)) {
840        if (insmod("/bt_drv.ko", "") < 0) {
841            UIM_ERR(" Error inserting bt_drv module, NO BT? ");
842        } else {
843            UIM_DBG(" Inserted bt_drv module");
844        }
845    } else {
846        UIM_DBG("BT driver module un-available... ");
847        UIM_DBG("BT driver built into the kernel ?");
848    }
849
850    if (0 == lstat("/fm_drv.ko", &file_stat)) {
851        if (insmod("/fm_drv.ko", "") < 0) {
852            UIM_ERR(" Error inserting fm_drv module, NO FM? ");
853        } else {
854            UIM_DBG(" Inserted fm_drv module");
855        }
856    } else {
857        UIM_DBG("FM driver module un-available... ");
858        UIM_DBG("FM driver built into the kernel ?");
859    }
860
861    if (0 == lstat("/gps_drv.ko", &file_stat)) {
862        if (insmod("/gps_drv.ko", "") < 0) {
863            UIM_ERR(" Error inserting gps_drv module, NO GPS? ");
864        } else {
865            UIM_DBG(" Inserted gps_drv module");
866        }
867    } else {
868        UIM_DBG("GPS driver module un-available... ");
869        UIM_DBG("GPS driver built into the kernel ?");
870    }
871
872    if (chmod("/dev/tifm", 0666) < 0) {
873        UIM_ERR("unable to chmod /dev/tifm");
874    }
875#endif
876    /* rfkill device's open/poll/read */
877    st_fd = open("/dev/rfkill", O_RDONLY);
878    if (st_fd < 0) {
879        UIM_DBG("unable to open /dev/rfkill (%s)", strerror(errno));
880        remove_modules();
881        return -1;
882    }
883
884
885    p.fd = st_fd;
886    p.events = POLLERR | POLLHUP | POLLOUT | POLLIN;
887
888    sigfillset(&sigs);
889    sigdelset(&sigs, SIGCHLD);
890    sigdelset(&sigs, SIGPIPE);
891    sigdelset(&sigs, SIGTERM);
892    sigdelset(&sigs, SIGINT);
893    sigdelset(&sigs, SIGHUP);
894
895RE_POLL:
896    while (!exiting) {
897        p.revents = 0;
898#ifdef ANDROID
899        err = ppoll(&p, 1, NULL, &sigs);
900#else
901        err = poll(&p, 1, -1);
902#endif /* ANDROID */
903        if (err < 0 && errno == EINTR) {
904            continue;
905        }
906        if (err) {
907            break;
908        }
909    }
910    if (!exiting) {
911        err = read(st_fd, &rf_event, sizeof(rf_event));
912        UIM_DBG("rf_event: %d, %d, %d, %d, %d\n", rf_event.idx,
913                rf_event.type, rf_event.op ,rf_event.hard,
914                rf_event.soft);
915        if ((rf_event.op == RFKILL_OP_CHANGE) &&
916                (rf_event.idx == rfkill_idx)) {
917            if (rf_event.hard == 1) /* hard blocked */ {
918                st_state = UNINSTALL_N_TI_WL;
919            } else    /* unblocked */ {
920                st_state = INSTALL_N_TI_WL;
921            }
922
923            if (prev_st_state != st_state) {
924                st_sig_handler(SIGUSR2);
925            }
926        }
927        goto RE_POLL;
928    }
929
930    if(remove_modules() < 0) {
931        UIM_ERR(" Error removing modules ");
932        close(st_fd);
933        return -1;
934    }
935
936    close(st_fd);
937    return 0;
938}
939