• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dump_uipc_event(tUIPC_EVENT event)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 
create_server_socket(const char * name)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 
accept_server_socket(int sfd)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 
uipc_main_init(void)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 
uipc_main_cleanup(void)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 */
uipc_check_task_flags_locked(void)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 
uipc_check_fd_locked(tUIPC_CH_ID ch_id)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 
uipc_check_interrupt_locked(void)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 
uipc_wakeup_locked(void)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 
uipc_setup_server_locked(tUIPC_CH_ID ch_id,char * name,tUIPC_RCV_CBACK * cback)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 
uipc_flush_ch_locked(tUIPC_CH_ID ch_id)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 
uipc_flush_locked(tUIPC_CH_ID ch_id)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 
uipc_close_ch_locked(tUIPC_CH_ID ch_id)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 
uipc_close_locked(tUIPC_CH_ID ch_id)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 
uipc_read_task(void * arg)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 
uipc_start_main_server_thread(void)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 */
uipc_stop_main_server_thread(void)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 
UIPC_Init(void * p_data)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  *******************************************************************************/
UIPC_Open(tUIPC_CH_ID ch_id,tUIPC_RCV_CBACK * p_cback)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 
UIPC_Close(tUIPC_CH_ID ch_id)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  *******************************************************************************/
UIPC_Send(tUIPC_CH_ID ch_id,UINT16 msg_evt,UINT8 * p_buf,UINT16 msglen)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 
UIPC_Read(tUIPC_CH_ID ch_id,UINT16 * p_msg_evt,UINT8 * p_buf,UINT32 len)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 
UIPC_Ioctl(tUIPC_CH_ID ch_id,UINT32 request,void * param)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