diff options
Diffstat (limited to 'udrv/ulinux/uipc.c')
-rw-r--r-- | udrv/ulinux/uipc.c | 894 |
1 files changed, 894 insertions, 0 deletions
diff --git a/udrv/ulinux/uipc.c b/udrv/ulinux/uipc.c new file mode 100644 index 0000000..9bb44df --- /dev/null +++ b/udrv/ulinux/uipc.c @@ -0,0 +1,894 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/***************************************************************************** + * + * Filename: uipc.c + * + * Description: UIPC implementation for bluedroid + * + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/socket.h> +#include <sys/un.h> +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include <sys/select.h> +#include <sys/poll.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/prctl.h> + + +#include "gki.h" +#include "data_types.h" +#include "uipc.h" + +#include <cutils/sockets.h> +#include "audio_a2dp_hw.h" + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ + +#define PCM_FILENAME "/data/test.pcm" + +#define MAX(a,b) ((a)>(b)?(a):(b)) + +#define CASE_RETURN_STR(const) case const: return #const; + +#define UIPC_DISCONNECTED (-1) + +#define UIPC_LOCK() /*BTIF_TRACE_EVENT1(" %s lock", __FUNCTION__);*/ pthread_mutex_lock(&uipc_main.mutex); +#define UIPC_UNLOCK() /*BTIF_TRACE_EVENT1("%s unlock", __FUNCTION__);*/ pthread_mutex_unlock(&uipc_main.mutex); + +/***************************************************************************** +** Local type definitions +******************************************************************************/ + +typedef enum { + UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1, +} tUIPC_TASK_FLAGS; + +typedef struct { + int srvfd; + int fd; + int read_poll_tmo_ms; + int task_evt_flags; /* event flags pending to be processed in read task */ + tUIPC_EVENT cond_flags; + pthread_mutex_t cond_mutex; + pthread_cond_t cond; + tUIPC_RCV_CBACK *cback; +} tUIPC_CHAN; + +typedef struct { + pthread_t tid; /* main thread id */ + int running; + pthread_mutex_t mutex; + + fd_set active_set; + fd_set read_set; + int max_fd; + int signal_fds[2]; + + tUIPC_CHAN ch[UIPC_CH_NUM]; +} tUIPC_MAIN; + + +/***************************************************************************** +** Static variables +******************************************************************************/ + +static tUIPC_MAIN uipc_main; + + +/***************************************************************************** +** Static functions +******************************************************************************/ + +static int uipc_close_ch_locked(tUIPC_CH_ID ch_id); + +/***************************************************************************** +** Externs +******************************************************************************/ + + +/***************************************************************************** +** Helper functions +******************************************************************************/ + + +const char* dump_uipc_event(tUIPC_EVENT event) +{ + switch(event) + { + CASE_RETURN_STR(UIPC_OPEN_EVT) + CASE_RETURN_STR(UIPC_CLOSE_EVT) + CASE_RETURN_STR(UIPC_RX_DATA_EVT) + CASE_RETURN_STR(UIPC_RX_DATA_READY_EVT) + CASE_RETURN_STR(UIPC_TX_DATA_READY_EVT) + default: + return "UNKNOWN MSG ID"; + } +} + +/***************************************************************************** +** +** Function +** +** Description +** +** Returns +** +*******************************************************************************/ + +static void uipc_wait(tUIPC_CH_ID ch_id, tUIPC_EVENT wait_event_flags) +{ + int ret; + tUIPC_CHAN *p = &uipc_main.ch[ch_id]; + + //BTIF_TRACE_EVENT2("WAIT UIPC CH %d EVT %x BEGIN", ch_id, wait_event_flags); + pthread_mutex_lock(&p->cond_mutex); + p->cond_flags |= wait_event_flags; + ret = pthread_cond_wait(&p->cond, &p->cond_mutex); + pthread_mutex_unlock(&p->cond_mutex); + //BTIF_TRACE_EVENT2("WAIT UIPC CH %d EVT %x DONE", ch_id, wait_event_flags); +} + +static void uipc_signal(tUIPC_CH_ID ch_id, tUIPC_EVENT event) +{ + int ret; + tUIPC_CHAN *p = &uipc_main.ch[ch_id]; + + //BTIF_TRACE_EVENT2("SIGNAL UIPC CH %d EVT %x BEGIN", ch_id, dump_uipc_event(event)); + pthread_mutex_lock(&p->cond_mutex); + + if (event & p->cond_flags) + { + //BTIF_TRACE_EVENT0("UNBLOCK"); + ret = pthread_cond_signal(&p->cond); + p->cond_flags = 0; + } + + pthread_mutex_unlock(&p->cond_mutex); +} + + + +/***************************************************************************** +** socket helper functions +*****************************************************************************/ + +static inline int create_server_socket(const char* name) +{ + int s = socket(AF_LOCAL, SOCK_STREAM, 0); + + BTIF_TRACE_EVENT1("create_server_socket %s", name); + + if(socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) + { + BTIF_TRACE_EVENT1("socket failed to create (%s)", strerror(errno)); + return -1; + } + + if(listen(s, 5) < 0) + { + BTIF_TRACE_EVENT1("listen failed", strerror(errno)); + close(s); + return -1; + } + + BTIF_TRACE_EVENT1("created socket fd %d", s); + return s; +} + +static int accept_server_socket(int sfd) +{ + struct sockaddr_un remote; + struct pollfd pfd; + int fd; + int len = sizeof(struct sockaddr_un); + + BTIF_TRACE_EVENT1("accept fd %d", sfd); + + /* make sure there is data to process */ + pfd.fd = sfd; + pfd.events = POLLIN; + + if (poll(&pfd, 1, 0) == 0) + { + BTIF_TRACE_EVENT0("accept poll timeout"); + return -1; + } + + //BTIF_TRACE_EVENT1("poll revents 0x%x", pfd.revents); + + if ((fd = accept(sfd, (struct sockaddr *)&remote, &len)) == -1) + { + BTIF_TRACE_ERROR1("sock accept failed (%s)", strerror(errno)); + return -1; + } + + //BTIF_TRACE_EVENT1("new fd %d", fd); + + return fd; +} + +/***************************************************************************** +** +** uipc helper functions +** +*****************************************************************************/ + +static int uipc_main_init(void) +{ + int i; + const pthread_mutexattr_t attr = PTHREAD_MUTEX_RECURSIVE; + pthread_mutex_init(&uipc_main.mutex, &attr); + + BTIF_TRACE_EVENT0("### uipc_main_init ###"); + + /* setup interrupt socket pair */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc_main.signal_fds) < 0) + { + return -1; + } + + FD_SET(uipc_main.signal_fds[0], &uipc_main.active_set); + uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.signal_fds[0]); + + for (i=0; i< UIPC_CH_NUM; i++) + { + tUIPC_CHAN *p = &uipc_main.ch[i]; + p->srvfd = UIPC_DISCONNECTED; + p->fd = UIPC_DISCONNECTED; + p->task_evt_flags = 0; + pthread_cond_init(&p->cond, NULL); + pthread_mutex_init(&p->cond_mutex, NULL); + p->cback = NULL; + } + + return 0; +} + +void uipc_main_cleanup(void) +{ + int i; + + BTIF_TRACE_EVENT0("uipc_main_cleanup"); + + close(uipc_main.signal_fds[0]); + close(uipc_main.signal_fds[1]); + + /* close any open channels */ + for (i=0; i<UIPC_CH_NUM; i++) + uipc_close_ch_locked(i); +} + + + +/* check pending events in read task */ +static void uipc_check_task_flags_locked(void) +{ + int i; + + for (i=0; i<UIPC_CH_NUM; i++) + { + //BTIF_TRACE_EVENT2("CHECK TASK FLAGS %x %x", uipc_main.ch[i].task_evt_flags, UIPC_TASK_FLAG_DISCONNECT_CHAN); + if (uipc_main.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) + { + uipc_main.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN; + uipc_close_ch_locked(i); + } + + /* add here */ + + } +} + + +static int uipc_check_fd_locked(tUIPC_CH_ID ch_id) +{ + if (ch_id >= UIPC_CH_NUM) + return -1; + + //BTIF_TRACE_EVENT2("CHECK SRVFD %d (ch %d)", uipc_main.ch[ch_id].srvfd, ch_id); + + if (FD_ISSET(uipc_main.ch[ch_id].srvfd, &uipc_main.read_set)) + { + BTIF_TRACE_EVENT1("INCOMING CONNECTION ON CH %d", ch_id); + + uipc_main.ch[ch_id].fd = accept_server_socket(uipc_main.ch[ch_id].srvfd); + + BTIF_TRACE_EVENT1("NEW FD %d", uipc_main.ch[ch_id].fd); + + if ((uipc_main.ch[ch_id].fd > 0) && uipc_main.ch[ch_id].cback) + { + /* if we have a callback we should add this fd to the active set + and notify user with callback event */ + BTIF_TRACE_EVENT1("ADD FD %d TO ACTIVE SET", uipc_main.ch[ch_id].fd); + FD_SET(uipc_main.ch[ch_id].fd, &uipc_main.active_set); + uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.ch[ch_id].fd); + } + + if (uipc_main.ch[ch_id].fd < 0) + { + BTIF_TRACE_ERROR2("FAILED TO ACCEPT CH %d (%s)", ch_id, strerror(errno)); + return -1; + } + + if (uipc_main.ch[ch_id].cback) + uipc_main.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT); + } + + //BTIF_TRACE_EVENT2("CHECK FD %d (ch %d)", uipc_main.ch[ch_id].fd, ch_id); + + if (FD_ISSET(uipc_main.ch[ch_id].fd, &uipc_main.read_set)) + { + //BTIF_TRACE_EVENT1("INCOMING DATA ON CH %d", ch_id); + + if (uipc_main.ch[ch_id].cback) + uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT); + } + return 0; +} + +static void uipc_check_interrupt_locked(void) +{ + if (FD_ISSET(uipc_main.signal_fds[0], &uipc_main.read_set)) + { + char sig_recv = 0; + //BTIF_TRACE_EVENT0("UIPC INTERRUPT"); + recv(uipc_main.signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL); + } +} + +static inline void uipc_wakeup_locked(void) +{ + char sig_on = 1; + BTIF_TRACE_EVENT0("UIPC SEND WAKE UP"); + send(uipc_main.signal_fds[1], &sig_on, sizeof(sig_on), 0); +} + +static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, char *name, tUIPC_RCV_CBACK *cback) +{ + int fd; + + BTIF_TRACE_EVENT1("SETUP CHANNEL SERVER %d", ch_id); + + if (ch_id >= UIPC_CH_NUM) + return -1; + + UIPC_LOCK(); + + fd = create_server_socket(name); + + if (fd < 0) + { + BTIF_TRACE_ERROR2("failed to setup %s", name, strerror(errno)); + UIPC_UNLOCK(); + return -1; + } + + BTIF_TRACE_EVENT1("ADD SERVER FD TO ACTIVE SET %d", fd); + FD_SET(fd, &uipc_main.active_set); + uipc_main.max_fd = MAX(uipc_main.max_fd, fd); + + uipc_main.ch[ch_id].srvfd = fd; + uipc_main.ch[ch_id].cback = cback; + uipc_main.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS; + + /* trigger main thread to update read set */ + uipc_wakeup_locked(); + + UIPC_UNLOCK(); + + return 0; +} + +static void uipc_flush_ch_locked(tUIPC_CH_ID ch_id) +{ + char buf; + struct pollfd pfd; + int ret; + + pfd.events = POLLIN|POLLHUP; + pfd.fd = uipc_main.ch[ch_id].fd; + + if (uipc_main.ch[ch_id].fd == UIPC_DISCONNECTED) + return; + + while (1) + { + ret = poll(&pfd, 1, 1); + BTIF_TRACE_EVENT3("uipc_flush_ch_locked polling : fd %d, rxev %x, ret %d", pfd.fd, pfd.revents, ret); + + if (pfd.revents | (POLLERR|POLLHUP)) + return; + + if (ret <= 0) + { + BTIF_TRACE_EVENT1("uipc_flush_ch_locked : error (%d)", ret); + return; + } + read(pfd.fd, &buf, 1); + } +} + + +static void uipc_flush_locked(tUIPC_CH_ID ch_id) +{ + if (ch_id >= UIPC_CH_NUM) + return; + + switch(ch_id) + { + case UIPC_CH_ID_AV_CTRL: + uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL); + break; + + case UIPC_CH_ID_AV_AUDIO: + uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO); + break; + } +} + + +static int uipc_close_ch_locked(tUIPC_CH_ID ch_id) +{ + int wakeup = 0; + + BTIF_TRACE_EVENT1("CLOSE CHANNEL %d", ch_id); + + if (ch_id >= UIPC_CH_NUM) + return -1; + + if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) + { + BTIF_TRACE_EVENT1("CLOSE SERVER (FD %d)", uipc_main.ch[ch_id].srvfd); + close(uipc_main.ch[ch_id].srvfd); + FD_CLR(uipc_main.ch[ch_id].srvfd, &uipc_main.active_set); + uipc_main.ch[ch_id].srvfd = UIPC_DISCONNECTED; + wakeup = 1; + } + + if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) + { + BTIF_TRACE_EVENT1("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd); + close(uipc_main.ch[ch_id].fd); + FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set); + uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED; + wakeup = 1; + } + + /* notify this connection is closed */ + if (uipc_main.ch[ch_id].cback) + uipc_main.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT); + + /* trigger main thread update if something was updated */ + if (wakeup) + uipc_wakeup_locked(); + + return 0; +} + + +void uipc_close_locked(tUIPC_CH_ID ch_id) +{ + if (uipc_main.ch[ch_id].srvfd == UIPC_DISCONNECTED) + { + BTIF_TRACE_EVENT1("CHANNEL %d ALREADY CLOSED", ch_id); + return; + } + + /* schedule close on this channel */ + uipc_main.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN; + uipc_wakeup_locked(); +} + + +static void uipc_read_task(void *arg) +{ + int ch_id; + int result; + + prctl(PR_SET_NAME, (unsigned long)"uipc-main", 0, 0, 0); + + while (uipc_main.running) + { + uipc_main.read_set = uipc_main.active_set; + + result = select(uipc_main.max_fd+1, &uipc_main.read_set, NULL, NULL, NULL); + + if (result == 0) + { + BTIF_TRACE_EVENT0("select timeout"); + continue; + } + else if (result < 0) + { + BTIF_TRACE_EVENT1("select failed %s", strerror(errno)); + continue; + } + + UIPC_LOCK(); + + /* clear any wakeup interrupt */ + uipc_check_interrupt_locked(); + + /* check pending task events */ + uipc_check_task_flags_locked(); + + /* make sure we service audio channel first */ + uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO); + + /* check for other connections */ + for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) + { + if (ch_id != UIPC_CH_ID_AV_AUDIO) + uipc_check_fd_locked(ch_id); + } + + UIPC_UNLOCK(); + } + + BTIF_TRACE_EVENT0("UIPC READ THREAD EXITING"); + + uipc_main_cleanup(); + + uipc_main.tid = 0; + + BTIF_TRACE_EVENT0("UIPC READ THREAD DONE"); +} + + +int uipc_start_main_server_thread(void) +{ + uipc_main.running = 1; + + if (pthread_create(&uipc_main.tid, (const pthread_attr_t *) NULL, (void*)uipc_read_task, NULL) < 0) + { + BTIF_TRACE_ERROR1("uipc_thread_create pthread_create failed:%d", errno); + return -1; + } + + return 0; +} + +/* blocking call */ +void uipc_stop_main_server_thread(void) +{ + /* request shutdown of read thread */ + UIPC_LOCK(); + uipc_main.running = 0; + uipc_wakeup_locked(); + UIPC_UNLOCK(); + + /* wait until read thread is fully terminated */ + if (uipc_main.tid > 0) + pthread_join(uipc_main.tid, NULL); +} + +/******************************************************************************* + ** + ** Function UIPC_Init + ** + ** Description Initialize UIPC module + ** + ** Returns void + ** + *******************************************************************************/ + +UDRV_API void UIPC_Init(void *p_data) +{ + BTIF_TRACE_DEBUG0("UIPC_Init"); + + memset(&uipc_main, 0, sizeof(tUIPC_MAIN)); + + uipc_main_init(); + + uipc_start_main_server_thread(); +} + +/******************************************************************************* + ** + ** Function UIPC_Open + ** + ** Description Open UIPC interface + ** + ** Returns TRUE in case of success, FALSE in case of failure. + ** + *******************************************************************************/ +UDRV_API BOOLEAN UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK *p_cback) +{ + BTIF_TRACE_DEBUG2("UIPC_Open : ch_id %d, p_cback %x", ch_id, p_cback); + + UIPC_LOCK(); + + if (ch_id >= UIPC_CH_NUM) + { + UIPC_UNLOCK(); + return FALSE; + } + + if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) + { + BTIF_TRACE_EVENT1("CHANNEL %d ALREADY OPEN", ch_id); + UIPC_UNLOCK(); + return 0; + } + + switch(ch_id) + { + case UIPC_CH_ID_AV_CTRL: + uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback); + break; + + case UIPC_CH_ID_AV_AUDIO: + uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback); + break; + } + + UIPC_UNLOCK(); + + return TRUE; +} + +/******************************************************************************* + ** + ** Function UIPC_Close + ** + ** Description Close UIPC interface + ** + ** Returns void + ** + *******************************************************************************/ + +UDRV_API void UIPC_Close(tUIPC_CH_ID ch_id) +{ + BTIF_TRACE_DEBUG1("UIPC_Close : ch_id %d", ch_id); + + /* special case handling uipc shutdown */ + if (ch_id != UIPC_CH_ID_ALL) + { + UIPC_LOCK(); + uipc_close_locked(ch_id); + UIPC_UNLOCK(); + } + else + { + BTIF_TRACE_DEBUG0("UIPC_Close : waiting for shutdown to complete"); + uipc_stop_main_server_thread(); + BTIF_TRACE_DEBUG0("UIPC_Close : shutdown complete"); + } +} + +/******************************************************************************* + ** + ** Function UIPC_SendBuf + ** + ** Description Called to transmit a message over UIPC. + ** Message buffer will be freed by UIPC_SendBuf. + ** + ** Returns TRUE in case of success, FALSE in case of failure. + ** + *******************************************************************************/ +UDRV_API BOOLEAN UIPC_SendBuf(tUIPC_CH_ID ch_id, BT_HDR *p_msg) +{ + BTIF_TRACE_DEBUG1("UIPC_SendBuf : ch_id %d NOT IMPLEMENTED", ch_id); + + UIPC_LOCK(); + + /* currently not used */ + + UIPC_UNLOCK(); + + return FALSE; +} + +/******************************************************************************* + ** + ** Function UIPC_Send + ** + ** Description Called to transmit a message over UIPC. + ** + ** Returns TRUE in case of success, FALSE in case of failure. + ** + *******************************************************************************/ +UDRV_API BOOLEAN UIPC_Send(tUIPC_CH_ID ch_id, UINT16 msg_evt, UINT8 *p_buf, + UINT16 msglen) +{ + int n; + + BTIF_TRACE_DEBUG2("UIPC_Send : ch_id:%d %d bytes", ch_id, msglen); + + UIPC_LOCK(); + + if (write(uipc_main.ch[ch_id].fd, p_buf, msglen) < 0) + { + BTIF_TRACE_ERROR1("failed to write (%s)", strerror(errno)); + } + + UIPC_UNLOCK(); + + return FALSE; +} + +/******************************************************************************* + ** + ** Function UIPC_ReadBuf + ** + ** Description Called to read a message from UIPC. + ** + ** Returns void + ** + *******************************************************************************/ +UDRV_API void UIPC_ReadBuf(tUIPC_CH_ID ch_id, BT_HDR *p_msg) +{ + BTIF_TRACE_DEBUG1("UIPC_ReadBuf : ch_id:%d NOT IMPLEMENTED", ch_id); + + UIPC_LOCK(); + UIPC_UNLOCK(); +} + +/******************************************************************************* + ** + ** Function UIPC_Read + ** + ** Description Called to read a message from UIPC. + ** + ** Returns return the number of bytes read. + ** + *******************************************************************************/ + +UDRV_API UINT32 UIPC_Read(tUIPC_CH_ID ch_id, UINT16 *p_msg_evt, UINT8 *p_buf, UINT32 len) +{ + int n; + int n_read = 0; + int fd = uipc_main.ch[ch_id].fd; + struct pollfd pfd; + + if (ch_id >= UIPC_CH_NUM) + { + BTIF_TRACE_ERROR1("UIPC_Read : invalid ch id %d", ch_id); + return 0; + } + + if (fd == UIPC_DISCONNECTED) + { + BTIF_TRACE_ERROR1("UIPC_Read : channel %d closed", ch_id); + return 0; + } + + //BTIF_TRACE_DEBUG4("UIPC_Read : ch_id %d, len %d, fd %d, polltmo %d", ch_id, len, + // fd, uipc_main.ch[ch_id].read_poll_tmo_ms); + + while (n_read < (int)len) + { + pfd.fd = fd; + pfd.events = POLLIN|POLLHUP; + + /* make sure there is data prior to attempting read to avoid blocking + a read for more than poll timeout */ + if (poll(&pfd, 1, uipc_main.ch[ch_id].read_poll_tmo_ms) == 0) + { + BTIF_TRACE_EVENT1("poll timeout (%d ms)", uipc_main.ch[ch_id].read_poll_tmo_ms); + return 0; + } + + //BTIF_TRACE_EVENT1("poll revents %x", pfd.revents); + + if (pfd.revents & (POLLHUP|POLLNVAL) ) + { + BTIF_TRACE_EVENT0("poll : channel detached remotely"); + UIPC_LOCK(); + uipc_close_locked(ch_id); + UIPC_UNLOCK(); + return 0; + } + + n = recv(fd, p_buf, len, 0); + + //BTIF_TRACE_EVENT1("read %d bytes", n); + + if (n == 0) + { + BTIF_TRACE_EVENT0("UIPC_Read : channel detached remotely"); + UIPC_LOCK(); + uipc_close_locked(ch_id); + UIPC_UNLOCK(); + return 0; + } + + if (n < 0) + { + BTIF_TRACE_EVENT1("UIPC_Read : read failed (%s)", strerror(errno)); + return 0; + } + + n_read+=n; + + } + + return n_read; +} + +/******************************************************************************* +** +** Function UIPC_Ioctl +** +** Description Called to control UIPC. +** +** Returns void +** +*******************************************************************************/ + +UDRV_API extern BOOLEAN UIPC_Ioctl(tUIPC_CH_ID ch_id, UINT32 request, void *param) +{ + BTIF_TRACE_DEBUG2("#### UIPC_Ioctl : ch_id %d, request %d ####", ch_id, request); + + UIPC_LOCK(); + + switch(request) + { + case UIPC_REQ_RX_FLUSH: + uipc_flush_locked(ch_id); + break; + + case UIPC_REG_CBACK: + //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); + uipc_main.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param; + break; + + case UIPC_REG_REMOVE_ACTIVE_READSET: + + /* user will read data directly and not use select loop */ + if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) + { + /* remove this channel from active set */ + FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set); + + /* refresh active set */ + uipc_wakeup_locked(); + } + break; + + case UIPC_SET_READ_POLL_TMO: + uipc_main.ch[ch_id].read_poll_tmo_ms = (int)param; + BTIF_TRACE_EVENT2("UIPC_SET_READ_POLL_TMO : CH %d, TMO %d ms", ch_id, uipc_main.ch[ch_id].read_poll_tmo_ms ); + break; + + default: + BTIF_TRACE_EVENT1("UIPC_Ioctl : request not handled (%d)", request); + break; + } + + UIPC_UNLOCK(); + + return FALSE; +} + |