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};
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 userial_evt_read_thread
131 **
132 ** Description The reading thread on EVT and ACL_IN channels
133 **
134 ** Returns void *
135 **
136 *******************************************************************************/
userial_read_thread(void * arg)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 *******************************************************************************/
userial_init(void)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 *******************************************************************************/
userial_open(userial_port_t port)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 *******************************************************************************/
userial_read(uint16_t msg_id,uint8_t * p_buffer,uint16_t len)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 *******************************************************************************/
userial_write(uint16_t msg_id,const uint8_t * p_data,uint16_t len)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
userial_close_reader(void)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 *******************************************************************************/
userial_close(void)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