blob: 7c8486af49138cd09915b82c20c49282358f5188 [file] [log] [blame]
/****************************************************************************
*
* Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd
*
****************************************************************************/
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#define LOG_TAG "BT_VENDOR"
#include <unistd.h>
#include <stdio.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/param.h>
#include "bt_vendor_lib.h"
#include "bt_vendor_slsi.h"
#define BLUETOOTH_ADDRESS_FILE "/sys/module/scsc_bt/parameters/bluetooth_address"
static const bt_vendor_callbacks_t *vcb;
static unsigned long long bt_addr;
static char h4_file[MAXPATHLEN] = "/dev/scsc_h4_0";
static int hci_fd = -1;
/*
* Internal helpers
*/
static void set_bluetooth_address(unsigned long long value)
{
BTVENDORI("Setting Bluetooth address");
if (!access(BLUETOOTH_ADDRESS_FILE, W_OK))
{
int bt_fd = open(BLUETOOTH_ADDRESS_FILE, O_RDWR);
if (bt_fd != -1)
{
char buf[15];
ssize_t res;
res = sprintf(buf, "0x%llx", value);
if (res != write(bt_fd, buf, res))
{
BTVENDORW("Unable setiting Bluetooth address (%s)", strerror(errno));
}
close(bt_fd);
}
else
{
BTVENDORW("Opening file: " BLUETOOTH_ADDRESS_FILE " - failed with: %s", strerror(errno));
}
}
else
{
BTVENDORW("Unable to access: " BLUETOOTH_ADDRESS_FILE " - error: %s", strerror(errno));
}
}
/*
* Internal interface
*/
static int hci_open(int *fds)
{
int h4_fd;
BTVENDORI("HCI open");
if (bt_addr != 0)
{
set_bluetooth_address(bt_addr);
}
BTVENDORI("Opening h4 device %s", h4_file);
h4_fd = open(h4_file, O_RDWR);
if (h4_fd == -1)
{
BTVENDORE("Open h4 device failed: %s (%d)", strerror(errno), errno);
return -1;
}
BTVENDORI("Open h4 device %s succeded", h4_file);
hci_fd = h4_fd;
*fds = h4_fd;
return 1;
}
static int hci_close(void)
{
int fd = hci_fd;
if (bt_addr != 0)
{
set_bluetooth_address(0);
}
hci_fd = -1;
return close(fd);
}
static int init(const bt_vendor_callbacks_t *p_cb, unsigned char *local_bdaddr)
{
/* Sanity check */
if (p_cb == NULL)
{
ALOGE("init failed with no user callbacks!");
return -1;
}
/* Store a reference to user callbacks */
vcb = (bt_vendor_callbacks_t *) p_cb;
/* Store the Bluetooth address */
bt_addr = (((unsigned long long) local_bdaddr[0]) << 40) |
(((unsigned long long) local_bdaddr[1]) << 32) |
(((unsigned long long) local_bdaddr[2]) << 24) |
(((unsigned long long) local_bdaddr[3]) << 16) |
(((unsigned long long) local_bdaddr[4]) << 8) |
((unsigned long long) local_bdaddr[5]);
return 0;
}
static int op(bt_vendor_opcode_t opcode, void *param)
{
int retval = 0;
switch (opcode)
{
case BT_VND_OP_POWER_CTRL:
{
break;
}
case BT_VND_OP_FW_CFG:
{
vcb->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
break;
}
case BT_VND_OP_SCO_CFG:
{
vcb->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
break;
}
case BT_VND_OP_USERIAL_OPEN:
{
retval = hci_open((int *) param);
BTVENDORD("hci_open returns: %d", retval);
break;
}
case BT_VND_OP_USERIAL_CLOSE:
{
retval = hci_close();
BTVENDORD("hci_close returns: %d", retval);
break;
}
case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
{
uint32_t *timeout_ms = (uint32_t *) param;
*timeout_ms = 3000; /* 3 Seconds delay until the idle alarm is fired */
break;
}
case BT_VND_OP_LPM_SET_MODE:
{
/* LPM not required on SoC solutions - return fail to disable it */
vcb->lpm_cb(BT_VND_OP_RESULT_FAIL);
break;
}
case BT_VND_OP_LPM_WAKE_SET_STATE:
{
break;
}
case BT_VND_OP_EPILOG:
{
vcb->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
break;
}
case BT_VND_OP_SET_AUDIO_STATE:
{
/* Unhandled - just ignore */
BTVENDORE("BT_VND_OP_SET_AUDIO_STATE - ignoring");
break;
}
default:
{
BTVENDORW("Hit default with opcode:0x%02X", opcode);
retval = -1;
break;
}
}
return retval;
}
static void cleanup(void)
{
if (hci_fd != -1)
{
int fd = hci_fd;
hci_fd = -1;
(void) close(fd);
}
return;
}
const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
sizeof(bt_vendor_interface_t),
init,
op,
cleanup,
};