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_mct.c 22 * 23 * Description: Contains open/read/write/close functions on multi-channels 24 * 25 ******************************************************************************/ 26 27 #define LOG_TAG "bt_userial_mct" 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 "vendor.h" 39 #include "bt_vendor_lib.h" 40 #include "bt_utils.h" 41 42 /****************************************************************************** 43 ** Constants & Macros 44 ******************************************************************************/ 45 46 #define USERIAL_DBG TRUE 47 48 #ifndef USERIAL_DBG 49 #define USERIAL_DBG FALSE 50 #endif 51 52 #if (USERIAL_DBG == TRUE) 53 #define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} 54 #else 55 #define USERIALDBG(param, ...) {} 56 #endif 57 58 #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1) 59 60 enum { 61 USERIAL_RX_EXIT, 62 }; 63 64 /****************************************************************************** 65 ** Externs 66 ******************************************************************************/ 67 uint16_t hci_mct_receive_evt_msg(void); 68 uint16_t hci_mct_receive_acl_msg(void); 69 70 71 /****************************************************************************** 72 ** Local type definitions 73 ******************************************************************************/ 74 75 typedef struct 76 { 77 int fd[CH_MAX]; 78 uint8_t port; 79 pthread_t read_thread; 80 BUFFER_Q rx_q; 81 HC_BT_HDR *p_rx_hdr; 82 } tUSERIAL_CB; 83 84 /****************************************************************************** 85 ** Static variables 86 ******************************************************************************/ 87 88 static tUSERIAL_CB userial_cb; 89 static volatile uint8_t userial_running = 0; 90 91 /****************************************************************************** 92 ** Static functions 93 ******************************************************************************/ 94 95 /***************************************************************************** 96 ** Socket signal functions to wake up userial_read_thread for termination 97 ** 98 ** creating an unnamed pair of connected sockets 99 ** - signal_fds[0]: join fd_set in select call of userial_read_thread 100 ** - signal_fds[1]: trigger from userial_close 101 *****************************************************************************/ 102 static int signal_fds[2]={0,1}; 103 static inline int create_signal_fds(fd_set* set) 104 { 105 if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0) 106 { 107 ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno); 108 return -1; 109 } 110 FD_SET(signal_fds[0], set); 111 return signal_fds[0]; 112 } 113 static inline int send_wakeup_signal(char sig_cmd) 114 { 115 return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0); 116 } 117 static inline char reset_signal() 118 { 119 char sig_recv = -1; 120 recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL); 121 return sig_recv; 122 } 123 static inline int is_signaled(fd_set* set) 124 { 125 return FD_ISSET(signal_fds[0], set); 126 } 127 128 /******************************************************************************* 129 ** 130 ** Function userial_evt_read_thread 131 ** 132 ** Description The reading thread on EVT and ACL_IN channels 133 ** 134 ** Returns void * 135 ** 136 *******************************************************************************/ 137 static void *userial_read_thread(void *arg) 138 { 139 UNUSED(arg); 140 141 fd_set input; 142 int n; 143 char reason = 0; 144 145 USERIALDBG("Entering userial_read_thread()"); 146 147 userial_running = 1; 148 149 raise_priority_a2dp(TASK_HIGH_USERIAL_READ); 150 151 while (userial_running) 152 { 153 /* Initialize the input fd set */ 154 FD_ZERO(&input); 155 FD_SET(userial_cb.fd[CH_EVT], &input); 156 FD_SET(userial_cb.fd[CH_ACL_IN], &input); 157 158 int fd_max = create_signal_fds(&input); 159 fd_max = (fd_max>userial_cb.fd[CH_EVT]) ? fd_max : userial_cb.fd[CH_EVT]; 160 fd_max = (fd_max>userial_cb.fd[CH_ACL_IN]) ? fd_max : userial_cb.fd[CH_ACL_IN]; 161 162 /* Do the select */ 163 n = 0; 164 n = select(fd_max+1, &input, NULL, NULL, NULL); 165 if(is_signaled(&input)) 166 { 167 reason = reset_signal(); 168 if (reason == USERIAL_RX_EXIT) 169 { 170 ALOGI("exiting userial_read_thread"); 171 userial_running = 0; 172 break; 173 } 174 } 175 176 if (n > 0) 177 { 178 /* We might have input */ 179 if (FD_ISSET(userial_cb.fd[CH_EVT], &input)) 180 { 181 hci_mct_receive_evt_msg(); 182 } 183 184 if (FD_ISSET(userial_cb.fd[CH_ACL_IN], &input)) 185 { 186 hci_mct_receive_acl_msg(); 187 } 188 } 189 else if (n < 0) 190 ALOGW( "select() Failed"); 191 else if (n == 0) 192 ALOGW( "Got a select() TIMEOUT"); 193 } /* while */ 194 195 userial_running = 0; 196 USERIALDBG("Leaving userial_evt_read_thread()"); 197 pthread_exit(NULL); 198 199 return NULL; // Compiler friendly 200 } 201 202 203 /***************************************************************************** 204 ** Userial API Functions 205 *****************************************************************************/ 206 207 /******************************************************************************* 208 ** 209 ** Function userial_init 210 ** 211 ** Description Initializes the userial driver 212 ** 213 *******************************************************************************/ 214 bool userial_init(void) 215 { 216 int idx; 217 218 USERIALDBG("userial_init"); 219 memset(&userial_cb, 0, sizeof(tUSERIAL_CB)); 220 for (idx=0; idx < CH_MAX; idx++) 221 userial_cb.fd[idx] = -1; 222 utils_queue_init(&(userial_cb.rx_q)); 223 return true; 224 } 225 226 227 /******************************************************************************* 228 ** 229 ** Function userial_open 230 ** 231 ** Description Open Bluetooth device with the port ID 232 ** 233 *******************************************************************************/ 234 bool userial_open(userial_port_t port) 235 { 236 int result; 237 238 USERIALDBG("userial_open(port:%d)", port); 239 240 if (userial_running) 241 { 242 /* Userial is open; close it first */ 243 userial_close(); 244 utils_delay(50); 245 } 246 247 if (port >= MAX_SERIAL_PORT) 248 { 249 ALOGE("Port > MAX_SERIAL_PORT"); 250 return false; 251 } 252 253 result = vendor_send_command(BT_VND_OP_USERIAL_OPEN, &userial_cb.fd); 254 if ((result != 2) && (result != 4)) 255 { 256 ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!", 257 result); 258 ALOGE("userial_open: HCI MCT expects 2 or 4 open file descriptors"); 259 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL); 260 return false; 261 } 262 263 ALOGI("CMD=%d, EVT=%d, ACL_Out=%d, ACL_In=%d", \ 264 userial_cb.fd[CH_CMD], userial_cb.fd[CH_EVT], \ 265 userial_cb.fd[CH_ACL_OUT], userial_cb.fd[CH_ACL_IN]); 266 267 if ((userial_cb.fd[CH_CMD] == -1) || (userial_cb.fd[CH_EVT] == -1) || 268 (userial_cb.fd[CH_ACL_OUT] == -1) || (userial_cb.fd[CH_ACL_IN] == -1)) 269 { 270 ALOGE("userial_open: failed to open BT transport"); 271 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL); 272 return false; 273 } 274 275 userial_cb.port = port; 276 277 /* Start listening thread */ 278 if (pthread_create(&userial_cb.read_thread, NULL, userial_read_thread, NULL) != 0) 279 { 280 ALOGE("pthread_create failed!"); 281 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL); 282 return false; 283 } 284 285 return true; 286 } 287 288 /******************************************************************************* 289 ** 290 ** Function userial_read 291 ** 292 ** Description Read data from the userial channel 293 ** 294 ** Returns Number of bytes actually read from the userial port and 295 ** copied into p_data. This may be less than len. 296 ** 297 *******************************************************************************/ 298 uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len) 299 { 300 int ret = -1; 301 int ch_idx = (msg_id == MSG_HC_TO_STACK_HCI_EVT) ? CH_EVT : CH_ACL_IN; 302 303 ret = read(userial_cb.fd[ch_idx], p_buffer, (size_t)len); 304 if (ret <= 0) 305 ALOGW( "userial_read: read() returned %d!", ret); 306 307 return (uint16_t) ((ret >= 0) ? ret : 0); 308 } 309 310 /******************************************************************************* 311 ** 312 ** Function userial_write 313 ** 314 ** Description Write data to the userial port 315 ** 316 ** Returns Number of bytes actually written to the userial port. This 317 ** may be less than len. 318 ** 319 *******************************************************************************/ 320 uint16_t userial_write(uint16_t msg_id, const uint8_t *p_data, uint16_t len) 321 { 322 int ret, total = 0; 323 int ch_idx = (msg_id == MSG_STACK_TO_HC_HCI_CMD) ? CH_CMD : CH_ACL_OUT; 324 325 while(len != 0) 326 { 327 ret = write(userial_cb.fd[ch_idx], p_data+total, len); 328 total += ret; 329 len -= ret; 330 } 331 332 return ((uint16_t)total); 333 } 334 335 void userial_close_reader(void) { 336 // Join the reader thread if it is still running. 337 if (userial_running) { 338 send_wakeup_signal(USERIAL_RX_EXIT); 339 int result = pthread_join(userial_cb.read_thread, NULL); 340 USERIALDBG("%s Joined userial reader thread: %d", __func__, result); 341 if (result) 342 ALOGE("%s failed to join reader thread: %d", __func__, result); 343 return; 344 } 345 ALOGW("%s Already closed userial reader thread", __func__); 346 } 347 348 /******************************************************************************* 349 ** 350 ** Function userial_close 351 ** 352 ** Description Close the userial port 353 ** 354 *******************************************************************************/ 355 void userial_close(void) 356 { 357 int idx, result; 358 359 USERIALDBG("userial_close"); 360 361 if (userial_running) 362 send_wakeup_signal(USERIAL_RX_EXIT); 363 364 if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0) 365 ALOGE( "pthread_join() FAILED result:%d", result); 366 367 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL); 368 369 for (idx=0; idx < CH_MAX; idx++) 370 userial_cb.fd[idx] = -1; 371 } 372