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 <assert.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <pthread.h> 33 #include <stdio.h> 34 #include <sys/eventfd.h> 35 #include <sys/prctl.h> 36 #include <sys/socket.h> 37 #include <utils/Log.h> 38 39 #include "bt_hci_bdroid.h" 40 #include "bt_utils.h" 41 #include "bt_vendor_lib.h" 42 #include "userial.h" 43 #include "utils.h" 44 #include "vendor.h" 45 46 /****************************************************************************** 47 ** Constants & Macros 48 ******************************************************************************/ 49 50 #ifndef USERIAL_DBG 51 #define USERIAL_DBG TRUE 52 #endif 53 54 #if (USERIAL_DBG == TRUE) 55 #define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} 56 #else 57 #define USERIALDBG(param, ...) {} 58 #endif 59 60 #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1) 61 62 // The set of events one can send to the userial read thread. 63 // Note that the values must be >= 0x8000000000000000 to guarantee delivery 64 // of the message (see eventfd(2) for details on blocking behaviour). 65 enum { 66 USERIAL_RX_EXIT = 0x8000000000000000ULL 67 }; 68 69 /****************************************************************************** 70 ** Externs 71 ******************************************************************************/ 72 73 /****************************************************************************** 74 ** Local type definitions 75 ******************************************************************************/ 76 77 typedef struct 78 { 79 int fd; 80 uint8_t port; 81 pthread_t read_thread; 82 BUFFER_Q rx_q; 83 HC_BT_HDR *p_rx_hdr; 84 } tUSERIAL_CB; 85 86 /****************************************************************************** 87 ** Static variables 88 ******************************************************************************/ 89 90 static tUSERIAL_CB userial_cb; 91 static volatile uint8_t userial_running = 0; 92 93 /***************************************************************************** 94 ** Socket signal functions to wake up userial_read_thread for termination 95 ** 96 ** creating an unnamed pair of connected sockets 97 ** - signal_fds[0]: join fd_set in select call of userial_read_thread 98 ** - signal_fds[1]: trigger from userial_close 99 *****************************************************************************/ 100 static int event_fd = -1; 101 102 static inline int add_event_fd(fd_set *set) { 103 if (event_fd == -1) { 104 event_fd = eventfd(0, 0); 105 if (event_fd == -1) { 106 ALOGE("%s unable to create event fd: %s", __func__, strerror(errno)); 107 return -1; 108 } 109 } 110 111 FD_SET(event_fd, set); 112 return event_fd; 113 } 114 115 static inline void send_event(uint64_t event_id) { 116 assert(event_fd != -1); 117 eventfd_write(event_fd, event_id); 118 } 119 120 static inline uint64_t read_event() { 121 assert(event_fd != -1); 122 123 uint64_t value = 0; 124 eventfd_read(event_fd, &value); 125 return value; 126 } 127 128 static inline bool is_event_available(fd_set *set) { 129 assert(event_fd != -1); 130 return !!FD_ISSET(event_fd, set); 131 } 132 133 /******************************************************************************* 134 ** 135 ** Function select_read 136 ** 137 ** Description check if fd is ready for reading and listen for termination 138 ** signal. need to use select in order to avoid collision 139 ** between read and close on the same fd 140 ** 141 ** Returns -1: termination 142 ** >=0: numbers of bytes read back from fd 143 ** 144 *******************************************************************************/ 145 static int select_read(int fd, uint8_t *pbuf, int len) 146 { 147 fd_set input; 148 int n = 0, ret = -1; 149 150 while (userial_running) 151 { 152 /* Initialize the input fd set */ 153 FD_ZERO(&input); 154 FD_SET(fd, &input); 155 int fd_max = add_event_fd(&input); 156 fd_max = fd_max > fd ? fd_max : fd; 157 158 /* Do the select */ 159 n = select(fd_max+1, &input, NULL, NULL, NULL); 160 if(is_event_available(&input)) 161 { 162 uint64_t event = read_event(); 163 switch (event) { 164 case USERIAL_RX_EXIT: 165 USERIALDBG("RX termination"); 166 return -1; 167 } 168 } 169 170 if (n > 0) 171 { 172 /* We might have input */ 173 if (FD_ISSET(fd, &input)) 174 { 175 ret = read(fd, pbuf, (size_t)len); 176 if (0 == ret) 177 ALOGW( "read() returned 0!" ); 178 179 return ret; 180 } 181 } 182 else if (n < 0) 183 ALOGW( "select() Failed"); 184 else if (n == 0) 185 ALOGW( "Got a select() TIMEOUT"); 186 187 } 188 189 return ret; 190 } 191 192 static void *userial_read_thread(void *arg) 193 { 194 int rx_length = 0; 195 HC_BT_HDR *p_buf = NULL; 196 uint8_t *p; 197 UNUSED(arg); 198 199 USERIALDBG("Entering userial_read_thread()"); 200 prctl(PR_SET_NAME, (unsigned long)"userial_read", 0, 0, 0); 201 202 userial_running = 1; 203 204 raise_priority_a2dp(TASK_HIGH_USERIAL_READ); 205 206 while (userial_running) 207 { 208 if (bt_hc_cbacks) 209 { 210 p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc( 211 BT_HC_HDR_SIZE + HCI_MAX_FRAME_SIZE + 1); /* H4 HDR = 1 */ 212 } 213 else 214 p_buf = NULL; 215 216 if (p_buf != NULL) 217 { 218 p_buf->offset = 0; 219 p_buf->layer_specific = 0; 220 221 p = (uint8_t *) (p_buf + 1); 222 int userial_fd = userial_cb.fd; 223 if (userial_fd != -1) 224 rx_length = select_read(userial_fd, p, HCI_MAX_FRAME_SIZE + 1); 225 else 226 rx_length = 0; 227 } 228 else 229 { 230 rx_length = 0; 231 utils_delay(100); 232 ALOGW("userial_read_thread() failed to gain buffers"); 233 continue; 234 } 235 236 237 if (rx_length > 0) 238 { 239 p_buf->len = (uint16_t)rx_length; 240 utils_enqueue(&(userial_cb.rx_q), p_buf); 241 bthc_rx_ready(); 242 } 243 else /* either 0 or < 0 */ 244 { 245 ALOGW("select_read return size <=0:%d, exiting userial_read_thread",\ 246 rx_length); 247 /* if we get here, we should have a buffer */ 248 bt_hc_cbacks->dealloc(p_buf); 249 /* negative value means exit thread */ 250 break; 251 } 252 } /* for */ 253 254 userial_running = 0; 255 USERIALDBG("Leaving userial_read_thread()"); 256 pthread_exit(NULL); 257 258 return NULL; // Compiler friendly 259 } 260 261 262 /***************************************************************************** 263 ** Userial API Functions 264 *****************************************************************************/ 265 266 bool userial_init(void) 267 { 268 USERIALDBG("userial_init"); 269 memset(&userial_cb, 0, sizeof(tUSERIAL_CB)); 270 userial_cb.fd = -1; 271 utils_queue_init(&userial_cb.rx_q); 272 return true; 273 } 274 275 bool userial_open(userial_port_t port) { 276 if (port >= MAX_SERIAL_PORT) { 277 ALOGE("%s serial port %d > %d (max).", __func__, port, MAX_SERIAL_PORT); 278 return false; 279 } 280 281 if (userial_running) { 282 userial_close(); 283 utils_delay(50); 284 } 285 286 // Call in to the vendor-specific library to open the serial port. 287 int fd_array[CH_MAX]; 288 for (int i = 0; i < CH_MAX; i++) 289 fd_array[i] = -1; 290 291 int num_ports = vendor_send_command(BT_VND_OP_USERIAL_OPEN, &fd_array); 292 293 if (num_ports != 1) { 294 ALOGE("%s opened wrong number of ports: got %d, expected 1.", __func__, num_ports); 295 goto error; 296 } 297 298 userial_cb.fd = fd_array[0]; 299 if (userial_cb.fd == -1) { 300 ALOGE("%s unable to open serial port.", __func__); 301 goto error; 302 } 303 304 userial_cb.port = port; 305 306 if (pthread_create(&userial_cb.read_thread, NULL, userial_read_thread, NULL)) { 307 ALOGE("%s unable to spawn read thread.", __func__); 308 goto error; 309 } 310 311 return true; 312 313 error: 314 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL); 315 return false; 316 } 317 318 uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len) 319 { 320 uint16_t total_len = 0; 321 uint16_t copy_len = 0; 322 uint8_t *p_data = NULL; 323 UNUSED(msg_id); 324 325 do 326 { 327 if(userial_cb.p_rx_hdr != NULL) 328 { 329 p_data = ((uint8_t *)(userial_cb.p_rx_hdr + 1)) + \ 330 (userial_cb.p_rx_hdr->offset); 331 332 if((userial_cb.p_rx_hdr->len) <= (len - total_len)) 333 copy_len = userial_cb.p_rx_hdr->len; 334 else 335 copy_len = (len - total_len); 336 337 memcpy((p_buffer + total_len), p_data, copy_len); 338 339 total_len += copy_len; 340 341 userial_cb.p_rx_hdr->offset += copy_len; 342 userial_cb.p_rx_hdr->len -= copy_len; 343 344 if(userial_cb.p_rx_hdr->len == 0) 345 { 346 if (bt_hc_cbacks) 347 bt_hc_cbacks->dealloc(userial_cb.p_rx_hdr); 348 349 userial_cb.p_rx_hdr = NULL; 350 } 351 } 352 353 if(userial_cb.p_rx_hdr == NULL) 354 { 355 userial_cb.p_rx_hdr=(HC_BT_HDR *)utils_dequeue(&(userial_cb.rx_q)); 356 } 357 } while ((userial_cb.p_rx_hdr != NULL) && (total_len < len)); 358 359 return total_len; 360 } 361 362 uint16_t userial_write(uint16_t msg_id, const uint8_t *p_data, uint16_t len) { 363 UNUSED(msg_id); 364 365 uint16_t total = 0; 366 while (len) { 367 ssize_t ret = write(userial_cb.fd, p_data + total, len); 368 switch (ret) { 369 case -1: 370 ALOGE("%s error writing to serial port: %s", __func__, strerror(errno)); 371 return total; 372 case 0: // don't loop forever in case write returns 0. 373 return total; 374 default: 375 total += ret; 376 len -= ret; 377 break; 378 } 379 } 380 381 return total; 382 } 383 384 void userial_close_reader(void) { 385 // Join the reader thread if it is still running. 386 if (userial_running) { 387 send_event(USERIAL_RX_EXIT); 388 int result = pthread_join(userial_cb.read_thread, NULL); 389 USERIALDBG("%s Joined userial reader thread: %d", __func__, result); 390 if (result) 391 ALOGE("%s failed to join reader thread: %d", __func__, result); 392 return; 393 } 394 ALOGW("%s Already closed userial reader thread", __func__); 395 } 396 397 void userial_close(void) { 398 assert(bt_hc_cbacks != NULL); 399 400 // Join the reader thread if it's still running. 401 if (userial_running) { 402 send_event(USERIAL_RX_EXIT); 403 int result = pthread_join(userial_cb.read_thread, NULL); 404 if (result) 405 ALOGE("%s failed to join reader thread: %d", __func__, result); 406 } 407 408 // Ask the vendor-specific library to close the serial port. 409 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL); 410 411 // Free all buffers still waiting in the RX queue. 412 // TODO: use list data structure and clean this up. 413 void *buf; 414 while ((buf = utils_dequeue(&userial_cb.rx_q)) != NULL) 415 bt_hc_cbacks->dealloc(buf); 416 417 userial_cb.fd = -1; 418 } 419