blob: 6e15233ac4aa9c842cf6c033c8c7ef6509e8992c [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
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>
Satish kumar sugasif9f2dbc2013-02-04 19:46:05 -080035#ifdef QCOM_WCN_SSR
36#include <termios.h>
37#include <sys/ioctl.h>
38#endif
rakesh reddy03b63652014-08-14 11:58:45 +053039#include <sys/prctl.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080040#include "bt_hci_bdroid.h"
41#include "userial.h"
42#include "utils.h"
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070043#include "vendor.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080044#include "bt_vendor_lib.h"
Zhihai Xu690401a2013-09-13 19:31:18 -070045#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080046
47/******************************************************************************
48** Constants & Macros
49******************************************************************************/
50
51#define USERIAL_DBG TRUE
52
53#ifndef USERIAL_DBG
54#define USERIAL_DBG FALSE
55#endif
56
57#if (USERIAL_DBG == TRUE)
58#define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
59#else
60#define USERIALDBG(param, ...) {}
61#endif
62
63#define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1)
Ajay Kumar06328fd2014-09-11 19:28:17 +053064#define MAX_RETRIAL_CLOSE 50
The Android Open Source Project5738f832012-12-12 16:00:35 -080065
66enum {
67 USERIAL_RX_EXIT,
The Android Open Source Project5738f832012-12-12 16:00:35 -080068};
69
Ajay Kumarc2dffa22014-06-11 22:09:20 +053070typedef enum {
71 USERIAL_STATE_OPENING,
72 USERIAL_STATE_OPENED,
73 USERIAL_STATE_IDLE
74} tUSERIAL_STATE;
75
The Android Open Source Project5738f832012-12-12 16:00:35 -080076/******************************************************************************
77** Externs
78******************************************************************************/
The Android Open Source Project5738f832012-12-12 16:00:35 -080079uint16_t hci_mct_receive_evt_msg(void);
80uint16_t hci_mct_receive_acl_msg(void);
81
82
83/******************************************************************************
84** Local type definitions
85******************************************************************************/
86
87typedef struct
88{
89 int fd[CH_MAX];
90 uint8_t port;
91 pthread_t read_thread;
92 BUFFER_Q rx_q;
93 HC_BT_HDR *p_rx_hdr;
94} tUSERIAL_CB;
95
96/******************************************************************************
97** Static variables
98******************************************************************************/
99
100static tUSERIAL_CB userial_cb;
101static volatile uint8_t userial_running = 0;
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530102static volatile uint8_t userial_close_pending = FALSE;
103static volatile tUSERIAL_STATE userial_state = USERIAL_STATE_IDLE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800104
105/******************************************************************************
106** Static functions
107******************************************************************************/
108
109/*****************************************************************************
110** Socket signal functions to wake up userial_read_thread for termination
111**
112** creating an unnamed pair of connected sockets
113** - signal_fds[0]: join fd_set in select call of userial_read_thread
114** - signal_fds[1]: trigger from userial_close
115*****************************************************************************/
116static int signal_fds[2]={0,1};
The Android Open Source Project5738f832012-12-12 16:00:35 -0800117static inline int create_signal_fds(fd_set* set)
118{
119 if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0)
120 {
121 ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno);
122 return -1;
123 }
124 FD_SET(signal_fds[0], set);
125 return signal_fds[0];
126}
127static inline int send_wakeup_signal(char sig_cmd)
128{
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700129 return TEMP_FAILURE_RETRY(send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800130}
131static inline char reset_signal()
132{
133 char sig_recv = -1;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700134 TEMP_FAILURE_RETRY(recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800135 return sig_recv;
136}
137static inline int is_signaled(fd_set* set)
138{
139 return FD_ISSET(signal_fds[0], set);
140}
141
142/*******************************************************************************
143**
144** Function userial_evt_read_thread
145**
146** Description The reading thread on EVT and ACL_IN channels
147**
148** Returns void *
149**
150*******************************************************************************/
151static void *userial_read_thread(void *arg)
152{
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700153 UNUSED(arg);
154
The Android Open Source Project5738f832012-12-12 16:00:35 -0800155 fd_set input;
156 int n;
157 char reason = 0;
158
159 USERIALDBG("Entering userial_read_thread()");
160
The Android Open Source Project5738f832012-12-12 16:00:35 -0800161 userial_running = 1;
162
rakesh reddy03b63652014-08-14 11:58:45 +0530163 prctl(PR_SET_NAME, (unsigned long)"bt_userial_mct", 0, 0, 0);
Zhihai Xu690401a2013-09-13 19:31:18 -0700164 raise_priority_a2dp(TASK_HIGH_USERIAL_READ);
165
The Android Open Source Project5738f832012-12-12 16:00:35 -0800166 while (userial_running)
167 {
168 /* Initialize the input fd set */
169 FD_ZERO(&input);
Sharvil Nanavati5055c9d2014-06-24 00:39:06 -0700170 FD_SET(userial_cb.fd[CH_EVT], &input);
171 FD_SET(userial_cb.fd[CH_ACL_IN], &input);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800172
173 int fd_max = create_signal_fds(&input);
174 fd_max = (fd_max>userial_cb.fd[CH_EVT]) ? fd_max : userial_cb.fd[CH_EVT];
175 fd_max = (fd_max>userial_cb.fd[CH_ACL_IN]) ? fd_max : userial_cb.fd[CH_ACL_IN];
176
177 /* Do the select */
178 n = 0;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700179 n = TEMP_FAILURE_RETRY(select(fd_max+1, &input, NULL, NULL, NULL));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800180 if(is_signaled(&input))
181 {
182 reason = reset_signal();
183 if (reason == USERIAL_RX_EXIT)
184 {
185 ALOGI("exiting userial_read_thread");
186 userial_running = 0;
187 break;
188 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800189 }
190
191 if (n > 0)
192 {
193 /* We might have input */
194 if (FD_ISSET(userial_cb.fd[CH_EVT], &input))
195 {
196 hci_mct_receive_evt_msg();
197 }
198
199 if (FD_ISSET(userial_cb.fd[CH_ACL_IN], &input))
200 {
201 hci_mct_receive_acl_msg();
202 }
203 }
204 else if (n < 0)
205 ALOGW( "select() Failed");
206 else if (n == 0)
207 ALOGW( "Got a select() TIMEOUT");
208 } /* while */
209
210 userial_running = 0;
211 USERIALDBG("Leaving userial_evt_read_thread()");
212 pthread_exit(NULL);
213
214 return NULL; // Compiler friendly
215}
Satish kumar sugasif9f2dbc2013-02-04 19:46:05 -0800216#ifdef QCOM_WCN_SSR
217/*******************************************************************************
218**
219** Function userial_dev_inreset
220**
221** Description checks for H/w reset events
222**
223** Returns reset status
224**
225*******************************************************************************/
226
227uint8_t userial_dev_inreset()
228{
229 volatile int serial_bits;
230 uint8_t dev_reset_done =0, retry_count = 0;
231 ioctl(userial_cb.fd[CH_EVT], TIOCMGET, &serial_bits);
232 if (serial_bits & TIOCM_OUT2) {
233 while(serial_bits & TIOCM_OUT1) {
234 ALOGW("userial_device in reset \n");
235 utils_delay(2000);
236 retry_count++;
237 ioctl(userial_cb.fd[CH_EVT], TIOCMGET, &serial_bits);
238 if((serial_bits & TIOCM_OUT1))
239 dev_reset_done = 0;
240 else
241 dev_reset_done = 1;
242 if(retry_count == 6)
243 break;
244 }
245 }
246 return dev_reset_done;
247}
248#endif
The Android Open Source Project5738f832012-12-12 16:00:35 -0800249
250
251/*****************************************************************************
252** Userial API Functions
253*****************************************************************************/
254
255/*******************************************************************************
256**
257** Function userial_init
258**
259** Description Initializes the userial driver
260**
The Android Open Source Project5738f832012-12-12 16:00:35 -0800261*******************************************************************************/
Sharvil Nanavati16715982014-04-26 00:58:15 -0700262bool userial_init(void)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800263{
264 int idx;
265
266 USERIALDBG("userial_init");
267 memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
268 for (idx=0; idx < CH_MAX; idx++)
269 userial_cb.fd[idx] = -1;
270 utils_queue_init(&(userial_cb.rx_q));
Sharvil Nanavati16715982014-04-26 00:58:15 -0700271 return true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800272}
273
274
275/*******************************************************************************
276**
277** Function userial_open
278**
279** Description Open Bluetooth device with the port ID
280**
The Android Open Source Project5738f832012-12-12 16:00:35 -0800281*******************************************************************************/
Sharvil Nanavati16715982014-04-26 00:58:15 -0700282bool userial_open(userial_port_t port)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800283{
Sharvil Nanavatidd28edb2014-07-17 00:53:01 -0700284 int result;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800285
286 USERIALDBG("userial_open(port:%d)", port);
287
288 if (userial_running)
289 {
Ajay Kumar06328fd2014-09-11 19:28:17 +0530290 USERIALDBG("userial_open: userial_running =1");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800291 /* Userial is open; close it first */
292 userial_close();
293 utils_delay(50);
294 }
295
Ajay Kumar06328fd2014-09-11 19:28:17 +0530296 userial_state = USERIAL_STATE_OPENING;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800297 if (port >= MAX_SERIAL_PORT)
298 {
299 ALOGE("Port > MAX_SERIAL_PORT");
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530300 userial_state = USERIAL_STATE_IDLE;
301 return FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800302 }
303
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700304 result = vendor_send_command(BT_VND_OP_USERIAL_OPEN, &userial_cb.fd);
305 if ((result != 2) && (result != 4))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800306 {
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700307 ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!",
308 result);
309 ALOGE("userial_open: HCI MCT expects 2 or 4 open file descriptors");
310 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530311 userial_state = USERIAL_STATE_IDLE;
312 return FALSE;
313 }
314
315 //This check handles the situation where userial_open takes time in BT_VND_OP_USERIAL_OPEN
316 //opening and meanwhile the close request comes.This way it will lead to crash since call
317 //flow will be like open-->close-->userial Rx thread created.
318 if(userial_close_pending == TRUE)
319 {
320 ALOGW("userial_open:Already got close request for userial port so not opening");
321 userial_close_pending = FALSE;
322 userial_state = USERIAL_STATE_IDLE;
323 return FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800324 }
325
326 ALOGI("CMD=%d, EVT=%d, ACL_Out=%d, ACL_In=%d", \
327 userial_cb.fd[CH_CMD], userial_cb.fd[CH_EVT], \
328 userial_cb.fd[CH_ACL_OUT], userial_cb.fd[CH_ACL_IN]);
329
330 if ((userial_cb.fd[CH_CMD] == -1) || (userial_cb.fd[CH_EVT] == -1) ||
331 (userial_cb.fd[CH_ACL_OUT] == -1) || (userial_cb.fd[CH_ACL_IN] == -1))
332 {
333 ALOGE("userial_open: failed to open BT transport");
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700334 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530335 userial_state = USERIAL_STATE_IDLE;
336 return FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800337 }
338
339 userial_cb.port = port;
340
341 /* Start listening thread */
Sharvil Nanavatidd28edb2014-07-17 00:53:01 -0700342 if (pthread_create(&userial_cb.read_thread, NULL, userial_read_thread, NULL) != 0)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800343 {
344 ALOGE("pthread_create failed!");
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700345 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530346 userial_state = USERIAL_STATE_IDLE;
347 return FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800348 }
349
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530350 userial_state = USERIAL_STATE_OPENED;
351 return TRUE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800352}
353
354/*******************************************************************************
355**
356** Function userial_read
357**
358** Description Read data from the userial channel
359**
360** Returns Number of bytes actually read from the userial port and
361** copied into p_data. This may be less than len.
362**
363*******************************************************************************/
Sharvil Nanavati16715982014-04-26 00:58:15 -0700364uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800365{
366 int ret = -1;
367 int ch_idx = (msg_id == MSG_HC_TO_STACK_HCI_EVT) ? CH_EVT : CH_ACL_IN;
368
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700369 ret = TEMP_FAILURE_RETRY(read(userial_cb.fd[ch_idx], p_buffer, (size_t)len));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800370 if (ret <= 0)
371 ALOGW( "userial_read: read() returned %d!", ret);
372
373 return (uint16_t) ((ret >= 0) ? ret : 0);
374}
375
376/*******************************************************************************
377**
378** Function userial_write
379**
380** Description Write data to the userial port
381**
382** Returns Number of bytes actually written to the userial port. This
383** may be less than len.
384**
385*******************************************************************************/
Sharvil Nanavati16715982014-04-26 00:58:15 -0700386uint16_t userial_write(uint16_t msg_id, const uint8_t *p_data, uint16_t len)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800387{
388 int ret, total = 0;
389 int ch_idx = (msg_id == MSG_STACK_TO_HC_HCI_CMD) ? CH_CMD : CH_ACL_OUT;
390
391 while(len != 0)
392 {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700393 ret = TEMP_FAILURE_RETRY(write(userial_cb.fd[ch_idx], p_data+total, len));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800394 total += ret;
395 len -= ret;
396 }
397
398 return ((uint16_t)total);
399}
400
Andre Eisenbach7c39dfe2014-08-17 16:32:26 -0700401void userial_close_reader(void) {
402 // Join the reader thread if it is still running.
403 if (userial_running) {
404 send_wakeup_signal(USERIAL_RX_EXIT);
405 int result = pthread_join(userial_cb.read_thread, NULL);
406 USERIALDBG("%s Joined userial reader thread: %d", __func__, result);
407 if (result)
408 ALOGE("%s failed to join reader thread: %d", __func__, result);
409 return;
410 }
411 ALOGW("%s Already closed userial reader thread", __func__);
412}
413
The Android Open Source Project5738f832012-12-12 16:00:35 -0800414/*******************************************************************************
415**
416** Function userial_close
417**
418** Description Close the userial port
419**
The Android Open Source Project5738f832012-12-12 16:00:35 -0800420*******************************************************************************/
421void userial_close(void)
422{
423 int idx, result;
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530424 int i = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800425
426 USERIALDBG("userial_close");
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530427 userial_close_pending = TRUE;
Ajay Kumar06328fd2014-09-11 19:28:17 +0530428 while((userial_state == USERIAL_STATE_OPENING) && (i< MAX_RETRIAL_CLOSE))
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530429 {
430 usleep(200);
431 i++;
432 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800433
Ajay Kumar06328fd2014-09-11 19:28:17 +0530434 if (i == MAX_RETRIAL_CLOSE)
435 USERIALDBG("USERIAL CLOSE : Timeout in creating userial read thread");
436
The Android Open Source Project5738f832012-12-12 16:00:35 -0800437 if (userial_running)
438 send_wakeup_signal(USERIAL_RX_EXIT);
439
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530440 if ((result=pthread_join(userial_cb.read_thread, NULL)) != 0)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800441 ALOGE( "pthread_join() FAILED result:%d", result);
442
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700443 vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800444
Ajay Kumarc2dffa22014-06-11 22:09:20 +0530445 userial_state = USERIAL_STATE_IDLE;
446 userial_close_pending = FALSE;
447
The Android Open Source Project5738f832012-12-12 16:00:35 -0800448 for (idx=0; idx < CH_MAX; idx++)
449 userial_cb.fd[idx] = -1;
450}