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