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
add_event_fd(fd_set * set)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
send_event(uint64_t event_id)115 static inline void send_event(uint64_t event_id) {
116 assert(event_fd != -1);
117 eventfd_write(event_fd, event_id);
118 }
119
read_event()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
is_event_available(fd_set * set)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 *******************************************************************************/
select_read(int fd,uint8_t * pbuf,int len)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
userial_read_thread(void * arg)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
userial_init(void)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
userial_open(userial_port_t port)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
userial_read(uint16_t msg_id,uint8_t * p_buffer,uint16_t len)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
userial_write(uint16_t msg_id,const uint8_t * p_data,uint16_t len)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
userial_close_reader(void)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
userial_close(void)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