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