Home | History | Annotate | Download | only in src
      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:      userial.c
     22  *
     23  *  Description:   Contains open/read/write/close functions on serial port
     24  *
     25  ******************************************************************************/
     26 
     27 #define LOG_TAG "bt_userial"
     28 
     29 #include <utils/Log.h>
     30 #include <pthread.h>
     31 #include <fcntl.h>
     32 #include <errno.h>
     33 #include <stdio.h>
     34 #include <sys/socket.h>
     35 #include "bt_hci_bdroid.h"
     36 #include "userial.h"
     37 #include "utils.h"
     38 #include "bt_vendor_lib.h"
     39 #include <sys/prctl.h>
     40 #include "bt_utils.h"
     41 
     42 /******************************************************************************
     43 **  Constants & Macros
     44 ******************************************************************************/
     45 
     46 #ifndef USERIAL_DBG
     47 #define USERIAL_DBG FALSE
     48 #endif
     49 
     50 #if (USERIAL_DBG == TRUE)
     51 #define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
     52 #else
     53 #define USERIALDBG(param, ...) {}
     54 #endif
     55 
     56 #ifndef ENABLE_USERIAL_TIMING_LOGS
     57 #define ENABLE_USERIAL_TIMING_LOGS FALSE
     58 #endif
     59 
     60 #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1)
     61 #define READ_LIMIT (BTHC_USERIAL_READ_MEM_SIZE - BT_HC_HDR_SIZE)
     62 
     63 enum {
     64     USERIAL_RX_EXIT,
     65     USERIAL_RX_FLOW_OFF,
     66     USERIAL_RX_FLOW_ON
     67 };
     68 
     69 /******************************************************************************
     70 **  Externs
     71 ******************************************************************************/
     72 
     73 extern bt_vendor_interface_t *bt_vnd_if;
     74 
     75 /******************************************************************************
     76 **  Local type definitions
     77 ******************************************************************************/
     78 
     79 typedef struct
     80 {
     81     int             fd;
     82     uint8_t         port;
     83     pthread_t       read_thread;
     84     BUFFER_Q        rx_q;
     85     HC_BT_HDR      *p_rx_hdr;
     86 } tUSERIAL_CB;
     87 
     88 /******************************************************************************
     89 **  Static variables
     90 ******************************************************************************/
     91 
     92 static tUSERIAL_CB userial_cb;
     93 static volatile uint8_t userial_running = 0;
     94 
     95 /******************************************************************************
     96 **  Static functions
     97 ******************************************************************************/
     98 
     99 #if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE)
    100 
    101 static void log_userial_tx_timing(int len)
    102 {
    103     #define USEC_PER_SEC 1000000L
    104     static struct timespec prev = {0, 0};
    105     struct timespec now, diff;
    106     unsigned int diff_us = 0;
    107     unsigned int now_us = 0;
    108 
    109     clock_gettime(CLOCK_MONOTONIC, &now);
    110     now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
    111     diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
    112 
    113     ALOGW("[userial] ts %08d diff : %08d len %d", now_us, diff_us,
    114                 len);
    115 
    116     prev = now;
    117 }
    118 
    119 #endif
    120 
    121 
    122 /*****************************************************************************
    123 **   Socket signal functions to wake up userial_read_thread for termination
    124 **
    125 **   creating an unnamed pair of connected sockets
    126 **      - signal_fds[0]: join fd_set in select call of userial_read_thread
    127 **      - signal_fds[1]: trigger from userial_close
    128 *****************************************************************************/
    129 static int signal_fds[2]={0,1};
    130 static uint8_t rx_flow_on = TRUE;
    131 static inline int create_signal_fds(fd_set* set)
    132 {
    133     if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0)
    134     {
    135         ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno);
    136         return -1;
    137     }
    138     FD_SET(signal_fds[0], set);
    139     return signal_fds[0];
    140 }
    141 static inline int send_wakeup_signal(char sig_cmd)
    142 {
    143     return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0);
    144 }
    145 static inline char reset_signal()
    146 {
    147     char sig_recv = -1;
    148     recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL);
    149     return sig_recv;
    150 }
    151 static inline int is_signaled(fd_set* set)
    152 {
    153     return FD_ISSET(signal_fds[0], set);
    154 }
    155 
    156 
    157 /*******************************************************************************
    158 **
    159 ** Function        select_read
    160 **
    161 ** Description     check if fd is ready for reading and listen for termination
    162 **                  signal. need to use select in order to avoid collision
    163 **                  between read and close on the same fd
    164 **
    165 ** Returns         -1: termination
    166 **                 >=0: numbers of bytes read back from fd
    167 **
    168 *******************************************************************************/
    169 static int select_read(int fd, uint8_t *pbuf, int len)
    170 {
    171     fd_set input;
    172     int n = 0, ret = -1;
    173     char reason = 0;
    174 
    175     while (userial_running)
    176     {
    177         /* Initialize the input fd set */
    178         FD_ZERO(&input);
    179         if (rx_flow_on == TRUE)
    180         {
    181             FD_SET(fd, &input);
    182         }
    183         int fd_max = create_signal_fds(&input);
    184         fd_max = fd_max > fd ? fd_max : fd;
    185 
    186         /* Do the select */
    187         n = select(fd_max+1, &input, NULL, NULL, NULL);
    188         if(is_signaled(&input))
    189         {
    190             reason = reset_signal();
    191             if (reason == USERIAL_RX_EXIT)
    192             {
    193                 USERIALDBG("RX termination");
    194                 return -1;
    195             }
    196             else if (reason == USERIAL_RX_FLOW_OFF)
    197             {
    198                 USERIALDBG("RX flow OFF");
    199                 rx_flow_on = FALSE;
    200             }
    201             else if (reason == USERIAL_RX_FLOW_ON)
    202             {
    203                 USERIALDBG("RX flow ON");
    204                 rx_flow_on = TRUE;
    205             }
    206         }
    207 
    208         if (n > 0)
    209         {
    210             /* We might have input */
    211             if (FD_ISSET(fd, &input))
    212             {
    213                 ret = read(fd, pbuf, (size_t)len);
    214                 if (0 == ret)
    215                     ALOGW( "read() returned 0!" );
    216 
    217                 return ret;
    218             }
    219         }
    220         else if (n < 0)
    221             ALOGW( "select() Failed");
    222         else if (n == 0)
    223             ALOGW( "Got a select() TIMEOUT");
    224 
    225     }
    226 
    227     return ret;
    228 }
    229 
    230 /*******************************************************************************
    231 **
    232 ** Function        userial_read_thread
    233 **
    234 ** Description
    235 **
    236 ** Returns         void *
    237 **
    238 *******************************************************************************/
    239 static void *userial_read_thread(void *arg)
    240 {
    241     int rx_length = 0;
    242     HC_BT_HDR *p_buf = NULL;
    243     uint8_t *p;
    244 
    245     USERIALDBG("Entering userial_read_thread()");
    246     prctl(PR_SET_NAME, (unsigned long)"userial_read", 0, 0, 0);
    247 
    248     rx_flow_on = TRUE;
    249     userial_running = 1;
    250 
    251     raise_priority_a2dp(TASK_HIGH_USERIAL_READ);
    252 
    253     while (userial_running)
    254     {
    255         if (bt_hc_cbacks)
    256         {
    257             p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc( \
    258                                                 BTHC_USERIAL_READ_MEM_SIZE);
    259         }
    260         else
    261             p_buf = NULL;
    262 
    263         if (p_buf != NULL)
    264         {
    265             p_buf->offset = 0;
    266             p_buf->layer_specific = 0;
    267 
    268             p = (uint8_t *) (p_buf + 1);
    269             rx_length = select_read(userial_cb.fd, p, READ_LIMIT);
    270         }
    271         else
    272         {
    273             rx_length = 0;
    274             utils_delay(100);
    275             ALOGW("userial_read_thread() failed to gain buffers");
    276             continue;
    277         }
    278 
    279 
    280         if (rx_length > 0)
    281         {
    282             p_buf->len = (uint16_t)rx_length;
    283             utils_enqueue(&(userial_cb.rx_q), p_buf);
    284             bthc_signal_event(HC_EVENT_RX);
    285         }
    286         else /* either 0 or < 0 */
    287         {
    288             ALOGW("select_read return size <=0:%d, exiting userial_read_thread",\
    289                  rx_length);
    290             /* if we get here, we should have a buffer */
    291             bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
    292             /* negative value means exit thread */
    293             break;
    294         }
    295     } /* for */
    296 
    297     userial_running = 0;
    298     USERIALDBG("Leaving userial_read_thread()");
    299     pthread_exit(NULL);
    300 
    301     return NULL;    // Compiler friendly
    302 }
    303 
    304 
    305 /*****************************************************************************
    306 **   Userial API Functions
    307 *****************************************************************************/
    308 
    309 /*******************************************************************************
    310 **
    311 ** Function        userial_init
    312 **
    313 ** Description     Initializes the userial driver
    314 **
    315 ** Returns         TRUE/FALSE
    316 **
    317 *******************************************************************************/
    318 uint8_t userial_init(void)
    319 {
    320     USERIALDBG("userial_init");
    321     memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
    322     userial_cb.fd = -1;
    323     utils_queue_init(&(userial_cb.rx_q));
    324     return TRUE;
    325 }
    326 
    327 
    328 /*******************************************************************************
    329 **
    330 ** Function        userial_open
    331 **
    332 ** Description     Open Bluetooth device with the port ID
    333 **
    334 ** Returns         TRUE/FALSE
    335 **
    336 *******************************************************************************/
    337 uint8_t userial_open(uint8_t port)
    338 {
    339     struct sched_param param;
    340     int policy, result;
    341     pthread_attr_t thread_attr;
    342     int fd_array[CH_MAX];
    343 
    344     USERIALDBG("userial_open(port:%d)", port);
    345 
    346     if (userial_running)
    347     {
    348         /* Userial is open; close it first */
    349         userial_close();
    350         utils_delay(50);
    351     }
    352 
    353     if (port >= MAX_SERIAL_PORT)
    354     {
    355         ALOGE("Port > MAX_SERIAL_PORT");
    356         return FALSE;
    357     }
    358 
    359     /* Calling vendor-specific part */
    360     if (bt_vnd_if)
    361     {
    362         result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &fd_array);
    363 
    364         if (result != 1)
    365         {
    366             ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!",
    367                     result);
    368             ALOGE("userial_open: HCI UART expects only one open fd");
    369             bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
    370             return FALSE;
    371         }
    372 
    373         userial_cb.fd = fd_array[0];
    374     }
    375     else
    376     {
    377         ALOGE("userial_open: missing vendor lib interface !!!");
    378         ALOGE("userial_open: unable to open UART port");
    379         return FALSE;
    380     }
    381 
    382     if (userial_cb.fd == -1)
    383     {
    384         ALOGE("userial_open: failed to open UART port");
    385         return FALSE;
    386     }
    387 
    388     USERIALDBG( "fd = %d", userial_cb.fd);
    389 
    390     userial_cb.port = port;
    391 
    392     pthread_attr_init(&thread_attr);
    393 
    394     if (pthread_create(&(userial_cb.read_thread), &thread_attr, \
    395                        userial_read_thread, NULL) != 0 )
    396     {
    397         ALOGE("pthread_create failed!");
    398         return FALSE;
    399     }
    400 
    401     if(pthread_getschedparam(userial_cb.read_thread, &policy, &param)==0)
    402     {
    403         policy = BTHC_LINUX_BASE_POLICY;
    404 #if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
    405         param.sched_priority = BTHC_USERIAL_READ_THREAD_PRIORITY;
    406 #endif
    407         result = pthread_setschedparam(userial_cb.read_thread, policy, &param);
    408         if (result != 0)
    409         {
    410             ALOGW("userial_open: pthread_setschedparam failed (%s)", \
    411                   strerror(result));
    412         }
    413     }
    414 
    415     return TRUE;
    416 }
    417 
    418 /*******************************************************************************
    419 **
    420 ** Function        userial_read
    421 **
    422 ** Description     Read data from the userial port
    423 **
    424 ** Returns         Number of bytes actually read from the userial port and
    425 **                 copied into p_data.  This may be less than len.
    426 **
    427 *******************************************************************************/
    428 uint16_t  userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len)
    429 {
    430     uint16_t total_len = 0;
    431     uint16_t copy_len = 0;
    432     uint8_t *p_data = NULL;
    433 
    434     do
    435     {
    436         if(userial_cb.p_rx_hdr != NULL)
    437         {
    438             p_data = ((uint8_t *)(userial_cb.p_rx_hdr + 1)) + \
    439                      (userial_cb.p_rx_hdr->offset);
    440 
    441             if((userial_cb.p_rx_hdr->len) <= (len - total_len))
    442                 copy_len = userial_cb.p_rx_hdr->len;
    443             else
    444                 copy_len = (len - total_len);
    445 
    446             memcpy((p_buffer + total_len), p_data, copy_len);
    447 
    448             total_len += copy_len;
    449 
    450             userial_cb.p_rx_hdr->offset += copy_len;
    451             userial_cb.p_rx_hdr->len -= copy_len;
    452 
    453             if(userial_cb.p_rx_hdr->len == 0)
    454             {
    455                 if (bt_hc_cbacks)
    456                     bt_hc_cbacks->dealloc((TRANSAC) userial_cb.p_rx_hdr, \
    457                                               (char *) (userial_cb.p_rx_hdr+1));
    458 
    459                 userial_cb.p_rx_hdr = NULL;
    460             }
    461         }
    462 
    463         if(userial_cb.p_rx_hdr == NULL)
    464         {
    465             userial_cb.p_rx_hdr=(HC_BT_HDR *)utils_dequeue(&(userial_cb.rx_q));
    466         }
    467     } while ((userial_cb.p_rx_hdr != NULL) && (total_len < len));
    468 
    469     return total_len;
    470 }
    471 
    472 /*******************************************************************************
    473 **
    474 ** Function        userial_write
    475 **
    476 ** Description     Write data to the userial port
    477 **
    478 ** Returns         Number of bytes actually written to the userial port. This
    479 **                 may be less than len.
    480 **
    481 *******************************************************************************/
    482 uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
    483 {
    484     int ret, total = 0;
    485 
    486     while(len != 0)
    487     {
    488 #if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE)
    489         log_userial_tx_timing(len);
    490 #endif
    491         ret = write(userial_cb.fd, p_data+total, len);
    492         total += ret;
    493         len -= ret;
    494     }
    495 
    496     return ((uint16_t)total);
    497 }
    498 
    499 /*******************************************************************************
    500 **
    501 ** Function        userial_close
    502 **
    503 ** Description     Close the userial port
    504 **
    505 ** Returns         None
    506 **
    507 *******************************************************************************/
    508 void userial_close(void)
    509 {
    510     int result;
    511     TRANSAC p_buf;
    512 
    513     USERIALDBG("userial_close(fd:%d)", userial_cb.fd);
    514 
    515     if (userial_running)
    516         send_wakeup_signal(USERIAL_RX_EXIT);
    517 
    518     if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0)
    519         ALOGE( "pthread_join() FAILED result:%d", result);
    520 
    521     /* Calling vendor-specific part */
    522     if (bt_vnd_if)
    523         bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
    524 
    525     userial_cb.fd = -1;
    526 
    527     if (bt_hc_cbacks)
    528     {
    529         while ((p_buf = utils_dequeue (&(userial_cb.rx_q))) != NULL)
    530         {
    531             bt_hc_cbacks->dealloc(p_buf, (char *) ((HC_BT_HDR *)p_buf+1));
    532         }
    533     }
    534 }
    535 
    536 /*******************************************************************************
    537 **
    538 ** Function        userial_ioctl
    539 **
    540 ** Description     ioctl inteface
    541 **
    542 ** Returns         None
    543 **
    544 *******************************************************************************/
    545 void userial_ioctl(userial_ioctl_op_t op, void *p_data)
    546 {
    547     switch(op)
    548     {
    549         case USERIAL_OP_RXFLOW_ON:
    550             if (userial_running)
    551                 send_wakeup_signal(USERIAL_RX_FLOW_ON);
    552             break;
    553 
    554         case USERIAL_OP_RXFLOW_OFF:
    555             if (userial_running)
    556                 send_wakeup_signal(USERIAL_RX_FLOW_OFF);
    557             break;
    558 
    559         case USERIAL_OP_INIT:
    560         default:
    561             break;
    562     }
    563 }
    564 
    565