• 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 <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 
76 typedef enum {
77     UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
78 } tUIPC_TASK_FLAGS;
79 
80 typedef 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 
91 typedef 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 
109 static tUIPC_MAIN uipc_main;
110 
111 
112 /*****************************************************************************
113 **  Static functions
114 ******************************************************************************/
115 
116 static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
117 
118 /*****************************************************************************
119 **  Externs
120 ******************************************************************************/
121 
122 
123 /*****************************************************************************
124 **   Helper functions
125 ******************************************************************************/
126 
127 
dump_uipc_event(tUIPC_EVENT event)128 const 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 
create_server_socket(const char * name)146 static 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 
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     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 
uipc_main_init(void)208 static 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 
uipc_main_cleanup(void)239 void 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 */
uipc_check_task_flags_locked(void)256 static 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 
uipc_check_fd_locked(tUIPC_CH_ID ch_id)275 static 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 
uipc_check_interrupt_locked(void)321 static 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 
uipc_wakeup_locked(void)331 static 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 
uipc_setup_server_locked(tUIPC_CH_ID ch_id,char * name,tUIPC_RCV_CBACK * cback)338 static 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 
uipc_flush_ch_locked(tUIPC_CH_ID ch_id)374 static 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 
uipc_flush_locked(tUIPC_CH_ID ch_id)404 static 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 
uipc_close_ch_locked(tUIPC_CH_ID ch_id)422 static 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 
uipc_close_locked(tUIPC_CH_ID ch_id)461 void 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 
uipc_read_task(void * arg)475 static 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 
uipc_start_main_server_thread(void)533 int 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 */
uipc_stop_main_server_thread(void)547 void 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 
UIPC_Init(void * p_data)570 UDRV_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  *******************************************************************************/
UIPC_Open(tUIPC_CH_ID ch_id,tUIPC_RCV_CBACK * p_cback)592 UDRV_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 
UIPC_Close(tUIPC_CH_ID ch_id)637 UDRV_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  *******************************************************************************/
UIPC_SendBuf(tUIPC_CH_ID ch_id,BT_HDR * p_msg)666 UDRV_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  *******************************************************************************/
UIPC_Send(tUIPC_CH_ID ch_id,UINT16 msg_evt,UINT8 * p_buf,UINT16 msglen)690 UDRV_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  *******************************************************************************/
UIPC_ReadBuf(tUIPC_CH_ID ch_id,BT_HDR * p_msg)719 UDRV_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 
UIPC_Read(tUIPC_CH_ID ch_id,UINT16 * p_msg_evt,UINT8 * p_buf,UINT32 len)739 UDRV_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 
UIPC_Ioctl(tUIPC_CH_ID ch_id,UINT32 request,void * param)822 UDRV_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