blob: 29ad374ad1d89ed9b699c51e55efdcf4634edd19 [file] [log] [blame]
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* MediaTek Inc. (C) 2016~2017. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "boots.h"
#define LOG_TAG "boots_hci"
#define HCI_MAX_DEV 1
#define BTPROTO_HCI 1
#define HCIDEVUP _IOW('H', 201, int)
#define HCIDEVDOWN _IOW('H', 202, int)
#define HCIDEVRESET _IOW('H', 203, int)
#define HCIDEVRESTAT _IOW('H', 204, int)
#define HCIGETDEVLIST _IOR('H', 210, int)
#define HCISETRAW _IOW('H', 220, int)
enum {
HCI_UP,
HCI_INIT,
HCI_RUNNING,
HCI_PSCAN,
HCI_ISCAN,
HCI_AUTH,
HCI_ENCRYPT,
HCI_INQUIRY,
HCI_RAW,
HCI_RESET,
};
struct sockaddr_hci {
unsigned short family;
unsigned short device;
unsigned short channel;
};
struct dev_info {
int index;
int skt_fd;
};
struct hci_dev_req {
uint16_t dev_id;
uint32_t dev_opt;
};
struct hci_dev_list_req {
uint16_t dev_num;
struct hci_dev_req dev_req[0]; /* hci_dev_req structures */
};
static int commPort = 0;
static struct dev_info hci_dev_info[HCI_MAX_DEV];
//---------------------------------------------------------------------------
static int boots_hci_open_dev(uint16_t index)
{
struct sockaddr_hci addr_hci;
int skt_fd;
/* Create HCI socket */
skt_fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (skt_fd < 0)
return skt_fd;
BPRINT_D("sock = %x", skt_fd);
/* Bind socket to the HCI device */
memset(&addr_hci, 0, sizeof(addr_hci));
addr_hci.family = AF_BLUETOOTH;
addr_hci.device = index;
/* 1 means HCI_USER_CHANNEL */
addr_hci.channel = 1;
if (bind(skt_fd, (struct sockaddr *) &addr_hci, sizeof(addr_hci)) < 0)
goto failed;
return skt_fd;
failed:
close(skt_fd);
return -1;
}
//---------------------------------------------------------------------------
static int boots_hci_close_dev(int skt_fd)
{
if (skt_fd < 0) {
BPRINT_E("boots_hci_close_dev %d", skt_fd);
return -1;
}
return close(skt_fd);
}
//---------------------------------------------------------------------------
static struct dev_info *boots_hci_init_device(uint16_t index)
{
struct dev_info *dev = NULL;
int skt_fd;
BPRINT_I("open HCI%d", index);
skt_fd = boots_hci_open_dev(index);
if (skt_fd < 0) {
BPRINT_E("Unable to open HCI%d: %s (%d)", index, strerror(errno), errno);
return NULL;
}
dev = &hci_dev_info[index];
memset(dev, 0, sizeof(*dev));
dev->index = index;
dev->skt_fd = skt_fd;
commPort = skt_fd;
/* HCI_CHANNEL_USER don't need to set filter */
/* Start HCI device */
/* If we use HCI_CHANNEL_RAW, we must be send HCIDEVUP to bluez stack */
/*
while (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {
BPRINT_E("Can't init device HCI%d: %s (%d)",
index, strerror(errno), errno);
sleep(1);
}*/
return dev;
}
//---------------------------------------------------------------------------
static int boots_hci_init_all_devices(void)
{
int skt_fd;
struct hci_dev_list_req *dev_list = NULL;
struct hci_dev_req *dev_req = NULL;
int i, ret = 0;
/* Create HCI socket to get HCI devices number*/
skt_fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (skt_fd < 0) {
BPRINT_E("Can't open HCI socket: %s (%d)", strerror(errno), errno);
ret = -1;
goto exit;
}
BPRINT_D("sock = %d", skt_fd);
dev_list = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
if (!dev_list) {
BPRINT_E("Can't allocate devlist buffer");
ret = -1;
goto exit;
}
dev_req = dev_list->dev_req;
dev_list->dev_num = HCI_MAX_DEV;
if (ioctl(skt_fd, HCIGETDEVLIST, dev_list) < 0) {
BPRINT_E("Can't get device list: %s (%d)", strerror(errno), errno);
ret = -1;
goto exit;
}
if (dev_list->dev_num == 0) {
BPRINT_E("No BT device.");
ret = -1;
goto exit;
}
BPRINT_I("BT dev_num = %d", dev_list->dev_num);
for (i = 0; i < dev_list->dev_num; i++, dev_req++) {
/* only support HCI0 */
if (dev_req->dev_id >= HCI_MAX_DEV)
continue;
boots_hci_init_device(dev_req->dev_id);
}
exit:
if (skt_fd >= 0)
close(skt_fd);
if (dev_list)
free(dev_list);
return ret;
}
//---------------------------------------------------------------------------
static int boots_hci_deinit_device(int index)
{
struct dev_info *dev = NULL;
dev = &hci_dev_info[index];
if (dev->skt_fd < 0)
return -1;
BPRINT_I("Stopping HCI%d socket %d", index, dev->skt_fd);
boots_hci_close_dev(dev->skt_fd);
memset(dev, 0, sizeof(*dev));
return 0;
}
//---------------------------------------------------------------------------
static int boots_hci_deinit_all_devices(void)
{
int i;
for (i = 0; i < HCI_MAX_DEV; i++)
boots_hci_deinit_device(i);
return 0;
}
//---------------------------------------------------------------------------
int boots_hci_enable(char *arg, void *func_cb)
{
UNUSED(boots_btif);
UNUSED(arg);
UNUSED(func_cb);
if (boots_hci_init_all_devices() < 0) {
BPRINT_E("adapter_ops_setup failed");
return -1;
}
else {
return commPort;
}
}
//---------------------------------------------------------------------------
int boots_hci_disable(int bt_fd)
{
UNUSED(bt_fd);
if (commPort >= 0) {
boots_hci_deinit_all_devices();
commPort = -1;
}
return 0;
}