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