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
74typedef enum {
75    UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
76} tUIPC_TASK_FLAGS;
77
78typedef 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
89typedef 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
107static tUIPC_MAIN uipc_main;
108
109
110/*****************************************************************************
111**  Static functions
112******************************************************************************/
113
114static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
115
116/*****************************************************************************
117**  Externs
118******************************************************************************/
119
120
121/*****************************************************************************
122**   Helper functions
123******************************************************************************/
124
125
126const 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
144static 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
170static 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
217static 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
250void 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 */
267static 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
286static 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
332static 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
342static 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
350static 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
386static 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
429static 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
447static 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
486void 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
500static 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
557int 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 */
571void 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
597void 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 *******************************************************************************/
619BOOLEAN 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
664void 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 *******************************************************************************/
692BOOLEAN 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
722UINT32 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
814extern 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