1/******************************************************************************
2 *
3 *  Copyright (C) 2012 Marvell International Ltd.
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#define LOG_TAG "bt_vendor_mrvl"
19
20#include <time.h>
21#include <errno.h>
22#include <sched.h>
23#include <stdio.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <termios.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <signal.h>
31#include <sys/types.h>
32#include <sys/select.h>
33#include <sys/mman.h>
34#include <pthread.h>
35#include <utils/Log.h>
36
37#include "bt_vendor_lib.h"
38
39
40/* ioctl command to release the read thread before driver close */
41#define MBTCHAR_IOCTL_RELEASE _IO('M', 1)
42
43#define VERSION "M002"
44
45
46/***********************************************************
47 *  Externs
48 ***********************************************************
49 */
50void hw_mrvl_config_start(void);
51void hw_mrvl_sco_config(void);
52
53/***********************************************************
54 *  Local variables
55 ***********************************************************
56 */
57static const char mchar_port[] = "/dev/mbtchar0";
58static int mchar_fd = -1;
59
60/***********************************************************
61 *  Global variables
62 ***********************************************************
63 */
64bt_vendor_callbacks_t *vnd_cb;
65unsigned char bdaddr[6];
66
67/***********************************************************
68 *  Local functions
69 ***********************************************************
70 */
71static int bt_vnd_mrvl_if_init(const bt_vendor_callbacks_t *p_cb,
72		unsigned char *local_bdaddr)
73{
74	ALOGI("Marvell BT Vendor Lib: ver %s", VERSION);
75	vnd_cb = (bt_vendor_callbacks_t *) p_cb;
76	memcpy(bdaddr, local_bdaddr, sizeof(bdaddr));
77	return 0;
78}
79
80static int bt_vnd_mrvl_if_op(bt_vendor_opcode_t opcode, void *param)
81{
82	int ret = 0;
83	int *power_state = NULL;
84	int local_st = 0;
85
86	/* ALOGD("opcode = %d", opcode); */
87	switch (opcode) {
88	case BT_VND_OP_POWER_CTRL:
89		power_state = (int *)param;
90		if (BT_VND_PWR_OFF == *power_state) {
91			ALOGD("Power off");
92		} else if (BT_VND_PWR_ON == *power_state) {
93			ALOGD("Power on");
94		} else {
95			ret = -1;
96		}
97		break;
98	case BT_VND_OP_FW_CFG:
99		hw_mrvl_config_start();
100		break;
101	case BT_VND_OP_SCO_CFG:
102		hw_mrvl_sco_config();
103		break;
104	case BT_VND_OP_USERIAL_OPEN:
105		mchar_fd = open(mchar_port, O_RDWR|O_NOCTTY);
106		if (mchar_fd < 0) {
107			ALOGE("Fail to open port %s", mchar_port);
108			ret = -1;
109		} else {
110			ALOGD("open port %s success", mchar_port);
111			ret = 1;
112		}
113		((int *)param)[0] = mchar_fd;
114		break;
115	case BT_VND_OP_USERIAL_CLOSE:
116		if (mchar_fd < 0) {
117			ret = -1;
118		} else {
119			/* mbtchar port is blocked on read. Release the port
120			 * before we close it.
121			 */
122			ioctl(mchar_fd, MBTCHAR_IOCTL_RELEASE, &local_st);
123			/* Give it sometime before we close the mbtchar */
124			usleep(1000);
125			ALOGD("close port %s", mchar_port);
126			if (close(mchar_fd) < 0) {
127				ALOGE("Fail to close port %s", mchar_port);
128				ret = -1;
129			} else {
130				mchar_fd = -1; /* closed successfully */
131			}
132		}
133		break;
134	case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
135		break;
136	case BT_VND_OP_LPM_SET_MODE:
137		/* TODO: Enable or disable LPM mode on BT Controller.
138		 * ret = xx;
139		 */
140		if (vnd_cb)
141			vnd_cb->lpm_cb(ret);
142
143		break;
144	case BT_VND_OP_LPM_WAKE_SET_STATE:
145		break;
146	case BT_VND_OP_EPILOG:
147		if (vnd_cb)
148			vnd_cb->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
149		break;
150	default:
151		ret = -1;
152		break;
153	} /* switch (opcode) */
154
155	return ret;
156}
157
158static void bt_vnd_mrvl_if_cleanup(void)
159{
160	return;
161}
162
163const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
164	sizeof(bt_vendor_interface_t),
165	bt_vnd_mrvl_if_init,
166	bt_vnd_mrvl_if_op,
167	bt_vnd_mrvl_if_cleanup,
168};
169
170