Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /******************************************************************************
     20  *
     21  *  Filename:      userial_mct.c
     22  *
     23  *  Description:   Contains open/read/write/close functions on multi-channels
     24  *
     25  ******************************************************************************/
     26 
     27 #define LOG_TAG "bt_userial_mct"
     28 
     29 #include <utils/Log.h>
     30 #include <pthread.h>
     31 #include <fcntl.h>
     32 #include <errno.h>
     33 #include <stdio.h>
     34 #include <sys/socket.h>
     35 #include "bt_hci_bdroid.h"
     36 #include "userial.h"
     37 #include "utils.h"
     38 #include "bt_vendor_lib.h"
     39 
     40 /******************************************************************************
     41 **  Constants & Macros
     42 ******************************************************************************/
     43 
     44 #define USERIAL_DBG TRUE
     45 
     46 #ifndef USERIAL_DBG
     47 #define USERIAL_DBG FALSE
     48 #endif
     49 
     50 #if (USERIAL_DBG == TRUE)
     51 #define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
     52 #else
     53 #define USERIALDBG(param, ...) {}
     54 #endif
     55 
     56 #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1)
     57 
     58 enum {
     59     USERIAL_RX_EXIT,
     60     USERIAL_RX_FLOW_OFF,
     61     USERIAL_RX_FLOW_ON
     62 };
     63 
     64 /******************************************************************************
     65 **  Externs
     66 ******************************************************************************/
     67 
     68 extern bt_vendor_interface_t *bt_vnd_if;
     69 uint16_t hci_mct_receive_evt_msg(void);
     70 uint16_t hci_mct_receive_acl_msg(void);
     71 
     72 
     73 /******************************************************************************
     74 **  Local type definitions
     75 ******************************************************************************/
     76 
     77 typedef struct
     78 {
     79     int             fd[CH_MAX];
     80     uint8_t         port;
     81     pthread_t       read_thread;
     82     BUFFER_Q        rx_q;
     83     HC_BT_HDR      *p_rx_hdr;
     84 } tUSERIAL_CB;
     85 
     86 /******************************************************************************
     87 **  Static variables
     88 ******************************************************************************/
     89 
     90 static tUSERIAL_CB userial_cb;
     91 static volatile uint8_t userial_running = 0;
     92 
     93 /******************************************************************************
     94 **  Static functions
     95 ******************************************************************************/
     96 
     97 /*****************************************************************************
     98 **   Socket signal functions to wake up userial_read_thread for termination
     99 **
    100 **   creating an unnamed pair of connected sockets
    101 **      - signal_fds[0]: join fd_set in select call of userial_read_thread
    102 **      - signal_fds[1]: trigger from userial_close
    103 *****************************************************************************/
    104 static int signal_fds[2]={0,1};
    105 static uint8_t rx_flow_on = TRUE;
    106 static inline int create_signal_fds(fd_set* set)
    107 {
    108     if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0)
    109     {
    110         ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno);
    111         return -1;
    112     }
    113     FD_SET(signal_fds[0], set);
    114     return signal_fds[0];
    115 }
    116 static inline int send_wakeup_signal(char sig_cmd)
    117 {
    118     return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0);
    119 }
    120 static inline char reset_signal()
    121 {
    122     char sig_recv = -1;
    123     recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL);
    124     return sig_recv;
    125 }
    126 static inline int is_signaled(fd_set* set)
    127 {
    128     return FD_ISSET(signal_fds[0], set);
    129 }
    130 
    131 /*******************************************************************************
    132 **
    133 ** Function        userial_evt_read_thread
    134 **
    135 ** Description     The reading thread on EVT and ACL_IN channels
    136 **
    137 ** Returns         void *
    138 **
    139 *******************************************************************************/
    140 static void *userial_read_thread(void *arg)
    141 {
    142     fd_set input;
    143     int n;
    144     char reason = 0;
    145 
    146     USERIALDBG("Entering userial_read_thread()");
    147 
    148     rx_flow_on = TRUE;
    149     userial_running = 1;
    150 
    151     while (userial_running)
    152     {
    153         /* Initialize the input fd set */
    154         FD_ZERO(&input);
    155         if (rx_flow_on == TRUE)
    156         {
    157             FD_SET(userial_cb.fd[CH_EVT], &input);
    158             FD_SET(userial_cb.fd[CH_ACL_IN], &input);
    159         }
    160 
    161         int fd_max = create_signal_fds(&input);
    162         fd_max = (fd_max>userial_cb.fd[CH_EVT]) ? fd_max : userial_cb.fd[CH_EVT];
    163         fd_max = (fd_max>userial_cb.fd[CH_ACL_IN]) ? fd_max : userial_cb.fd[CH_ACL_IN];
    164 
    165         /* Do the select */
    166         n = 0;
    167         n = select(fd_max+1, &input, NULL, NULL, NULL);
    168         if(is_signaled(&input))
    169         {
    170             reason = reset_signal();
    171             if (reason == USERIAL_RX_EXIT)
    172             {
    173                 ALOGI("exiting userial_read_thread");
    174                 userial_running = 0;
    175                 break;
    176             }
    177             else if (reason == USERIAL_RX_FLOW_OFF)
    178             {
    179                 USERIALDBG("RX flow OFF");
    180                 rx_flow_on = FALSE;
    181             }
    182             else if (reason == USERIAL_RX_FLOW_ON)
    183             {
    184                 USERIALDBG("RX flow ON");
    185                 rx_flow_on = TRUE;
    186             }
    187         }
    188 
    189         if (n > 0)
    190         {
    191             /* We might have input */
    192             if (FD_ISSET(userial_cb.fd[CH_EVT], &input))
    193             {
    194                 hci_mct_receive_evt_msg();
    195             }
    196 
    197             if (FD_ISSET(userial_cb.fd[CH_ACL_IN], &input))
    198             {
    199                 hci_mct_receive_acl_msg();
    200             }
    201         }
    202         else if (n < 0)
    203             ALOGW( "select() Failed");
    204         else if (n == 0)
    205             ALOGW( "Got a select() TIMEOUT");
    206     } /* while */
    207 
    208     userial_running = 0;
    209     USERIALDBG("Leaving userial_evt_read_thread()");
    210     pthread_exit(NULL);
    211 
    212     return NULL;    // Compiler friendly
    213 }
    214 
    215 
    216 /*****************************************************************************
    217 **   Userial API Functions
    218 *****************************************************************************/
    219 
    220 /*******************************************************************************
    221 **
    222 ** Function        userial_init
    223 **
    224 ** Description     Initializes the userial driver
    225 **
    226 ** Returns         TRUE/FALSE
    227 **
    228 *******************************************************************************/
    229 uint8_t userial_init(void)
    230 {
    231     int idx;
    232 
    233     USERIALDBG("userial_init");
    234     memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
    235     for (idx=0; idx < CH_MAX; idx++)
    236         userial_cb.fd[idx] = -1;
    237     utils_queue_init(&(userial_cb.rx_q));
    238     return TRUE;
    239 }
    240 
    241 
    242 /*******************************************************************************
    243 **
    244 ** Function        userial_open
    245 **
    246 ** Description     Open Bluetooth device with the port ID
    247 **
    248 ** Returns         TRUE/FALSE
    249 **
    250 *******************************************************************************/
    251 uint8_t userial_open(uint8_t port)
    252 {
    253     struct sched_param param;
    254     int policy, result;
    255     pthread_attr_t thread_attr;
    256 
    257     USERIALDBG("userial_open(port:%d)", port);
    258 
    259     if (userial_running)
    260     {
    261         /* Userial is open; close it first */
    262         userial_close();
    263         utils_delay(50);
    264     }
    265 
    266     if (port >= MAX_SERIAL_PORT)
    267     {
    268         ALOGE("Port > MAX_SERIAL_PORT");
    269         return FALSE;
    270     }
    271 
    272     /* Calling vendor-specific part */
    273     if (bt_vnd_if)
    274     {
    275         result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &userial_cb.fd);
    276 
    277         if ((result != 2) && (result != 4))
    278         {
    279             ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!",
    280                     result);
    281             ALOGE("userial_open: HCI MCT expects 2 or 4 open file descriptors");
    282             bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
    283             return FALSE;
    284         }
    285     }
    286     else
    287     {
    288         ALOGE("userial_open: missing vendor lib interface !!!");
    289         ALOGE("userial_open: unable to open BT transport");
    290         return FALSE;
    291     }
    292 
    293     ALOGI("CMD=%d, EVT=%d, ACL_Out=%d, ACL_In=%d", \
    294         userial_cb.fd[CH_CMD], userial_cb.fd[CH_EVT], \
    295         userial_cb.fd[CH_ACL_OUT], userial_cb.fd[CH_ACL_IN]);
    296 
    297     if ((userial_cb.fd[CH_CMD] == -1) || (userial_cb.fd[CH_EVT] == -1) ||
    298         (userial_cb.fd[CH_ACL_OUT] == -1) || (userial_cb.fd[CH_ACL_IN] == -1))
    299     {
    300         ALOGE("userial_open: failed to open BT transport");
    301         bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
    302         return FALSE;
    303     }
    304 
    305     userial_cb.port = port;
    306 
    307     /* Start listening thread */
    308     pthread_attr_init(&thread_attr);
    309 
    310     if (pthread_create(&(userial_cb.read_thread), &thread_attr, \
    311                        userial_read_thread, NULL) != 0 )
    312     {
    313         ALOGE("pthread_create failed!");
    314         bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
    315         return FALSE;
    316     }
    317 
    318     if(pthread_getschedparam(userial_cb.read_thread, &policy, &param)==0)
    319     {
    320         policy = BTHC_LINUX_BASE_POLICY;
    321 #if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
    322         param.sched_priority = BTHC_USERIAL_READ_THREAD_PRIORITY;
    323 #endif
    324         result=pthread_setschedparam(userial_cb.read_thread,policy,&param);
    325         if (result != 0)
    326         {
    327             ALOGW("userial_open: pthread_setschedparam failed (%s)", \
    328                   strerror(result));
    329         }
    330     }
    331 
    332     return TRUE;
    333 }
    334 
    335 /*******************************************************************************
    336 **
    337 ** Function        userial_read
    338 **
    339 ** Description     Read data from the userial channel
    340 **
    341 ** Returns         Number of bytes actually read from the userial port and
    342 **                 copied into p_data.  This may be less than len.
    343 **
    344 *******************************************************************************/
    345 uint16_t  userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len)
    346 {
    347     int ret = -1;
    348     int ch_idx = (msg_id == MSG_HC_TO_STACK_HCI_EVT) ? CH_EVT : CH_ACL_IN;
    349 
    350     ret = read(userial_cb.fd[ch_idx], p_buffer, (size_t)len);
    351     if (ret <= 0)
    352         ALOGW( "userial_read: read() returned %d!", ret);
    353 
    354     return (uint16_t) ((ret >= 0) ? ret : 0);
    355 }
    356 
    357 /*******************************************************************************
    358 **
    359 ** Function        userial_write
    360 **
    361 ** Description     Write data to the userial port
    362 **
    363 ** Returns         Number of bytes actually written to the userial port. This
    364 **                 may be less than len.
    365 **
    366 *******************************************************************************/
    367 uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
    368 {
    369     int ret, total = 0;
    370     int ch_idx = (msg_id == MSG_STACK_TO_HC_HCI_CMD) ? CH_CMD : CH_ACL_OUT;
    371 
    372     while(len != 0)
    373     {
    374         ret = write(userial_cb.fd[ch_idx], p_data+total, len);
    375         total += ret;
    376         len -= ret;
    377     }
    378 
    379     return ((uint16_t)total);
    380 }
    381 
    382 /*******************************************************************************
    383 **
    384 ** Function        userial_close
    385 **
    386 ** Description     Close the userial port
    387 **
    388 ** Returns         None
    389 **
    390 *******************************************************************************/
    391 void userial_close(void)
    392 {
    393     int idx, result;
    394 
    395     USERIALDBG("userial_close");
    396 
    397     if (userial_running)
    398         send_wakeup_signal(USERIAL_RX_EXIT);
    399 
    400     if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0)
    401         ALOGE( "pthread_join() FAILED result:%d", result);
    402 
    403     /* Calling vendor-specific part */
    404     if (bt_vnd_if)
    405         bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
    406 
    407     for (idx=0; idx < CH_MAX; idx++)
    408         userial_cb.fd[idx] = -1;
    409 }
    410 
    411 /*******************************************************************************
    412 **
    413 ** Function        userial_ioctl
    414 **
    415 ** Description     ioctl inteface
    416 **
    417 ** Returns         None
    418 **
    419 *******************************************************************************/
    420 void userial_ioctl(userial_ioctl_op_t op, void *p_data)
    421 {
    422     switch(op)
    423     {
    424         case USERIAL_OP_RXFLOW_ON:
    425             if (userial_running)
    426                 send_wakeup_signal(USERIAL_RX_FLOW_ON);
    427             break;
    428 
    429         case USERIAL_OP_RXFLOW_OFF:
    430             if (userial_running)
    431                 send_wakeup_signal(USERIAL_RX_FLOW_OFF);
    432             break;
    433 
    434         case USERIAL_OP_INIT:
    435         default:
    436             break;
    437     }
    438 }
    439 
    440