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).
65enum {
66    USERIAL_RX_EXIT     = 0x8000000000000000ULL
67};
68
69/******************************************************************************
70**  Externs
71******************************************************************************/
72
73/******************************************************************************
74**  Local type definitions
75******************************************************************************/
76
77typedef 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
90static tUSERIAL_CB userial_cb;
91static 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*****************************************************************************/
100static int event_fd = -1;
101
102static 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
115static inline void send_event(uint64_t event_id) {
116    assert(event_fd != -1);
117    eventfd_write(event_fd, event_id);
118}
119
120static 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
128static 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*******************************************************************************/
145static 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
192static 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
266bool 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
275bool 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
313error:
314    vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
315    return false;
316}
317
318uint16_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
362uint16_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
384void 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
397void 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