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