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