• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param)==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, &param);
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