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