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.cc
22 *
23 * Description: UIPC implementation for fluoride
24 *
25 *****************************************************************************/
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/mman.h>
34 #include <sys/poll.h>
35 #include <sys/prctl.h>
36 #include <sys/select.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <sys/un.h>
40 #include <unistd.h>
41 #include <mutex>
42
43 #include "audio_a2dp_hw/include/audio_a2dp_hw.h"
44 #include "bt_common.h"
45 #include "bt_types.h"
46 #include "bt_utils.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) \
60 case const: \
61 return #const;
62
63 #define UIPC_DISCONNECTED (-1)
64
65 #define SAFE_FD_ISSET(fd, set) (((fd) == -1) ? false : FD_ISSET((fd), (set)))
66
67 #define UIPC_FLUSH_BUFFER_SIZE 1024
68
69 /*****************************************************************************
70 * Local type definitions
71 *****************************************************************************/
72
73 typedef enum {
74 UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
75 } tUIPC_TASK_FLAGS;
76
77 typedef struct {
78 int srvfd;
79 int fd;
80 int read_poll_tmo_ms;
81 int task_evt_flags; /* event flags pending to be processed in read task */
82 tUIPC_RCV_CBACK* cback;
83 } tUIPC_CHAN;
84
85 typedef struct {
86 pthread_t tid; /* main thread id */
87 int running;
88 std::recursive_mutex mutex;
89
90 fd_set active_set;
91 fd_set read_set;
92 int max_fd;
93 int signal_fds[2];
94
95 tUIPC_CHAN ch[UIPC_CH_NUM];
96 } tUIPC_MAIN;
97
98 /*****************************************************************************
99 * Static variables
100 *****************************************************************************/
101
102 static tUIPC_MAIN uipc_main;
103
104 /*****************************************************************************
105 * Static functions
106 *****************************************************************************/
107
108 static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
109
110 /*****************************************************************************
111 * Externs
112 *****************************************************************************/
113
114 /*****************************************************************************
115 * Helper functions
116 *****************************************************************************/
117
dump_uipc_event(tUIPC_EVENT event)118 const char* dump_uipc_event(tUIPC_EVENT event) {
119 switch (event) {
120 CASE_RETURN_STR(UIPC_OPEN_EVT)
121 CASE_RETURN_STR(UIPC_CLOSE_EVT)
122 CASE_RETURN_STR(UIPC_RX_DATA_EVT)
123 CASE_RETURN_STR(UIPC_RX_DATA_READY_EVT)
124 CASE_RETURN_STR(UIPC_TX_DATA_READY_EVT)
125 default:
126 return "UNKNOWN MSG ID";
127 }
128 }
129
130 /*****************************************************************************
131 * socket helper functions
132 ****************************************************************************/
133
create_server_socket(const char * name)134 static inline int create_server_socket(const char* name) {
135 int s = socket(AF_LOCAL, SOCK_STREAM, 0);
136 if (s < 0) return -1;
137
138 BTIF_TRACE_EVENT("create_server_socket %s", name);
139
140 if (osi_socket_local_server_bind(s, name,
141 #if defined(OS_GENERIC)
142 ANDROID_SOCKET_NAMESPACE_FILESYSTEM
143 #else // !defined(OS_GENERIC)
144 ANDROID_SOCKET_NAMESPACE_ABSTRACT
145 #endif // defined(OS_GENERIC)
146 ) < 0) {
147 BTIF_TRACE_EVENT("socket failed to create (%s)", strerror(errno));
148 close(s);
149 return -1;
150 }
151
152 if (listen(s, 5) < 0) {
153 BTIF_TRACE_EVENT("listen failed", strerror(errno));
154 close(s);
155 return -1;
156 }
157
158 BTIF_TRACE_EVENT("created socket fd %d", s);
159 return s;
160 }
161
accept_server_socket(int sfd)162 static int accept_server_socket(int sfd) {
163 struct sockaddr_un remote;
164 struct pollfd pfd;
165 int fd;
166 socklen_t len = sizeof(struct sockaddr_un);
167
168 BTIF_TRACE_EVENT("accept fd %d", sfd);
169
170 /* make sure there is data to process */
171 pfd.fd = sfd;
172 pfd.events = POLLIN;
173
174 int poll_ret;
175 OSI_NO_INTR(poll_ret = poll(&pfd, 1, 0));
176 if (poll_ret == 0) {
177 BTIF_TRACE_WARNING("accept poll timeout");
178 return -1;
179 }
180
181 // BTIF_TRACE_EVENT("poll revents 0x%x", pfd.revents);
182
183 OSI_NO_INTR(fd = accept(sfd, (struct sockaddr*)&remote, &len));
184 if (fd == -1) {
185 BTIF_TRACE_ERROR("sock accept failed (%s)", strerror(errno));
186 return -1;
187 }
188
189 // match socket buffer size option with client
190 const int size = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
191 int ret =
192 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
193 if (ret < 0) {
194 BTIF_TRACE_ERROR("setsockopt failed (%s)", strerror(errno));
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 int i;
210
211 BTIF_TRACE_EVENT("### uipc_main_init ###");
212
213 uipc_main.tid = 0;
214 uipc_main.running = 0;
215 memset(&uipc_main.active_set, 0, sizeof(uipc_main.active_set));
216 memset(&uipc_main.read_set, 0, sizeof(uipc_main.read_set));
217 uipc_main.max_fd = 0;
218 memset(&uipc_main.signal_fds, 0, sizeof(uipc_main.signal_fds));
219 memset(&uipc_main.ch, 0, sizeof(uipc_main.ch));
220
221 /* setup interrupt socket pair */
222 if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc_main.signal_fds) < 0) {
223 return -1;
224 }
225
226 FD_SET(uipc_main.signal_fds[0], &uipc_main.active_set);
227 uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.signal_fds[0]);
228
229 for (i = 0; i < UIPC_CH_NUM; i++) {
230 tUIPC_CHAN* p = &uipc_main.ch[i];
231 p->srvfd = UIPC_DISCONNECTED;
232 p->fd = UIPC_DISCONNECTED;
233 p->task_evt_flags = 0;
234 p->cback = NULL;
235 }
236
237 return 0;
238 }
239
uipc_main_cleanup(void)240 void uipc_main_cleanup(void) {
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++) uipc_close_ch_locked(i);
250 }
251
252 /* check pending events in read task */
uipc_check_task_flags_locked(void)253 static void uipc_check_task_flags_locked(void) {
254 int i;
255
256 for (i = 0; i < UIPC_CH_NUM; i++) {
257 if (uipc_main.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) {
258 uipc_main.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
259 uipc_close_ch_locked(i);
260 }
261
262 /* add here */
263 }
264 }
265
uipc_check_fd_locked(tUIPC_CH_ID ch_id)266 static int uipc_check_fd_locked(tUIPC_CH_ID ch_id) {
267 if (ch_id >= UIPC_CH_NUM) return -1;
268
269 // BTIF_TRACE_EVENT("CHECK SRVFD %d (ch %d)", uipc_main.ch[ch_id].srvfd,
270 // ch_id);
271
272 if (SAFE_FD_ISSET(uipc_main.ch[ch_id].srvfd, &uipc_main.read_set)) {
273 BTIF_TRACE_EVENT("INCOMING CONNECTION ON CH %d", ch_id);
274
275 // Close the previous connection
276 if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
277 BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
278 close(uipc_main.ch[ch_id].fd);
279 FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
280 uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
281 }
282
283 uipc_main.ch[ch_id].fd = accept_server_socket(uipc_main.ch[ch_id].srvfd);
284
285 BTIF_TRACE_EVENT("NEW FD %d", uipc_main.ch[ch_id].fd);
286
287 if ((uipc_main.ch[ch_id].fd >= 0) && uipc_main.ch[ch_id].cback) {
288 /* if we have a callback we should add this fd to the active set
289 and notify user with callback event */
290 BTIF_TRACE_EVENT("ADD FD %d TO ACTIVE SET", uipc_main.ch[ch_id].fd);
291 FD_SET(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
292 uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.ch[ch_id].fd);
293 }
294
295 if (uipc_main.ch[ch_id].fd < 0) {
296 BTIF_TRACE_ERROR("FAILED TO ACCEPT CH %d (%s)", ch_id, strerror(errno));
297 return -1;
298 }
299
300 if (uipc_main.ch[ch_id].cback)
301 uipc_main.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
302 }
303
304 // BTIF_TRACE_EVENT("CHECK FD %d (ch %d)", uipc_main.ch[ch_id].fd, ch_id);
305
306 if (SAFE_FD_ISSET(uipc_main.ch[ch_id].fd, &uipc_main.read_set)) {
307 // BTIF_TRACE_EVENT("INCOMING DATA ON CH %d", ch_id);
308
309 if (uipc_main.ch[ch_id].cback)
310 uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
311 }
312 return 0;
313 }
314
uipc_check_interrupt_locked(void)315 static void uipc_check_interrupt_locked(void) {
316 if (SAFE_FD_ISSET(uipc_main.signal_fds[0], &uipc_main.read_set)) {
317 char sig_recv = 0;
318 OSI_NO_INTR(recv(uipc_main.signal_fds[0], &sig_recv, sizeof(sig_recv),
319 MSG_WAITALL));
320 }
321 }
322
uipc_wakeup_locked(void)323 static inline void uipc_wakeup_locked(void) {
324 char sig_on = 1;
325 BTIF_TRACE_EVENT("UIPC SEND WAKE UP");
326
327 OSI_NO_INTR(send(uipc_main.signal_fds[1], &sig_on, sizeof(sig_on), 0));
328 }
329
uipc_setup_server_locked(tUIPC_CH_ID ch_id,const char * name,tUIPC_RCV_CBACK * cback)330 static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, const char* name,
331 tUIPC_RCV_CBACK* cback) {
332 int fd;
333
334 BTIF_TRACE_EVENT("SETUP CHANNEL SERVER %d", ch_id);
335
336 if (ch_id >= UIPC_CH_NUM) return -1;
337
338 std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
339
340 fd = create_server_socket(name);
341
342 if (fd < 0) {
343 BTIF_TRACE_ERROR("failed to setup %s", name, strerror(errno));
344 return -1;
345 }
346
347 BTIF_TRACE_EVENT("ADD SERVER FD TO ACTIVE SET %d", fd);
348 FD_SET(fd, &uipc_main.active_set);
349 uipc_main.max_fd = MAX(uipc_main.max_fd, fd);
350
351 uipc_main.ch[ch_id].srvfd = fd;
352 uipc_main.ch[ch_id].cback = cback;
353 uipc_main.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
354
355 /* trigger main thread to update read set */
356 uipc_wakeup_locked();
357
358 return 0;
359 }
360
uipc_flush_ch_locked(tUIPC_CH_ID ch_id)361 static void uipc_flush_ch_locked(tUIPC_CH_ID ch_id) {
362 char buf[UIPC_FLUSH_BUFFER_SIZE];
363 struct pollfd pfd;
364
365 pfd.events = POLLIN;
366 pfd.fd = uipc_main.ch[ch_id].fd;
367
368 if (uipc_main.ch[ch_id].fd == UIPC_DISCONNECTED) {
369 BTIF_TRACE_EVENT("%s() - fd disconnected. Exiting", __func__);
370 return;
371 }
372
373 while (1) {
374 int ret;
375 OSI_NO_INTR(ret = poll(&pfd, 1, 1));
376 if (ret == 0) {
377 BTIF_TRACE_VERBOSE("%s(): poll() timeout - nothing to do. Exiting",
378 __func__);
379 return;
380 }
381 if (ret < 0) {
382 BTIF_TRACE_WARNING(
383 "%s() - poll() failed: return %d errno %d (%s). Exiting", __func__,
384 ret, errno, strerror(errno));
385 return;
386 }
387 BTIF_TRACE_VERBOSE("%s() - polling fd %d, revents: 0x%x, ret %d", __func__,
388 pfd.fd, pfd.revents, ret);
389 if (pfd.revents & (POLLERR | POLLHUP)) {
390 BTIF_TRACE_WARNING("%s() - POLLERR or POLLHUP. Exiting", __func__);
391 return;
392 }
393
394 /* read sufficiently large buffer to ensure flush empties socket faster than
395 it is getting refilled */
396 read(pfd.fd, &buf, UIPC_FLUSH_BUFFER_SIZE);
397 }
398 }
399
uipc_flush_locked(tUIPC_CH_ID ch_id)400 static void uipc_flush_locked(tUIPC_CH_ID ch_id) {
401 if (ch_id >= UIPC_CH_NUM) return;
402
403 switch (ch_id) {
404 case UIPC_CH_ID_AV_CTRL:
405 uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL);
406 break;
407
408 case UIPC_CH_ID_AV_AUDIO:
409 uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO);
410 break;
411 }
412 }
413
uipc_close_ch_locked(tUIPC_CH_ID ch_id)414 static int uipc_close_ch_locked(tUIPC_CH_ID ch_id) {
415 int wakeup = 0;
416
417 BTIF_TRACE_EVENT("CLOSE CHANNEL %d", ch_id);
418
419 if (ch_id >= UIPC_CH_NUM) return -1;
420
421 if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
422 BTIF_TRACE_EVENT("CLOSE SERVER (FD %d)", uipc_main.ch[ch_id].srvfd);
423 close(uipc_main.ch[ch_id].srvfd);
424 FD_CLR(uipc_main.ch[ch_id].srvfd, &uipc_main.active_set);
425 uipc_main.ch[ch_id].srvfd = UIPC_DISCONNECTED;
426 wakeup = 1;
427 }
428
429 if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
430 BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
431 close(uipc_main.ch[ch_id].fd);
432 FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
433 uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
434 wakeup = 1;
435 }
436
437 /* notify this connection is closed */
438 if (uipc_main.ch[ch_id].cback)
439 uipc_main.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
440
441 /* trigger main thread update if something was updated */
442 if (wakeup) uipc_wakeup_locked();
443
444 return 0;
445 }
446
uipc_close_locked(tUIPC_CH_ID ch_id)447 void uipc_close_locked(tUIPC_CH_ID ch_id) {
448 if (uipc_main.ch[ch_id].srvfd == UIPC_DISCONNECTED) {
449 BTIF_TRACE_EVENT("CHANNEL %d ALREADY CLOSED", ch_id);
450 return;
451 }
452
453 /* schedule close on this channel */
454 uipc_main.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
455 uipc_wakeup_locked();
456 }
457
uipc_read_task(UNUSED_ATTR void * arg)458 static void* uipc_read_task(UNUSED_ATTR void* arg) {
459 int ch_id;
460 int result;
461
462 prctl(PR_SET_NAME, (unsigned long)"uipc-main", 0, 0, 0);
463
464 raise_priority_a2dp(TASK_UIPC_READ);
465
466 while (uipc_main.running) {
467 uipc_main.read_set = uipc_main.active_set;
468
469 result =
470 select(uipc_main.max_fd + 1, &uipc_main.read_set, NULL, NULL, NULL);
471
472 if (result == 0) {
473 BTIF_TRACE_EVENT("select timeout");
474 continue;
475 }
476 if (result < 0) {
477 if (errno != EINTR) {
478 BTIF_TRACE_EVENT("select failed %s", strerror(errno));
479 }
480 continue;
481 }
482
483 {
484 std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
485
486 /* clear any wakeup interrupt */
487 uipc_check_interrupt_locked();
488
489 /* check pending task events */
490 uipc_check_task_flags_locked();
491
492 /* make sure we service audio channel first */
493 uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);
494
495 /* check for other connections */
496 for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
497 if (ch_id != UIPC_CH_ID_AV_AUDIO) uipc_check_fd_locked(ch_id);
498 }
499 }
500 }
501
502 BTIF_TRACE_EVENT("UIPC READ THREAD EXITING");
503
504 uipc_main_cleanup();
505
506 uipc_main.tid = 0;
507
508 BTIF_TRACE_EVENT("UIPC READ THREAD DONE");
509
510 return nullptr;
511 }
512
uipc_start_main_server_thread(void)513 int uipc_start_main_server_thread(void) {
514 uipc_main.running = 1;
515
516 if (pthread_create(&uipc_main.tid, (const pthread_attr_t*)NULL,
517 uipc_read_task, nullptr) < 0) {
518 BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
519 return -1;
520 }
521
522 return 0;
523 }
524
525 /* blocking call */
uipc_stop_main_server_thread(void)526 void uipc_stop_main_server_thread(void) {
527 /* request shutdown of read thread */
528 {
529 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
530 uipc_main.running = 0;
531 uipc_wakeup_locked();
532 }
533
534 /* wait until read thread is fully terminated */
535 /* tid might hold pointer value where it's value
536 is negative vaule with singed bit is set, so
537 corrected the logic to check zero or non zero */
538 if (uipc_main.tid) pthread_join(uipc_main.tid, NULL);
539 }
540
541 /*******************************************************************************
542 **
543 ** Function UIPC_Init
544 **
545 ** Description Initialize UIPC module
546 **
547 ** Returns void
548 **
549 ******************************************************************************/
550
UIPC_Init(UNUSED_ATTR void * p_data)551 void UIPC_Init(UNUSED_ATTR void* p_data) {
552 BTIF_TRACE_DEBUG("UIPC_Init");
553
554 uipc_main_init();
555 uipc_start_main_server_thread();
556 }
557
558 /*******************************************************************************
559 **
560 ** Function UIPC_Open
561 **
562 ** Description Open UIPC interface
563 **
564 ** Returns true in case of success, false in case of failure.
565 **
566 ******************************************************************************/
UIPC_Open(tUIPC_CH_ID ch_id,tUIPC_RCV_CBACK * p_cback)567 bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback) {
568 BTIF_TRACE_DEBUG("UIPC_Open : ch_id %d, p_cback %x", ch_id, p_cback);
569
570 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
571
572 if (ch_id >= UIPC_CH_NUM) {
573 return false;
574 }
575
576 if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
577 BTIF_TRACE_EVENT("CHANNEL %d ALREADY OPEN", ch_id);
578 return 0;
579 }
580
581 switch (ch_id) {
582 case UIPC_CH_ID_AV_CTRL:
583 uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback);
584 break;
585
586 case UIPC_CH_ID_AV_AUDIO:
587 uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback);
588 break;
589 }
590
591 return true;
592 }
593
594 /*******************************************************************************
595 **
596 ** Function UIPC_Close
597 **
598 ** Description Close UIPC interface
599 **
600 ** Returns void
601 **
602 ******************************************************************************/
603
UIPC_Close(tUIPC_CH_ID ch_id)604 void UIPC_Close(tUIPC_CH_ID ch_id) {
605 BTIF_TRACE_DEBUG("UIPC_Close : ch_id %d", ch_id);
606
607 /* special case handling uipc shutdown */
608 if (ch_id != UIPC_CH_ID_ALL) {
609 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
610 uipc_close_locked(ch_id);
611 return;
612 }
613 BTIF_TRACE_DEBUG("UIPC_Close : waiting for shutdown to complete");
614 uipc_stop_main_server_thread();
615 BTIF_TRACE_DEBUG("UIPC_Close : shutdown complete");
616 }
617
618 /*******************************************************************************
619 **
620 ** Function UIPC_Send
621 **
622 ** Description Called to transmit a message over UIPC.
623 **
624 ** Returns true in case of success, false in case of failure.
625 **
626 ******************************************************************************/
UIPC_Send(tUIPC_CH_ID ch_id,UNUSED_ATTR uint16_t msg_evt,const uint8_t * p_buf,uint16_t msglen)627 bool UIPC_Send(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t msg_evt,
628 const uint8_t* p_buf, uint16_t msglen) {
629 BTIF_TRACE_DEBUG("UIPC_Send : ch_id:%d %d bytes", ch_id, msglen);
630
631 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
632
633 ssize_t ret;
634 OSI_NO_INTR(ret = write(uipc_main.ch[ch_id].fd, p_buf, msglen));
635 if (ret < 0) {
636 BTIF_TRACE_ERROR("failed to write (%s)", strerror(errno));
637 }
638
639 return false;
640 }
641
642 /*******************************************************************************
643 **
644 ** Function UIPC_Read
645 **
646 ** Description Called to read a message from UIPC.
647 **
648 ** Returns return the number of bytes read.
649 **
650 ******************************************************************************/
651
UIPC_Read(tUIPC_CH_ID ch_id,UNUSED_ATTR uint16_t * p_msg_evt,uint8_t * p_buf,uint32_t len)652 uint32_t UIPC_Read(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t* p_msg_evt,
653 uint8_t* p_buf, uint32_t len) {
654 int n_read = 0;
655 int fd = uipc_main.ch[ch_id].fd;
656 struct pollfd pfd;
657
658 if (ch_id >= UIPC_CH_NUM) {
659 BTIF_TRACE_ERROR("UIPC_Read : invalid ch id %d", ch_id);
660 return 0;
661 }
662
663 if (fd == UIPC_DISCONNECTED) {
664 BTIF_TRACE_ERROR("UIPC_Read : channel %d closed", ch_id);
665 return 0;
666 }
667
668 while (n_read < (int)len) {
669 pfd.fd = fd;
670 pfd.events = POLLIN | POLLHUP;
671
672 /* make sure there is data prior to attempting read to avoid blocking
673 a read for more than poll timeout */
674
675 int poll_ret;
676 OSI_NO_INTR(poll_ret = poll(&pfd, 1, uipc_main.ch[ch_id].read_poll_tmo_ms));
677 if (poll_ret == 0) {
678 BTIF_TRACE_WARNING("poll timeout (%d ms)",
679 uipc_main.ch[ch_id].read_poll_tmo_ms);
680 break;
681 }
682 if (poll_ret < 0) {
683 BTIF_TRACE_ERROR("%s(): poll() failed: return %d errno %d (%s)", __func__,
684 poll_ret, errno, strerror(errno));
685 break;
686 }
687
688 // BTIF_TRACE_EVENT("poll revents %x", pfd.revents);
689
690 if (pfd.revents & (POLLHUP | POLLNVAL)) {
691 BTIF_TRACE_WARNING("poll : channel detached remotely");
692 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
693 uipc_close_locked(ch_id);
694 return 0;
695 }
696
697 ssize_t n;
698 OSI_NO_INTR(n = recv(fd, p_buf + n_read, len - n_read, 0));
699
700 // BTIF_TRACE_EVENT("read %d bytes", n);
701
702 if (n == 0) {
703 BTIF_TRACE_WARNING("UIPC_Read : channel detached remotely");
704 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
705 uipc_close_locked(ch_id);
706 return 0;
707 }
708
709 if (n < 0) {
710 BTIF_TRACE_WARNING("UIPC_Read : read failed (%s)", strerror(errno));
711 return 0;
712 }
713
714 n_read += n;
715 }
716
717 return n_read;
718 }
719
720 /*******************************************************************************
721 *
722 * Function UIPC_Ioctl
723 *
724 * Description Called to control UIPC.
725 *
726 * Returns void
727 *
728 ******************************************************************************/
729
UIPC_Ioctl(tUIPC_CH_ID ch_id,uint32_t request,void * param)730 extern bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param) {
731 BTIF_TRACE_DEBUG("#### UIPC_Ioctl : ch_id %d, request %d ####", ch_id,
732 request);
733 std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
734
735 switch (request) {
736 case UIPC_REQ_RX_FLUSH:
737 uipc_flush_locked(ch_id);
738 break;
739
740 case UIPC_REG_CBACK:
741 // BTIF_TRACE_EVENT("register callback ch %d srvfd %d, fd %d", ch_id,
742 // uipc_main.ch[ch_id].srvfd, uipc_main.ch[ch_id].fd);
743 uipc_main.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param;
744 break;
745
746 case UIPC_REG_REMOVE_ACTIVE_READSET:
747 /* user will read data directly and not use select loop */
748 if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
749 /* remove this channel from active set */
750 FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
751
752 /* refresh active set */
753 uipc_wakeup_locked();
754 }
755 break;
756
757 case UIPC_SET_READ_POLL_TMO:
758 uipc_main.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
759 BTIF_TRACE_EVENT("UIPC_SET_READ_POLL_TMO : CH %d, TMO %d ms", ch_id,
760 uipc_main.ch[ch_id].read_poll_tmo_ms);
761 break;
762
763 default:
764 BTIF_TRACE_EVENT("UIPC_Ioctl : request not handled (%d)", request);
765 break;
766 }
767
768 return false;
769 }
770