Home | History | Annotate | Download | only in ulinux
      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:      uipc.cc
     22  *
     23  *  Description:   UIPC implementation for fluoride
     24  *
     25  *****************************************************************************/
     26 
     27 #include <errno.h>
     28 #include <fcntl.h>
     29 #include <signal.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <sys/mman.h>
     34 #include <sys/poll.h>
     35 #include <sys/prctl.h>
     36 #include <sys/select.h>
     37 #include <sys/socket.h>
     38 #include <sys/stat.h>
     39 #include <sys/un.h>
     40 #include <unistd.h>
     41 #include <mutex>
     42 
     43 #include "audio_a2dp_hw/include/audio_a2dp_hw.h"
     44 #include "bt_common.h"
     45 #include "bt_types.h"
     46 #include "bt_utils.h"
     47 #include "osi/include/osi.h"
     48 #include "osi/include/socket_utils/sockets.h"
     49 #include "uipc.h"
     50 
     51 /*****************************************************************************
     52  *  Constants & Macros
     53  *****************************************************************************/
     54 
     55 #define PCM_FILENAME "/data/test.pcm"
     56 
     57 #define MAX(a, b) ((a) > (b) ? (a) : (b))
     58 
     59 #define CASE_RETURN_STR(const) \
     60   case const:                  \
     61     return #const;
     62 
     63 #define UIPC_DISCONNECTED (-1)
     64 
     65 #define SAFE_FD_ISSET(fd, set) (((fd) == -1) ? false : FD_ISSET((fd), (set)))
     66 
     67 #define UIPC_FLUSH_BUFFER_SIZE 1024
     68 
     69 /*****************************************************************************
     70  *  Local type definitions
     71  *****************************************************************************/
     72 
     73 typedef enum {
     74   UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
     75 } tUIPC_TASK_FLAGS;
     76 
     77 typedef struct {
     78   int srvfd;
     79   int fd;
     80   int read_poll_tmo_ms;
     81   int task_evt_flags; /* event flags pending to be processed in read task */
     82   tUIPC_RCV_CBACK* cback;
     83 } tUIPC_CHAN;
     84 
     85 typedef struct {
     86   pthread_t tid; /* main thread id */
     87   int running;
     88   std::recursive_mutex mutex;
     89 
     90   fd_set active_set;
     91   fd_set read_set;
     92   int max_fd;
     93   int signal_fds[2];
     94 
     95   tUIPC_CHAN ch[UIPC_CH_NUM];
     96 } tUIPC_MAIN;
     97 
     98 /*****************************************************************************
     99  *  Static variables
    100  *****************************************************************************/
    101 
    102 static tUIPC_MAIN uipc_main;
    103 
    104 /*****************************************************************************
    105  *  Static functions
    106  *****************************************************************************/
    107 
    108 static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
    109 
    110 /*****************************************************************************
    111  *  Externs
    112  *****************************************************************************/
    113 
    114 /*****************************************************************************
    115  *   Helper functions
    116  *****************************************************************************/
    117 
    118 const char* dump_uipc_event(tUIPC_EVENT event) {
    119   switch (event) {
    120     CASE_RETURN_STR(UIPC_OPEN_EVT)
    121     CASE_RETURN_STR(UIPC_CLOSE_EVT)
    122     CASE_RETURN_STR(UIPC_RX_DATA_EVT)
    123     CASE_RETURN_STR(UIPC_RX_DATA_READY_EVT)
    124     CASE_RETURN_STR(UIPC_TX_DATA_READY_EVT)
    125     default:
    126       return "UNKNOWN MSG ID";
    127   }
    128 }
    129 
    130 /*****************************************************************************
    131  *   socket helper functions
    132  ****************************************************************************/
    133 
    134 static inline int create_server_socket(const char* name) {
    135   int s = socket(AF_LOCAL, SOCK_STREAM, 0);
    136   if (s < 0) return -1;
    137 
    138   BTIF_TRACE_EVENT("create_server_socket %s", name);
    139 
    140   if (osi_socket_local_server_bind(s, name,
    141 #if defined(OS_GENERIC)
    142                                    ANDROID_SOCKET_NAMESPACE_FILESYSTEM
    143 #else   // !defined(OS_GENERIC)
    144                                    ANDROID_SOCKET_NAMESPACE_ABSTRACT
    145 #endif  // defined(OS_GENERIC)
    146                                    ) < 0) {
    147     BTIF_TRACE_EVENT("socket failed to create (%s)", strerror(errno));
    148     close(s);
    149     return -1;
    150   }
    151 
    152   if (listen(s, 5) < 0) {
    153     BTIF_TRACE_EVENT("listen failed", strerror(errno));
    154     close(s);
    155     return -1;
    156   }
    157 
    158   BTIF_TRACE_EVENT("created socket fd %d", s);
    159   return s;
    160 }
    161 
    162 static int accept_server_socket(int sfd) {
    163   struct sockaddr_un remote;
    164   struct pollfd pfd;
    165   int fd;
    166   socklen_t len = sizeof(struct sockaddr_un);
    167 
    168   BTIF_TRACE_EVENT("accept fd %d", sfd);
    169 
    170   /* make sure there is data to process */
    171   pfd.fd = sfd;
    172   pfd.events = POLLIN;
    173 
    174   int poll_ret;
    175   OSI_NO_INTR(poll_ret = poll(&pfd, 1, 0));
    176   if (poll_ret == 0) {
    177     BTIF_TRACE_WARNING("accept poll timeout");
    178     return -1;
    179   }
    180 
    181   // BTIF_TRACE_EVENT("poll revents 0x%x", pfd.revents);
    182 
    183   OSI_NO_INTR(fd = accept(sfd, (struct sockaddr*)&remote, &len));
    184   if (fd == -1) {
    185     BTIF_TRACE_ERROR("sock accept failed (%s)", strerror(errno));
    186     return -1;
    187   }
    188 
    189   // match socket buffer size option with client
    190   const int size = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
    191   int ret =
    192       setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
    193   if (ret < 0) {
    194     BTIF_TRACE_ERROR("setsockopt failed (%s)", strerror(errno));
    195   }
    196 
    197   // BTIF_TRACE_EVENT("new fd %d", fd);
    198 
    199   return fd;
    200 }
    201 
    202 /*****************************************************************************
    203  *
    204  *   uipc helper functions
    205  *
    206  ****************************************************************************/
    207 
    208 static int uipc_main_init(void) {
    209   int i;
    210 
    211   BTIF_TRACE_EVENT("### uipc_main_init ###");
    212 
    213   uipc_main.tid = 0;
    214   uipc_main.running = 0;
    215   memset(&uipc_main.active_set, 0, sizeof(uipc_main.active_set));
    216   memset(&uipc_main.read_set, 0, sizeof(uipc_main.read_set));
    217   uipc_main.max_fd = 0;
    218   memset(&uipc_main.signal_fds, 0, sizeof(uipc_main.signal_fds));
    219   memset(&uipc_main.ch, 0, sizeof(uipc_main.ch));
    220 
    221   /* setup interrupt socket pair */
    222   if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc_main.signal_fds) < 0) {
    223     return -1;
    224   }
    225 
    226   FD_SET(uipc_main.signal_fds[0], &uipc_main.active_set);
    227   uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.signal_fds[0]);
    228 
    229   for (i = 0; i < UIPC_CH_NUM; i++) {
    230     tUIPC_CHAN* p = &uipc_main.ch[i];
    231     p->srvfd = UIPC_DISCONNECTED;
    232     p->fd = UIPC_DISCONNECTED;
    233     p->task_evt_flags = 0;
    234     p->cback = NULL;
    235   }
    236 
    237   return 0;
    238 }
    239 
    240 void uipc_main_cleanup(void) {
    241   int i;
    242 
    243   BTIF_TRACE_EVENT("uipc_main_cleanup");
    244 
    245   close(uipc_main.signal_fds[0]);
    246   close(uipc_main.signal_fds[1]);
    247 
    248   /* close any open channels */
    249   for (i = 0; i < UIPC_CH_NUM; i++) uipc_close_ch_locked(i);
    250 }
    251 
    252 /* check pending events in read task */
    253 static void uipc_check_task_flags_locked(void) {
    254   int i;
    255 
    256   for (i = 0; i < UIPC_CH_NUM; i++) {
    257     if (uipc_main.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) {
    258       uipc_main.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
    259       uipc_close_ch_locked(i);
    260     }
    261 
    262     /* add here */
    263   }
    264 }
    265 
    266 static int uipc_check_fd_locked(tUIPC_CH_ID ch_id) {
    267   if (ch_id >= UIPC_CH_NUM) return -1;
    268 
    269   // BTIF_TRACE_EVENT("CHECK SRVFD %d (ch %d)", uipc_main.ch[ch_id].srvfd,
    270   // ch_id);
    271 
    272   if (SAFE_FD_ISSET(uipc_main.ch[ch_id].srvfd, &uipc_main.read_set)) {
    273     BTIF_TRACE_EVENT("INCOMING CONNECTION ON CH %d", ch_id);
    274 
    275     // Close the previous connection
    276     if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
    277       BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
    278       close(uipc_main.ch[ch_id].fd);
    279       FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
    280       uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
    281     }
    282 
    283     uipc_main.ch[ch_id].fd = accept_server_socket(uipc_main.ch[ch_id].srvfd);
    284 
    285     BTIF_TRACE_EVENT("NEW FD %d", uipc_main.ch[ch_id].fd);
    286 
    287     if ((uipc_main.ch[ch_id].fd >= 0) && uipc_main.ch[ch_id].cback) {
    288       /*  if we have a callback we should add this fd to the active set
    289           and notify user with callback event */
    290       BTIF_TRACE_EVENT("ADD FD %d TO ACTIVE SET", uipc_main.ch[ch_id].fd);
    291       FD_SET(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
    292       uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.ch[ch_id].fd);
    293     }
    294 
    295     if (uipc_main.ch[ch_id].fd < 0) {
    296       BTIF_TRACE_ERROR("FAILED TO ACCEPT CH %d (%s)", ch_id, strerror(errno));
    297       return -1;
    298     }
    299 
    300     if (uipc_main.ch[ch_id].cback)
    301       uipc_main.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
    302   }
    303 
    304   // BTIF_TRACE_EVENT("CHECK FD %d (ch %d)", uipc_main.ch[ch_id].fd, ch_id);
    305 
    306   if (SAFE_FD_ISSET(uipc_main.ch[ch_id].fd, &uipc_main.read_set)) {
    307     // BTIF_TRACE_EVENT("INCOMING DATA ON CH %d", ch_id);
    308 
    309     if (uipc_main.ch[ch_id].cback)
    310       uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
    311   }
    312   return 0;
    313 }
    314 
    315 static void uipc_check_interrupt_locked(void) {
    316   if (SAFE_FD_ISSET(uipc_main.signal_fds[0], &uipc_main.read_set)) {
    317     char sig_recv = 0;
    318     OSI_NO_INTR(recv(uipc_main.signal_fds[0], &sig_recv, sizeof(sig_recv),
    319                      MSG_WAITALL));
    320   }
    321 }
    322 
    323 static inline void uipc_wakeup_locked(void) {
    324   char sig_on = 1;
    325   BTIF_TRACE_EVENT("UIPC SEND WAKE UP");
    326 
    327   OSI_NO_INTR(send(uipc_main.signal_fds[1], &sig_on, sizeof(sig_on), 0));
    328 }
    329 
    330 static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, const char* name,
    331                                     tUIPC_RCV_CBACK* cback) {
    332   int fd;
    333 
    334   BTIF_TRACE_EVENT("SETUP CHANNEL SERVER %d", ch_id);
    335 
    336   if (ch_id >= UIPC_CH_NUM) return -1;
    337 
    338   std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
    339 
    340   fd = create_server_socket(name);
    341 
    342   if (fd < 0) {
    343     BTIF_TRACE_ERROR("failed to setup %s", name, strerror(errno));
    344     return -1;
    345   }
    346 
    347   BTIF_TRACE_EVENT("ADD SERVER FD TO ACTIVE SET %d", fd);
    348   FD_SET(fd, &uipc_main.active_set);
    349   uipc_main.max_fd = MAX(uipc_main.max_fd, fd);
    350 
    351   uipc_main.ch[ch_id].srvfd = fd;
    352   uipc_main.ch[ch_id].cback = cback;
    353   uipc_main.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
    354 
    355   /* trigger main thread to update read set */
    356   uipc_wakeup_locked();
    357 
    358   return 0;
    359 }
    360 
    361 static void uipc_flush_ch_locked(tUIPC_CH_ID ch_id) {
    362   char buf[UIPC_FLUSH_BUFFER_SIZE];
    363   struct pollfd pfd;
    364 
    365   pfd.events = POLLIN;
    366   pfd.fd = uipc_main.ch[ch_id].fd;
    367 
    368   if (uipc_main.ch[ch_id].fd == UIPC_DISCONNECTED) {
    369     BTIF_TRACE_EVENT("%s() - fd disconnected. Exiting", __func__);
    370     return;
    371   }
    372 
    373   while (1) {
    374     int ret;
    375     OSI_NO_INTR(ret = poll(&pfd, 1, 1));
    376     if (ret == 0) {
    377       BTIF_TRACE_VERBOSE("%s(): poll() timeout - nothing to do. Exiting",
    378                          __func__);
    379       return;
    380     }
    381     if (ret < 0) {
    382       BTIF_TRACE_WARNING(
    383           "%s() - poll() failed: return %d errno %d (%s). Exiting", __func__,
    384           ret, errno, strerror(errno));
    385       return;
    386     }
    387     BTIF_TRACE_VERBOSE("%s() - polling fd %d, revents: 0x%x, ret %d", __func__,
    388                        pfd.fd, pfd.revents, ret);
    389     if (pfd.revents & (POLLERR | POLLHUP)) {
    390       BTIF_TRACE_WARNING("%s() - POLLERR or POLLHUP. Exiting", __func__);
    391       return;
    392     }
    393 
    394     /* read sufficiently large buffer to ensure flush empties socket faster than
    395        it is getting refilled */
    396     read(pfd.fd, &buf, UIPC_FLUSH_BUFFER_SIZE);
    397   }
    398 }
    399 
    400 static void uipc_flush_locked(tUIPC_CH_ID ch_id) {
    401   if (ch_id >= UIPC_CH_NUM) return;
    402 
    403   switch (ch_id) {
    404     case UIPC_CH_ID_AV_CTRL:
    405       uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL);
    406       break;
    407 
    408     case UIPC_CH_ID_AV_AUDIO:
    409       uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO);
    410       break;
    411   }
    412 }
    413 
    414 static int uipc_close_ch_locked(tUIPC_CH_ID ch_id) {
    415   int wakeup = 0;
    416 
    417   BTIF_TRACE_EVENT("CLOSE CHANNEL %d", ch_id);
    418 
    419   if (ch_id >= UIPC_CH_NUM) return -1;
    420 
    421   if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
    422     BTIF_TRACE_EVENT("CLOSE SERVER (FD %d)", uipc_main.ch[ch_id].srvfd);
    423     close(uipc_main.ch[ch_id].srvfd);
    424     FD_CLR(uipc_main.ch[ch_id].srvfd, &uipc_main.active_set);
    425     uipc_main.ch[ch_id].srvfd = UIPC_DISCONNECTED;
    426     wakeup = 1;
    427   }
    428 
    429   if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
    430     BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
    431     close(uipc_main.ch[ch_id].fd);
    432     FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
    433     uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
    434     wakeup = 1;
    435   }
    436 
    437   /* notify this connection is closed */
    438   if (uipc_main.ch[ch_id].cback)
    439     uipc_main.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
    440 
    441   /* trigger main thread update if something was updated */
    442   if (wakeup) uipc_wakeup_locked();
    443 
    444   return 0;
    445 }
    446 
    447 void uipc_close_locked(tUIPC_CH_ID ch_id) {
    448   if (uipc_main.ch[ch_id].srvfd == UIPC_DISCONNECTED) {
    449     BTIF_TRACE_EVENT("CHANNEL %d ALREADY CLOSED", ch_id);
    450     return;
    451   }
    452 
    453   /* schedule close on this channel */
    454   uipc_main.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
    455   uipc_wakeup_locked();
    456 }
    457 
    458 static void* uipc_read_task(UNUSED_ATTR void* arg) {
    459   int ch_id;
    460   int result;
    461 
    462   prctl(PR_SET_NAME, (unsigned long)"uipc-main", 0, 0, 0);
    463 
    464   raise_priority_a2dp(TASK_UIPC_READ);
    465 
    466   while (uipc_main.running) {
    467     uipc_main.read_set = uipc_main.active_set;
    468 
    469     result =
    470         select(uipc_main.max_fd + 1, &uipc_main.read_set, NULL, NULL, NULL);
    471 
    472     if (result == 0) {
    473       BTIF_TRACE_EVENT("select timeout");
    474       continue;
    475     }
    476     if (result < 0) {
    477       if (errno != EINTR) {
    478         BTIF_TRACE_EVENT("select failed %s", strerror(errno));
    479       }
    480       continue;
    481     }
    482 
    483     {
    484       std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
    485 
    486       /* clear any wakeup interrupt */
    487       uipc_check_interrupt_locked();
    488 
    489       /* check pending task events */
    490       uipc_check_task_flags_locked();
    491 
    492       /* make sure we service audio channel first */
    493       uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);
    494 
    495       /* check for other connections */
    496       for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
    497         if (ch_id != UIPC_CH_ID_AV_AUDIO) uipc_check_fd_locked(ch_id);
    498       }
    499     }
    500   }
    501 
    502   BTIF_TRACE_EVENT("UIPC READ THREAD EXITING");
    503 
    504   uipc_main_cleanup();
    505 
    506   uipc_main.tid = 0;
    507 
    508   BTIF_TRACE_EVENT("UIPC READ THREAD DONE");
    509 
    510   return nullptr;
    511 }
    512 
    513 int uipc_start_main_server_thread(void) {
    514   uipc_main.running = 1;
    515 
    516   if (pthread_create(&uipc_main.tid, (const pthread_attr_t*)NULL,
    517                      uipc_read_task, nullptr) < 0) {
    518     BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
    519     return -1;
    520   }
    521 
    522   return 0;
    523 }
    524 
    525 /* blocking call */
    526 void uipc_stop_main_server_thread(void) {
    527   /* request shutdown of read thread */
    528   {
    529     std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    530     uipc_main.running = 0;
    531     uipc_wakeup_locked();
    532   }
    533 
    534   /* wait until read thread is fully terminated */
    535   /* tid might hold pointer value where it's value
    536      is negative vaule with singed bit is set, so
    537      corrected the logic to check zero or non zero */
    538   if (uipc_main.tid) pthread_join(uipc_main.tid, NULL);
    539 }
    540 
    541 /*******************************************************************************
    542  **
    543  ** Function         UIPC_Init
    544  **
    545  ** Description      Initialize UIPC module
    546  **
    547  ** Returns          void
    548  **
    549  ******************************************************************************/
    550 
    551 void UIPC_Init(UNUSED_ATTR void* p_data) {
    552   BTIF_TRACE_DEBUG("UIPC_Init");
    553 
    554   uipc_main_init();
    555   uipc_start_main_server_thread();
    556 }
    557 
    558 /*******************************************************************************
    559  **
    560  ** Function         UIPC_Open
    561  **
    562  ** Description      Open UIPC interface
    563  **
    564  ** Returns          true in case of success, false in case of failure.
    565  **
    566  ******************************************************************************/
    567 bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback) {
    568   BTIF_TRACE_DEBUG("UIPC_Open : ch_id %d, p_cback %x", ch_id, p_cback);
    569 
    570   std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    571 
    572   if (ch_id >= UIPC_CH_NUM) {
    573     return false;
    574   }
    575 
    576   if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
    577     BTIF_TRACE_EVENT("CHANNEL %d ALREADY OPEN", ch_id);
    578     return 0;
    579   }
    580 
    581   switch (ch_id) {
    582     case UIPC_CH_ID_AV_CTRL:
    583       uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback);
    584       break;
    585 
    586     case UIPC_CH_ID_AV_AUDIO:
    587       uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback);
    588       break;
    589   }
    590 
    591   return true;
    592 }
    593 
    594 /*******************************************************************************
    595  **
    596  ** Function         UIPC_Close
    597  **
    598  ** Description      Close UIPC interface
    599  **
    600  ** Returns          void
    601  **
    602  ******************************************************************************/
    603 
    604 void UIPC_Close(tUIPC_CH_ID ch_id) {
    605   BTIF_TRACE_DEBUG("UIPC_Close : ch_id %d", ch_id);
    606 
    607   /* special case handling uipc shutdown */
    608   if (ch_id != UIPC_CH_ID_ALL) {
    609     std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    610     uipc_close_locked(ch_id);
    611     return;
    612   }
    613   BTIF_TRACE_DEBUG("UIPC_Close : waiting for shutdown to complete");
    614   uipc_stop_main_server_thread();
    615   BTIF_TRACE_DEBUG("UIPC_Close : shutdown complete");
    616 }
    617 
    618 /*******************************************************************************
    619  **
    620  ** Function         UIPC_Send
    621  **
    622  ** Description      Called to transmit a message over UIPC.
    623  **
    624  ** Returns          true in case of success, false in case of failure.
    625  **
    626  ******************************************************************************/
    627 bool UIPC_Send(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t msg_evt,
    628                const uint8_t* p_buf, uint16_t msglen) {
    629   BTIF_TRACE_DEBUG("UIPC_Send : ch_id:%d %d bytes", ch_id, msglen);
    630 
    631   std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    632 
    633   ssize_t ret;
    634   OSI_NO_INTR(ret = write(uipc_main.ch[ch_id].fd, p_buf, msglen));
    635   if (ret < 0) {
    636     BTIF_TRACE_ERROR("failed to write (%s)", strerror(errno));
    637   }
    638 
    639   return false;
    640 }
    641 
    642 /*******************************************************************************
    643  **
    644  ** Function         UIPC_Read
    645  **
    646  ** Description      Called to read a message from UIPC.
    647  **
    648  ** Returns          return the number of bytes read.
    649  **
    650  ******************************************************************************/
    651 
    652 uint32_t UIPC_Read(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t* p_msg_evt,
    653                    uint8_t* p_buf, uint32_t len) {
    654   int n_read = 0;
    655   int fd = uipc_main.ch[ch_id].fd;
    656   struct pollfd pfd;
    657 
    658   if (ch_id >= UIPC_CH_NUM) {
    659     BTIF_TRACE_ERROR("UIPC_Read : invalid ch id %d", ch_id);
    660     return 0;
    661   }
    662 
    663   if (fd == UIPC_DISCONNECTED) {
    664     BTIF_TRACE_ERROR("UIPC_Read : channel %d closed", ch_id);
    665     return 0;
    666   }
    667 
    668   while (n_read < (int)len) {
    669     pfd.fd = fd;
    670     pfd.events = POLLIN | POLLHUP;
    671 
    672     /* make sure there is data prior to attempting read to avoid blocking
    673        a read for more than poll timeout */
    674 
    675     int poll_ret;
    676     OSI_NO_INTR(poll_ret = poll(&pfd, 1, uipc_main.ch[ch_id].read_poll_tmo_ms));
    677     if (poll_ret == 0) {
    678       BTIF_TRACE_WARNING("poll timeout (%d ms)",
    679                          uipc_main.ch[ch_id].read_poll_tmo_ms);
    680       break;
    681     }
    682     if (poll_ret < 0) {
    683       BTIF_TRACE_ERROR("%s(): poll() failed: return %d errno %d (%s)", __func__,
    684                        poll_ret, errno, strerror(errno));
    685       break;
    686     }
    687 
    688     // BTIF_TRACE_EVENT("poll revents %x", pfd.revents);
    689 
    690     if (pfd.revents & (POLLHUP | POLLNVAL)) {
    691       BTIF_TRACE_WARNING("poll : channel detached remotely");
    692       std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    693       uipc_close_locked(ch_id);
    694       return 0;
    695     }
    696 
    697     ssize_t n;
    698     OSI_NO_INTR(n = recv(fd, p_buf + n_read, len - n_read, 0));
    699 
    700     // BTIF_TRACE_EVENT("read %d bytes", n);
    701 
    702     if (n == 0) {
    703       BTIF_TRACE_WARNING("UIPC_Read : channel detached remotely");
    704       std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    705       uipc_close_locked(ch_id);
    706       return 0;
    707     }
    708 
    709     if (n < 0) {
    710       BTIF_TRACE_WARNING("UIPC_Read : read failed (%s)", strerror(errno));
    711       return 0;
    712     }
    713 
    714     n_read += n;
    715   }
    716 
    717   return n_read;
    718 }
    719 
    720 /*******************************************************************************
    721  *
    722  * Function         UIPC_Ioctl
    723  *
    724  * Description      Called to control UIPC.
    725  *
    726  * Returns          void
    727  *
    728  ******************************************************************************/
    729 
    730 extern bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param) {
    731   BTIF_TRACE_DEBUG("#### UIPC_Ioctl : ch_id %d, request %d ####", ch_id,
    732                    request);
    733   std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
    734 
    735   switch (request) {
    736     case UIPC_REQ_RX_FLUSH:
    737       uipc_flush_locked(ch_id);
    738       break;
    739 
    740     case UIPC_REG_CBACK:
    741       // BTIF_TRACE_EVENT("register callback ch %d srvfd %d, fd %d", ch_id,
    742       // uipc_main.ch[ch_id].srvfd, uipc_main.ch[ch_id].fd);
    743       uipc_main.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param;
    744       break;
    745 
    746     case UIPC_REG_REMOVE_ACTIVE_READSET:
    747       /* user will read data directly and not use select loop */
    748       if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
    749         /* remove this channel from active set */
    750         FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
    751 
    752         /* refresh active set */
    753         uipc_wakeup_locked();
    754       }
    755       break;
    756 
    757     case UIPC_SET_READ_POLL_TMO:
    758       uipc_main.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
    759       BTIF_TRACE_EVENT("UIPC_SET_READ_POLL_TMO : CH %d, TMO %d ms", ch_id,
    760                        uipc_main.ch[ch_id].read_poll_tmo_ms);
    761       break;
    762 
    763     default:
    764       BTIF_TRACE_EVENT("UIPC_Ioctl : request not handled (%d)", request);
    765       break;
    766   }
    767 
    768   return false;
    769 }
    770