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