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