BDROID_DIR := $(TOP_DIR)system/bt
LOCAL_SRC_FILES := \
+ codec/msbc/sbc.c \
+ src/rtk_socket.c \
src/bt_vendor_rtk.c \
src/hardware.c \
src/userial_vendor.c \
src/bt_skbuff.c \
src/hci_h5.c \
src/rtk_parse.c \
+ src/rtk_btservice.c \
+ src/hardware_uart.c \
+ src/hardware_usb.c \
+ src/rtk_heartbeat.c \
+ src/rtk_poll.c \
src/rtk_btsnoop_net.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/codec/msbc \
$(BDROID_DIR)/hci/include
LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_CPPFLAGS := -Werror -Wunused-parameter
include $(BUILD_SHARED_LIBRARY)
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* todo items:
+
+ use a log2 table for byte integer scale factors calculation (sum log2 results for high and low bytes)
+ fill bitpool by 16 bits instead of one at a time in bits allocation/bitpool generation
+ port to the dsp
+ don't consume more bytes than passed into the encoder
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//#include <stdint.h>
+#include <malloc.h>
+#include <string.h>
+//#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+#include "cutils/log.h"
+
+
+#define SBC_SYNCWORD 0xAD
+#define SBC_POOLTAG 'CBSR'
+
+/* sampling frequency */
+#define SBC_FS_16 0x00
+#define SBC_FS_32 0x01
+#define SBC_FS_44 0x02
+#define SBC_FS_48 0x03
+
+/* nrof_blocks */
+#define SBC_NB_4 0x00
+#define SBC_NB_8 0x01
+#define SBC_NB_12 0x02
+#define SBC_NB_16 0x03
+
+/* channel mode */
+#define SBC_CM_MONO 0x00
+#define SBC_CM_DUAL_CHANNEL 0x01
+#define SBC_CM_STEREO 0x02
+#define SBC_CM_JOINT_STEREO 0x03
+
+/* allocation mode */
+#define SBC_AM_LOUDNESS 0x00
+#define SBC_AM_SNR 0x01
+
+/* subbands */
+#define SBC_SB_4 0x00
+#define SBC_SB_8 0x01
+
+#define SBC_ALIGN_BITS 4
+#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
+
+
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned int u_int32_t;
+
+#ifndef UINT
+typedef unsigned int UINT;
+#endif
+
+
+#if defined(WIN32) && !defined(__cplusplus)
+
+#define inline __inline
+
+#endif
+
+typedef long long sbc_extended_t;
+/*
+static __inline void sbc_synthesize_four(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk);
+*/
+
+
+/* This structure contains an unpacked SBC frame.
+ Yes, there is probably quite some unused space herein */
+struct sbc_frame
+{
+ uint16_t sampling_frequency; /* in kHz */
+ unsigned char blocks;
+ enum {
+ MONO = SBC_CM_MONO,
+ DUAL_CHANNEL = SBC_CM_DUAL_CHANNEL,
+ STEREO = SBC_CM_STEREO,
+ JOINT_STEREO = SBC_CM_JOINT_STEREO
+ } channel_mode;
+ uint8_t channels;
+ enum {
+ LOUDNESS = SBC_AM_LOUDNESS,
+ SNR = SBC_AM_SNR
+ } allocation_method;
+ uint8_t subbands;
+ uint8_t bitpool;
+ uint8_t join; /* bit number x set means joint stereo has been used in subband x */
+ int scale_factor[2][8]; /* only the lower 4 bits of every element are to be used */
+ uint16_t audio_sample[16][2][8]; /* raw integer subband samples in the frame */
+
+ int sb_sample_f[16][2][8];
+ int sb_sample[16][2][8]; /* modified subband samples */
+ short pcm_sample[2][16*8]; /* original pcm audio samples */
+};
+
+struct sbc_decoder_state {
+ int subbands;
+ long long V[2][170];
+ int offset[2][16];
+};
+
+struct sbc_encoder_state {
+ int subbands;
+ int32_t X[2][80];
+};
+
+/*
+ * Calculates the CRC-8 of the first len bits in data
+ */
+static const uint8_t crc_table[256] = {
+ 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
+ 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
+ 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
+ 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
+ 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
+ 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
+ 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
+ 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
+ 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
+ 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
+ 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
+ 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
+ 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
+ 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
+ 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
+ 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
+ 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
+ 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
+ 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
+ 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
+ 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
+ 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
+ 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
+ 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
+ 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
+ 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
+ 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
+ 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
+ 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
+ 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
+ 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
+ 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
+};
+
+static uint8_t sbc_crc8(const uint8_t * data, size_t len)
+{
+ uint8_t crc = 0x0f;
+ size_t i;
+ uint8_t octet;
+
+ for (i = 0; i < len / 8; i++)
+ crc = crc_table[crc ^ data[i]];
+
+ octet = data[i];
+ for (i = 0; i < len % 8; i++)
+ {
+ char bit = ((octet ^ crc) & 0x80) >> 7;
+
+ crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
+
+ octet = octet << 1;
+ }
+
+ return crc;
+}
+
+/*
+ * Code straight from the spec to calculate the bits array
+ * Takes a pointer to the frame in question, a pointer to the bits array and the sampling frequency (as 2 bit integer)
+ */
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8], uint8_t sf)
+{
+ if (frame->channel_mode == MONO || frame->channel_mode == DUAL_CHANNEL)
+ {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ for (ch = 0; ch < frame->channels; ch++)
+ {
+ if (frame->allocation_method == SNR)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ }
+ }
+
+ else
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (frame->scale_factor[ch][sb] == 0)
+ {
+ bitneed[ch][sb] = -5;
+ }
+ else
+ {
+ if (frame->subbands == 4)
+ {
+ loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+ }
+
+ else
+ {
+ loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+ }
+
+ if (loudness > 0)
+ {
+ bitneed[ch][sb] = loudness / 2;
+ }
+
+ else
+ {
+ bitneed[ch][sb] = loudness;
+ }
+ }
+ }
+ }
+
+ max_bitneed = 0;
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+
+ bitcount = 0;
+ slicecount = 0;
+ bitslice = max_bitneed + 1;
+ do
+ {
+ bitslice--;
+ bitcount += slicecount;
+ slicecount = 0;
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+ {
+ slicecount++;
+ }
+
+ else if (bitneed[ch][sb] == bitslice + 1)
+ {
+ slicecount += 2;
+ }
+ }
+ } while (bitcount + slicecount < frame->bitpool);
+
+ if (bitcount + slicecount == frame->bitpool)
+ {
+ bitcount += slicecount;
+ bitslice--;
+ }
+
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (bitneed[ch][sb] < bitslice + 2)
+ {
+ bits[ch][sb] = 0;
+ }
+
+ else
+ {
+ bits[ch][sb] = bitneed[ch][sb] - bitslice;
+ if (bits[ch][sb] > 16)
+ bits[ch][sb] = 16;
+ }
+ }
+
+ sb = 0;
+ while (bitcount < frame->bitpool && sb < frame->subbands)
+ {
+ if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16))
+ {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+
+ else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1))
+ {
+ bits[ch][sb] = 2;
+ bitcount += 2;
+ }
+ sb++;
+ }
+
+ sb = 0;
+ while (bitcount < frame->bitpool && sb < frame->subbands)
+ {
+ if (bits[ch][sb] < 16)
+ {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ sb++;
+ }
+
+ }
+
+ }
+
+ else if (frame->channel_mode == STEREO || frame->channel_mode == JOINT_STEREO)
+ {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ if (frame->allocation_method == SNR)
+ {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ }
+ }
+ }
+
+ else
+ {
+ for (ch = 0; ch < 2; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (frame->scale_factor[ch][sb] == 0)
+ {
+ bitneed[ch][sb] = -5;
+ }
+
+ else
+ {
+ if (frame->subbands == 4)
+ {
+ loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+ }
+
+ else
+ {
+ loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+ }
+
+ if (loudness > 0)
+ {
+ bitneed[ch][sb] = loudness / 2;
+ }
+
+ else
+ {
+ bitneed[ch][sb] = loudness;
+ }
+ }
+ }
+ }
+ }
+
+ max_bitneed = 0;
+ for (ch = 0; ch < 2; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+
+ bitcount = 0;
+ slicecount = 0;
+ bitslice = max_bitneed + 1;
+ do {
+ bitslice--;
+ bitcount += slicecount;
+ slicecount = 0;
+ for (ch = 0; ch < 2; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+ {
+ slicecount++;
+ }
+
+ else if (bitneed[ch][sb] == bitslice + 1)
+ {
+ slicecount += 2;
+ }
+ }
+ }
+ } while (bitcount + slicecount < frame->bitpool);
+
+ if (bitcount + slicecount == frame->bitpool)
+ {
+ bitcount += slicecount;
+ bitslice--;
+ }
+
+ for (ch = 0; ch < 2; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (bitneed[ch][sb] < bitslice + 2)
+ {
+ bits[ch][sb] = 0;
+ }
+
+ else
+ {
+ bits[ch][sb] = bitneed[ch][sb] - bitslice;
+ if (bits[ch][sb] > 16)
+ bits[ch][sb] = 16;
+ }
+ }
+ }
+
+ ch = 0;
+ sb = 0;
+ while ((bitcount < frame->bitpool) && (sb < frame->subbands))
+ {
+ if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16))
+ {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+
+ else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1))
+ {
+ bits[ch][sb] = 2;
+ bitcount += 2;
+ }
+ if (ch == 1)
+ {
+ ch = 0;
+ sb++;
+ }
+ else
+ {
+ ch = 1;
+ }
+ }
+
+ ch = 0;
+ sb = 0;
+ while ((bitcount < frame->bitpool) && (sb < frame->subbands))
+ {
+ if (bits[ch][sb] < 16)
+ {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ if (ch == 1)
+ {
+ ch = 0;
+ sb++;
+ }
+
+ else
+ {
+ ch = 1;
+ }
+ }
+
+ }
+}
+
+/*
+ * Unpacks a SBC frame at the beginning of the stream in data,
+ * which has at most len bytes into frame.
+ * Returns the length in bytes of the packed frame, or a negative
+ * value on error. The error codes are:
+ *
+ * -1 Data stream too short
+ * -2 Sync byte incorrect
+ * -3 CRC8 incorrect
+ * -4 Bitpool value out of bounds
+ */
+static int sbc_unpack_frame(const uint8_t * data, struct sbc_frame *frame, size_t len)
+{
+ UINT consumed;
+ /* Will copy the parts of the header that are relevant to crc calculation here */
+ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int crc_pos = 0;
+ int32_t temp;
+
+ uint8_t sf; /* sampling_frequency, temporarily needed as array index */
+
+// int audio_sample;
+ int ch, sb, blk, bit; /* channel, subband, block and bit standard counters */
+ int bits[2][8]; /* bits distribution */
+ int levels[2][8]; /* levels derived from that */
+
+ if (len < 4)
+ {
+ //DbgPrint("Exit when len < 4\n");
+ return -1;
+ }
+
+ if (data[0] != SBC_SYNCWORD)
+ {
+ //DbgPrint("Exit when data[0] != SBC_SYNCWORD\n");
+ return -2;
+ }
+
+#if 0
+ sf = (data[1] >> 6) & 0x03;
+ switch (sf) {
+ case SBC_FS_16:
+ frame->sampling_frequency = 16000;
+ break;
+ case SBC_FS_32:
+ frame->sampling_frequency = 32000;
+ break;
+ case SBC_FS_44:
+ frame->sampling_frequency = 44100;
+ break;
+ case SBC_FS_48:
+ frame->sampling_frequency = 48000;
+ break;
+ }
+
+ switch ((data[1] >> 4) & 0x03) {
+ case SBC_NB_4:
+ frame->blocks = 4;
+ break;
+ case SBC_NB_8:
+ frame->blocks = 8;
+ break;
+ case SBC_NB_12:
+ frame->blocks = 12;
+ break;
+ case SBC_NB_16:
+ frame->blocks = 16;
+ break;
+ }
+
+ frame->channel_mode = (data[1] >> 2) & 0x03;
+ switch (frame->channel_mode) {
+ case MONO:
+ frame->channels = 1;
+ break;
+ case DUAL_CHANNEL: /* fall-through */
+ case STEREO:
+ case JOINT_STEREO:
+ frame->channels = 2;
+ break;
+ }
+
+ frame->allocation_method = (data[1] >> 1) & 0x01;
+ frame->subbands = (data[1] & 0x01) ? 8 : 4;
+ frame->bitpool = data[2];
+#endif
+
+ frame->sampling_frequency = 16000;
+ frame->blocks = 15;
+ frame->channel_mode = MONO;
+ frame->channels = 1;
+ frame->allocation_method = SBC_AM_LOUDNESS;
+ frame->subbands = 8;
+ frame->bitpool = 26;
+
+
+ if (((frame->channel_mode == MONO || frame->channel_mode == DUAL_CHANNEL)
+ && frame->bitpool > 16 * frame->subbands)
+ || ((frame->channel_mode == STEREO || frame->channel_mode == JOINT_STEREO)
+ && frame->bitpool > 32 * frame->subbands))
+ {
+ //DbgPrint("Exit when frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&"
+ // "frame->bitpool > 16 * frame->subbands\n");
+ return -4;
+ }
+
+ /* data[3] is crc, we're checking it later */
+ consumed = 32;
+#if 1
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+#endif
+
+#if 0
+ crc_header[0] = 0x31;
+ crc_header[1] = 0x1a;
+#endif
+
+ crc_pos = 16;
+
+ if (frame->channel_mode == JOINT_STEREO)
+ {
+ if (len * 8 < consumed + frame->subbands)
+ return -1;
+
+ frame->join = 0x00;
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ frame->join |= ((data[4] >> (7 - sb)) & 0x01) << sb;
+ }
+ if (frame->subbands == 4) {
+ crc_header[crc_pos / 8] = data[4] & 0xf0;
+ } else {
+ crc_header[crc_pos / 8] = data[4];
+ }
+
+ consumed += frame->subbands;
+ crc_pos += frame->subbands;
+ }
+
+ if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
+ {
+ //DbgPrint("len * 8 < consumed + (4 * frame->subbands * frame->channels\n");
+ return -1;
+ }
+
+ for (ch = 0; ch < frame->channels; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ /* FIXME assert(consumed % 4 == 0); */
+ frame->scale_factor[ch][sb] = (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
+ crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
+
+ consumed += 4;
+ crc_pos += 4;
+ }
+ }
+
+ if (data[3] != sbc_crc8(crc_header, crc_pos))
+ {
+ ALOGD("sbc_crc %02x -> %02x\n",data[3],sbc_crc8(crc_header, crc_pos));
+ return -3;
+ }
+
+ sf = SBC_FS_16;
+ sbc_calculate_bits(frame, bits, sf);
+
+ for (ch = 0; ch < frame->channels; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+ }
+ }
+#if 0
+ for (blk = 0; blk < frame->blocks; blk++)
+ {
+ for (ch = 0; ch < frame->channels; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (levels[ch][sb] > 0)
+ {
+ audio_sample = 0;
+ for (bit = 0; bit < bits[ch][sb]; bit++)
+ {
+ if (consumed > len * 8)
+ {
+ LogEvent("Exit when consumed > len * 8\n");
+ return -1;
+ }
+
+ if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
+ audio_sample |= 1 << (bits[ch][sb] - bit - 1);
+
+ consumed++;
+ }
+
+ frame->sb_sample[blk][ch][sb] =
+ (((audio_sample << 1) | 1) << frame->scale_factor[ch][sb]) /
+ levels[ch][sb] - (1 << frame->scale_factor[ch][sb]);
+ }
+
+ else
+ frame->sb_sample[blk][ch][sb] = 0;
+ }
+ }
+ }
+#endif
+
+#if 1
+
+ for (blk = 0; blk < frame->blocks; blk++)
+ {
+ for (ch = 0; ch < frame->channels; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ frame->audio_sample[blk][ch][sb] = 0;
+ if (bits[ch][sb] == 0)
+ continue;
+
+ for (bit = 0; bit < bits[ch][sb]; bit++)
+ {
+ int b; /* A bit */
+ if (consumed > len * 8)
+ return -1;
+
+ b = (data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01;
+ frame->audio_sample[blk][ch][sb] |= b << (bits[ch][sb] - bit - 1);
+
+ consumed++;
+ }
+ }
+ }
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++)
+ {
+ for (ch = 0; ch < frame->channels; ch++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (levels[ch][sb] > 0)
+ {
+ frame->sb_sample[blk][ch][sb] =
+ (((frame->audio_sample[blk][ch][sb] << 16) | 0x8000) / levels[ch][sb]) - 0x8000;
+
+ frame->sb_sample[blk][ch][sb] >>= 3;
+ frame->sb_sample[blk][ch][sb] = (frame->sb_sample[blk][ch][sb] << (frame->scale_factor[ch][sb] + 1)); // Q13
+ }
+ else
+ {
+ frame->sb_sample[blk][ch][sb] = 0;
+ }
+ }
+ }
+ }
+#endif
+
+ if (frame->channel_mode == JOINT_STEREO)
+ {
+ for (blk = 0; blk < frame->blocks; blk++)
+ {
+ for (sb = 0; sb < frame->subbands; sb++)
+ {
+ if (frame->join & (0x01 << sb)) {
+ temp = frame->sb_sample[blk][0][sb] + frame->sb_sample[blk][1][sb];
+ frame->sb_sample[blk][1][sb] = frame->sb_sample[blk][0][sb] - frame->sb_sample[blk][1][sb];
+ frame->sb_sample[blk][0][sb] = temp;
+ }
+ }
+ }
+ }
+
+ if ((consumed & 0x7) != 0)
+ consumed += 8 - (consumed & 0x7);
+
+
+ return consumed >> 3;
+}
+
+static void sbc_decoder_init(struct sbc_decoder_state *state, const struct sbc_frame *frame)
+{
+ int i, ch;
+
+ memset(state->V, 0, sizeof(state->V));
+ state->subbands = frame->subbands;
+
+ for (ch = 0; ch < 2; ch++)
+ for (i = 0; i < frame->subbands * 2; i++)
+ state->offset[ch][i] = (10 * i + 10);
+}
+
+static __inline void sbc_synthesize_four(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, j, k, idx;
+ sbc_extended_t res;
+
+ for(i = 0; i < 8; i++) {
+ /* Shifting */
+ state->offset[ch][i]--;
+ if(state->offset[ch][i] < 0) {
+ state->offset[ch][i] = 79;
+ for(j = 0; j < 9; j++) {
+ state->V[ch][j+80] = state->V[ch][j];
+ }
+ }
+ }
+
+
+ for(i = 0; i < 8; i++) {
+ /* Distribute the new matrix value to the shifted position */
+ SBC_FIXED_0(res);
+ for (j = 0; j < 4; j++) {
+ MULA(res, synmatrix4[i][j], frame->sb_sample[blk][ch][j]);
+ }
+ state->V[ch][state->offset[ch][i]] = SCALE4_STAGED1(res);
+ }
+
+ /* Compute the samples */
+ for(idx = 0, i = 0; i < 4; i++) {
+ k = (i + 4) & 0xf;
+ SBC_FIXED_0(res);
+ for(j = 0; j < 10; idx++) {
+ MULA(res, state->V[ch][state->offset[ch][i]+j++], sbc_proto_4_40m0[idx]);
+ MULA(res, state->V[ch][state->offset[ch][k]+j++], sbc_proto_4_40m1[idx]);
+ }
+ /* Store in output */
+ frame->pcm_sample[ch][blk * 4 + i] = (short)SCALE4_STAGED2(res); // Q0
+ }
+}
+
+static __inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, j, k, idx;
+ sbc_extended_t res;
+
+ for(i = 0; i < 16; i++) {
+ /* Shifting */
+ state->offset[ch][i]--;
+ if(state->offset[ch][i] < 0) {
+ state->offset[ch][i] = 159;
+ for(j = 0; j < 9; j++) {
+ state->V[ch][j+160] = state->V[ch][j];
+ }
+ }
+ }
+
+ for(i = 0; i < 16; i++) {
+ /* Distribute the new matrix value to the shifted position */
+ SBC_FIXED_0(res);
+ for (j = 0; j < 8; j++) {
+ MULA(res, synmatrix8[i][j], frame->sb_sample[blk][ch][j]); // Q28 = Q15 * Q13
+ }
+ state->V[ch][state->offset[ch][i]] = SCALE8_STAGED1(res); // Q10
+ }
+
+
+ /* Compute the samples */
+ for(idx = 0, i = 0; i < 8; i++) {
+ k = (i + 8) & 0xf;
+ SBC_FIXED_0(res);
+ for(j = 0; j < 10; idx++) {
+ MULA(res, state->V[ch][state->offset[ch][i]+j++], sbc_proto_8_80m0[idx]);
+ MULA(res, state->V[ch][state->offset[ch][k]+j++], sbc_proto_8_80m1[idx]);
+ }
+ /* Store in output */
+ frame->pcm_sample[ch][blk * 8 + i] = (short)SCALE8_STAGED2(res); // Q0
+
+ }
+}
+
+static int sbc_synthesize_audio(struct sbc_decoder_state *state, struct sbc_frame *frame)
+{
+ int ch, blk;
+
+ switch (frame->subbands) {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_synthesize_four(state, frame, ch, blk);
+ }
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_synthesize_eight(state, frame, ch, blk);
+ }
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+static void sbc_encoder_init(struct sbc_encoder_state *state, const struct sbc_frame *frame)
+{
+ memset(&state->X, 0, sizeof(state->X));
+ state->subbands = frame->subbands;
+}
+
+static __inline void _sbc_analyze_four(const int32_t *in, int32_t *out)
+{
+
+ sbc_extended_t res;
+ sbc_extended_t t[8];
+
+ out[0] = out[1] = out[2] = out[3] = 0;
+
+ MUL(res, _sbc_proto_4[0], (in[8] - in[32])); // Q18
+ MULA(res, _sbc_proto_4[1], (in[16] - in[24]));
+ t[0] = SCALE4_STAGE1(res); // Q8
+
+ MUL(res, _sbc_proto_4[2], in[1]);
+ MULA(res, _sbc_proto_4[3], in[9]);
+ MULA(res, _sbc_proto_4[4], in[17]);
+ MULA(res, _sbc_proto_4[5], in[25]);
+ MULA(res, _sbc_proto_4[6], in[33]);
+ t[1] = SCALE4_STAGE1(res);
+
+ MUL(res, _sbc_proto_4[7], in[2]);
+ MULA(res, _sbc_proto_4[8], in[10]);
+ MULA(res, _sbc_proto_4[9], in[18]);
+ MULA(res, _sbc_proto_4[10], in[26]);
+ MULA(res, _sbc_proto_4[11], in[34]);
+ t[2] = SCALE4_STAGE1(res);
+
+ MUL(res, _sbc_proto_4[12], in[3]);
+ MULA(res, _sbc_proto_4[13], in[11]);
+ MULA(res, _sbc_proto_4[14], in[19]);
+ MULA(res, _sbc_proto_4[15], in[27]);
+ MULA(res, _sbc_proto_4[16], in[35]);
+ t[3] = SCALE4_STAGE1(res);
+
+ MUL(res, _sbc_proto_4[17], in[4]);
+ MULA(res, _sbc_proto_4[18], (in[12] + in[28]));
+ MULA(res, _sbc_proto_4[19], in[20]);
+ MULA(res, _sbc_proto_4[17], in[36]);
+ t[4] = SCALE4_STAGE1(res);
+
+ MUL(res, _sbc_proto_4[16], in[5]);
+ MULA(res, _sbc_proto_4[15], in[13]);
+ MULA(res, _sbc_proto_4[14], in[21]);
+ MULA(res, _sbc_proto_4[13], in[29]);
+ MULA(res, _sbc_proto_4[12], in[37]);
+ t[5] = SCALE4_STAGE1(res);
+
+ MUL(res, _sbc_proto_4[11], in[6]);
+ MULA(res, _sbc_proto_4[10], in[14]);
+ MULA(res, _sbc_proto_4[9], in[22]);
+ MULA(res, _sbc_proto_4[8], in[30]);
+ MULA(res, _sbc_proto_4[7], in[38]);
+ t[6] = SCALE4_STAGE1(res);
+
+ MUL(res, _sbc_proto_4[6], in[7]);
+ MULA(res, _sbc_proto_4[5], in[15]);
+ MULA(res, _sbc_proto_4[4], in[23]);
+ MULA(res, _sbc_proto_4[3], in[31]);
+ MULA(res, _sbc_proto_4[2], in[39]);
+ t[7] = SCALE4_STAGE1(res);
+
+ MUL(res, _anamatrix4[0], t[0]);
+ MULA(res, _anamatrix4[1], t[1]);
+ MULA(res, _anamatrix4[2], t[2]);
+ MULA(res, _anamatrix4[1], t[3]);
+ MULA(res, _anamatrix4[0], t[4]);
+ MULA(res, _anamatrix4[3], t[5]);
+ MULA(res, -_anamatrix4[3], t[7]);
+ out[0] = (int)SCALE4_STAGE2(res); // Q0
+
+ MUL(res, -_anamatrix4[0], t[0]);
+ MULA(res, _anamatrix4[3], t[1]);
+ MULA(res, _anamatrix4[2], t[2]);
+ MULA(res, _anamatrix4[3], t[3]);
+ MULA(res, -_anamatrix4[0], t[4]);
+ MULA(res, -_anamatrix4[1], t[5]);
+ MULA(res, _anamatrix4[1], t[7]);
+ out[1] = (int)SCALE4_STAGE2(res);
+
+
+ MUL(res, -_anamatrix4[0], t[0]);
+ MULA(res, -_anamatrix4[3], t[1]);
+ MULA(res, _anamatrix4[2], t[2]);
+ MULA(res, -_anamatrix4[3], t[3]);
+ MULA(res, -_anamatrix4[0], t[4]);
+ MULA(res, _anamatrix4[1], t[5]);
+ MULA(res, -_anamatrix4[1], t[7]);
+ out[2] = (int)SCALE4_STAGE2(res);
+
+ MUL(res, _anamatrix4[0], t[0]);
+ MULA(res, -_anamatrix4[1], t[1]);
+ MULA(res, _anamatrix4[2], t[2]);
+ MULA(res, -_anamatrix4[1], t[3]);
+ MULA(res, _anamatrix4[0], t[4]);
+ MULA(res, -_anamatrix4[3], t[5]);
+ MULA(res, _anamatrix4[3], t[7]);
+ out[3] = (int)SCALE4_STAGE2(res);
+}
+static __inline void sbc_analyze_four(struct sbc_encoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i;
+ /* Input 4 New Audio Samples */
+ for (i = 39; i >= 4; i--)
+ state->X[ch][i] = state->X[ch][i - 4];
+ for (i = 3; i >= 0; i--)
+ state->X[ch][i] = frame->pcm_sample[ch][blk * 4 + (3 - i)];
+ _sbc_analyze_four(state->X[ch], frame->sb_sample_f[blk][ch]);
+}
+
+static __inline void _sbc_analyze_eight(const int32_t *in, int32_t *out)
+{
+ sbc_extended_t res;
+ sbc_extended_t t[8];
+
+ out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = 0;
+
+ MUL(res, _sbc_proto_8[0], (in[16] - in[64])); // Q18 = Q18 * Q0
+ MULA(res, _sbc_proto_8[1], (in[32] - in[48]));
+ MULA(res, _sbc_proto_8[2], in[4]);
+ MULA(res, _sbc_proto_8[3], in[20]);
+ MULA(res, _sbc_proto_8[4], in[36]);
+ MULA(res, _sbc_proto_8[5], in[52]);
+ t[0] = SCALE8_STAGE1(res); // Q10
+
+ MUL(res, _sbc_proto_8[6], in[2]);
+ MULA(res, _sbc_proto_8[7], in[18]);
+ MULA(res, _sbc_proto_8[8], in[34]);
+ MULA(res, _sbc_proto_8[9], in[50]);
+ MULA(res, _sbc_proto_8[10], in[66]);
+ t[1] = SCALE8_STAGE1(res);
+
+ MUL(res, _sbc_proto_8[11], in[1]);
+ MULA(res, _sbc_proto_8[12], in[17]);
+ MULA(res, _sbc_proto_8[13], in[33]);
+ MULA(res, _sbc_proto_8[14], in[49]);
+ MULA(res, _sbc_proto_8[15], in[65]);
+ MULA(res, _sbc_proto_8[16], in[3]);
+ MULA(res, _sbc_proto_8[17], in[19]);
+ MULA(res, _sbc_proto_8[18], in[35]);
+ MULA(res, _sbc_proto_8[19], in[51]);
+ MULA(res, _sbc_proto_8[20], in[67]);
+ t[2] = SCALE8_STAGE1(res);
+
+ MUL(res, _sbc_proto_8[21], in[5]);
+ MULA(res, _sbc_proto_8[22], in[21]);
+ MULA(res, _sbc_proto_8[23], in[37]);
+ MULA(res, _sbc_proto_8[24], in[53]);
+ MULA(res, _sbc_proto_8[25], in[69]);
+ MULA(res, -_sbc_proto_8[15], in[15]);
+ MULA(res, -_sbc_proto_8[14], in[31]);
+ MULA(res, -_sbc_proto_8[13], in[47]);
+ MULA(res, -_sbc_proto_8[12], in[63]);
+ MULA(res, -_sbc_proto_8[11], in[79]);
+ t[3] = SCALE8_STAGE1(res);
+
+ MUL(res, _sbc_proto_8[26], in[6]);
+ MULA(res, _sbc_proto_8[27], in[22]);
+ MULA(res, _sbc_proto_8[28], in[38]);
+ MULA(res, _sbc_proto_8[29], in[54]);
+ MULA(res, _sbc_proto_8[30], in[70]);
+ MULA(res, -_sbc_proto_8[10], in[14]);
+ MULA(res, -_sbc_proto_8[9], in[30]);
+ MULA(res, -_sbc_proto_8[8], in[46]);
+ MULA(res, -_sbc_proto_8[7], in[62]);
+ MULA(res, -_sbc_proto_8[6], in[78]);
+ t[4] = SCALE8_STAGE1(res);
+
+ MUL(res, _sbc_proto_8[31], in[7]);
+ MULA(res, _sbc_proto_8[32], in[23]);
+ MULA(res, _sbc_proto_8[33], in[39]);
+ MULA(res, _sbc_proto_8[34], in[55]);
+ MULA(res, _sbc_proto_8[35], in[71]);
+ MULA(res, -_sbc_proto_8[20], in[13]);
+ MULA(res, -_sbc_proto_8[19], in[29]);
+ MULA(res, -_sbc_proto_8[18], in[45]);
+ MULA(res, -_sbc_proto_8[17], in[61]);
+ MULA(res, -_sbc_proto_8[16], in[77]);
+ t[5] = SCALE8_STAGE1(res);
+
+ MUL(res, _sbc_proto_8[36], (in[8] + in[72]));
+ MULA(res, _sbc_proto_8[37], in[24]);
+ MULA(res, _sbc_proto_8[38], in[40]);
+ MULA(res, _sbc_proto_8[37], in[56]);
+ MULA(res, -_sbc_proto_8[39], in[12]);
+ MULA(res, -_sbc_proto_8[5], in[28]);
+ MULA(res, -_sbc_proto_8[4], in[44]);
+ MULA(res, -_sbc_proto_8[3], in[60]);
+ MULA(res, -_sbc_proto_8[2], in[76]);
+ t[6] = SCALE8_STAGE1(res);
+
+ MUL(res, _sbc_proto_8[35], in[9]);
+ MULA(res, _sbc_proto_8[34], in[25]);
+ MULA(res, _sbc_proto_8[33], in[41]);
+ MULA(res, _sbc_proto_8[32], in[57]);
+ MULA(res, _sbc_proto_8[31], in[73]);
+ MULA(res, -_sbc_proto_8[25], in[11]);
+ MULA(res, -_sbc_proto_8[24], in[27]);
+ MULA(res, -_sbc_proto_8[23], in[43]);
+ MULA(res, -_sbc_proto_8[22], in[59]);
+ MULA(res, -_sbc_proto_8[21], in[75]);
+ t[7] = SCALE8_STAGE1(res);
+
+ MUL(res, _anamatrix8[0], t[0]); // = Q14 * Q10
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, _anamatrix8[2], t[2]);
+ MULA(res, _anamatrix8[3], t[3]);
+ MULA(res, _anamatrix8[6], t[4]);
+ MULA(res, _anamatrix8[4], t[5]);
+ MULA(res, _anamatrix8[1], t[6]);
+ MULA(res, _anamatrix8[5], t[7]);
+ out[0] = (int)SCALE8_STAGE2(res); // Q0
+
+ MUL(res, _anamatrix8[1], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, _anamatrix8[3], t[2]);
+ MULA(res, -_anamatrix8[5], t[3]);
+ MULA(res, -_anamatrix8[6], t[4]);
+ MULA(res, -_anamatrix8[2], t[5]);
+ MULA(res, -_anamatrix8[0], t[6]);
+ MULA(res, -_anamatrix8[4], t[7]);
+ out[1] = (int)SCALE8_STAGE2(res);
+
+ MUL(res, -_anamatrix8[1], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, _anamatrix8[4], t[2]);
+ MULA(res, -_anamatrix8[2], t[3]);
+ MULA(res, -_anamatrix8[6], t[4]);
+ MULA(res, _anamatrix8[5], t[5]);
+ MULA(res, _anamatrix8[0], t[6]);
+ MULA(res, _anamatrix8[3], t[7]);
+ out[2] = (int)SCALE8_STAGE2(res);
+
+ MUL(res, -_anamatrix8[0], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, _anamatrix8[5], t[2]);
+ MULA(res, -_anamatrix8[4], t[3]);
+ MULA(res, _anamatrix8[6], t[4]);
+ MULA(res, _anamatrix8[3], t[5]);
+ MULA(res, -_anamatrix8[1], t[6]);
+ MULA(res, -_anamatrix8[2], t[7]);
+ out[3] = (int)SCALE8_STAGE2(res);
+
+ MUL(res, -_anamatrix8[0], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, -_anamatrix8[5], t[2]);
+ MULA(res, _anamatrix8[4], t[3]);
+ MULA(res, _anamatrix8[6], t[4]);
+ MULA(res, -_anamatrix8[3], t[5]);
+ MULA(res, -_anamatrix8[1], t[6]);
+ MULA(res, _anamatrix8[2], t[7]);
+ out[4] = (int)SCALE8_STAGE2(res);
+
+ MUL(res, -_anamatrix8[1], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, -_anamatrix8[4], t[2]);
+ MULA(res, _anamatrix8[2], t[3]);
+ MULA(res, -_anamatrix8[6], t[4]);
+ MULA(res, -_anamatrix8[5], t[5]);
+ MULA(res, _anamatrix8[0], t[6]);
+ MULA(res, -_anamatrix8[3], t[7]);
+ out[5] = (int)SCALE8_STAGE2(res);
+
+ MUL(res, _anamatrix8[1], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, -_anamatrix8[3], t[2]);
+ MULA(res, _anamatrix8[5], t[3]);
+ MULA(res, -_anamatrix8[6], t[4]);
+ MULA(res, _anamatrix8[2], t[5]);
+ MULA(res, -_anamatrix8[0], t[6]);
+ MULA(res, _anamatrix8[4], t[7]);
+ out[6] = (int)SCALE8_STAGE2(res);
+
+ MUL(res, _anamatrix8[0], t[0]);
+ MULA(res, _anamatrix8[7], t[1]);
+ MULA(res, -_anamatrix8[2], t[2]);
+ MULA(res, -_anamatrix8[3], t[3]);
+ MULA(res, _anamatrix8[6], t[4]);
+ MULA(res, -_anamatrix8[4], t[5]);
+ MULA(res, _anamatrix8[1], t[6]);
+ MULA(res, -_anamatrix8[5], t[7]);
+ out[7] = (int)SCALE8_STAGE2(res);
+}
+
+static __inline void sbc_analyze_eight(struct sbc_encoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i;
+
+ /* Input 8 Audio Samples */
+ for (i = 79; i >= 8; i--)
+ state->X[ch][i] = state->X[ch][i - 8];
+ for (i = 7; i >= 0; i--)
+ state->X[ch][i] = frame->pcm_sample[ch][blk * 8 + (7 - i)];
+ _sbc_analyze_eight(state->X[ch], frame->sb_sample_f[blk][ch]);
+}
+
+static int sbc_analyze_audio(struct sbc_encoder_state *state, struct sbc_frame *frame)
+{
+ int ch, blk;
+
+ switch (frame->subbands)
+ {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++)
+ for (blk = 0; blk < frame->blocks; blk++) {
+ sbc_analyze_four(state, frame, ch, blk);
+ }
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++)
+ for (blk = 0; blk < frame->blocks; blk++) {
+ sbc_analyze_eight(state, frame, ch, blk);
+ }
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+/*
+ * Packs the SBC frame from frame into the memory at data. At most len
+ * bytes will be used, should more memory be needed an appropriate
+ * error code will be returned. Returns the length of the packed frame
+ * on success or a negative value on error.
+ *
+ * The error codes are:
+ * -1 Not enough memory reserved
+ * -2 Unsupported sampling rate
+ * -3 Unsupported number of blocks
+ * -4 Unsupported number of subbands
+ * -5 Bitpool value out of bounds
+ * -99 not implemented
+ */
+
+static int sbc_pack_frame(uint8_t * data, struct sbc_frame *frame, size_t len)
+{
+ size_t produced;
+ /* Will copy the header parts for CRC-8 calculation here */
+ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int crc_pos = 0;
+
+ uint8_t sf; /* Sampling frequency as temporary value for table lookup */
+
+ int ch, sb, blk, bit; /* channel, subband, block and bit counters */
+ int bits[2][8]; /* bits distribution */
+ int levels[2][8]; /* levels are derived from that */
+
+ u_int32_t scalefactor[2][8]; /* derived from frame->scale_factor */
+
+ if (len < 4)
+ {
+ return -1;
+ }
+
+ /* Clear first 4 bytes of data (that's the constant length part of the SBC header) */
+ memset(data, 0, 4);
+
+ data[0] = SBC_SYNCWORD;
+
+ if (frame->sampling_frequency == 16000)
+ {
+ data[1] |= (SBC_FS_16 & 0x03) << 6;
+ sf = SBC_FS_16;
+ }
+ else if (frame->sampling_frequency == 32000)
+ {
+ data[1] |= (SBC_FS_32 & 0x03) << 6;
+ sf = SBC_FS_32;
+ }
+ else if (frame->sampling_frequency == 44100)
+ {
+ data[1] |= (SBC_FS_44 & 0x03) << 6;
+ sf = SBC_FS_44;
+ }
+ else if (frame->sampling_frequency == 48000)
+ {
+ data[1] |= (SBC_FS_48 & 0x03) << 6;
+ sf = SBC_FS_48;
+ }
+ else
+ {
+ return -2;
+ }
+
+ switch (frame->blocks)
+ {
+ case 4:
+ data[1] |= (SBC_NB_4 & 0x03) << 4;
+ break;
+ case 8:
+ data[1] |= (SBC_NB_8 & 0x03) << 4;
+ break;
+ case 12:
+ data[1] |= (SBC_NB_12 & 0x03) << 4;
+ break;
+ case 15:
+ data[1] |= (SBC_NB_16 & 0x03) << 4;
+ break;
+ default:
+ return -3;
+ break;
+ }
+
+ data[1] |= (frame->channel_mode & 0x03) << 2;
+
+ data[1] |= (frame->allocation_method & 0x01) << 1;
+
+ switch (frame->subbands) {
+ case 4:
+ /* Nothing to do */
+ break;
+ case 8:
+ data[1] |= 0x01;
+ break;
+ default:
+ return -4;
+ break;
+ }
+
+ data[2] = frame->bitpool;
+ if (((frame->channel_mode == MONO || frame->channel_mode == DUAL_CHANNEL)
+ && frame->bitpool > 16 * frame->subbands)
+ || ((frame->channel_mode == STEREO || frame->channel_mode == JOINT_STEREO)
+ && frame->bitpool > 32 * frame->subbands)) {
+ return -5;
+ }
+
+ /* Can't fill in crc yet */
+
+ produced = 32;
+
+ // evan.
+ data[1] = 0x00;
+ data[2] = 0x00;
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ frame->scale_factor[ch][sb] = 0;
+ scalefactor[ch][sb] = 2;
+ for (blk = 0; blk < frame->blocks; blk++) {
+ while (scalefactor[ch][sb] < (u_int32_t)fabs(frame->sb_sample_f[blk][ch][sb])) {
+ frame->scale_factor[ch][sb]++;
+ scalefactor[ch][sb] *= 2;
+ }
+ }
+ }
+ }
+
+ if (frame->channel_mode == JOINT_STEREO) {
+ int32_t sb_sample_j[16][2][7]; /* like frame->sb_sample but joint stereo */
+ u_int32_t scalefactor_j[2][7], scale_factor_j[2][7]; /* scalefactor and scale_factor in joint case */
+
+ /* Calculate joint stereo signal */
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ for (blk = 0; blk < frame->blocks; blk++) {
+ sb_sample_j[blk][0][sb] = (frame->sb_sample_f[blk][0][sb] + frame->sb_sample_f[blk][1][sb]) >> 1;
+ sb_sample_j[blk][1][sb] = (frame->sb_sample_f[blk][0][sb] - frame->sb_sample_f[blk][1][sb]) >> 1;
+ }
+ }
+
+ /* calculate scale_factor_j and scalefactor_j for joint case */
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ scale_factor_j[ch][sb] = 0;
+ scalefactor_j[ch][sb] = 2;
+ for (blk = 0; blk < frame->blocks; blk++) {
+ while (scalefactor_j[ch][sb] < (u_int32_t)fabs(sb_sample_j[blk][ch][sb])) {
+ scale_factor_j[ch][sb]++;
+ scalefactor_j[ch][sb] *= 2;
+ }
+ }
+ }
+ }
+
+ /* decide which subbands to join */
+ frame->join = 0;
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ if ((scalefactor[0][sb] + scalefactor[1][sb]) >
+ (scalefactor_j[0][sb] + scalefactor_j[1][sb]) ) {
+ /* use joint stereo for this subband */
+ frame->join |= 1 << sb;
+ frame->scale_factor[0][sb] = scale_factor_j[0][sb];
+ frame->scale_factor[1][sb] = scale_factor_j[1][sb];
+ scalefactor[0][sb] = scalefactor_j[0][sb];
+ scalefactor[1][sb] = scalefactor_j[1][sb];
+ for (blk = 0; blk < frame->blocks; blk++) {
+ frame->sb_sample_f[blk][0][sb] = sb_sample_j[blk][0][sb];
+ frame->sb_sample_f[blk][1][sb] = sb_sample_j[blk][1][sb];
+ }
+ }
+ }
+
+ if (len * 8 < produced + frame->subbands)
+ return -1;
+
+ data[4] = 0;
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ data[4] |= ((frame->join >> sb) & 0x01) << (7 - sb);
+ }
+ if (frame->subbands == 4) {
+ crc_header[crc_pos / 8] = data[4] & 0xf0;
+ } else {
+ crc_header[crc_pos / 8] = data[4];
+ }
+
+ produced += frame->subbands;
+ crc_pos += frame->subbands;
+ }
+
+ if (len * 8 < produced + (4 * frame->subbands * frame->channels))
+ return -1;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (produced % 8 == 0)
+ data[produced / 8] = 0;
+ data[produced / 8] |= ((frame->scale_factor[ch][sb] & 0x0F) << (4 - (produced % 8)));
+ crc_header[crc_pos / 8] |= ((frame->scale_factor[ch][sb] & 0x0F) << (4 - (crc_pos % 8)));
+
+ produced += 4;
+ crc_pos += 4;
+ }
+ }
+
+ data[3] = sbc_crc8(crc_header, crc_pos);
+
+
+
+ sbc_calculate_bits(frame, bits, sf);
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+ }
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (levels[ch][sb] > 0) {
+ frame->audio_sample[blk][ch][sb] =
+ (uint16_t) ((((frame->sb_sample_f[blk][ch][sb]*levels[ch][sb]) >> (frame->scale_factor[ch][sb] + 1)) +
+ levels[ch][sb]) >> 1);
+ } else {
+ frame->audio_sample[blk][ch][sb] = 0;
+ }
+ }
+ }
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (bits[ch][sb] != 0) {
+ for (bit = 0; bit < bits[ch][sb]; bit++) {
+ int b; /* A bit */
+ if (produced > len * 8) {
+ return -1;
+ }
+ if (produced % 8 == 0) {
+ data[produced / 8] = 0;
+ }
+ b = ((frame->audio_sample[blk][ch][sb]) >> (bits[ch][sb] - bit -
+ 1)) & 0x01;
+ data[produced / 8] |= b << (7 - (produced % 8));
+ produced++;
+ }
+ }
+ }
+ }
+ }
+
+ if (produced % 8 != 0) {
+ produced += 8 - (produced % 8);
+ }
+
+ return (int)(produced / 8);
+}
+
+struct sbc_priv {
+ int init;
+ struct sbc_frame frame;
+ struct sbc_decoder_state dec_state;
+ struct sbc_encoder_state enc_state;
+};
+
+int sbc_init(sbc_t *sbc)//int sbc_init(sbc_t *sbc, unsigned long flags)
+{
+ if (!sbc)
+ return -EIO;
+
+ //flags = flags;
+
+ memset(sbc, 0, sizeof(sbc_t));
+
+ sbc->priv = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
+ if (!sbc->priv)
+ return -ENOMEM;
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc->rate = 16000;
+ sbc->channels = 1;
+ sbc->joint = 0;
+ sbc->subbands = 8;
+ sbc->blocks = 15;
+ sbc->bitpool = 26;
+
+ return 0;
+}
+
+int sbc_reinit(sbc_t *sbc)//int sbc_reinit(sbc_t *sbc, unsigned long flags)
+{
+ struct sbc_priv *priv;
+
+ if (!sbc || !sbc->priv)
+ return -EIO;
+
+ //flags = flags;
+ priv = sbc->priv;
+
+ if (priv->init == 1)
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ return 0;
+}
+
+
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc)
+ {
+ //DbgPrint("Exit.when sbc is NULL.\n");
+ return -EIO;
+ }
+
+ if (!sbc && !input)
+ {
+ //DbgPrint("!sbc && !input\n");
+ return -EIO;
+ }
+
+ priv = sbc->priv;
+ if(!priv)
+ return -99;
+
+ framelen = sbc_unpack_frame(input, &priv->frame, input_len);
+
+ if (!priv->init)
+ {
+ sbc_decoder_init(&priv->dec_state, &priv->frame);
+ priv->init = 1;
+
+ sbc->rate = priv->frame.sampling_frequency;
+ sbc->channels = priv->frame.channels;
+ sbc->subbands = priv->frame.subbands;
+ sbc->blocks = priv->frame.blocks;
+ sbc->bitpool = priv->frame.bitpool;
+ }
+
+ if (!output)
+ {
+ //DbgPrint("!output\n");
+ return framelen;
+ }
+
+ if (written)
+ *written = 0;
+
+ if (framelen <= 0)
+ {
+ //DbgPrint("Exit when framelen <= 0\n");
+ return framelen;
+ }
+
+ samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
+
+ ptr = output;
+ if (output_len < samples * priv->frame.channels * 2)
+ samples = output_len / (priv->frame.channels * 2);
+
+/*
+ if (!sbc->data)
+ {
+ sbc->size = samples * priv->frame.channels * 2;
+ sbc->data = malloc(sbc->size);
+ }
+
+
+ if (sbc->size < samples * priv->frame.channels * 2)
+ {
+ sbc->size = samples * priv->frame.channels * 2;
+ sbc->data = realloc(sbc->data, sbc->size);
+ }
+
+ if (!sbc->data)
+ {
+ sbc->size = 0;
+ return -ENOMEM;
+ }
+*/
+
+ for (i = 0; i < samples; i++)
+ {
+ for (ch = 0; ch < priv->frame.channels; ch++)
+ {
+ int16_t s;
+ s = priv->frame.pcm_sample[ch][i];
+ /*
+ *ptr++ = (s & 0xff00) >> 8;
+ *ptr++ = (s & 0x00ff);
+ */
+ *ptr++ = (s & 0x00ff);
+ *ptr++ = (s & 0xff00) >> 8;
+ }
+ }
+
+ if (written)
+ *written = samples * priv->frame.channels * 2;
+
+ return framelen;
+}
+
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc)
+ {
+ //DbgPrint("Exit, when !sbc.\n");
+ return -EIO;
+ }
+
+
+ if (!sbc && !input)
+ {
+ //DbgPrint("Exit, when !sbc && !input.\n");
+ return -EIO;
+ }
+
+ /// make sure sbc has been initialized
+ priv = sbc->priv;
+ if(priv == NULL){
+ //DbgPrint("priv == NULL\n");
+ return -EIO;
+ }
+
+ if (written)
+ *written = 0;
+
+ if (!priv->init)
+ {
+ //DbgPrint("Initial priv->frame ,when priv->init is null\n");
+ priv->frame.sampling_frequency = sbc->rate;
+ priv->frame.channels = sbc->channels;
+ priv->frame.channel_mode = MONO;
+ priv->frame.allocation_method = LOUDNESS;
+ priv->frame.subbands = sbc->subbands;
+ priv->frame.blocks = sbc->blocks;
+ priv->frame.bitpool = sbc->bitpool;
+
+ sbc_encoder_init(&priv->enc_state, &priv->frame);
+ priv->init = 1;
+ }
+
+ /* input must be large enough to encode a complete frame */
+ if (input_len < 240)
+ {
+ //DbgPrint("Exit, when input_len < priv->frame.codesize..\n");
+ return 0;
+ }
+
+ /* output must be large enough to receive the encoded frame */
+ if (!output || output_len < 57)
+ {
+ //DbgPrint("Exit, when !output || output_len < priv->frame.length\n");
+ return -ENOSPC;
+ }
+
+ ptr = input;
+ for (i = 0; i < priv->frame.subbands * priv->frame.blocks; i++)
+ {
+ for (ch = 0; ch < sbc->channels; ch++)
+ {
+ // int16_t s = (ptr[0] & 0xff) << 8 | (ptr[1] & 0xff);
+ int16_t s = (ptr[1] & 0xff) << 8 | (ptr[0] & 0xff);
+ ptr += 2;
+ priv->frame.pcm_sample[ch][i] = s;
+ }
+ }
+
+ samples = 0;
+ samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
+
+ if (!sbc->data)
+ {
+ sbc->size = 1024;
+// sbc->data = malloc(sbc->size);
+ sbc->data = malloc(sbc->size);
+ if (!sbc->data)
+ {
+ //DbgPrint("sbc->data allocate failed!!!\n");
+ return -ENOMEM;
+ }
+ memset(sbc->data, 0, sbc->size);
+ }
+
+ if (!sbc->data)
+ {
+ sbc->size = 0;
+ //DbgPrint("sbc->data is null, so exit!!!\n");
+ return -ENOMEM;
+ }
+
+ framelen = sbc_pack_frame(output, &priv->frame, output_len);
+ if (written)
+ {
+ *written = (int)framelen;//in 64 bit os, it should be okay.
+ }
+
+ sbc->len = framelen;
+ sbc->duration = (1000000 * priv->frame.subbands * priv->frame.blocks) / sbc->rate;
+
+ return samples * sbc->channels * 2;
+}
+
+
+void sbc_finish(sbc_t *sbc)
+{
+ if (!sbc)
+ return;
+
+ if (sbc->data)
+ free(sbc->data);
+
+
+ if (sbc->priv)
+ {
+ free(sbc->priv);
+ }
+ memset(sbc, 0, sizeof(sbc_t));
+}
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_H
+#define __SBC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct sbc_struct {
+ unsigned long flags;
+ unsigned short rate;
+ unsigned char channels;
+ unsigned char joint;
+ unsigned char blocks;
+ unsigned char subbands;
+ unsigned char bitpool;
+
+ void *data;
+ int size;
+ int len;
+
+ unsigned long duration;
+
+ void *priv;
+};
+
+typedef struct sbc_struct sbc_t;
+
+int sbc_init(sbc_t *sbc);//int sbc_init(sbc_t *sbc, unsigned long flags);
+
+int sbc_reinit(sbc_t *sbc);//int sbc_reinit(sbc_t *sbc, unsigned long flags);
+
+
+int sbc_encode(sbc_t *sbc,
+ void *input,
+ int input_len,
+ void *output,
+ int output_len,
+ int *written);
+
+int sbc_decode(sbc_t *sbc,
+ void *input,
+ int input_len,
+ void *output,
+ int output_len,
+ int *written);
+
+void sbc_finish(sbc_t *sbc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SBC_H */
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define fabs(x) ((x) < 0 ? -(x) : (x))
+/* C does not provide an explicit arithmetic shift right but this will
+ always be correct and every compiler *should* generate optimal code */
+#define ASR(val, bits) ((-2 >> 1 == -1) ? \
+ ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
+#define ASR_64(val, bits) ((-2 >> 1 == -1) ? \
+ ((long long)(val)) >> (bits) : ((long long) (val)) / (1 << (bits)))
+
+#define SCALE_PROTO4_TBL 15
+#define SCALE_ANA4_TBL 16
+#define SCALE_PROTO8_TBL 15
+#define SCALE_ANA8_TBL 16
+#define SCALE_SPROTO4_TBL 16
+#define SCALE_SPROTO8_TBL 16
+#define SCALE_NPROTO4_TBL 10
+#define SCALE_NPROTO8_TBL 12
+#define SCALE_SAMPLES 14
+#define SCALE4_STAGE1_BITS 10
+#define SCALE4_STAGE2_BITS 21
+#define SCALE4_STAGED1_BITS 18
+#define SCALE4_STAGED2_BITS 23
+#define SCALE8_STAGE1_BITS 8
+#define SCALE8_STAGE2_BITS 24
+#define SCALE8_STAGED1_BITS 18
+#define SCALE8_STAGED2_BITS 23
+
+//typedef int int32_t;
+//typedef int32_t sbc_fixed_t;
+//typedef long long sbc_extended_t;
+
+#define SCALE4_STAGE1(src) ASR_64(src, SCALE4_STAGE1_BITS)
+#define SCALE4_STAGE2(src) ASR_64(src, SCALE4_STAGE2_BITS)
+#define SCALE4_STAGED1(src) ASR_64(src, SCALE4_STAGED1_BITS)
+#define SCALE4_STAGED2(src) ASR_64(src, SCALE4_STAGED2_BITS)
+#define SCALE8_STAGE1(src) ASR_64(src, SCALE8_STAGE1_BITS)
+#define SCALE8_STAGE2(src) ASR_64(src, SCALE8_STAGE2_BITS)
+#define SCALE8_STAGED1(src) ASR_64(src, SCALE8_STAGED1_BITS)
+#define SCALE8_STAGED2(src) ASR_64(src, SCALE8_STAGED2_BITS)
+
+#define SBC_FIXED_0(val) { val = 0; }
+#define ADD(dst, src) { dst += src; }
+#define SUB(dst, src) { dst -= src; }
+#define MUL(dst, a, b) { dst = (sbc_extended_t) (a) * (b); }
+#define MULA(dst, a, b) { dst += (sbc_extended_t) (a) * (b); }
+#define DIV2(dst, src) { dst = ASR(src, 1); }
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sbc_math.h"
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset4[4][4] = {
+ { -1, 0, 0, 0 },
+ { -2, 0, 0, 1 },
+ { -2, 0, 0, 1 },
+ { -2, 0, 0, 1 }
+};
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset8[4][8] = {
+ { -2, 0, 0, 0, 0, 0, 0, 1 },
+ { -3, 0, 0, 0, 0, 0, 1, 2 },
+ { -4, 0, 0, 0, 0, 0, 1, 2 },
+ { -4, 0, 0, 0, 0, 0, 1, 2 }
+};
+
+#define SP4(val) ASR(val, SCALE_PROTO4_TBL)
+#define SA4(val) ASR(val, SCALE_ANA4_TBL)
+#define SP8(val) ASR(val, SCALE_PROTO8_TBL)
+#define SA8(val) ASR(val, SCALE_ANA8_TBL)
+#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
+#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
+#define SN4(val) ASR(val, SCALE_NPROTO4_TBL)
+#define SN8(val) ASR(val, SCALE_NPROTO8_TBL)
+
+static const int32_t _sbc_proto_4[20] = {
+ SP4(0x02cb3e8c), SP4(0x22b63dc0), SP4(0x002329cc), SP4(0x053b7548),
+ SP4(0x31eab940), SP4(0xec1f5e60), SP4(0xff3773a8), SP4(0x0061c5a7),
+ SP4(0x07646680), SP4(0x3f239480), SP4(0xf89f23a8), SP4(0x007a4737),
+ SP4(0x00b32807), SP4(0x083ddc80), SP4(0x4825e480), SP4(0x0191e578),
+ SP4(0x00ff11ca), SP4(0x00fb7991), SP4(0x069fdc58), SP4(0x4b584000)
+};
+
+static const int32_t _anamatrix4[4] = {
+ SA4(0x2d413cc0), SA4(0x3b20d780), SA4(0x40000000), SA4(0x187de2a0)
+};
+
+static const int32_t _sbc_proto_8[40] = {
+ SP8(0x02e5cd20), SP8(0x22d0c200), SP8(0x006bfe27), SP8(0x07808930),
+ SP8(0x3f1c8800), SP8(0xf8810d70), SP8(0x002cfdc6), SP8(0x055acf28),
+ SP8(0x31f566c0), SP8(0xebfe57e0), SP8(0xff27c437), SP8(0x001485cc),
+ SP8(0x041c6e58), SP8(0x2a7cfa80), SP8(0xe4c4a240), SP8(0xfe359e4c),
+ SP8(0x0048b1f8), SP8(0x0686ce30), SP8(0x38eec5c0), SP8(0xf2a1b9f0),
+ SP8(0xffe8904a), SP8(0x0095698a), SP8(0x0824a480), SP8(0x443b3c00),
+ SP8(0xfd7badc8), SP8(0x00d3e2d9), SP8(0x00c183d2), SP8(0x084e1950),
+ SP8(0x4810d800), SP8(0x017f43fe), SP8(0x01056dd8), SP8(0x00e9cb9f),
+ SP8(0x07d7d090), SP8(0x4a708980), SP8(0x0488fae8), SP8(0x0113bd20),
+ SP8(0x0107b1a8), SP8(0x069fb3c0), SP8(0x4b3db200), SP8(0x00763f48)
+};
+
+static const int32_t sbc_proto_4_40m0[] = {
+ SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
+ SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
+ SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
+ SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
+ SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
+};
+
+static const int32_t sbc_proto_4_40m1[] = {
+ SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
+ SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
+ SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
+ SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
+ SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
+};
+
+static const int32_t sbc_proto_8_80m0[] = {
+ SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
+ SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
+ SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
+ SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
+ SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
+ SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
+ SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
+ SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
+ SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
+ SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
+};
+
+static const int32_t sbc_proto_8_80m1[] = {
+ SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
+ SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
+ SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
+ SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
+ SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
+ SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
+ SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
+ SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
+ SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
+ SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
+};
+
+static const int32_t _anamatrix8[8] = {
+ SA8(0x3b20d780), SA8(0x187de2a0), SA8(0x3ec52f80), SA8(0x3536cc40),
+ SA8(0x238e7680), SA8(0x0c7c5c20), SA8(0x2d413cc0), SA8(0x40000000)
+};
+
+static const int32_t synmatrix4[8][4] = {
+ { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
+ { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
+ { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
+ { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
+ { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
+ { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
+ { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
+ { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
+};
+
+static const int32_t synmatrix8[16][8] = {
+ { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
+ SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
+ { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
+ SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
+ { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
+ SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
+ { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
+ SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
+ { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
+ SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
+ { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
+ SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
+ { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
+ SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
+ { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
+ SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
+ { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
+ SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
+ { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+ SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
+ { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+ SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+ { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+ SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+ { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
+ SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
+ { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+ SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+ { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+ SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+ { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+ SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
+};
#ifndef BT_SKBUFF_H
#define BT_SKBUFF_H
#include "bt_list.h"
+#include <stdbool.h>
#ifndef EXTERN
#define EXTERN
/**
check whether queue is empty
*/
-EXTERN unsigned char
+EXTERN bool
RtbQueueIsEmpty(
IN RTB_QUEUE_HEAD* RtkQueueHead
);
-
//annie_tmp
EXTERN unsigned char
RtbCheckQueueLen(
#define BTVNDDBG(param, ...) {}
#endif
+#define DOWN_FW_CFG _IOW('H', 201, int)
+#define SET_ISO_CFG _IOW('H', 202, int)
+#define GET_USB_INFO _IOW('H', 203, int)
+#define RESET_CONTROLLER _IOW('H', 204, int)
/* Device port name where Bluetooth controller attached */
#ifndef BLUETOOTH_UART_DEVICE_PORT
-#define BLUETOOTH_UART_DEVICE_PORT "/dev/ttyO1" /* maguro */
+#define BLUETOOTH_UART_DEVICE_PORT "/dev/ttyS1" /* maguro */
#endif
/* Location of firmware patch files */
* firmware patchram (.hcd) file.
*/
#ifndef USE_CONTROLLER_BDADDR
-#define USE_CONTROLLER_BDADDR FALSE
+#define USE_CONTROLLER_BDADDR TRUE //FALSE
#endif
/* sleep mode
--- /dev/null
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(d) (d)
+#define cpu_to_le32(d) (d)
+#define le16_to_cpu(d) (d)
+#define le32_to_cpu(d) (d)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(d) bswap_16(d)
+#define cpu_to_le32(d) bswap_32(d)
+#define le16_to_cpu(d) bswap_16(d)
+#define le32_to_cpu(d) bswap_32(d)
+#else
+#error "Unknown byte order"
+#endif
+
+#define FIRMWARE_DIRECTORY "/vendor//etc/firmware/%s"
+#define BT_CONFIG_DIRECTORY "/vendor/etc/firmware/%s"
+#define PATCH_DATA_FIELD_MAX_SIZE 252
+#define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55
+#define MAX_PATCH_SIZE_24K (1024*24) //24K
+#define MAX_PATCH_SIZE_40K (1024*40) //40K
+
+#define MAX_ORG_CONFIG_SIZE (0x100*14)
+#define MAX_ALT_CONFIG_SIZE (0x100*2)
+
+#define STREAM_TO_UINT8(u8, p) \
+ { \
+ (u8) = (uint8_t)(*(p)); \
+ (p) += 1; \
+ }
+
+struct rtk_bt_vendor_config_entry{
+ uint16_t offset;
+ uint8_t entry_len;
+ uint8_t entry_data[0];
+} __attribute__ ((packed));
+
+struct rtk_bt_vendor_config{
+ uint32_t signature;
+ uint16_t data_len;
+ struct rtk_bt_vendor_config_entry entry[0];
+} __attribute__ ((packed));
+
+#define HCI_CMD_MAX_LEN 258
+
+#define HCI_VERSION_MASK_10 (1<<0) //Bluetooth Core Spec 1.0b
+#define HCI_VERSION_MASK_11 (1<<1) //Bluetooth Core Spec 1.1
+#define HCI_VERSION_MASK_12 (1<<2) //Bluetooth Core Spec 1.2
+#define HCI_VERSION_MASK_20 (1<<3) //Bluetooth Core Spec 2.0+EDR
+#define HCI_VERSION_MASK_21 (1<<4) //Bluetooth Core Spec 2.1+EDR
+#define HCI_VERSION_MASK_30 (1<<5) //Bluetooth Core Spec 3.0+HS
+#define HCI_VERSION_MASK_40 (1<<6) //Bluetooth Core Spec 4.0
+#define HCI_VERSION_MASK_41 (1<<7) //Bluetooth Core Spec 4.1
+#define HCI_VERSION_MASK_42 (1<<8) //Bluetooth Core Spec 4.2
+#define HCI_VERSION_MASK_ALL (0xFFFFFFFF)
+
+#define HCI_REVISION_MASK_ALL (0xFFFFFFFF)
+
+#define LMP_SUBVERSION_NONE (0x0)
+#define LMPSUBVERSION_8723a (0x1200)
+
+#define CHIPTYPE_NONE (0x1F) //Chip Type's range: 0x0 ~ 0xF
+#define CHIP_TYPE_MASK_ALL (0xFFFFFFFF)
+
+#define PROJECT_ID_MASK_ALL (0xFFFFFFFF) // temp used for unknow project id for a new chip
+
+#define PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE (0x1)
+
+#define CONFIG_MAC_OFFSET_GEN_1_2 (0x3C) //MAC's OFFSET in config/efuse for realtek generation 1~2 bluetooth chip
+#define CONFIG_MAC_OFFSET_GEN_3PLUS (0x44) //MAC's OFFSET in config/efuse for rtk generation 3+ bluetooth chip
+
+#define HCI_EVT_CMD_CMPL_OPCODE_OFFSET (3) //opcode's offset in COMMAND Completed Event
+#define HCI_EVT_CMD_CMPL_STATUS_OFFSET (5) //status's offset in COMMAND Completed Event
+
+#define HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET (6) //HCI_Version's offset in COMMAND Completed Event for OpCode 0x1001(Read Local Version Information Command)
+#define HCI_EVT_CMD_CMPL_OP1001_HCI_REVISION_OFFSET (7) //HCI_Revision's offset in COMMAND Completed Event for OpCode 0x1001(Read Local Version Information Command)
+#define HCI_EVT_CMD_CMPL_OP1001_LMP_SUBVERSION_OFFSET (12) //LMP Subversion's offset in COMMAND Completed Event for OpCode 0x1001(Read Local Version Information Command)
+#define HCI_EVT_CMD_CMPL_OP0C14_LOCAL_NAME_OFFSET (6) //Local Name's offset in COMMAND Completed Event for OpCode 0x0C14(Read Local Name Command)
+#define HCI_EVT_CMD_CMPL_OP1009_BDADDR_OFFSET (6) //BD_ADDR's offset in COMMAND Completed Event for OpCode 0x1009(Read BD_ADDR Command)
+#define HCI_EVT_CMD_CMPL_OPFC6D_EVERSION_OFFSET (6) //eversion's offset in COMMAND Completed Event for OpCode 0xfc6d(Read eVERSION Vendor Command)
+#define HCI_EVT_CMD_CMPL_OPFC61_CHIPTYPE_OFFSET (6) //chip type's offset in COMMAND Completed Event for OpCode 0xfc61(Read ChipType Vendor Command)
+
+//#define UPDATE_BAUDRATE_CMD_PARAM_SIZE (6)
+#define HCI_CMD_PREAMBLE_SIZE (3)
+#define HCI_CMD_READ_CHIP_TYPE_SIZE (5)
+//#define HCD_REC_PAYLOAD_LEN_BYTE (2)
+//#define BD_ADDR_LEN (6)
+//#define LOCAL_NAME_BUFFER_LEN (32)
+//#define LOCAL_BDADDR_PATH_BUFFER_LEN (256)
+
+#define H5_SYNC_REQ_SIZE (2)
+#define H5_SYNC_RESP_SIZE (2)
+#define H5_CONF_REQ_SIZE (3)
+#define H5_CONF_RESP_SIZE (2)
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/* Hardware Configuration State */
+enum {
+ HW_CFG_H5_INIT = 1,
+ HW_CFG_READ_LOCAL_VER,
+ HW_CFG_READ_ECO_VER, //eco version
+ HW_CFG_READ_CHIP_TYPE,
+ HW_CFG_START,
+ HW_CFG_SET_UART_BAUD_HOST,//change FW baudrate
+ HW_CFG_SET_UART_BAUD_CONTROLLER,//change Host baudrate
+ HW_CFG_SET_UART_HW_FLOW_CONTROL,
+ HW_CFG_RESET_CHANNEL_CONTROLLER,
+ HW_RESET_CONTROLLER,
+ HARDWARE_INIT_COMPLETE,
+ HW_CFG_DL_FW_PATCH
+};
+
+/* h/w config control block */
+typedef struct
+{
+ uint32_t max_patch_size;
+ uint32_t baudrate;
+ uint16_t lmp_subversion;
+ uint16_t lmp_subversion_default;
+ uint16_t lmp_sub_current;
+ uint8_t state; /* Hardware configuration state */
+ uint8_t eversion;
+ uint32_t project_id_mask;
+ uint8_t hci_version;
+ uint8_t hci_revision;
+ uint8_t chip_type;
+ uint8_t dl_fw_flag;
+ int fw_len; /* FW patch file len */
+ size_t config_len; /* Config patch file len */
+ unsigned int total_len; /* FW & config extracted buf len */
+ uint8_t *fw_buf; /* FW patch file buf */
+ uint8_t *config_buf; /* Config patch file buf */
+ uint8_t *total_buf; /* FW & config extracted buf */
+ uint8_t patch_frag_cnt; /* Patch fragment count download */
+ uint8_t patch_frag_idx; /* Current patch fragment index */
+ uint8_t patch_frag_len; /* Patch fragment length */
+ uint8_t patch_frag_tail; /* Last patch fragment length */
+ uint8_t hw_flow_cntrl; /* Uart flow control, bit7:set, bit0:enable */
+ uint16_t vid; /* usb vendor id */
+ uint16_t pid; /* usb product id */
+ uint8_t heartbeat; /*heartbeat*/
+} bt_hw_cfg_cb_t;
+
+/* low power mode parameters */
+typedef struct
+{
+ uint8_t sleep_mode; /* 0(disable),1(UART),9(H5) */
+ uint8_t host_stack_idle_threshold; /* Unit scale 300ms/25ms */
+ uint8_t host_controller_idle_threshold; /* Unit scale 300ms/25ms */
+ uint8_t bt_wake_polarity; /* 0=Active Low, 1= Active High */
+ uint8_t host_wake_polarity; /* 0=Active Low, 1= Active High */
+ uint8_t allow_host_sleep_during_sco;
+ uint8_t combine_sleep_mode_and_lpm;
+ uint8_t enable_uart_txd_tri_state; /* UART_TXD Tri-State */
+ uint8_t sleep_guard_time; /* sleep guard time in 12.5ms */
+ uint8_t wakeup_guard_time; /* wakeup guard time in 12.5ms */
+ uint8_t txd_config; /* TXD is high in sleep state */
+ uint8_t pulsed_host_wake; /* pulsed host wake if mode = 1 */
+} bt_lpm_param_t;
+
+#define ROM_LMP_NONE 0x0000
+#define ROM_LMP_8723a 0x1200
+#define ROM_LMP_8723b 0x8723
+#define ROM_LMP_8821a 0X8821
+#define ROM_LMP_8761a 0X8761
+#define ROM_LMP_8703a 0x8723
+#define ROM_LMP_8763a 0x8763
+#define ROM_LMP_8703b 0x8703
+#define ROM_LMP_8723c 0x8703
+#define ROM_LMP_8822b 0x8822
+#define ROM_LMP_8723d 0x8723
+#define ROM_LMP_8821c 0x8821
+
+struct rtk_epatch_entry{
+ uint16_t chip_id;
+ uint16_t patch_length;
+ uint32_t patch_offset;
+ uint32_t svn_version;
+ uint32_t coex_version;
+} __attribute__ ((packed));
+
+struct rtk_epatch{
+ uint8_t signature[8];
+ uint32_t fw_version;
+ uint16_t number_of_patch;
+ struct rtk_epatch_entry entry[0];
+} __attribute__ ((packed));
+
+
+
+
+#endif
#define HCI_VSC_SET_WAKE_UP_DEVICE 0xFC7B
#define HCI_VSC_BT_OFF 0xFC28
#define HCI_READ_LMP_VERSION 0x1001
+#define HCI_VENDOR_RESET 0x0C03
+#define HCI_VENDOR_FORCE_RESET_AND_PATCHABLE 0xFC66
+
#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
--- /dev/null
+#ifndef RTK_BTSERVICE_H
+#define RTK_BTSERVICE_H
+
+#include <stdio.h>
+#include <cutils/log.h>
+
+#define HCI_RTKBT_AUTOPAIR_EVT 0x30
+
+#define STREAM_TO_UINT8(u8, p) \
+ { \
+ (u8) = (uint8_t)(*(p)); \
+ (p) += 1; \
+ }
+
+
+#endif
+
+
}rtk_parse_manager_t;
-const rtk_parse_manager_t *rtk_parse_manager_get_interface();
+rtk_parse_manager_t *rtk_parse_manager_get_interface();
#ifdef __LITTLE_ENDIAN
struct sbc_frame_hdr {
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Realtek, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bt_vendor_lib.h"
+
+typedef void (*timed_out)(union sigval arg);
+
+
+void poll_init(timed_out ptr_timeout,uint32_t timeout);
+
+void poll_cleanup(void);
+
+void poll_enable(uint8_t turn_on);
+
+void poll_timer_flush(void);
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Realtek Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: userial_vendor.h
+ *
+ * Description: Contains vendor-specific definitions used in serial port
+ * controls
+ *
+ ******************************************************************************/
+
+#ifndef RTK_SOCKET_H
+#define RTK_SOCKET_H
+
+#include "bt_vendor_rtk.h"
+#include "userial.h"
+#include <sys/poll.h>
+#include <assert.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/un.h>
+
+
+#ifdef CONFIG_SCO_OVER_HCI
+#define SCO_CTRL_PATH "/data/misc/bluedroid/.sco_ctrl"
+#define SCO_DATA_PATH "/data/misc/bluedroid/.sco_data"
+
+typedef enum {
+ SCO_CTRL_CMD_NONE,
+ SCO_CTRL_CMD_CHECK_READY,
+ SCO_CTRL_CMD_OUT_START,
+ SCO_CTRL_CMD_IN_START,
+ SCO_CTRL_CMD_OUT_STOP,
+ SCO_CTRL_CMD_IN_STOP,
+ SCO_CTRL_CMD_SUSPEND,
+ SCO_CTRL_GET_AUDIO_CONFIG,
+ SCO_CTRL_CMD_OFFLOAD_START,
+} tSCO_CTRL_CMD;
+
+#define SCO_SAMPLE_RATE_8K 1
+#define SCO_SAMPLE_RATE_16K 2
+
+#endif
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len);
+int Skt_Read_noblock(int fd, uint8_t *p_buf, uint32_t len);
+bool Skt_Send(int fd, uint8_t *p_buf, uint16_t msglen);
+int Skt_Send_noblock(int fd, uint8_t *p_buf, uint16_t msglen);
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * - 1 control system sysfs proc env & property
+ */
+#ifndef BT_UNUSED_H
+#define BT_UNUSED_H
+#ifdef __GNUC__
+# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+# define UNUSED(x) UNUSED_ ## x
+#endif
+#endif /*BT_UNUSED_H*/
** Returns None
**
*******************************************************************************/
-void upio_set(uint8_t pio, uint8_t action, uint8_t polarity);
+void upio_set(uint8_t pio, uint8_t action);//void upio_set(uint8_t pio, uint8_t action, uint8_t polarity);
/*******************************************************************************
/******************************************************************************
** Constants & Macros
******************************************************************************/
+#define RTK_NO_INTR(fn) do {} while ((fn) == -1 && errno == EINTR)
+
#define RTK_GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
#define RTK_START_PACKET_BOUNDARY 2
/******************************************************************************
** Type definitions
******************************************************************************/
+ // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+#define COMMAND_PREAMBLE_SIZE 3
+ // 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+#define ACL_PREAMBLE_SIZE 4
+ // 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+#define SCO_PREAMBLE_SIZE 3
+ // 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
+#define EVENT_PREAMBLE_SIZE 2
+
+#define HCI_PACKET_TYPE_TO_INDEX(type) ((type) - 1)
+
+#define COMMON_DATA_LENGTH_INDEX 3
+
+#define EVENT_DATA_LENGTH_INDEX 2
/* Structure used to configure serial port during open */
typedef struct
int userial_socket_open(void);
-int userial_vendor_usb_ioctl(int operation);
+int userial_vendor_usb_ioctl(int operation, void* param);
int userial_vendor_usb_open(void);
+void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length);
+
+#define RTK_HANDLE_EVENT
+#define RTK_HANDLE_CMD
+#define CONFIG_SCO_OVER_HCI
#endif /* USERIAL_VENDOR_H */
uint32_t QueueLen;
pthread_mutex_t Lock;
uint8_t Id[RTB_QUEUE_ID_LENGTH];
-}RTB_QUEUE_HEAD, *PRTB_QUEUE_HEAD;
+}*PRTB_QUEUE_HEAD;
//****************************************************************************
// FUNCTION
\return : FALSE Queue is not empty
TRU Queue is empty
*/
-unsigned char
+bool
RtbQueueIsEmpty(
IN RTB_QUEUE_HEAD* RtkQueueHead
)
#undef NDEBUG
#define LOG_TAG "libbt_vendor"
-#define RTKBT_RELEASE_NAME "20171107_BT_ANDROID_8.x"
+#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1"
#include <utils/Log.h>
#include "bt_vendor_rtk.h"
#include "upio.h"
extern char rtk_btsnoop_path[];
extern uint8_t coex_log_enable;
extern void hw_config_start(char transtype);
+extern void hw_usb_config_start(char transtype,uint32_t val);
+extern void RTK_btservice_init();
#if (HW_END_WITH_HCI_RESET == TRUE)
void hw_epilog_process(void);
#define RTKBT_CONF_FILE "/vendor/etc/bluetooth/rtkbt.conf"
#define USB_DEVICE_DIR "/sys/bus/usb/devices"
#define DEBUG_SCAN_USB FALSE
-#define DOWN_FW_CFG _IOW('H', 201, int)
/******************************************************************************
** Static Variables
}
int line_num = 0;
char line[1024];
- char value[1024];
+ //char value[1024];
while (fgets(line, sizeof(line), fp)) {
char *line_ptr = rtk_trim(line);
++line_num;
FILE *fp = fopen(RTKBT_CONF_FILE, "rt");
if (!fp) {
ALOGE("%s unable to open file '%s': %s", __func__, RTKBT_CONF_FILE, strerror(errno));
- strcpy(rtkbt_device_node,"/dev/rtk_btusb");
+ strcpy(rtkbt_device_node,"/dev/rtkbt_dev");
return;
}
split = strchr(line_ptr, '=');
if (!split) {
ALOGE("%s no key/value separator found on line %d.", __func__, line_num);
- strcpy(rtkbt_device_node,"/dev/rtk_btusb");
+ strcpy(rtkbt_device_node,"/dev/rtkbt_dev");
return;
}
if(rtkbt_device_node[0]=='?'){
/*1.Scan_Usb_Device*/
if(Scan_Usb_Devices_For_RTK(USB_DEVICE_DIR) == 0x01) {
- strcpy(rtkbt_device_node,"/dev/rtk_btusb");
+ strcpy(rtkbt_device_node,"/dev/rtkbt_dev");
}
else{
int i = 0;
}
}
- if(split = strchr(rtkbt_device_node, ':')) {
+ if((split = strchr(rtkbt_device_node, ':')) != NULL) {
*split = '\0';
if(!strcmp(rtk_trim(split + 1), "H5")) {
rtkbt_transtype |= RTKBT_TRANS_H5;
rtkbt_transtype |= RTKBT_TRANS_H4;
}
}
- else if(strcmp(rtkbt_device_node, "/dev/rtk_btusb")) {
+ else if(strcmp(rtkbt_device_node, "/dev/rtkbt_dev")) {
//default use h5
rtkbt_transtype |= RTKBT_TRANS_H5;
}
- if(strcmp(rtkbt_device_node, "/dev/rtk_btusb")) {
+ if(strcmp(rtkbt_device_node, "/dev/rtkbt_dev")) {
rtkbt_transtype |= RTKBT_TRANS_UART;
}
else {
hw_config_start(rtkbt_transtype);
}
else {
- BTVNDDBG("usb op for %d", opcode);
- ALOGE("Bt_vendor_rtk Op for BT_VND_OP_FW_CFG");
- retval = userial_vendor_usb_ioctl(DOWN_FW_CFG);
- if(retval>0){
- ALOGE("Bt_vendor_rtk Download Fw Success");
- bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
- }else{
- ALOGE("Bt_vendor_rtk Download Fw failed: %s(%d)", strerror(errno), errno);
- if(rtkbt_auto_restart) {
- bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
- kill(getpid(), SIGKILL);
- }
- }
+ retval = userial_vendor_usb_ioctl(GET_USB_INFO, NULL);
+ hw_usb_config_start(RTKBT_TRANS_H4,retval);
}
+ RTK_btservice_init();
}
break;
BTVNDDBG("USB op for %d", opcode);
int fd, idx = 0;
int (*fd_array)[] = (int (*)[]) param;
- if(userial_vendor_usb_open() != -1){
- retval = 1;
+ for(idx = 0; idx < 10; idx++) {
+ if(userial_vendor_usb_open() != -1){
+ retval = 1;
+ break;
+ }
}
- do {
- idx++;
- usleep(500000);
- }while(userial_vendor_usb_open() == -1 && idx < 10);
fd = userial_socket_open();
if (fd != -1)
{
- for (idx=0; idx < CH_MAX; idx++)
+ for (idx = 0; idx < CH_MAX; idx++)
(*fd_array)[idx] = fd;
}
else
******************************************************************************/
#define LOG_TAG "bt_hwcfg"
-#define RTKBT_RELEASE_NAME "20171107_BT_ANDROID_8.x"
+#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1"
#include <utils/Log.h>
#include <sys/types.h>
#include <unistd.h>
#include <endian.h>
#include <byteswap.h>
+#include <unistd.h>
#include "bt_vendor_lib.h"
-
+#include "hardware.h"
/******************************************************************************
** Constants & Macros
******************************************************************************/
#define RTK_VERSION "4.1.1"
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define cpu_to_le16(d) (d)
-#define cpu_to_le32(d) (d)
-#define le16_to_cpu(d) (d)
-#define le32_to_cpu(d) (d)
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define cpu_to_le16(d) bswap_16(d)
-#define cpu_to_le32(d) bswap_32(d)
-#define le16_to_cpu(d) bswap_16(d)
-#define le32_to_cpu(d) bswap_32(d)
-#else
-#error "Unknown byte order"
-#endif
-
-#define FIRMWARE_DIRECTORY "/vendor/etc/firmware/%s"
-#define BT_CONFIG_DIRECTORY "/vendor/etc/firmware/%s"
-#define PATCH_DATA_FIELD_MAX_SIZE 252
-#define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55
-#define MAX_PATCH_SIZE_24K (1024*24) //24K
-#define MAX_PATCH_SIZE_40K (1024*40) //40K
-
-#define MAX_ORG_CONFIG_SIZE (0x100*14)
-#define MAX_ALT_CONFIG_SIZE (0x100*2)
-
-struct rtk_bt_vendor_config_entry{
- uint16_t offset;
- uint8_t entry_len;
- uint8_t entry_data[0];
-} __attribute__ ((packed));
-
-struct rtk_bt_vendor_config{
- uint32_t signature;
- uint16_t data_len;
- struct rtk_bt_vendor_config_entry entry[0];
-} __attribute__ ((packed));
-
-#define HCI_CMD_MAX_LEN 258
-
-#define HCI_VERSION_MASK_10 (1<<0) //Bluetooth Core Spec 1.0b
-#define HCI_VERSION_MASK_11 (1<<1) //Bluetooth Core Spec 1.1
-#define HCI_VERSION_MASK_12 (1<<2) //Bluetooth Core Spec 1.2
-#define HCI_VERSION_MASK_20 (1<<3) //Bluetooth Core Spec 2.0+EDR
-#define HCI_VERSION_MASK_21 (1<<4) //Bluetooth Core Spec 2.1+EDR
-#define HCI_VERSION_MASK_30 (1<<5) //Bluetooth Core Spec 3.0+HS
-#define HCI_VERSION_MASK_40 (1<<6) //Bluetooth Core Spec 4.0
-#define HCI_VERSION_MASK_41 (1<<7) //Bluetooth Core Spec 4.1
-#define HCI_VERSION_MASK_42 (1<<8) //Bluetooth Core Spec 4.2
-#define HCI_VERSION_MASK_ALL (0xFFFFFFFF)
-
-#define HCI_REVISION_MASK_ALL (0xFFFFFFFF)
-
-#define LMP_SUBVERSION_NONE (0x0)
-#define LMPSUBVERSION_8723a (0x1200)
-
-#define CHIPTYPE_NONE (0x1F) //Chip Type's range: 0x0 ~ 0xF
-#define CHIP_TYPE_MASK_ALL (0xFFFFFFFF)
-
-#define PROJECT_ID_MASK_ALL (0xFFFFFFFF) // temp used for unknow project id for a new chip
-
-#define PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE (0x1)
-
-#define CONFIG_MAC_OFFSET_GEN_1_2 (0x3C) //MAC's OFFSET in config/efuse for realtek generation 1~2 bluetooth chip
-#define CONFIG_MAC_OFFSET_GEN_3PLUS (0x44) //MAC's OFFSET in config/efuse for rtk generation 3+ bluetooth chip
-
-#define HCI_EVT_CMD_CMPL_OPCODE_OFFSET (3) //opcode's offset in COMMAND Completed Event
-#define HCI_EVT_CMD_CMPL_STATUS_OFFSET (5) //status's offset in COMMAND Completed Event
-
-#define HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET (6) //HCI_Version's offset in COMMAND Completed Event for OpCode 0x1001(Read Local Version Information Command)
-#define HCI_EVT_CMD_CMPL_OP1001_HCI_REVISION_OFFSET (7) //HCI_Revision's offset in COMMAND Completed Event for OpCode 0x1001(Read Local Version Information Command)
-#define HCI_EVT_CMD_CMPL_OP1001_LMP_SUBVERSION_OFFSET (12) //LMP Subversion's offset in COMMAND Completed Event for OpCode 0x1001(Read Local Version Information Command)
-#define HCI_EVT_CMD_CMPL_OP0C14_LOCAL_NAME_OFFSET (6) //Local Name's offset in COMMAND Completed Event for OpCode 0x0C14(Read Local Name Command)
-#define HCI_EVT_CMD_CMPL_OP1009_BDADDR_OFFSET (6) //BD_ADDR's offset in COMMAND Completed Event for OpCode 0x1009(Read BD_ADDR Command)
-#define HCI_EVT_CMD_CMPL_OPFC6D_EVERSION_OFFSET (6) //eversion's offset in COMMAND Completed Event for OpCode 0xfc6d(Read eVERSION Vendor Command)
-#define HCI_EVT_CMD_CMPL_OPFC61_CHIPTYPE_OFFSET (6) //chip type's offset in COMMAND Completed Event for OpCode 0xfc61(Read ChipType Vendor Command)
-
-//#define UPDATE_BAUDRATE_CMD_PARAM_SIZE (6)
-#define HCI_CMD_PREAMBLE_SIZE (3)
-#define HCI_CMD_READ_CHIP_TYPE_SIZE (5)
-//#define HCD_REC_PAYLOAD_LEN_BYTE (2)
-//#define BD_ADDR_LEN (6)
-//#define LOCAL_NAME_BUFFER_LEN (32)
-//#define LOCAL_BDADDR_PATH_BUFFER_LEN (256)
-
-#define H5_SYNC_REQ_SIZE (2)
-#define H5_SYNC_RESP_SIZE (2)
-#define H5_CONF_REQ_SIZE (3)
-#define H5_CONF_RESP_SIZE (2)
-
-/******************************************************************************
-** Local type definitions
-******************************************************************************/
-
-/* Hardware Configuration State */
-enum {
- HW_CFG_H5_INIT = 1,
- HW_CFG_READ_LOCAL_VER,
- HW_CFG_READ_ECO_VER, //eco version
- HW_CFG_READ_CHIP_TYPE,
- HW_CFG_START,
- HW_CFG_SET_UART_BAUD_HOST,//change FW baudrate
- HW_CFG_SET_UART_BAUD_CONTROLLER,//change Host baudrate
- HW_CFG_SET_UART_HW_FLOW_CONTROL,
- HW_CFG_DL_FW_PATCH
-};
-
-/* h/w config control block */
-typedef struct
-{
- uint32_t max_patch_size;
- uint32_t baudrate;
- uint16_t lmp_subversion;
- uint8_t state; /* Hardware configuration state */
- uint8_t eversion;
- uint32_t project_id_mask;
- uint8_t hci_version;
- uint8_t hci_revision;
- uint8_t chip_type;
- uint8_t dl_fw_flag;
- int fw_len; /* FW patch file len */
- int config_len; /* Config patch file len */
- int total_len; /* FW & config extracted buf len */
- uint8_t *fw_buf; /* FW patch file buf */
- uint8_t *config_buf; /* Config patch file buf */
- uint8_t *total_buf; /* FW & config extracted buf */
- uint8_t patch_frag_cnt; /* Patch fragment count download */
- uint8_t patch_frag_idx; /* Current patch fragment index */
- uint8_t patch_frag_len; /* Patch fragment length */
- uint8_t patch_frag_tail; /* Last patch fragment length */
- uint8_t hw_flow_cntrl; /* Uart flow control, bit7:set, bit0:enable */
-} bt_hw_cfg_cb_t;
-
-/* low power mode parameters */
-typedef struct
-{
- uint8_t sleep_mode; /* 0(disable),1(UART),9(H5) */
- uint8_t host_stack_idle_threshold; /* Unit scale 300ms/25ms */
- uint8_t host_controller_idle_threshold; /* Unit scale 300ms/25ms */
- uint8_t bt_wake_polarity; /* 0=Active Low, 1= Active High */
- uint8_t host_wake_polarity; /* 0=Active Low, 1= Active High */
- uint8_t allow_host_sleep_during_sco;
- uint8_t combine_sleep_mode_and_lpm;
- uint8_t enable_uart_txd_tri_state; /* UART_TXD Tri-State */
- uint8_t sleep_guard_time; /* sleep guard time in 12.5ms */
- uint8_t wakeup_guard_time; /* wakeup guard time in 12.5ms */
- uint8_t txd_config; /* TXD is high in sleep state */
- uint8_t pulsed_host_wake; /* pulsed host wake if mode = 1 */
-} bt_lpm_param_t;
-
/******************************************************************************
** Externs
******************************************************************************/
-void hw_config_cback(void *p_evt_buf);
+//void hw_config_cback(void *p_evt_buf);
+//void hw_usb_config_cback(void *p_evt_buf);
+
extern uint8_t vnd_local_bd_addr[BD_ADDR_LEN];
extern bool rtkbt_auto_restart;
/******************************************************************************
** Static variables
******************************************************************************/
-static bt_hw_cfg_cb_t hw_cfg_cb;
+bt_hw_cfg_cb_t hw_cfg_cb;
-//#define BT_CHIP_PROBE_SIMULATION
-#ifdef BT_CHIP_PROBE_SIMULATION
-static bt_hw_cfg_cb_t hw_cfg_test;
-struct bt_chip_char{
- uint16_t lmp_subversion;
- uint8_t hci_version;
- uint8_t hci_revision;
- uint8_t chip_type;
-};
-struct bt_chip_char bt_chip_chars[] = \
-{
- {0x8723, 0x4, 0xb, CHIPTYPE_NONE}, //8703as
- {0x8723, 0x6, 0xb, CHIPTYPE_NONE}, //8723bs
- {0x8703, 0x4, 0xd, 0x7}, //8703bs
- {0x8703, 0x6, 0xb, 0x3}, //8723cs-cg
- {0x8703, 0x6, 0xb, 0x4}, //8723cs-vf
- {0x8703, 0x6, 0xb, 0x5}, //8723cs-xx
- {0x8723, 0x6, 0xd, CHIPTYPE_NONE}, //8723ds
-};
-#endif
+/*
static bt_lpm_param_t lpm_param =
{
LPM_SLEEP_MODE,
LPM_HOST_WAKE_POLARITY,
LPM_ALLOW_HOST_SLEEP_DURING_SCO,
LPM_COMBINE_SLEEP_MODE_AND_LPM,
- LPM_ENABLE_UART_TXD_TRI_STATE,
- 0, /* not applicable */
- 0, /* not applicable */
- 0, /* not applicable */
- LPM_PULSED_HOST_WAKE
-};
-
-//signature: realtech
-const uint8_t RTK_EPATCH_SIGNATURE[8]={0x52,0x65,0x61,0x6C,0x74,0x65,0x63,0x68};
-//Extension Section IGNATURE:0x77FD0451
-const uint8_t EXTENSION_SECTION_SIGNATURE[4]={0x51,0x04,0xFD,0x77};
-
-typedef struct {
- uint16_t lmp_subversion;
- uint32_t hci_version_mask;
- uint32_t hci_revision_mask;
- uint32_t chip_type_mask;
- uint32_t project_id_mask;
- char *patch_name;
- char *config_name;
- uint16_t mac_offset;
- uint32_t max_patch_size;
-} patch_info;
-
-static patch_info patch_table[] = {
-/* lmp_subv hci_version_mask hci_revision_mask chip_type_mask project_id_mask fw name config name mac offset max_patch_size */
- {0x1200, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<0, "rtl8723as_fw", "rtl8723as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723AS
-
- {0x8723, ~(HCI_VERSION_MASK_21), ~(1<<0xd), CHIP_TYPE_MASK_ALL, 1<<1, "rtl8723bs_fw", "rtl8723bs_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723BS
-// {0x8723, ~(HCI_VERSION_MASK_21), ~(1<<0xd), CHIP_TYPE_MASK_ALL, 1<<1, "rtl8723bs_VQ0_fw", "rtl8723bs_VQ0_config", CONFIG_MAC_OFFSET_GEN_1_2}, //Rtl8723BS_VQ0
- {0x8821, HCI_VERSION_MASK_ALL, ~(1<<0xc), CHIP_TYPE_MASK_ALL, 1<<2, "rtl8821as_fw", "rtl8821as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8821AS
- {0x8761, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<3, "rtl8761at_fw", "rtl8761at_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8761AW
- {0x8723, HCI_VERSION_MASK_21, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<4, "rtl8703as_fw", "rtl8703as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8703AS
-
- {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<7, 1<<6, "rtl8703bs_fw", "rtl8703bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8703BS
- {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<5, 1<<7, "rtl8723cs_xx_fw", "rtl8723cs_xx_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_xx
- {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<3, 1<<7, "rtl8723cs_cg_fw", "rtl8723cs_cg_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_cg
- {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<4, 1<<7, "rtl8723cs_vf_fw", "rtl8723cs_vf_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_vf
- {0x8822, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<8, "rtl8822bs_fw", "rtl8822bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8822BS
-
- {0x8723, HCI_VERSION_MASK_ALL, (1<<0xd), ~(1<<7), 1<<9, "rtl8723ds_fw", "rtl8723ds_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //Rtl8723ds
- {0x8723, HCI_VERSION_MASK_ALL, (1<<0xd), 1<<7, 1<<9, "rtl8703cs_fw", "rtl8703cs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //Rtl8703cs
- {0x8821, HCI_VERSION_MASK_ALL, (1<<0xc), CHIP_TYPE_MASK_ALL, 1<<10, "rtl8821cs_fw", "rtl8821cs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //RTL8821CS
-/* todo: RTL8703CS */
-
- {LMP_SUBVERSION_NONE,HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, PROJECT_ID_MASK_ALL, "rtl_none_fw", "rtl_none_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}
-};
-
-struct rtk_epatch_entry{
- uint16_t chip_id;
- uint16_t patch_length;
- uint32_t patch_offset;
- uint32_t svn_version;
- uint32_t coex_version;
-} __attribute__ ((packed));
-
-struct rtk_epatch{
- uint8_t signature[8];
- uint32_t fw_version;
- uint16_t number_of_patch;
- struct rtk_epatch_entry entry[0];
-} __attribute__ ((packed));
-
-
-int check_match_state(bt_hw_cfg_cb_t *cfg,uint32_t mask)
-{
- patch_info *patch_entry;
- int res = 0;
-
- for(patch_entry = patch_table; patch_entry->lmp_subversion != LMP_SUBVERSION_NONE; patch_entry++) {
- if(patch_entry->lmp_subversion != cfg->lmp_subversion)
- continue;
- if((patch_entry->hci_version_mask!=HCI_VERSION_MASK_ALL)&&((patch_entry->hci_version_mask&(1<<cfg->hci_version))==0))
- continue;
- if((patch_entry->hci_revision_mask!=HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<<cfg->hci_revision))==0))
- continue;
- if((mask&PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE)&&(patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL)&&((patch_entry->chip_type_mask&(1<<cfg->chip_type))==0))
- continue;
- res++;
- }
- ALOGI( "check_match_state return %d(cfg->lmp_subversion:0x%x cfg->hci_vesion:0x%x cfg->hci_revision:0x%x cfg->chip_type:0x%x mask:%08x)\n",
- res, cfg->lmp_subversion, cfg->hci_version, cfg->hci_revision, cfg->chip_type, mask);
- return res;
-}
-patch_info* get_patch_entry(bt_hw_cfg_cb_t *cfg)
-{
- patch_info *patch_entry;
-
- ALOGI("get_patch_entry(lmp_subversion:0x%x hci_vesion:0x%x cfg->hci_revision:0x%x chip_type:0x%x)\n",
- cfg->lmp_subversion, cfg->hci_version, cfg->hci_revision, cfg->chip_type);
- for(patch_entry = patch_table; patch_entry->lmp_subversion != LMP_SUBVERSION_NONE; patch_entry++) {
- if(patch_entry->lmp_subversion != cfg->lmp_subversion)
- continue;
- if((patch_entry->hci_version_mask != HCI_VERSION_MASK_ALL)&&((patch_entry->hci_version_mask&(1<<cfg->hci_version)) == 0))
- continue;
- if((patch_entry->hci_revision_mask != HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<<cfg->hci_revision)) == 0))
- continue;
- if((patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL)&&((patch_entry->chip_type_mask&(1<<cfg->chip_type)) == 0))
- continue;
- break;
- }
- ALOGI("get_patch_entry return(patch_name:%s config_name:%s mac_offset:0x%x)\n",
- patch_entry->patch_name, patch_entry->config_name, patch_entry->mac_offset);
- return patch_entry;
-}
-
-/*******************************************************************************
-**
-** Function line_speed_to_userial_baud
-**
-** Description helper function converts line speed number into USERIAL baud
-** rate symbol
-**
-** Returns unit8_t (USERIAL baud symbol)
-**
-*******************************************************************************/
-uint8_t line_speed_to_userial_baud(uint32_t line_speed)
-{
- uint8_t baud;
-
- if (line_speed == 4000000)
- baud = USERIAL_BAUD_4M;
- else if (line_speed == 3000000)
- baud = USERIAL_BAUD_3M;
- else if (line_speed == 2000000)
- baud = USERIAL_BAUD_2M;
- else if (line_speed == 1500000)
- baud = USERIAL_BAUD_1_5M;
- else if (line_speed == 1000000)
- baud = USERIAL_BAUD_1M;
- else if (line_speed == 921600)
- baud = USERIAL_BAUD_921600;
- else if (line_speed == 460800)
- baud = USERIAL_BAUD_460800;
- else if (line_speed == 230400)
- baud = USERIAL_BAUD_230400;
- else if (line_speed == 115200)
- baud = USERIAL_BAUD_115200;
- else if (line_speed == 57600)
- baud = USERIAL_BAUD_57600;
- else if (line_speed == 19200)
- baud = USERIAL_BAUD_19200;
- else if (line_speed == 9600)
- baud = USERIAL_BAUD_9600;
- else if (line_speed == 1200)
- baud = USERIAL_BAUD_1200;
- else if (line_speed == 600)
- baud = USERIAL_BAUD_600;
- else
- {
- ALOGE( "userial vendor: unsupported baud speed %d", line_speed);
- baud = USERIAL_BAUD_115200;
- }
-
- return baud;
-}
-
-typedef struct _baudrate_ex
-{
- uint32_t rtk_speed;
- uint32_t uart_speed;
-}baudrate_ex;
-
-baudrate_ex baudrates[] =
-{
- {0x00006004, 921600},
- {0x05F75004, 921600},//RTL8723BS
- {0x00004003, 1500000},
- {0x04928002, 1500000},//RTL8723BS
- {0x00005002, 2000000},//same as RTL8723AS
- {0x00008001, 3000000},
- {0x04928001, 3000000},//RTL8723BS
- {0x06B58001, 3000000},//add RTL8703as
- {0x00007001, 3500000},
- {0x052A6001, 3500000},//RTL8723BS
- {0x00005001, 4000000},//same as RTL8723AS
- {0x0000701d, 115200},
- {0x0252C014, 115200}//RTL8723BS
-};
-
-/**
-* Change realtek Bluetooth speed to uart speed. It is matching in the struct baudrates:
-*
-* @code
-* baudrate_ex baudrates[] =
-* {
-* {0x7001, 3500000},
-* {0x6004, 921600},
-* {0x4003, 1500000},
-* {0x5001, 4000000},
-* {0x5002, 2000000},
-* {0x8001, 3000000},
-* {0x701d, 115200}
-* };
-* @endcode
-*
-* If there is no match in baudrates, uart speed will be set as #115200.
-*
-* @param rtk_speed realtek Bluetooth speed
-* @param uart_speed uart speed
-*
-*/
-static void rtk_speed_to_uart_speed(uint32_t rtk_speed, uint32_t* uart_speed)
-{
- *uart_speed = 115200;
-
- uint8_t i;
- for (i=0; i< sizeof(baudrates)/sizeof(baudrate_ex); i++)
- {
- if (baudrates[i].rtk_speed == rtk_speed)
- {
- *uart_speed = baudrates[i].uart_speed;
- return;
- }
- }
- return;
-}
-
-/**
-* Change uart speed to realtek Bluetooth speed. It is matching in the struct baudrates:
-*
-* @code
-* baudrate_ex baudrates[] =
-* {
-* {0x7001, 3500000},
-* {0x6004, 921600},
-* {0x4003, 1500000},
-* {0x5001, 4000000},
-* {0x5002, 2000000},
-* {0x8001, 3000000},
-* {0x701d, 115200}
-* };
-* @endcode
-*
-* If there is no match in baudrates, realtek Bluetooth speed will be set as #0x701D.
-*
-* @param uart_speed uart speed
-* @param rtk_speed realtek Bluetooth speed
-*
-*/
-static inline void uart_speed_to_rtk_speed(uint32_t uart_speed, uint32_t* rtk_speed)
-{
- *rtk_speed = 0x701D;
-
- unsigned int i;
- for (i=0; i< sizeof(baudrates)/sizeof(baudrate_ex); i++)
- {
- if (baudrates[i].uart_speed == uart_speed)
- {
- *rtk_speed = baudrates[i].rtk_speed;
- return;
- }
- }
- return;
-}
-
-
-/*******************************************************************************
-**
-** Function hw_config_set_bdaddr
-**
-** Description Program controller's Bluetooth Device Address
-**
-** Returns TRUE, if valid address is sent
-** FALSE, otherwise
-**
-*******************************************************************************/
-static uint8_t hw_config_set_controller_baudrate(HC_BT_HDR *p_buf, uint32_t baudrate)
-{
- uint8_t retval = FALSE;
- uint8_t *p = (uint8_t *) (p_buf + 1);
-
- UINT16_TO_STREAM(p, HCI_VSC_UPDATE_BAUDRATE);
- *p++ = 4; /* parameter length */
- UINT32_TO_STREAM(p, baudrate);
-
- p_buf->len = HCI_CMD_PREAMBLE_SIZE + 4;
-
- retval = bt_vendor_cbacks->xmit_cb(HCI_VSC_UPDATE_BAUDRATE, p_buf, \
- hw_config_cback);
-
- return (retval);
-}
-
-static int getmacaddr(unsigned char * addr)
+ LPM_ENABLE_UART_TXD_TRI_STATE,*/
+ //0, /* not applicable */
+ // 0, /* not applicable */
+ // 0, /* not applicable */
+ /*LPM_PULSED_HOST_WAKE
+};*/
+
+int getmacaddr(unsigned char * addr)
{
int i = 0;
char data[256], *str;
return -1;
}
-static inline int getAltSettings(patch_info *patch_entry, unsigned short *offset, int max_group_cnt)
-{
- int n = 0;
- if(patch_entry)
- offset[n++] = patch_entry->mac_offset;
-/*
-//sample code, add special settings
-
- offset[n++] = 0x15B;
-*/
- return n;
-}
-static inline int getAltSettingVal(patch_info *patch_entry, unsigned short offset, unsigned char * val)
-{
- int res = 0;
-
- switch(offset)
- {
-/*
-//sample code, add special settings
- case 0x15B:
- val[0] = 0x0B;
- val[1] = 0x0B;
- val[2] = 0x0B;
- val[3] = 0x0B;
- res = 4;
- break;
-*/
- default:
- res = 0;
- break;
- }
- if((patch_entry)&&(offset == patch_entry->mac_offset)&&(res == 0))
- {
- if(getmacaddr(val) == 0){
- ALOGI("MAC: %02x:%02x:%02x:%02x:%02x:%02x", val[5], val[4], val[3], val[2], val[1], val[0]);
- res = 6;
- }
- }
- return res;
-}
-
-void rtk_update_altsettings(patch_info *patch_entry, unsigned char* config_buf_ptr, size_t *config_len_ptr)
-{
- unsigned short offset[256], data_len;
- unsigned char val[256];
-
- struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) config_buf_ptr;
- struct rtk_bt_vendor_config_entry* entry = config->entry;
- size_t config_len = *config_len_ptr;
- int count = 0,temp = 0, i = 0, j;
-
- ALOGI("ORG Config len=%08x:\n", config_len);
- for(i=0;i<=config_len;i+=0x10)
- {
- ALOGI("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
- config_buf_ptr[i], config_buf_ptr[i+1], config_buf_ptr[i+2], config_buf_ptr[i+3], config_buf_ptr[i+4], config_buf_ptr[i+5], config_buf_ptr[i+6], config_buf_ptr[i+7], \
- config_buf_ptr[i+8], config_buf_ptr[i+9], config_buf_ptr[i+10], config_buf_ptr[i+11], config_buf_ptr[i+12], config_buf_ptr[i+13], config_buf_ptr[i+14], config_buf_ptr[i+15]);
- }
-
- memset(offset, 0, sizeof(offset));
- memset(val, 0, sizeof(val));
- data_len = le16_to_cpu(config->data_len);
-
- count = getAltSettings(patch_entry, offset, sizeof(offset)/sizeof(unsigned short));
- if(count <= 0){
- ALOGI("rtk_update_altsettings: No AltSettings");
- return;
- }else{
- ALOGI("rtk_update_altsettings: %d AltSettings", count);
- }
-
- if (data_len != config_len - sizeof(struct rtk_bt_vendor_config))
- {
- ALOGE("rtk_update_altsettings: config len(%x) is not right(%x)", data_len, config_len-sizeof(struct rtk_bt_vendor_config));
- return;
- }
-
- for (i=0; i<data_len;)
- {
- for(j = 0; j < count;j++)
- {
- if(le16_to_cpu(entry->offset) == offset[j])
- offset[j] = 0;
- }
- if(getAltSettingVal(patch_entry, le16_to_cpu(entry->offset), val) == entry->entry_len){
- ALOGI("rtk_update_altsettings: replace %04x[%02x]", le16_to_cpu(entry->offset), entry->entry_len);
- memcpy(entry->entry_data, val, entry->entry_len);
- }
- temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
- i += temp;
- entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
- }
- for(j = 0; j < count;j++){
- if(offset[j] == 0)
- continue;
- entry->entry_len = getAltSettingVal(patch_entry, offset[j], val);
- if(entry->entry_len <= 0)
- continue;
- entry->offset = cpu_to_le16(offset[j]);
- memcpy(entry->entry_data, val, entry->entry_len);
- ALOGI("rtk_update_altsettings: add %04x[%02x]", le16_to_cpu(entry->offset), entry->entry_len);
- temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
- i += temp;
- entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
- }
- config->data_len = cpu_to_le16(i);
- *config_len_ptr = i+sizeof(struct rtk_bt_vendor_config);
-
- ALOGI("NEW Config len=%08x:\n", *config_len_ptr);
- for(i=0;i<=(*config_len_ptr);i+=0x10)
- {
- ALOGI("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
- config_buf_ptr[i], config_buf_ptr[i+1], config_buf_ptr[i+2], config_buf_ptr[i+3], config_buf_ptr[i+4], config_buf_ptr[i+5], config_buf_ptr[i+6], config_buf_ptr[i+7], \
- config_buf_ptr[i+8], config_buf_ptr[i+9], config_buf_ptr[i+10], config_buf_ptr[i+11], config_buf_ptr[i+12], config_buf_ptr[i+13], config_buf_ptr[i+14], config_buf_ptr[i+15]);
- }
- return;
-}
-
-uint32_t rtk_parse_config_file(unsigned char** config_buf, size_t* filelen, uint8_t bt_addr[6], uint16_t mac_offset)
-{
- struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) *config_buf;
- uint16_t config_len = le16_to_cpu(config->data_len), temp = 0;
- struct rtk_bt_vendor_config_entry* entry = config->entry;
- unsigned int i = 0;
- uint32_t baudrate = 0;
- uint32_t config_has_bdaddr = 0;
- uint8_t *p;
-
- if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC)
- {
- ALOGE("config signature magic number(0x%x) is not set to RTK_VENDOR_CONFIG_MAGIC", config->signature);
- return 0;
- }
-
- if (config_len != *filelen - sizeof(struct rtk_bt_vendor_config))
- {
- ALOGE("config len(0x%x) is not right(0x%x)", config_len, *filelen-sizeof(struct rtk_bt_vendor_config));
- return 0;
- }
-
- for (i=0; i<config_len;)
- {
- switch(le16_to_cpu(entry->offset))
- {
- case 0xc:
- {
- p = (uint8_t *)entry->entry_data;
- STREAM_TO_UINT32(baudrate, p);
- if (entry->entry_len >= 12)
- {
- hw_cfg_cb.hw_flow_cntrl |= 0x80; /* bit7 set hw flow control */
- if (entry->entry_data[12] & 0x04) /* offset 0x18, bit2 */
- hw_cfg_cb.hw_flow_cntrl |= 1; /* bit0 enable hw flow control */
- }
-
- ALOGI("config baud rate to :0x%08x, hwflowcontrol:0x%x, 0x%x", baudrate, entry->entry_data[12], hw_cfg_cb.hw_flow_cntrl);
- break;
- }
-#if (USE_CONTROLLER_BDADDR == FALSE)
- case 0x44:
- case 0x3c:
- {
- config_has_bdaddr = 1;
- int j=0;
- for (j=0; j<entry->entry_len; j++)
- entry->entry_data[j] = bt_addr[entry->entry_len - 1- j];
- ALOGI("rtk_parse_config_file: DO NOT USE_CONTROLLER_BDADDR, config has bdaddr");
- ALOGI("rtk_parse_config_file : CONFIG_ADDR is: %02X:%02X:%02X:%02X:%02X:%02X",
- bt_addr[0], bt_addr[1],
- bt_addr[2], bt_addr[3],
- bt_addr[4], bt_addr[5]);
- break;
- }
-#endif
- default:
- ALOGI("config offset(0x%x),length(0x%x)", entry->offset, entry->entry_len);
- break;
- }
- temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
- i += temp;
- entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
- }
-
- return baudrate;
-}
-
-uint32_t rtk_get_bt_config(unsigned char** config_buf,
- uint32_t* config_baud_rate, char * config_file_short_name, uint16_t mac_offset)
-{
- char bt_config_file_name[PATH_MAX] = {0};
- struct stat st;
- size_t filelen;
- int fd;
- FILE* file = NULL;
-
- sprintf(bt_config_file_name, BT_CONFIG_DIRECTORY, config_file_short_name);
- ALOGI("BT config file: %s", bt_config_file_name);
-
- if (stat(bt_config_file_name, &st) < 0)
- {
- ALOGE("can't access bt config file:%s, errno:%d\n", bt_config_file_name, errno);
- return -1;
- }
-
- filelen = st.st_size;
- if(filelen > MAX_ORG_CONFIG_SIZE)
- {
- ALOGE("bt config file is too large(>0x%04x)", MAX_ORG_CONFIG_SIZE);
- return -1;
- }
-
- if ((fd = open(bt_config_file_name, O_RDONLY)) < 0)
- {
- ALOGE("Can't open bt config file");
- return -1;
- }
-
- if ((*config_buf = malloc(MAX_ORG_CONFIG_SIZE+MAX_ALT_CONFIG_SIZE)) == NULL)
- {
- ALOGE("malloc buffer for config file fail(0x%x)\n", filelen);
- close(fd);
- return -1;
- }
-
- if (read(fd, *config_buf, filelen) < (ssize_t)filelen)
- {
- ALOGE("Can't load bt config file");
- free(*config_buf);
- close(fd);
- return -1;
- }
-
- *config_baud_rate = rtk_parse_config_file(config_buf, &filelen, vnd_local_bd_addr, mac_offset);
- ALOGI("Get config baud rate from config file:0x%x", *config_baud_rate);
-
- close(fd);
- return filelen;
-}
-
int rtk_get_bt_firmware(uint8_t** fw_buf, char* fw_short_name)
{
char filename[PATH_MAX] = {0};
return data;
}
+uint8_t get_heartbeat_from_hardware()
+{
+ return hw_cfg_cb.heartbeat;
+}
+
struct rtk_epatch_entry *rtk_get_patch_entry(bt_hw_cfg_cb_t *cfg_cb)
{
uint16_t i;
return entry;
}
-void rtk_get_bt_final_patch(bt_hw_cfg_cb_t* cfg_cb)
-{
- uint8_t proj_id = 0;
- struct rtk_epatch_entry* entry = NULL;
- struct rtk_epatch *patch = (struct rtk_epatch *)cfg_cb->fw_buf;
- int iBtCalLen = 0;
-
- if(cfg_cb->lmp_subversion == LMPSUBVERSION_8723a)
- {
- if(memcmp(cfg_cb->fw_buf, RTK_EPATCH_SIGNATURE, 8) == 0)
- {
- ALOGE("8723as check signature error!");
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
- else
- {
- cfg_cb->total_len = cfg_cb->fw_len + cfg_cb->config_len;
- if (!(cfg_cb->total_buf = malloc(cfg_cb->total_len)))
- {
- ALOGE("can't alloc memory for fw&config, errno:%d", errno);
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
- else
- {
- ALOGI("8723as, fw copy direct");
- memcpy(cfg_cb->total_buf, cfg_cb->fw_buf, cfg_cb->fw_len);
- memcpy(cfg_cb->total_buf+cfg_cb->fw_len, cfg_cb->config_buf, cfg_cb->config_len);
- cfg_cb->dl_fw_flag = 1;
- goto free_buf;
- }
- }
- }
-
- if (memcmp(cfg_cb->fw_buf, RTK_EPATCH_SIGNATURE, 8))
- {
- ALOGE("check signature error");
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
-
- /* check the extension section signature */
- if (memcmp(cfg_cb->fw_buf + cfg_cb->fw_len - 4, EXTENSION_SECTION_SIGNATURE, 4))
- {
- ALOGE("check extension section signature error");
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
-
- proj_id = rtk_get_fw_project_id(cfg_cb->fw_buf + cfg_cb->fw_len - 5);
-
- if((hw_cfg_cb.project_id_mask != PROJECT_ID_MASK_ALL)&& ((hw_cfg_cb.project_id_mask&(1<<proj_id)) ==0))
- {
- ALOGE("hw_cfg_cb.project_id_mask is 0x%08x, fw project_id is %d, does not match!!!",
- hw_cfg_cb.project_id_mask, proj_id);
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
-
- entry = rtk_get_patch_entry(cfg_cb);
- if (entry)
- {
- cfg_cb->total_len = entry->patch_length + cfg_cb->config_len;
- }
- else
- {
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
-
- ALOGI("total_len = 0x%x", cfg_cb->total_len);
-
- if (!(cfg_cb->total_buf = malloc(cfg_cb->total_len)))
- {
- ALOGE("Can't alloc memory for multi fw&config, errno:%d", errno);
- cfg_cb->dl_fw_flag = 0;
- goto free_buf;
- }
- else
- {
- memcpy(cfg_cb->total_buf, cfg_cb->fw_buf + entry->patch_offset, entry->patch_length);
- memcpy(cfg_cb->total_buf + entry->patch_length - 4, &patch->fw_version, 4);
- memcpy(&entry->svn_version, cfg_cb->total_buf + entry->patch_length - 8, 4);
- memcpy(&entry->coex_version, cfg_cb->total_buf + entry->patch_length - 12, 4);
- ALOGI("BTCOEX:20%06d-%04x svn_version:%d lmp_subversion:0x%x hci_version:0x%x hci_revision:0x%x chip_type:%d Cut:%d libbt-vendor_uart version:%s\n",
- ((entry->coex_version >> 16) & 0x7ff) + ((entry->coex_version >> 27) * 10000),
- (entry->coex_version & 0xffff), entry->svn_version, cfg_cb->lmp_subversion, cfg_cb->hci_version, cfg_cb->hci_revision, cfg_cb->chip_type, cfg_cb->eversion+1, RTK_VERSION);
- }
-
- if (cfg_cb->config_len)
- {
- memcpy(cfg_cb->total_buf+entry->patch_length, cfg_cb->config_buf, cfg_cb->config_len);
- }
-
- cfg_cb->dl_fw_flag = 1;
- ALOGI("Fw:%s exists, config file:%s exists", (cfg_cb->fw_len>0)?"":"not", (cfg_cb->config_len>0)?"":"not");
-
-free_buf:
- if (cfg_cb->fw_len > 0)
- {
- free(cfg_cb->fw_buf);
- cfg_cb->fw_len = 0;
- }
-
- if (cfg_cb->config_len > 0)
- {
- free(cfg_cb->config_buf);
- cfg_cb->config_len = 0;
- }
-
- if(entry)
- {
- free(entry);
- }
-}
-
-static int hci_download_patch_h4(HC_BT_HDR *p_buf, int index, uint8_t *data, int len)
-{
- uint8_t retval = FALSE;
- uint8_t *p = (uint8_t *) (p_buf + 1);
-
- UINT16_TO_STREAM(p, HCI_VSC_DOWNLOAD_FW_PATCH);
- *p++ = 1 + len; /* parameter length */
- *p++ = index;
- memcpy(p, data, len);
- p_buf->len = HCI_CMD_PREAMBLE_SIZE + 1+len;
-
- hw_cfg_cb.state = HW_CFG_DL_FW_PATCH;
-
- retval = bt_vendor_cbacks->xmit_cb(HCI_VSC_DOWNLOAD_FW_PATCH, p_buf, hw_config_cback);
- return retval;
-}
-
-/*******************************************************************************
-**
-** Function hw_config_cback
-**
-** Description Callback function for controller configuration
-**
-** Returns None
-**
-*******************************************************************************/
-void hw_config_cback(void *p_mem)
-{
- HC_BT_HDR *p_evt_buf = NULL;
- uint8_t *p = NULL, *pp=NULL;
- uint8_t status = 0;
- uint16_t opcode = 0;
- HC_BT_HDR *p_buf = NULL;
- uint8_t is_proceeding = FALSE;
- int i = 0;
- uint8_t iIndexRx = 0;
- patch_info* prtk_patch_file_info = NULL;
- uint32_t host_baudrate = 0;
-
-#if (USE_CONTROLLER_BDADDR == TRUE)
- const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
-#endif
-
- if(p_mem != NULL)
- {
- p_evt_buf = (HC_BT_HDR *) p_mem;
- status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET);
- p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE_OFFSET;
- STREAM_TO_UINT16(opcode,p);
- }
-
- if(opcode == HCI_VSC_H5_INIT) {
- if(status != 0) {
- ALOGE("%s, status = %d", __func__, status);
- if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
- bt_vendor_cbacks->dealloc(p_evt_buf);
- if(rtkbt_auto_restart) {
- bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
- kill(getpid(), SIGKILL);
- }
- return;
- }
- }
-
- /* Ask a new buffer big enough to hold any HCI commands sent in here */
- /*a cut fc6d status==1*/
- if (((status == 0) ||(opcode == HCI_VSC_READ_ROM_VERSION)) && bt_vendor_cbacks)
- p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_MAX_LEN);
-
- if (p_buf != NULL)
- {
- p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
- p_buf->offset = 0;
- p_buf->len = 0;
- p_buf->layer_specific = 0;
-
- BTVNDDBG("hw_cfg_cb.state = %i", hw_cfg_cb.state);
- switch (hw_cfg_cb.state)
- {
- case HW_CFG_H5_INIT:
- {
- p = (uint8_t *)(p_buf + 1);
- UINT16_TO_STREAM(p, HCI_READ_LMP_VERSION);
- *p++ = 0;
- p_buf->len = HCI_CMD_PREAMBLE_SIZE;
-
- hw_cfg_cb.state = HW_CFG_READ_LOCAL_VER;
- is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_READ_LMP_VERSION, p_buf, hw_config_cback);
- break;
- }
- case HW_CFG_READ_LOCAL_VER:
- {
- if (status == 0)
- {
- p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET);
- STREAM_TO_UINT16(hw_cfg_cb.hci_version, p);
- p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_REVISION_OFFSET);
- STREAM_TO_UINT16(hw_cfg_cb.hci_revision, p);
- p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_LMP_SUBVERSION_OFFSET;
- STREAM_TO_UINT16(hw_cfg_cb.lmp_subversion, p);
- BTVNDDBG("lmp_subversion = 0x%x hw_cfg_cb.hci_version = 0x%x hw_cfg_cb.hci_revision = 0x%x", hw_cfg_cb.lmp_subversion, hw_cfg_cb.hci_version, hw_cfg_cb.hci_revision);
- if(hw_cfg_cb.lmp_subversion == LMPSUBVERSION_8723a)
- {
- hw_cfg_cb.state = HW_CFG_START;
- goto CFG_START;
- }
- else
- {
- hw_cfg_cb.state = HW_CFG_READ_ECO_VER;
- p = (uint8_t *) (p_buf + 1);
- UINT16_TO_STREAM(p, HCI_VSC_READ_ROM_VERSION);
- *p++ = 0;
- p_buf->len = HCI_CMD_PREAMBLE_SIZE;
- is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_ROM_VERSION, p_buf, hw_config_cback);
- }
- }
- break;
- }
- case HW_CFG_READ_ECO_VER:
- {
- if(status == 0)
- {
- hw_cfg_cb.eversion = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPFC6D_EVERSION_OFFSET);
- BTVNDDBG("hw_config_cback chip_id of the IC:%d", hw_cfg_cb.eversion+1);
- }
- else if(1 == status)
- {
- hw_cfg_cb.eversion = 0;
- }
- else
- {
- is_proceeding = FALSE;
- break;
- }
-
- if(check_match_state(&hw_cfg_cb, 0) > 1) // check if have multiple matched patch_entry by lmp_subversion,hci_version, hci_revision
- {
- hw_cfg_cb.state = HW_CFG_READ_CHIP_TYPE;
- p = (uint8_t *) (p_buf + 1);
- UINT16_TO_STREAM(p, HCI_VSC_READ_CHIP_TYPE);
- *p++ = 5;
- UINT8_TO_STREAM(p, 0x00);
- UINT32_TO_STREAM(p, 0xB000A094);
- p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_CMD_READ_CHIP_TYPE_SIZE;
-
- pp = (uint8_t *) (p_buf + 1);
- for (i = 0; i < p_buf->len; i++)
- BTVNDDBG("get chip type command data[%d]= 0x%x", i, *(pp+i));
-
- is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_CHIP_TYPE, p_buf, hw_config_cback);
- break;
- }
- else
- {
- hw_cfg_cb.state = HW_CFG_START;
- goto CFG_START;
- }
- }
- case HW_CFG_READ_CHIP_TYPE:
- {
- BTVNDDBG("READ_CHIP_TYPE status = %d, length = %d", status, p_evt_buf->len);
- p = (uint8_t *)(p_evt_buf + 1) ;
- for (i = 0; i < p_evt_buf->len; i++)
- BTVNDDBG("READ_CHIP_TYPE event data[%d]= 0x%x", i, *(p+i));
- if(status == 0)
- {
- hw_cfg_cb.chip_type = ((*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPFC61_CHIPTYPE_OFFSET))&0x0F);
- BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.lmp_subversion = 0x%x", hw_cfg_cb.lmp_subversion);
- BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.hci_version = 0x%x", hw_cfg_cb.hci_version);
- BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.hci_revision = 0x%x", hw_cfg_cb.hci_revision);
- BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.chip_type = 0x%x", hw_cfg_cb.chip_type);
- }
- else
- {
- is_proceeding = FALSE;
- break;
- }
- if(check_match_state(&hw_cfg_cb, PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE) > 1) // check if have multiple matched patch_entry by lmp_subversion,hci_version, hci_revision and chiptype
- {
- BTVNDDBG("check_match_state(lmp_subversion:0x%04x, hci_version:%d, hci_revision:%d chip_type:%d): Multi Matched Patch\n", hw_cfg_cb.lmp_subversion, hw_cfg_cb.hci_version, hw_cfg_cb.hci_revision, hw_cfg_cb.chip_type);
- is_proceeding = FALSE;
- break;
- }
- hw_cfg_cb.state = HW_CFG_START;
- }
-CFG_START:
- case HW_CFG_START:
- {
-#ifdef BT_CHIP_PROBE_SIMULATION
- {
- int ii;
- memcpy(&hw_cfg_test, &hw_cfg_cb, sizeof(hw_cfg_test));
- for(i=0;i<sizeof(bt_chip_chars)/sizeof(bt_chip_chars[0]);i++)
- {
- BTVNDDBG("BT_CHIP_PROBE_SIMULATION loop:%d $$$ BEGIN $$$\n", i);
- hw_cfg_test.lmp_subversion = bt_chip_chars[i].lmp_subversion;
- hw_cfg_test.hci_version = bt_chip_chars[i].hci_version;
- hw_cfg_test.hci_revision = bt_chip_chars[i].hci_revision;
- hw_cfg_test.chip_type = CHIPTYPE_NONE;
- if(check_match_state(&hw_cfg_test, 0) > 1){
- BTVNDDBG("check_match_state hw_cfg_test(lmp_subversion:0x%04x, hci_version:%d, hci_revision:%d chip_type:%d): Multi Matched Patch\n", hw_cfg_test.lmp_subversion, hw_cfg_test.hci_version, hw_cfg_test.hci_revision, hw_cfg_test.chip_type);
- if(bt_chip_chars[i].chip_type != CHIPTYPE_NONE){
- BTVNDDBG("BT_CHIP_PROBE_SIMULATION loop:%d *** Include ChipType ***\n", i);
- hw_cfg_test.chip_type = bt_chip_chars[i].chip_type;
- if(check_match_state(&hw_cfg_test, PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE) > 1){
- BTVNDDBG("check_match_state hw_cfg_test(lmp_subversion:0x%04x, hci_version:%d, hci_revision:%d chip_type:%d): Multi Matched Patch\n", hw_cfg_test.lmp_subversion, hw_cfg_test.hci_version, hw_cfg_test.hci_revision, hw_cfg_test.chip_type);
- }else{
- prtk_patch_file_info = get_patch_entry(&hw_cfg_test);
- }
- }
- }else{
- prtk_patch_file_info = get_patch_entry(&hw_cfg_test);
- }
- BTVNDDBG("BT_CHIP_PROBE_SIMULATION loop:%d $$$ END $$$\n", i);
- }
- }
-#endif
- //get efuse config file and patch code file
- prtk_patch_file_info = get_patch_entry(&hw_cfg_cb);
-
-
- if((prtk_patch_file_info == NULL) || (prtk_patch_file_info->lmp_subversion == 0))
- {
- ALOGE("get patch entry error");
- is_proceeding = FALSE;
- break;
- }
- hw_cfg_cb.max_patch_size = prtk_patch_file_info->max_patch_size;
- hw_cfg_cb.config_len = rtk_get_bt_config(&hw_cfg_cb.config_buf, &hw_cfg_cb.baudrate, prtk_patch_file_info->config_name, prtk_patch_file_info->mac_offset);
- if (hw_cfg_cb.config_len < 0)
- {
- ALOGE("Get Config file fail, just use efuse settings");
- hw_cfg_cb.config_len = 0;
- }
- rtk_update_altsettings(prtk_patch_file_info, hw_cfg_cb.config_buf, &(hw_cfg_cb.config_len));
-
- hw_cfg_cb.fw_len = rtk_get_bt_firmware(&hw_cfg_cb.fw_buf, prtk_patch_file_info->patch_name);
- if (hw_cfg_cb.fw_len < 0)
- {
- ALOGE("Get BT firmware fail");
- hw_cfg_cb.fw_len = 0;
- }
- else{
- hw_cfg_cb.project_id_mask = prtk_patch_file_info->project_id_mask;
- rtk_get_bt_final_patch(&hw_cfg_cb);
- }
- BTVNDDBG("Check total_len(0x%08x) max_patch_size(0x%08x)", hw_cfg_cb.total_len, hw_cfg_cb.max_patch_size);
- if (hw_cfg_cb.total_len > hw_cfg_cb.max_patch_size)
- {
- ALOGE("total length of fw&config(0x%08x) larger than max_patch_size(0x%08x)", hw_cfg_cb.total_len, hw_cfg_cb.max_patch_size);
- is_proceeding = FALSE;
- break;
- }
-
- if ((hw_cfg_cb.total_len > 0) && hw_cfg_cb.dl_fw_flag)
- {
- hw_cfg_cb.patch_frag_cnt = hw_cfg_cb.total_len / PATCH_DATA_FIELD_MAX_SIZE;
- hw_cfg_cb.patch_frag_tail = hw_cfg_cb.total_len % PATCH_DATA_FIELD_MAX_SIZE;
- if (hw_cfg_cb.patch_frag_tail)
- hw_cfg_cb.patch_frag_cnt += 1;
- else
- hw_cfg_cb.patch_frag_tail = PATCH_DATA_FIELD_MAX_SIZE;
- BTVNDDBG("patch fragment count %d, tail len %d", hw_cfg_cb.patch_frag_cnt, hw_cfg_cb.patch_frag_tail);
- }
- else
- {
- is_proceeding = FALSE;
- break;
- }
-
- if ((hw_cfg_cb.baudrate == 0) && ((hw_cfg_cb.hw_flow_cntrl & 0x80) == 0))
- {
- BTVNDDBG("no baudrate to set and no need to set hw flow control");
- goto DOWNLOAD_FW;
- }
-
- if ((hw_cfg_cb.baudrate == 0) && (hw_cfg_cb.hw_flow_cntrl & 0x80))
- {
- BTVNDDBG("no baudrate to set but set hw flow control is needed");
- goto SET_HW_FLCNTRL;
- }
- }
- /* fall through intentionally */
- case HW_CFG_SET_UART_BAUD_CONTROLLER:
- BTVNDDBG("bt vendor lib: set CONTROLLER UART baud 0x%x", hw_cfg_cb.baudrate);
- hw_cfg_cb.state = HW_CFG_SET_UART_BAUD_HOST;
- is_proceeding = hw_config_set_controller_baudrate(p_buf, hw_cfg_cb.baudrate);
- break;
-
- case HW_CFG_SET_UART_BAUD_HOST:
- /* update baud rate of host's UART port */
- rtk_speed_to_uart_speed(hw_cfg_cb.baudrate, &host_baudrate);
- BTVNDDBG("bt vendor lib: set HOST UART baud %i", host_baudrate);
- userial_vendor_set_baud(line_speed_to_userial_baud(host_baudrate));
-
- if((hw_cfg_cb.hw_flow_cntrl & 0x80) == 0)
- goto DOWNLOAD_FW;
-
-SET_HW_FLCNTRL:
- case HW_CFG_SET_UART_HW_FLOW_CONTROL:
- BTVNDDBG("Change HW flowcontrol setting");
- if(hw_cfg_cb.hw_flow_cntrl & 0x01)
- {
- userial_vendor_set_hw_fctrl(1);
- }
- else
- {
- userial_vendor_set_hw_fctrl(0);
- }
- ms_delay(100);
- hw_cfg_cb.state = HW_CFG_DL_FW_PATCH;
-
-DOWNLOAD_FW:
- case HW_CFG_DL_FW_PATCH:
- BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, opcode:0x%x", status, opcode);
-
- //recv command complete event for patch code download command
- if(opcode == HCI_VSC_DOWNLOAD_FW_PATCH)
- {
- iIndexRx = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET + 1);
- BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, iIndexRx:%i", status, iIndexRx);
- hw_cfg_cb.patch_frag_idx++;
-
- if(iIndexRx&0x80)
- {
- BTVNDDBG("vendor lib fwcfg completed");
- free(hw_cfg_cb.total_buf);
- hw_cfg_cb.total_len = 0;
-
- bt_vendor_cbacks->dealloc(p_buf);
- bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
-
- hw_cfg_cb.state = 0;
- is_proceeding = TRUE;
- break;
- }
- }
-
- if (hw_cfg_cb.patch_frag_idx < hw_cfg_cb.patch_frag_cnt)
- {
- iIndexRx = hw_cfg_cb.patch_frag_idx?((hw_cfg_cb.patch_frag_idx-1)%0x7f+1):0;
- if (hw_cfg_cb.patch_frag_idx == hw_cfg_cb.patch_frag_cnt - 1)
- {
- BTVNDDBG("HW_CFG_DL_FW_PATCH: send last fw fragment");
- iIndexRx |= 0x80;
- hw_cfg_cb.patch_frag_len = hw_cfg_cb.patch_frag_tail;
- }
- else
- {
- iIndexRx &= 0x7F;
- hw_cfg_cb.patch_frag_len = PATCH_DATA_FIELD_MAX_SIZE;
- }
- }
-
- is_proceeding = hci_download_patch_h4(p_buf, iIndexRx,
- hw_cfg_cb.total_buf+(hw_cfg_cb.patch_frag_idx*PATCH_DATA_FIELD_MAX_SIZE),
- hw_cfg_cb.patch_frag_len);
- break;
-
- default:
- break;
- } // switch(hw_cfg_cb.state)
- } // if (p_buf != NULL)
-
- /* Free the RX event buffer */
- if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
- bt_vendor_cbacks->dealloc(p_evt_buf);
-
- if (is_proceeding == FALSE)
- {
- ALOGE("vendor lib fwcfg aborted!!!");
- if (bt_vendor_cbacks)
- {
- if (p_buf != NULL)
- bt_vendor_cbacks->dealloc(p_buf);
-
- bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
- }
-
- if(hw_cfg_cb.config_len)
- {
- free(hw_cfg_cb.config_buf);
- hw_cfg_cb.config_len = 0;
- }
-
- if(hw_cfg_cb.fw_len)
- {
- free(hw_cfg_cb.fw_buf);
- hw_cfg_cb.fw_len= 0;
- }
-
- if(hw_cfg_cb.total_len)
- {
- free(hw_cfg_cb.total_buf);
- hw_cfg_cb.total_len = 0;
- }
- hw_cfg_cb.state = 0;
- }
-}
-
/******************************************************************************
** LPM Static Functions
******************************************************************************/
}
-/*****************************************************************************
-** Hardware Configuration Interface Functions
-*****************************************************************************/
-
-
-/*******************************************************************************
-**
-** Function hw_config_start
-**
-** Description Kick off controller initialization process
-**
-** Returns None
-**
-*******************************************************************************/
-void hw_config_start(char transtype)
-{
- memset(&hw_cfg_cb, 0, sizeof(bt_hw_cfg_cb_t));
- hw_cfg_cb.dl_fw_flag = 1;
- hw_cfg_cb.chip_type = CHIPTYPE_NONE;
- BTVNDDBG("RTKBT_RELEASE_NAME: %s",RTKBT_RELEASE_NAME);
- BTVNDDBG("\nRealtek libbt-vendor_uart Version %s \n",RTK_VERSION);
- HC_BT_HDR *p_buf = NULL;
- uint8_t *p;
-
- BTVNDDBG("hw_config_start, transtype = 0x%x \n", transtype);
- /* Start from sending H5 INIT */
- if (bt_vendor_cbacks)
- {
- /* Must allocate command buffer via HC's alloc API */
- p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
- HCI_CMD_PREAMBLE_SIZE);
- if(p_buf)
- {
- p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
- p_buf->offset = 0;
- p_buf->layer_specific = 0;
- p_buf->len = HCI_CMD_PREAMBLE_SIZE;
-
- p = (uint8_t *) (p_buf + 1);
-
- if(transtype & RTKBT_TRANS_H4) {
- p = (uint8_t *)(p_buf + 1);
- UINT16_TO_STREAM(p, HCI_READ_LMP_VERSION);
- *p++ = 0;
- p_buf->len = HCI_CMD_PREAMBLE_SIZE;
-
- hw_cfg_cb.state = HW_CFG_READ_LOCAL_VER;
- bt_vendor_cbacks->xmit_cb(HCI_READ_LMP_VERSION, p_buf, hw_config_cback);
- }
- else {
- UINT16_TO_STREAM(p, HCI_VSC_H5_INIT);
- *p = 0; /* parameter length */
- hw_cfg_cb.state = HW_CFG_H5_INIT;
-
- bt_vendor_cbacks->xmit_cb(HCI_VSC_H5_INIT, p_buf, hw_config_cback);
- }
- }
- else {
- ALOGE("%s buffer alloc fail!", __func__);
- }
- }
- else
- ALOGE("%s call back is null", __func__);
-}
-
#if (HW_END_WITH_HCI_RESET == TRUE)
/******************************************************************************
*
--- /dev/null
+#define LOG_TAG "bt_hwcfg_uart"
+#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_rtk.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "upio.h"
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <unistd.h>
+
+#include "bt_vendor_lib.h"
+#include "hardware.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+#define RTK_VERSION "4.1.1"
+
+extern uint8_t vnd_local_bd_addr[BD_ADDR_LEN];
+extern bool rtkbt_auto_restart;
+extern bt_hw_cfg_cb_t hw_cfg_cb;
+void hw_config_cback(void *p_evt_buf);
+extern int getmacaddr(unsigned char * addr);
+extern uint8_t rtk_get_fw_project_id(uint8_t *p_buf);
+extern struct rtk_epatch_entry *rtk_get_patch_entry(bt_hw_cfg_cb_t *cfg_cb);
+extern int rtk_get_bt_firmware(uint8_t** fw_buf, char* fw_short_name);
+
+
+
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+//static bt_hw_cfg_cb_t hw_cfg_cb;
+
+//#define BT_CHIP_PROBE_SIMULATION
+#ifdef BT_CHIP_PROBE_SIMULATION
+static bt_hw_cfg_cb_t hw_cfg_test;
+struct bt_chip_char{
+ uint16_t lmp_subversion;
+ uint8_t hci_version;
+ uint8_t hci_revision;
+ uint8_t chip_type;
+};
+struct bt_chip_char bt_chip_chars[] = \
+{
+ {0x8723, 0x4, 0xb, CHIPTYPE_NONE}, //8703as
+ {0x8723, 0x6, 0xb, CHIPTYPE_NONE}, //8723bs
+ {0x8703, 0x4, 0xd, 0x7}, //8703bs
+ {0x8703, 0x6, 0xb, 0x3}, //8723cs-cg
+ {0x8703, 0x6, 0xb, 0x4}, //8723cs-vf
+ {0x8703, 0x6, 0xb, 0x5}, //8723cs-xx
+ {0x8723, 0x6, 0xd, CHIPTYPE_NONE}, //8723ds
+};
+#endif
+
+typedef struct {
+ uint16_t lmp_subversion;
+ uint32_t hci_version_mask;
+ uint32_t hci_revision_mask;
+ uint32_t chip_type_mask;
+ uint32_t project_id_mask;
+ char *patch_name;
+ char *config_name;
+ uint16_t mac_offset;
+ uint32_t max_patch_size;
+} patch_info;
+
+static patch_info patch_table[] = {
+/* lmp_subv hci_version_mask hci_revision_mask chip_type_mask project_id_mask fw name config name mac offset max_patch_size */
+ {0x1200, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<0, "rtl8723as_fw", "rtl8723as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723AS
+
+ {0x8723, ~(HCI_VERSION_MASK_21), ~(1<<0xd), CHIP_TYPE_MASK_ALL, 1<<1, "rtl8723bs_fw", "rtl8723bs_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723BS
+// {0x8723, ~(HCI_VERSION_MASK_21), ~(1<<0xd), CHIP_TYPE_MASK_ALL, 1<<1, "rtl8723bs_VQ0_fw", "rtl8723bs_VQ0_config", CONFIG_MAC_OFFSET_GEN_1_2}, //Rtl8723BS_VQ0
+ {0x8821, HCI_VERSION_MASK_ALL, ~(1<<0xc), CHIP_TYPE_MASK_ALL, 1<<2, "rtl8821as_fw", "rtl8821as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8821AS
+ {0x8761, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<3, "rtl8761at_fw", "rtl8761at_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8761AW
+ {0x8723, HCI_VERSION_MASK_21, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<4, "rtl8703as_fw", "rtl8703as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8703AS
+
+ {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<7, 1<<6, "rtl8703bs_fw", "rtl8703bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8703BS
+ {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<5, 1<<7, "rtl8723cs_xx_fw", "rtl8723cs_xx_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_xx
+ {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<3, 1<<7, "rtl8723cs_cg_fw", "rtl8723cs_cg_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_cg
+ {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<4, 1<<7, "rtl8723cs_vf_fw", "rtl8723cs_vf_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_vf
+ {0x8822, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<8, "rtl8822bs_fw", "rtl8822bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8822BS
+
+ {0x8723, HCI_VERSION_MASK_ALL, (1<<0xd), ~(1<<7), 1<<9, "rtl8723ds_fw", "rtl8723ds_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //Rtl8723ds
+ {0x8723, HCI_VERSION_MASK_ALL, (1<<0xd), 1<<7, 1<<9, "rtl8703cs_fw", "rtl8703cs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //Rtl8703cs
+ {0x8821, HCI_VERSION_MASK_ALL, (1<<0xc), CHIP_TYPE_MASK_ALL, 1<<10, "rtl8821cs_fw", "rtl8821cs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //RTL8821CS
+/* todo: RTL8703CS */
+
+ {LMP_SUBVERSION_NONE,HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, PROJECT_ID_MASK_ALL, "rtl_none_fw", "rtl_none_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}
+};
+
+/*
+static bt_lpm_param_t lpm_param =
+{
+ LPM_SLEEP_MODE,
+ LPM_IDLE_THRESHOLD,
+ LPM_HC_IDLE_THRESHOLD,
+ LPM_BT_WAKE_POLARITY,
+ LPM_HOST_WAKE_POLARITY,
+ LPM_ALLOW_HOST_SLEEP_DURING_SCO,
+ LPM_COMBINE_SLEEP_MODE_AND_LPM,
+ LPM_ENABLE_UART_TXD_TRI_STATE,*/
+ //0, /* not applicable */
+ // 0, /* not applicable */
+ // 0, /* not applicable */
+ /*LPM_PULSED_HOST_WAKE
+};*/
+//signature: realtech
+static const uint8_t RTK_EPATCH_SIGNATURE[8]={0x52,0x65,0x61,0x6C,0x74,0x65,0x63,0x68};
+//Extension Section IGNATURE:0x77FD0451
+static const uint8_t EXTENSION_SECTION_SIGNATURE[4]={0x51,0x04,0xFD,0x77};
+
+static int check_match_state(bt_hw_cfg_cb_t *cfg,uint32_t mask)
+{
+ patch_info *patch_entry;
+ int res = 0;
+
+ for(patch_entry = patch_table; patch_entry->lmp_subversion != LMP_SUBVERSION_NONE; patch_entry++) {
+ if(patch_entry->lmp_subversion != cfg->lmp_subversion)
+ continue;
+ if((patch_entry->hci_version_mask!=HCI_VERSION_MASK_ALL)&&((patch_entry->hci_version_mask&(1<<cfg->hci_version))==0))
+ continue;
+ if((patch_entry->hci_revision_mask!=HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<<cfg->hci_revision))==0))
+ continue;
+ if((mask&PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE)&&(patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL)&&((patch_entry->chip_type_mask&(1<<cfg->chip_type))==0))
+ continue;
+ res++;
+ }
+ ALOGI( "check_match_state return %d(cfg->lmp_subversion:0x%x cfg->hci_vesion:0x%x cfg->hci_revision:0x%x cfg->chip_type:0x%x mask:%08x)\n",
+ res, cfg->lmp_subversion, cfg->hci_version, cfg->hci_revision, cfg->chip_type, mask);
+ return res;
+}
+
+static patch_info* get_patch_entry(bt_hw_cfg_cb_t *cfg)
+{
+ patch_info *patch_entry;
+
+ ALOGI("get_patch_entry(lmp_subversion:0x%x hci_vesion:0x%x cfg->hci_revision:0x%x chip_type:0x%x)\n",
+ cfg->lmp_subversion, cfg->hci_version, cfg->hci_revision, cfg->chip_type);
+ for(patch_entry = patch_table; patch_entry->lmp_subversion != LMP_SUBVERSION_NONE; patch_entry++) {
+ if(patch_entry->lmp_subversion != cfg->lmp_subversion)
+ continue;
+ if((patch_entry->hci_version_mask != HCI_VERSION_MASK_ALL)&&((patch_entry->hci_version_mask&(1<<cfg->hci_version)) == 0))
+ continue;
+ if((patch_entry->hci_revision_mask != HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<<cfg->hci_revision)) == 0))
+ continue;
+ if((patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL)&&((patch_entry->chip_type_mask&(1<<cfg->chip_type)) == 0))
+ continue;
+ break;
+ }
+ ALOGI("get_patch_entry return(patch_name:%s config_name:%s mac_offset:0x%x)\n",
+ patch_entry->patch_name, patch_entry->config_name, patch_entry->mac_offset);
+ return patch_entry;
+}
+
+typedef struct _baudrate_ex
+{
+ uint32_t rtk_speed;
+ uint32_t uart_speed;
+}baudrate_ex;
+
+baudrate_ex baudrates[] =
+{
+ {0x00006004, 921600},
+ {0x05F75004, 921600},//RTL8723BS
+ {0x00004003, 1500000},
+ {0x04928002, 1500000},//RTL8723BS
+ {0x00005002, 2000000},//same as RTL8723AS
+ {0x00008001, 3000000},
+ {0x04928001, 3000000},//RTL8723BS
+ {0x06B58001, 3000000},//add RTL8703as
+ {0x00007001, 3500000},
+ {0x052A6001, 3500000},//RTL8723BS
+ {0x00005001, 4000000},//same as RTL8723AS
+ {0x0000701d, 115200},
+ {0x0252C014, 115200}//RTL8723BS
+};
+
+/**
+* Change realtek Bluetooth speed to uart speed. It is matching in the struct baudrates:
+*
+* @code
+* baudrate_ex baudrates[] =
+* {
+* {0x7001, 3500000},
+* {0x6004, 921600},
+* {0x4003, 1500000},
+* {0x5001, 4000000},
+* {0x5002, 2000000},
+* {0x8001, 3000000},
+* {0x701d, 115200}
+* };
+* @endcode
+*
+* If there is no match in baudrates, uart speed will be set as #115200.
+*
+* @param rtk_speed realtek Bluetooth speed
+* @param uart_speed uart speed
+*
+*/
+static void rtk_speed_to_uart_speed(uint32_t rtk_speed, uint32_t* uart_speed)
+{
+ *uart_speed = 115200;
+
+ uint8_t i;
+ for (i=0; i< sizeof(baudrates)/sizeof(baudrate_ex); i++)
+ {
+ if (baudrates[i].rtk_speed == rtk_speed)
+ {
+ *uart_speed = baudrates[i].uart_speed;
+ return;
+ }
+ }
+ return;
+}
+
+/**
+* Change uart speed to realtek Bluetooth speed. It is matching in the struct baudrates:
+*
+* @code
+* baudrate_ex baudrates[] =
+* {
+* {0x7001, 3500000},
+* {0x6004, 921600},
+* {0x4003, 1500000},
+* {0x5001, 4000000},
+* {0x5002, 2000000},
+* {0x8001, 3000000},
+* {0x701d, 115200}
+* };
+* @endcode
+*
+* If there is no match in baudrates, realtek Bluetooth speed will be set as #0x701D.
+*
+* @param uart_speed uart speed
+* @param rtk_speed realtek Bluetooth speed
+*
+*//*
+static inline void uart_speed_to_rtk_speed(uint32_t uart_speed, uint32_t* rtk_speed)
+{
+ *rtk_speed = 0x701D;
+
+ unsigned int i;
+ for (i=0; i< sizeof(baudrates)/sizeof(baudrate_ex); i++)
+ {
+ if (baudrates[i].uart_speed == uart_speed)
+ {
+ *rtk_speed = baudrates[i].rtk_speed;
+ return;
+ }
+ }
+ return;
+}
+*/
+
+/*******************************************************************************
+**
+** Function hw_config_set_bdaddr
+**
+** Description Program controller's Bluetooth Device Address
+**
+** Returns TRUE, if valid address is sent
+** FALSE, otherwise
+**
+*******************************************************************************/
+static uint8_t hw_config_set_controller_baudrate(HC_BT_HDR *p_buf, uint32_t baudrate)
+{
+ uint8_t retval = FALSE;
+ uint8_t *p = (uint8_t *) (p_buf + 1);
+
+ UINT16_TO_STREAM(p, HCI_VSC_UPDATE_BAUDRATE);
+ *p++ = 4; /* parameter length */
+ UINT32_TO_STREAM(p, baudrate);
+
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE + 4;
+
+ retval = bt_vendor_cbacks->xmit_cb(HCI_VSC_UPDATE_BAUDRATE, p_buf, \
+ hw_config_cback);
+
+ return (retval);
+}
+
+/*******************************************************************************
+**
+** Function line_speed_to_userial_baud
+**
+** Description helper function converts line speed number into USERIAL baud
+** rate symbol
+**
+** Returns unit8_t (USERIAL baud symbol)
+**
+*******************************************************************************/
+static uint8_t line_speed_to_userial_baud(uint32_t line_speed)
+{
+ uint8_t baud;
+
+ if (line_speed == 4000000)
+ baud = USERIAL_BAUD_4M;
+ else if (line_speed == 3000000)
+ baud = USERIAL_BAUD_3M;
+ else if (line_speed == 2000000)
+ baud = USERIAL_BAUD_2M;
+ else if (line_speed == 1500000)
+ baud = USERIAL_BAUD_1_5M;
+ else if (line_speed == 1000000)
+ baud = USERIAL_BAUD_1M;
+ else if (line_speed == 921600)
+ baud = USERIAL_BAUD_921600;
+ else if (line_speed == 460800)
+ baud = USERIAL_BAUD_460800;
+ else if (line_speed == 230400)
+ baud = USERIAL_BAUD_230400;
+ else if (line_speed == 115200)
+ baud = USERIAL_BAUD_115200;
+ else if (line_speed == 57600)
+ baud = USERIAL_BAUD_57600;
+ else if (line_speed == 19200)
+ baud = USERIAL_BAUD_19200;
+ else if (line_speed == 9600)
+ baud = USERIAL_BAUD_9600;
+ else if (line_speed == 1200)
+ baud = USERIAL_BAUD_1200;
+ else if (line_speed == 600)
+ baud = USERIAL_BAUD_600;
+ else
+ {
+ ALOGE( "userial vendor: unsupported baud speed %d", line_speed);
+ baud = USERIAL_BAUD_115200;
+ }
+
+ return baud;
+}
+
+
+
+/**
+* Change uart speed to realtek Bluetooth speed. It is matching in the struct baudrates:
+*
+* @code
+* baudrate_ex baudrates[] =
+* {
+* {0x7001, 3500000},
+* {0x6004, 921600},
+* {0x4003, 1500000},
+* {0x5001, 4000000},
+* {0x5002, 2000000},
+* {0x8001, 3000000},
+* {0x701d, 115200}
+* };
+* @endcode
+*
+* If there is no match in baudrates, realtek Bluetooth speed will be set as #0x701D.
+*
+* @param uart_speed uart speed
+* @param rtk_speed realtek Bluetooth speed
+*
+*//*
+static inline void uart_speed_to_rtk_speed(uint32_t uart_speed, uint32_t* rtk_speed)
+{
+ *rtk_speed = 0x701D;
+
+ unsigned int i;
+ for (i=0; i< sizeof(baudrates)/sizeof(baudrate_ex); i++)
+ {
+ if (baudrates[i].uart_speed == uart_speed)
+ {
+ *rtk_speed = baudrates[i].rtk_speed;
+ return;
+ }
+ }
+ return;
+}
+*/
+
+
+static inline int getAltSettings(patch_info *patch_entry, unsigned short *offset)//(patch_info *patch_entry, unsigned short *offset, int max_group_cnt)
+{
+ int n = 0;
+ if(patch_entry)
+ offset[n++] = patch_entry->mac_offset;
+/*
+//sample code, add special settings
+
+ offset[n++] = 0x15B;
+*/
+ return n;
+}
+static inline int getAltSettingVal(patch_info *patch_entry, unsigned short offset, unsigned char * val)
+{
+ int res = 0;
+
+ switch(offset)
+ {
+/*
+//sample code, add special settings
+ case 0x15B:
+ val[0] = 0x0B;
+ val[1] = 0x0B;
+ val[2] = 0x0B;
+ val[3] = 0x0B;
+ res = 4;
+ break;
+*/
+ default:
+ res = 0;
+ break;
+ }
+ if((patch_entry)&&(offset == patch_entry->mac_offset)&&(res == 0))
+ {
+ if(getmacaddr(val) == 0){
+ ALOGI("MAC: %02x:%02x:%02x:%02x:%02x:%02x", val[5], val[4], val[3], val[2], val[1], val[0]);
+ res = 6;
+ }
+ }
+ return res;
+}
+
+
+static void rtk_update_altsettings(patch_info *patch_entry, unsigned char* config_buf_ptr, size_t *config_len_ptr)
+{
+ unsigned short offset[256], data_len;
+ unsigned char val[256];
+
+ struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) config_buf_ptr;
+ struct rtk_bt_vendor_config_entry* entry = config->entry;
+ size_t config_len = *config_len_ptr;
+ unsigned int i = 0;
+ int count = 0,temp = 0, j;
+
+ ALOGI("ORG Config len=%08zx:\n", config_len);
+ for(i=0;i<=config_len;i+=0x10)
+ {
+ ALOGI("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
+ config_buf_ptr[i], config_buf_ptr[i+1], config_buf_ptr[i+2], config_buf_ptr[i+3], config_buf_ptr[i+4], config_buf_ptr[i+5], config_buf_ptr[i+6], config_buf_ptr[i+7], \
+ config_buf_ptr[i+8], config_buf_ptr[i+9], config_buf_ptr[i+10], config_buf_ptr[i+11], config_buf_ptr[i+12], config_buf_ptr[i+13], config_buf_ptr[i+14], config_buf_ptr[i+15]);
+ }
+
+ memset(offset, 0, sizeof(offset));
+ memset(val, 0, sizeof(val));
+ data_len = le16_to_cpu(config->data_len);
+
+ count = getAltSettings(patch_entry, offset);//getAltSettings(patch_entry, offset, sizeof(offset)/sizeof(unsigned short));
+ if(count <= 0){
+ ALOGI("rtk_update_altsettings: No AltSettings");
+ return;
+ }else{
+ ALOGI("rtk_update_altsettings: %d AltSettings", count);
+ }
+
+ if (data_len != config_len - sizeof(struct rtk_bt_vendor_config))
+ {
+ ALOGE("rtk_update_altsettings: config len(%x) is not right(%lx)", data_len, (unsigned long)(config_len-sizeof(struct rtk_bt_vendor_config)));
+ return;
+ }
+
+ for (i=0; i<data_len;)
+ {
+ for(j = 0; j < count;j++)
+ {
+ if(le16_to_cpu(entry->offset) == offset[j])
+ offset[j] = 0;
+ }
+ if(getAltSettingVal(patch_entry, le16_to_cpu(entry->offset), val) == entry->entry_len){
+ ALOGI("rtk_update_altsettings: replace %04x[%02x]", le16_to_cpu(entry->offset), entry->entry_len);
+ memcpy(entry->entry_data, val, entry->entry_len);
+ }
+ temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
+ i += temp;
+ entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
+ }
+ for(j = 0; j < count;j++){
+ if(offset[j] == 0)
+ continue;
+ entry->entry_len = getAltSettingVal(patch_entry, offset[j], val);
+ if(entry->entry_len <= 0)
+ continue;
+ entry->offset = cpu_to_le16(offset[j]);
+ memcpy(entry->entry_data, val, entry->entry_len);
+ ALOGI("rtk_update_altsettings: add %04x[%02x]", le16_to_cpu(entry->offset), entry->entry_len);
+ temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
+ i += temp;
+ entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
+ }
+ config->data_len = cpu_to_le16(i);
+ *config_len_ptr = i+sizeof(struct rtk_bt_vendor_config);
+
+ ALOGI("NEW Config len=%08zx:\n", *config_len_ptr);
+ for(i=0;i<=(*config_len_ptr);i+=0x10)
+ {
+ ALOGI("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
+ config_buf_ptr[i], config_buf_ptr[i+1], config_buf_ptr[i+2], config_buf_ptr[i+3], config_buf_ptr[i+4], config_buf_ptr[i+5], config_buf_ptr[i+6], config_buf_ptr[i+7], \
+ config_buf_ptr[i+8], config_buf_ptr[i+9], config_buf_ptr[i+10], config_buf_ptr[i+11], config_buf_ptr[i+12], config_buf_ptr[i+13], config_buf_ptr[i+14], config_buf_ptr[i+15]);
+ }
+ return;
+}
+
+
+static uint32_t rtk_parse_config_file(unsigned char** config_buf, size_t* filelen, uint8_t bt_addr[6], uint16_t mac_offset)
+{
+ struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) *config_buf;
+ uint16_t config_len = le16_to_cpu(config->data_len), temp = 0;
+ struct rtk_bt_vendor_config_entry* entry = config->entry;
+ unsigned int i = 0;
+ uint32_t baudrate = 0;
+ uint8_t heartbeat_buf = 0;
+ //uint32_t config_has_bdaddr = 0;
+ uint8_t *p;
+
+ ALOGD("bt_addr = %x", bt_addr[0]);
+ if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC)
+ {
+ ALOGE("config signature magic number(0x%x) is not set to RTK_VENDOR_CONFIG_MAGIC", config->signature);
+ return 0;
+ }
+
+ if (config_len != *filelen - sizeof(struct rtk_bt_vendor_config))
+ {
+ ALOGE("config len(0x%x) is not right(0x%lx)", config_len, (unsigned long)(*filelen-sizeof(struct rtk_bt_vendor_config)));
+ return 0;
+ }
+
+ hw_cfg_cb.heartbeat = 0;
+ for (i=0; i<config_len;)
+ {
+ switch(le16_to_cpu(entry->offset))
+ {
+ case 0xc:
+ {
+ p = (uint8_t *)entry->entry_data;
+ STREAM_TO_UINT32(baudrate, p);
+ if (entry->entry_len >= 12)
+ {
+ hw_cfg_cb.hw_flow_cntrl |= 0x80; /* bit7 set hw flow control */
+ if (entry->entry_data[12] & 0x04) /* offset 0x18, bit2 */
+ hw_cfg_cb.hw_flow_cntrl |= 1; /* bit0 enable hw flow control */
+ }
+
+ ALOGI("config baud rate to :0x%08x, hwflowcontrol:0x%x, 0x%x", baudrate, entry->entry_data[12], hw_cfg_cb.hw_flow_cntrl);
+ break;
+ }
+ case 0x017a:
+ {
+ if(mac_offset == CONFIG_MAC_OFFSET_GEN_1_2)
+ {
+ p = (uint8_t *)entry->entry_data;
+ STREAM_TO_UINT8(heartbeat_buf, p);
+ if((heartbeat_buf & 0x02) && (heartbeat_buf & 0x10))
+ hw_cfg_cb.heartbeat = 1;
+ else
+ hw_cfg_cb.heartbeat = 0;
+
+ ALOGI("config 0x017a heartbeat = %d",hw_cfg_cb.heartbeat);
+ }
+ break;
+ }
+ case 0x01be:
+ {
+ if(mac_offset == CONFIG_MAC_OFFSET_GEN_3PLUS)
+ {
+ p = (uint8_t *)entry->entry_data;
+ STREAM_TO_UINT8(heartbeat_buf, p);
+ if((heartbeat_buf & 0x02) && (heartbeat_buf & 0x10))
+ hw_cfg_cb.heartbeat = 1;
+ else
+ hw_cfg_cb.heartbeat = 0;
+
+ ALOGI("config 0x01be heartbeat = %d",hw_cfg_cb.heartbeat);
+ }
+ break;
+ }
+ default:
+ ALOGI("config offset(0x%x),length(0x%x)", entry->offset, entry->entry_len);
+ break;
+ }
+ temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
+ i += temp;
+ entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
+ }
+
+ return baudrate;
+}
+
+static void rtk_get_bt_final_patch(bt_hw_cfg_cb_t* cfg_cb)
+{
+ uint8_t proj_id = 0;
+ struct rtk_epatch_entry* entry = NULL;
+ struct rtk_epatch *patch = (struct rtk_epatch *)cfg_cb->fw_buf;
+ //int iBtCalLen = 0;
+
+ if(cfg_cb->lmp_subversion == LMPSUBVERSION_8723a)
+ {
+ if(memcmp(cfg_cb->fw_buf, RTK_EPATCH_SIGNATURE, 8) == 0)
+ {
+ ALOGE("8723as check signature error!");
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+ else
+ {
+ cfg_cb->total_len = cfg_cb->fw_len + cfg_cb->config_len;
+ if (!(cfg_cb->total_buf = malloc(cfg_cb->total_len)))
+ {
+ ALOGE("can't alloc memory for fw&config, errno:%d", errno);
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+ else
+ {
+ ALOGI("8723as, fw copy direct");
+ memcpy(cfg_cb->total_buf, cfg_cb->fw_buf, cfg_cb->fw_len);
+ memcpy(cfg_cb->total_buf+cfg_cb->fw_len, cfg_cb->config_buf, cfg_cb->config_len);
+ cfg_cb->dl_fw_flag = 1;
+ goto free_buf;
+ }
+ }
+ }
+
+ if (memcmp(cfg_cb->fw_buf, RTK_EPATCH_SIGNATURE, 8))
+ {
+ ALOGE("check signature error");
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ /* check the extension section signature */
+ if (memcmp(cfg_cb->fw_buf + cfg_cb->fw_len - 4, EXTENSION_SECTION_SIGNATURE, 4))
+ {
+ ALOGE("check extension section signature error");
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ proj_id = rtk_get_fw_project_id(cfg_cb->fw_buf + cfg_cb->fw_len - 5);
+
+ if((hw_cfg_cb.project_id_mask != PROJECT_ID_MASK_ALL)&& ((hw_cfg_cb.project_id_mask&(1<<proj_id)) ==0))
+ {
+ ALOGE("hw_cfg_cb.project_id_mask is 0x%08x, fw project_id is %d, does not match!!!",
+ hw_cfg_cb.project_id_mask, proj_id);
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ entry = rtk_get_patch_entry(cfg_cb);
+ if (entry)
+ {
+ cfg_cb->total_len = entry->patch_length + cfg_cb->config_len;
+ }
+ else
+ {
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ ALOGI("total_len = 0x%x", cfg_cb->total_len);
+
+ if (!(cfg_cb->total_buf = malloc(cfg_cb->total_len)))
+ {
+ ALOGE("Can't alloc memory for multi fw&config, errno:%d", errno);
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+ else
+ {
+ memcpy(cfg_cb->total_buf, cfg_cb->fw_buf + entry->patch_offset, entry->patch_length);
+ memcpy(cfg_cb->total_buf + entry->patch_length - 4, &patch->fw_version, 4);
+ memcpy(&entry->svn_version, cfg_cb->total_buf + entry->patch_length - 8, 4);
+ memcpy(&entry->coex_version, cfg_cb->total_buf + entry->patch_length - 12, 4);
+ ALOGI("BTCOEX:20%06d-%04x svn_version:%d lmp_subversion:0x%x hci_version:0x%x hci_revision:0x%x chip_type:%d Cut:%d libbt-vendor_uart version:%s\n",
+ ((entry->coex_version >> 16) & 0x7ff) + ((entry->coex_version >> 27) * 10000),
+ (entry->coex_version & 0xffff), entry->svn_version, cfg_cb->lmp_subversion, cfg_cb->hci_version, cfg_cb->hci_revision, cfg_cb->chip_type, cfg_cb->eversion+1, RTK_VERSION);
+ }
+
+ if (cfg_cb->config_len)
+ {
+ memcpy(cfg_cb->total_buf+entry->patch_length, cfg_cb->config_buf, cfg_cb->config_len);
+ }
+
+ cfg_cb->dl_fw_flag = 1;
+ ALOGI("Fw:%s exists, config file:%s exists", (cfg_cb->fw_len>0)?"":"not", (cfg_cb->config_len>0)?"":"not");
+
+free_buf:
+ if (cfg_cb->fw_len > 0)
+ {
+ free(cfg_cb->fw_buf);
+ cfg_cb->fw_len = 0;
+ }
+
+ if (cfg_cb->config_len > 0)
+ {
+ free(cfg_cb->config_buf);
+ cfg_cb->config_len = 0;
+ }
+
+ if(entry)
+ {
+ free(entry);
+ }
+}
+
+static uint32_t rtk_get_bt_config(unsigned char** config_buf,
+ uint32_t* config_baud_rate, char * config_file_short_name, uint16_t mac_offset)
+{
+ char bt_config_file_name[PATH_MAX] = {0};
+ struct stat st;
+ size_t filelen;
+ int fd;
+ //FILE* file = NULL;
+
+ sprintf(bt_config_file_name, BT_CONFIG_DIRECTORY, config_file_short_name);
+ ALOGI("BT config file: %s", bt_config_file_name);
+
+ if (stat(bt_config_file_name, &st) < 0)
+ {
+ ALOGE("can't access bt config file:%s, errno:%d\n", bt_config_file_name, errno);
+ return -1;
+ }
+
+ filelen = st.st_size;
+ if(filelen > MAX_ORG_CONFIG_SIZE)
+ {
+ ALOGE("bt config file is too large(>0x%04x)", MAX_ORG_CONFIG_SIZE);
+ return -1;
+ }
+
+ if ((fd = open(bt_config_file_name, O_RDONLY)) < 0)
+ {
+ ALOGE("Can't open bt config file");
+ return -1;
+ }
+
+ if ((*config_buf = malloc(MAX_ORG_CONFIG_SIZE+MAX_ALT_CONFIG_SIZE)) == NULL)
+ {
+ ALOGE("malloc buffer for config file fail(0x%zx)\n", filelen);
+ close(fd);
+ return -1;
+ }
+
+ if (read(fd, *config_buf, filelen) < (ssize_t)filelen)
+ {
+ ALOGE("Can't load bt config file");
+ free(*config_buf);
+ close(fd);
+ return -1;
+ }
+
+ *config_baud_rate = rtk_parse_config_file(config_buf, &filelen, vnd_local_bd_addr, mac_offset);
+ ALOGI("Get config baud rate from config file:0x%x", *config_baud_rate);
+
+ close(fd);
+ return filelen;
+}
+
+
+static int hci_download_patch_h4(HC_BT_HDR *p_buf, int index, uint8_t *data, int len)
+{
+ uint8_t retval = FALSE;
+ uint8_t *p = (uint8_t *) (p_buf + 1);
+
+ UINT16_TO_STREAM(p, HCI_VSC_DOWNLOAD_FW_PATCH);
+ *p++ = 1 + len; /* parameter length */
+ *p++ = index;
+ memcpy(p, data, len);
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE + 1+len;
+
+ hw_cfg_cb.state = HW_CFG_DL_FW_PATCH;
+
+ retval = bt_vendor_cbacks->xmit_cb(HCI_VSC_DOWNLOAD_FW_PATCH, p_buf, hw_config_cback);
+ return retval;
+}
+
+/*******************************************************************************
+**
+** Function hw_config_cback
+**
+** Description Callback function for controller configuration
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_config_cback(void *p_mem)
+{
+ HC_BT_HDR *p_evt_buf = NULL;
+ uint8_t *p = NULL, *pp=NULL;
+ uint8_t status = 0;
+ uint16_t opcode = 0;
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t is_proceeding = FALSE;
+ int i = 0;
+ uint8_t iIndexRx = 0;
+ patch_info* prtk_patch_file_info = NULL;
+ uint32_t host_baudrate = 0;
+
+#if (USE_CONTROLLER_BDADDR == TRUE)
+ //const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
+#endif
+
+ if(p_mem != NULL)
+ {
+ p_evt_buf = (HC_BT_HDR *) p_mem;
+ status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET);
+ p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE_OFFSET;
+ STREAM_TO_UINT16(opcode,p);
+ }
+
+ if(opcode == HCI_VSC_H5_INIT) {
+ if(status != 0) {
+ ALOGE("%s, status = %d", __func__, status);
+ if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
+ bt_vendor_cbacks->dealloc(p_evt_buf);
+ if(rtkbt_auto_restart) {
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ kill(getpid(), SIGKILL);
+ }
+ return;
+ }
+ }
+
+ /* Ask a new buffer big enough to hold any HCI commands sent in here */
+ /*a cut fc6d status==1*/
+ if (((status == 0) ||(opcode == HCI_VSC_READ_ROM_VERSION)) && bt_vendor_cbacks)
+ p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_MAX_LEN);
+
+ if (p_buf != NULL)
+ {
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+
+ BTVNDDBG("hw_cfg_cb.state = %i", hw_cfg_cb.state);
+ switch (hw_cfg_cb.state)
+ {
+ case HW_CFG_H5_INIT:
+ {
+ p = (uint8_t *)(p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_READ_LMP_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ hw_cfg_cb.state = HW_CFG_READ_LOCAL_VER;
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_READ_LMP_VERSION, p_buf, hw_config_cback);
+ break;
+ }
+ case HW_CFG_READ_LOCAL_VER:
+ {
+ if (status == 0)
+ {
+ p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET);
+ STREAM_TO_UINT16(hw_cfg_cb.hci_version, p);
+ p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_REVISION_OFFSET);
+ STREAM_TO_UINT16(hw_cfg_cb.hci_revision, p);
+ p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_LMP_SUBVERSION_OFFSET;
+ STREAM_TO_UINT16(hw_cfg_cb.lmp_subversion, p);
+ BTVNDDBG("lmp_subversion = 0x%x hw_cfg_cb.hci_version = 0x%x hw_cfg_cb.hci_revision = 0x%x", hw_cfg_cb.lmp_subversion, hw_cfg_cb.hci_version, hw_cfg_cb.hci_revision);
+ if(hw_cfg_cb.lmp_subversion == LMPSUBVERSION_8723a)
+ {
+ hw_cfg_cb.state = HW_CFG_START;
+ goto CFG_START;
+ }
+ else
+ {
+ hw_cfg_cb.state = HW_CFG_READ_ECO_VER;
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_READ_ROM_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_ROM_VERSION, p_buf, hw_config_cback);
+ }
+ }
+ break;
+ }
+ case HW_CFG_READ_ECO_VER:
+ {
+ if(status == 0)
+ {
+ hw_cfg_cb.eversion = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPFC6D_EVERSION_OFFSET);
+ BTVNDDBG("hw_config_cback chip_id of the IC:%d", hw_cfg_cb.eversion+1);
+ }
+ else if(1 == status)
+ {
+ hw_cfg_cb.eversion = 0;
+ }
+ else
+ {
+ is_proceeding = FALSE;
+ break;
+ }
+
+ if(check_match_state(&hw_cfg_cb, 0) > 1) // check if have multiple matched patch_entry by lmp_subversion,hci_version, hci_revision
+ {
+ hw_cfg_cb.state = HW_CFG_READ_CHIP_TYPE;
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_READ_CHIP_TYPE);
+ *p++ = 5;
+ UINT8_TO_STREAM(p, 0x00);
+ UINT32_TO_STREAM(p, 0xB000A094);
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_CMD_READ_CHIP_TYPE_SIZE;
+
+ pp = (uint8_t *) (p_buf + 1);
+ for (i = 0; i < p_buf->len; i++)
+ BTVNDDBG("get chip type command data[%d]= 0x%x", i, *(pp+i));
+
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_CHIP_TYPE, p_buf, hw_config_cback);
+ break;
+ }
+ else
+ {
+ hw_cfg_cb.state = HW_CFG_START;
+ goto CFG_START;
+ }
+ }
+ case HW_CFG_READ_CHIP_TYPE:
+ {
+ BTVNDDBG("READ_CHIP_TYPE status = %d, length = %d", status, p_evt_buf->len);
+ p = (uint8_t *)(p_evt_buf + 1) ;
+ for (i = 0; i < p_evt_buf->len; i++)
+ BTVNDDBG("READ_CHIP_TYPE event data[%d]= 0x%x", i, *(p+i));
+ if(status == 0)
+ {
+ hw_cfg_cb.chip_type = ((*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPFC61_CHIPTYPE_OFFSET))&0x0F);
+ BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.lmp_subversion = 0x%x", hw_cfg_cb.lmp_subversion);
+ BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.hci_version = 0x%x", hw_cfg_cb.hci_version);
+ BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.hci_revision = 0x%x", hw_cfg_cb.hci_revision);
+ BTVNDDBG("READ_CHIP_TYPE hw_cfg_cb.chip_type = 0x%x", hw_cfg_cb.chip_type);
+ }
+ else
+ {
+ is_proceeding = FALSE;
+ break;
+ }
+ if(check_match_state(&hw_cfg_cb, PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE) > 1) // check if have multiple matched patch_entry by lmp_subversion,hci_version, hci_revision and chiptype
+ {
+ BTVNDDBG("check_match_state(lmp_subversion:0x%04x, hci_version:%d, hci_revision:%d chip_type:%d): Multi Matched Patch\n", hw_cfg_cb.lmp_subversion, hw_cfg_cb.hci_version, hw_cfg_cb.hci_revision, hw_cfg_cb.chip_type);
+ is_proceeding = FALSE;
+ break;
+ }
+ hw_cfg_cb.state = HW_CFG_START;
+ }
+CFG_START:
+ case HW_CFG_START:
+ {
+#ifdef BT_CHIP_PROBE_SIMULATION
+ {
+ int ii;
+ memcpy(&hw_cfg_test, &hw_cfg_cb, sizeof(hw_cfg_test));
+ for(i=0;i<sizeof(bt_chip_chars)/sizeof(bt_chip_chars[0]);i++)
+ {
+ BTVNDDBG("BT_CHIP_PROBE_SIMULATION loop:%d $$$ BEGIN $$$\n", i);
+ hw_cfg_test.lmp_subversion = bt_chip_chars[i].lmp_subversion;
+ hw_cfg_test.hci_version = bt_chip_chars[i].hci_version;
+ hw_cfg_test.hci_revision = bt_chip_chars[i].hci_revision;
+ hw_cfg_test.chip_type = CHIPTYPE_NONE;
+ if(check_match_state(&hw_cfg_test, 0) > 1){
+ BTVNDDBG("check_match_state hw_cfg_test(lmp_subversion:0x%04x, hci_version:%d, hci_revision:%d chip_type:%d): Multi Matched Patch\n", hw_cfg_test.lmp_subversion, hw_cfg_test.hci_version, hw_cfg_test.hci_revision, hw_cfg_test.chip_type);
+ if(bt_chip_chars[i].chip_type != CHIPTYPE_NONE){
+ BTVNDDBG("BT_CHIP_PROBE_SIMULATION loop:%d *** Include ChipType ***\n", i);
+ hw_cfg_test.chip_type = bt_chip_chars[i].chip_type;
+ if(check_match_state(&hw_cfg_test, PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE) > 1){
+ BTVNDDBG("check_match_state hw_cfg_test(lmp_subversion:0x%04x, hci_version:%d, hci_revision:%d chip_type:%d): Multi Matched Patch\n", hw_cfg_test.lmp_subversion, hw_cfg_test.hci_version, hw_cfg_test.hci_revision, hw_cfg_test.chip_type);
+ }else{
+ prtk_patch_file_info = get_patch_entry(&hw_cfg_test);
+ }
+ }
+ }else{
+ prtk_patch_file_info = get_patch_entry(&hw_cfg_test);
+ }
+ BTVNDDBG("BT_CHIP_PROBE_SIMULATION loop:%d $$$ END $$$\n", i);
+ }
+ }
+#endif
+ //get efuse config file and patch code file
+ prtk_patch_file_info = get_patch_entry(&hw_cfg_cb);
+
+
+ if((prtk_patch_file_info == NULL) || (prtk_patch_file_info->lmp_subversion == 0))
+ {
+ ALOGE("get patch entry error");
+ is_proceeding = FALSE;
+ break;
+ }
+ hw_cfg_cb.max_patch_size = prtk_patch_file_info->max_patch_size;
+ hw_cfg_cb.config_len = rtk_get_bt_config(&hw_cfg_cb.config_buf, &hw_cfg_cb.baudrate, prtk_patch_file_info->config_name, prtk_patch_file_info->mac_offset);
+ if (hw_cfg_cb.config_len < 0)
+ {
+ ALOGE("Get Config file fail, just use efuse settings");
+ hw_cfg_cb.config_len = 0;
+ }
+ rtk_update_altsettings(prtk_patch_file_info, hw_cfg_cb.config_buf, &(hw_cfg_cb.config_len));
+
+ hw_cfg_cb.fw_len = rtk_get_bt_firmware(&hw_cfg_cb.fw_buf, prtk_patch_file_info->patch_name);
+ if (hw_cfg_cb.fw_len < 0)
+ {
+ ALOGE("Get BT firmware fail");
+ hw_cfg_cb.fw_len = 0;
+ }
+ else{
+ hw_cfg_cb.project_id_mask = prtk_patch_file_info->project_id_mask;
+ rtk_get_bt_final_patch(&hw_cfg_cb);
+ }
+ BTVNDDBG("Check total_len(0x%08x) max_patch_size(0x%08x)", hw_cfg_cb.total_len, hw_cfg_cb.max_patch_size);
+ if (hw_cfg_cb.total_len > hw_cfg_cb.max_patch_size)
+ {
+ ALOGE("total length of fw&config(0x%08x) larger than max_patch_size(0x%08x)", hw_cfg_cb.total_len, hw_cfg_cb.max_patch_size);
+ is_proceeding = FALSE;
+ break;
+ }
+
+ if ((hw_cfg_cb.total_len > 0) && hw_cfg_cb.dl_fw_flag)
+ {
+ hw_cfg_cb.patch_frag_cnt = hw_cfg_cb.total_len / PATCH_DATA_FIELD_MAX_SIZE;
+ hw_cfg_cb.patch_frag_tail = hw_cfg_cb.total_len % PATCH_DATA_FIELD_MAX_SIZE;
+ if (hw_cfg_cb.patch_frag_tail)
+ hw_cfg_cb.patch_frag_cnt += 1;
+ else
+ hw_cfg_cb.patch_frag_tail = PATCH_DATA_FIELD_MAX_SIZE;
+ BTVNDDBG("patch fragment count %d, tail len %d", hw_cfg_cb.patch_frag_cnt, hw_cfg_cb.patch_frag_tail);
+ }
+ else
+ {
+ is_proceeding = FALSE;
+ break;
+ }
+
+ if ((hw_cfg_cb.baudrate == 0) && ((hw_cfg_cb.hw_flow_cntrl & 0x80) == 0))
+ {
+ BTVNDDBG("no baudrate to set and no need to set hw flow control");
+ goto DOWNLOAD_FW;
+ }
+
+ if ((hw_cfg_cb.baudrate == 0) && (hw_cfg_cb.hw_flow_cntrl & 0x80))
+ {
+ BTVNDDBG("no baudrate to set but set hw flow control is needed");
+ goto SET_HW_FLCNTRL;
+ }
+ }
+ /* fall through intentionally */
+ case HW_CFG_SET_UART_BAUD_CONTROLLER:
+ BTVNDDBG("bt vendor lib: set CONTROLLER UART baud 0x%x", hw_cfg_cb.baudrate);
+ hw_cfg_cb.state = HW_CFG_SET_UART_BAUD_HOST;
+ is_proceeding = hw_config_set_controller_baudrate(p_buf, hw_cfg_cb.baudrate);
+ break;
+
+ case HW_CFG_SET_UART_BAUD_HOST:
+ /* update baud rate of host's UART port */
+ rtk_speed_to_uart_speed(hw_cfg_cb.baudrate, &host_baudrate);
+ BTVNDDBG("bt vendor lib: set HOST UART baud %i", host_baudrate);
+ userial_vendor_set_baud(line_speed_to_userial_baud(host_baudrate));
+
+ if((hw_cfg_cb.hw_flow_cntrl & 0x80) == 0)
+ goto DOWNLOAD_FW;
+
+SET_HW_FLCNTRL:
+ case HW_CFG_SET_UART_HW_FLOW_CONTROL:
+ BTVNDDBG("Change HW flowcontrol setting");
+ if(hw_cfg_cb.hw_flow_cntrl & 0x01)
+ {
+ userial_vendor_set_hw_fctrl(1);
+ }
+ else
+ {
+ userial_vendor_set_hw_fctrl(0);
+ }
+ ms_delay(100);
+ hw_cfg_cb.state = HW_CFG_DL_FW_PATCH;
+
+DOWNLOAD_FW:
+ case HW_CFG_DL_FW_PATCH:
+ BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, opcode:0x%x", status, opcode);
+
+ //recv command complete event for patch code download command
+ if(opcode == HCI_VSC_DOWNLOAD_FW_PATCH)
+ {
+ iIndexRx = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET + 1);
+ BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, iIndexRx:%i", status, iIndexRx);
+ hw_cfg_cb.patch_frag_idx++;
+
+ if(iIndexRx&0x80)
+ {
+ BTVNDDBG("vendor lib fwcfg completed");
+ free(hw_cfg_cb.total_buf);
+ hw_cfg_cb.total_len = 0;
+
+ bt_vendor_cbacks->dealloc(p_buf);
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+ hw_cfg_cb.state = 0;
+ is_proceeding = TRUE;
+ break;
+ }
+ }
+
+ if (hw_cfg_cb.patch_frag_idx < hw_cfg_cb.patch_frag_cnt)
+ {
+ iIndexRx = hw_cfg_cb.patch_frag_idx?((hw_cfg_cb.patch_frag_idx-1)%0x7f+1):0;
+ if (hw_cfg_cb.patch_frag_idx == hw_cfg_cb.patch_frag_cnt - 1)
+ {
+ BTVNDDBG("HW_CFG_DL_FW_PATCH: send last fw fragment");
+ iIndexRx |= 0x80;
+ hw_cfg_cb.patch_frag_len = hw_cfg_cb.patch_frag_tail;
+ }
+ else
+ {
+ iIndexRx &= 0x7F;
+ hw_cfg_cb.patch_frag_len = PATCH_DATA_FIELD_MAX_SIZE;
+ }
+ }
+
+ is_proceeding = hci_download_patch_h4(p_buf, iIndexRx,
+ hw_cfg_cb.total_buf+(hw_cfg_cb.patch_frag_idx*PATCH_DATA_FIELD_MAX_SIZE),
+ hw_cfg_cb.patch_frag_len);
+ break;
+
+ default:
+ break;
+ } // switch(hw_cfg_cb.state)
+ } // if (p_buf != NULL)
+
+ /* Free the RX event buffer */
+ if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
+ bt_vendor_cbacks->dealloc(p_evt_buf);
+
+ if (is_proceeding == FALSE)
+ {
+ ALOGE("vendor lib fwcfg aborted!!!");
+ if (bt_vendor_cbacks)
+ {
+ if (p_buf != NULL)
+ bt_vendor_cbacks->dealloc(p_buf);
+
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ }
+
+ if(hw_cfg_cb.config_len)
+ {
+ free(hw_cfg_cb.config_buf);
+ hw_cfg_cb.config_len = 0;
+ }
+
+ if(hw_cfg_cb.fw_len)
+ {
+ free(hw_cfg_cb.fw_buf);
+ hw_cfg_cb.fw_len= 0;
+ }
+
+ if(hw_cfg_cb.total_len)
+ {
+ free(hw_cfg_cb.total_buf);
+ hw_cfg_cb.total_len = 0;
+ }
+ hw_cfg_cb.state = 0;
+ }
+}
+
+/*****************************************************************************
+** Hardware Configuration Interface Functions
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function hw_config_start
+**
+** Description Kick off controller initialization process
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_config_start(char transtype)
+{
+ memset(&hw_cfg_cb, 0, sizeof(bt_hw_cfg_cb_t));
+ hw_cfg_cb.dl_fw_flag = 1;
+ hw_cfg_cb.chip_type = CHIPTYPE_NONE;
+ BTVNDDBG("RTKBT_RELEASE_NAME: %s",RTKBT_RELEASE_NAME);
+ BTVNDDBG("\nRealtek libbt-vendor_uart Version %s \n",RTK_VERSION);
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t *p;
+
+ BTVNDDBG("hw_config_start, transtype = 0x%x \n", transtype);
+ /* Start from sending H5 INIT */
+ if (bt_vendor_cbacks)
+ {
+ /* Must allocate command buffer via HC's alloc API */
+ p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+ HCI_CMD_PREAMBLE_SIZE);
+ if(p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ p = (uint8_t *) (p_buf + 1);
+
+ if(transtype & RTKBT_TRANS_H4) {
+ p = (uint8_t *)(p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_READ_LMP_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ hw_cfg_cb.state = HW_CFG_READ_LOCAL_VER;
+ bt_vendor_cbacks->xmit_cb(HCI_READ_LMP_VERSION, p_buf, hw_config_cback);
+ }
+ else {
+ UINT16_TO_STREAM(p, HCI_VSC_H5_INIT);
+ *p = 0; /* parameter length */
+ hw_cfg_cb.state = HW_CFG_H5_INIT;
+
+ bt_vendor_cbacks->xmit_cb(HCI_VSC_H5_INIT, p_buf, hw_config_cback);
+ }
+ }
+ else {
+ ALOGE("%s buffer alloc fail!", __func__);
+ }
+ }
+ else
+ ALOGE("%s call back is null", __func__);
+}
+
--- /dev/null
+#define LOG_TAG "bt_hwcfg_usb"
+#define RTKBT_RELEASE_NAME "Test"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_rtk.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "upio.h"
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <unistd.h>
+
+#include "bt_vendor_lib.h"
+#include "hardware.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+#define RTK_VERSION "4.1.1"
+
+extern uint8_t vnd_local_bd_addr[BD_ADDR_LEN];
+extern bool rtkbt_auto_restart;
+void hw_usb_config_cback(void *p_evt_buf);
+extern bt_hw_cfg_cb_t hw_cfg_cb;
+extern int getmacaddr(unsigned char * addr);
+extern struct rtk_epatch_entry *rtk_get_patch_entry(bt_hw_cfg_cb_t *cfg_cb);
+extern int rtk_get_bt_firmware(uint8_t** fw_buf, char* fw_short_name);
+extern uint8_t rtk_get_fw_project_id(uint8_t *p_buf);
+
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+//static bt_hw_cfg_cb_t hw_cfg_cb;
+
+typedef struct {
+ uint16_t vid;
+ uint16_t pid;
+ uint16_t lmp_sub_default;
+ uint16_t lmp_sub;
+ uint16_t eversion;
+ char *mp_patch_name;
+ char *patch_name;
+ char *config_name;
+ uint8_t *fw_cache;
+ int fw_len;
+ uint16_t mac_offset;
+ uint32_t max_patch_size;
+} usb_patch_info;
+
+static usb_patch_info usb_fw_patch_table[] = {
+/* { vid, pid, lmp_sub_default, lmp_sub, everion, mp_fw_name, fw_name, config_name, fw_cache, fw_len, mac_offset } */
+{ 0x0BDA, 0x1724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723A */
+{ 0x0BDA, 0x8723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE */
+{ 0x0BDA, 0xA723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE for LI */
+{ 0x0BDA, 0x0723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE */
+{ 0x13D3, 0x3394, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE for Azurewave*/
+
+{ 0x0BDA, 0x0724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
+{ 0x0BDA, 0x8725, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
+{ 0x0BDA, 0x872A, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
+{ 0x0BDA, 0x872B, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
+
+{ 0x0BDA, 0xb720, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BU */
+{ 0x0BDA, 0xb72A, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BU */
+{ 0x0BDA, 0xb728, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for LC */
+{ 0x0BDA, 0xb723, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
+{ 0x0BDA, 0xb72B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
+{ 0x0BDA, 0xb001, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for HP */
+{ 0x0BDA, 0xb002, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
+{ 0x0BDA, 0xb003, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
+{ 0x0BDA, 0xb004, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
+{ 0x0BDA, 0xb005, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
+
+{ 0x13D3, 0x3410, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Azurewave */
+{ 0x13D3, 0x3416, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Azurewave */
+{ 0x13D3, 0x3459, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Azurewave */
+{ 0x0489, 0xE085, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Foxconn */
+{ 0x0489, 0xE08B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Foxconn */
+
+{ 0x0BDA, 0x2850, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU */
+{ 0x0BDA, 0xA761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU only */
+{ 0x0BDA, 0x818B, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761aw8192eu_fw", "rtl8761aw8192eu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AW + 8192EU */
+{ 0x0BDA, 0x818C, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761aw8192eu_fw", "rtl8761aw8192eu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AW + 8192EU */
+{ 0x0BDA, 0x8760, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU + 8192EE */
+{ 0x0BDA, 0xB761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AUV only */
+{ 0x0BDA, 0x8761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU + 8192EE for LI */
+{ 0x0BDA, 0x8A60, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU + 8812AE */
+
+{ 0x0BDA, 0x8821, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
+{ 0x0BDA, 0x0821, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
+{ 0x0BDA, 0x0823, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AU */
+{ 0x13D3, 0x3414, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
+{ 0x13D3, 0x3458, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
+{ 0x13D3, 0x3461, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
+{ 0x13D3, 0x3462, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
+
+{ 0x0BDA, 0xB822, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, /* RTL8822BE */
+{ 0x0BDA, 0xB82C, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, /* RTL8822BU */
+{ 0x0BDA, 0xB023, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, /* RTL8822BE */
+{ 0x0BDA, 0xB703, 0x8703, 0, 0, "mp_rtl8723c_fw", "rtl8723c_fw", "rtl8723c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, /* RTL8723CU */
+/* todo: RTL8703BU */
+
+{ 0x0BDA, 0xD723, 0x8723, 0, 0, "mp_rtl8723d_fw", "rtl8723d_fw", "rtl8723d_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8723DU */
+{ 0x0BDA, 0xD720, 0x8723, 0, 0, "mp_rtl8723d_fw", "rtl8723d_fw", "rtl8723d_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8723DE */
+{ 0x0BDA, 0xB820, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CU */
+{ 0x0BDA, 0xC820, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CU */
+{ 0x0BDA, 0xC821, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CE */
+/* todo: RTL8703CU */
+
+/* NOTE: must append patch entries above the null entry */
+{ 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 0, 0, 0 }
+};
+
+
+uint16_t usb_project_id[] = {
+ ROM_LMP_8723a,
+ ROM_LMP_8723b,
+ ROM_LMP_8821a,
+ ROM_LMP_8761a,
+ ROM_LMP_8703a,
+ ROM_LMP_8763a,
+ ROM_LMP_8703b,
+ ROM_LMP_8723c,
+ ROM_LMP_8822b,
+ ROM_LMP_8723d,
+ ROM_LMP_8821c,
+ ROM_LMP_NONE
+};
+//signature: realtech
+static const uint8_t RTK_EPATCH_SIGNATURE[8]={0x52,0x65,0x61,0x6C,0x74,0x65,0x63,0x68};
+//Extension Section IGNATURE:0x77FD0451
+static const uint8_t EXTENSION_SECTION_SIGNATURE[4]={0x51,0x04,0xFD,0x77};
+
+static inline int getUsbAltSettings(usb_patch_info *patch_entry, unsigned short *offset)//(patch_info *patch_entry, unsigned short *offset, int max_group_cnt)
+{
+ int n = 0;
+ if(patch_entry)
+ offset[n++] = patch_entry->mac_offset;
+/*
+//sample code, add special settings
+
+ offset[n++] = 0x15B;
+*/
+ return n;
+}
+
+static inline int getUsbAltSettingVal(usb_patch_info *patch_entry, unsigned short offset, unsigned char * val)
+{
+ int res = 0;
+
+ switch(offset)
+ {
+/*
+//sample code, add special settings
+ case 0x15B:
+ val[0] = 0x0B;
+ val[1] = 0x0B;
+ val[2] = 0x0B;
+ val[3] = 0x0B;
+ res = 4;
+ break;
+*/
+ default:
+ res = 0;
+ break;
+ }
+ if((patch_entry)&&(offset == patch_entry->mac_offset)&&(res == 0))
+ {
+ if(getmacaddr(val) == 0){
+ ALOGI("MAC: %02x:%02x:%02x:%02x:%02x:%02x", val[5], val[4], val[3], val[2], val[1], val[0]);
+ res = 6;
+ }
+ }
+ return res;
+}
+
+static void rtk_usb_update_altsettings(usb_patch_info *patch_entry, unsigned char* config_buf_ptr, size_t *config_len_ptr)
+{
+ unsigned short offset[256], data_len;
+ unsigned char val[256];
+
+ struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) config_buf_ptr;
+ struct rtk_bt_vendor_config_entry* entry = config->entry;
+ size_t config_len = *config_len_ptr;
+ unsigned int i = 0;
+ int count = 0,temp = 0, j;
+
+ ALOGI("ORG Config len=%08zx:\n", config_len);
+ for(i=0;i<=config_len;i+=0x10)
+ {
+ ALOGI("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
+ config_buf_ptr[i], config_buf_ptr[i+1], config_buf_ptr[i+2], config_buf_ptr[i+3], config_buf_ptr[i+4], config_buf_ptr[i+5], config_buf_ptr[i+6], config_buf_ptr[i+7], \
+ config_buf_ptr[i+8], config_buf_ptr[i+9], config_buf_ptr[i+10], config_buf_ptr[i+11], config_buf_ptr[i+12], config_buf_ptr[i+13], config_buf_ptr[i+14], config_buf_ptr[i+15]);
+ }
+
+ memset(offset, 0, sizeof(offset));
+ memset(val, 0, sizeof(val));
+ data_len = le16_to_cpu(config->data_len);
+
+ count = getUsbAltSettings(patch_entry, offset);//getAltSettings(patch_entry, offset, sizeof(offset)/sizeof(unsigned short));
+ if(count <= 0){
+ ALOGI("rtk_update_altsettings: No AltSettings");
+ return;
+ }else{
+ ALOGI("rtk_update_altsettings: %d AltSettings", count);
+ }
+
+ if (data_len != config_len - sizeof(struct rtk_bt_vendor_config))
+ {
+ ALOGE("rtk_update_altsettings: config len(%x) is not right(%lx)", data_len, (unsigned long)(config_len-sizeof(struct rtk_bt_vendor_config)));
+ return;
+ }
+
+ for (i=0; i<data_len;)
+ {
+ for(j = 0; j < count;j++)
+ {
+ if(le16_to_cpu(entry->offset) == offset[j])
+ offset[j] = 0;
+ }
+ if(getUsbAltSettingVal(patch_entry, le16_to_cpu(entry->offset), val) == entry->entry_len){
+ ALOGI("rtk_update_altsettings: replace %04x[%02x]", le16_to_cpu(entry->offset), entry->entry_len);
+ memcpy(entry->entry_data, val, entry->entry_len);
+ }
+ temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
+ i += temp;
+ entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
+ }
+ for(j = 0; j < count;j++){
+ if(offset[j] == 0)
+ continue;
+ entry->entry_len = getUsbAltSettingVal(patch_entry, offset[j], val);
+ if(entry->entry_len <= 0)
+ continue;
+ entry->offset = cpu_to_le16(offset[j]);
+ memcpy(entry->entry_data, val, entry->entry_len);
+ ALOGI("rtk_update_altsettings: add %04x[%02x]", le16_to_cpu(entry->offset), entry->entry_len);
+ temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
+ i += temp;
+ entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
+ }
+ config->data_len = cpu_to_le16(i);
+ *config_len_ptr = i+sizeof(struct rtk_bt_vendor_config);
+
+ ALOGI("NEW Config len=%08zx:\n", *config_len_ptr);
+ for(i=0;i<=(*config_len_ptr);i+=0x10)
+ {
+ ALOGI("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
+ config_buf_ptr[i], config_buf_ptr[i+1], config_buf_ptr[i+2], config_buf_ptr[i+3], config_buf_ptr[i+4], config_buf_ptr[i+5], config_buf_ptr[i+6], config_buf_ptr[i+7], \
+ config_buf_ptr[i+8], config_buf_ptr[i+9], config_buf_ptr[i+10], config_buf_ptr[i+11], config_buf_ptr[i+12], config_buf_ptr[i+13], config_buf_ptr[i+14], config_buf_ptr[i+15]);
+ }
+ return;
+}
+
+
+static void rtk_usb_parse_config_file(unsigned char** config_buf, size_t* filelen, uint8_t bt_addr[6], uint16_t mac_offset)
+{
+ struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) *config_buf;
+ uint16_t config_len = le16_to_cpu(config->data_len), temp = 0;
+ struct rtk_bt_vendor_config_entry* entry = config->entry;
+ unsigned int i = 0;
+ uint8_t heartbeat_buf = 0;
+ //uint32_t config_has_bdaddr = 0;
+ uint8_t *p;
+
+ ALOGD("bt_addr = %x", bt_addr[0]);
+ if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC)
+ {
+ ALOGE("config signature magic number(0x%x) is not set to RTK_VENDOR_CONFIG_MAGIC", config->signature);
+ return;
+ }
+
+ if (config_len != *filelen - sizeof(struct rtk_bt_vendor_config))
+ {
+ ALOGE("config len(0x%x) is not right(0x%zx)", config_len, *filelen-sizeof(struct rtk_bt_vendor_config));
+ return;
+ }
+
+ hw_cfg_cb.heartbeat = 0;
+ for (i=0; i<config_len;)
+ {
+ switch(le16_to_cpu(entry->offset))
+ {
+ case 0x017a:
+ {
+ if(mac_offset == CONFIG_MAC_OFFSET_GEN_1_2)
+ {
+ p = (uint8_t *)entry->entry_data;
+ STREAM_TO_UINT8(heartbeat_buf, p);
+ if((heartbeat_buf & 0x02) && (heartbeat_buf & 0x10))
+ hw_cfg_cb.heartbeat = 1;
+ else
+ hw_cfg_cb.heartbeat = 0;
+
+ ALOGI("config 0x017a heartbeat = %d",hw_cfg_cb.heartbeat);
+ }
+ break;
+ }
+ case 0x01be:
+ {
+ if(mac_offset == CONFIG_MAC_OFFSET_GEN_3PLUS)
+ {
+ p = (uint8_t *)entry->entry_data;
+ STREAM_TO_UINT8(heartbeat_buf, p);
+ if((heartbeat_buf & 0x02) && (heartbeat_buf & 0x10))
+ hw_cfg_cb.heartbeat = 1;
+ else
+ hw_cfg_cb.heartbeat = 0;
+
+ ALOGI("config 0x01be heartbeat = %d",hw_cfg_cb.heartbeat);
+ }
+ break;
+ }
+ default:
+ ALOGI("config offset(0x%x),length(0x%x)", entry->offset, entry->entry_len);
+ break;
+ }
+ temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
+ i += temp;
+ entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
+ }
+
+ return;
+}
+
+static uint32_t rtk_usb_get_bt_config(unsigned char** config_buf,
+ char * config_file_short_name, uint16_t mac_offset)
+{
+ char bt_config_file_name[PATH_MAX] = {0};
+ struct stat st;
+ size_t filelen;
+ int fd;
+ //FILE* file = NULL;
+
+ sprintf(bt_config_file_name, BT_CONFIG_DIRECTORY, config_file_short_name);
+ ALOGI("BT config file: %s", bt_config_file_name);
+
+ if (stat(bt_config_file_name, &st) < 0)
+ {
+ ALOGE("can't access bt config file:%s, errno:%d\n", bt_config_file_name, errno);
+ return -1;
+ }
+
+ filelen = st.st_size;
+ if(filelen > MAX_ORG_CONFIG_SIZE)
+ {
+ ALOGE("bt config file is too large(>0x%04x)", MAX_ORG_CONFIG_SIZE);
+ return -1;
+ }
+
+ if ((fd = open(bt_config_file_name, O_RDONLY)) < 0)
+ {
+ ALOGE("Can't open bt config file");
+ return -1;
+ }
+
+ if ((*config_buf = malloc(MAX_ORG_CONFIG_SIZE+MAX_ALT_CONFIG_SIZE)) == NULL)
+ {
+ ALOGE("malloc buffer for config file fail(0x%zx)\n", filelen);
+ close(fd);
+ return -1;
+ }
+
+ if (read(fd, *config_buf, filelen) < (ssize_t)filelen)
+ {
+ ALOGE("Can't load bt config file");
+ free(*config_buf);
+ close(fd);
+ return -1;
+ }
+
+ rtk_usb_parse_config_file(config_buf, &filelen, vnd_local_bd_addr, mac_offset);
+
+ close(fd);
+ return filelen;
+}
+
+static usb_patch_info *rtk_usb_get_fw_table_entry(uint16_t vid, uint16_t pid)
+{
+ usb_patch_info *patch_entry = usb_fw_patch_table;
+
+ uint32_t entry_size = sizeof(usb_fw_patch_table) / sizeof(usb_fw_patch_table[0]);
+ uint32_t i;
+
+ for (i = 0; i < entry_size; i++, patch_entry++) {
+ if ((vid == patch_entry->vid)&&(pid == patch_entry->pid))
+ break;
+ }
+
+ if (i == entry_size) {
+ ALOGE("%s: No fw table entry found", __func__);
+ return NULL;
+ }
+
+ return patch_entry;
+}
+
+static void rtk_usb_get_bt_final_patch(bt_hw_cfg_cb_t* cfg_cb)
+{
+ uint8_t proj_id = 0;
+ struct rtk_epatch_entry* entry = NULL;
+ struct rtk_epatch *patch = (struct rtk_epatch *)cfg_cb->fw_buf;
+ //int iBtCalLen = 0;
+
+ if(cfg_cb->lmp_subversion == LMPSUBVERSION_8723a)
+ {
+ if(memcmp(cfg_cb->fw_buf, RTK_EPATCH_SIGNATURE, 8) == 0)
+ {
+ ALOGE("8723as check signature error!");
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+ else
+ {
+ cfg_cb->total_len = cfg_cb->fw_len + cfg_cb->config_len;
+ if (!(cfg_cb->total_buf = malloc(cfg_cb->total_len)))
+ {
+ ALOGE("can't alloc memory for fw&config, errno:%d", errno);
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+ else
+ {
+ ALOGI("8723as, fw copy direct");
+ memcpy(cfg_cb->total_buf, cfg_cb->fw_buf, cfg_cb->fw_len);
+ memcpy(cfg_cb->total_buf+cfg_cb->fw_len, cfg_cb->config_buf, cfg_cb->config_len);
+ //cfg_cb->lmp_sub_current = *(uint16_t *)(cfg_cb->total_buf + cfg_cb->total_len - cfg_cb->config_len - 4);
+ cfg_cb->dl_fw_flag = 1;
+ goto free_buf;
+ }
+ }
+ }
+
+ if (memcmp(cfg_cb->fw_buf, RTK_EPATCH_SIGNATURE, 8))
+ {
+ ALOGE("check signature error");
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ /* check the extension section signature */
+ if (memcmp(cfg_cb->fw_buf + cfg_cb->fw_len - 4, EXTENSION_SECTION_SIGNATURE, 4))
+ {
+ ALOGE("check extension section signature error");
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ proj_id = rtk_get_fw_project_id(cfg_cb->fw_buf + cfg_cb->fw_len - 5);
+ if(usb_project_id[proj_id] != hw_cfg_cb.lmp_subversion_default)
+ {
+ ALOGE("usb_project_id is 0x%08x, fw project_id is %d, does not match!!!",
+ usb_project_id[proj_id], hw_cfg_cb.lmp_subversion);
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ entry = rtk_get_patch_entry(cfg_cb);
+ if (entry)
+ {
+ cfg_cb->total_len = entry->patch_length + cfg_cb->config_len;
+ }
+ else
+ {
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+
+ ALOGI("total_len = 0x%x", cfg_cb->total_len);
+
+ if (!(cfg_cb->total_buf = malloc(cfg_cb->total_len)))
+ {
+ ALOGE("Can't alloc memory for multi fw&config, errno:%d", errno);
+ cfg_cb->dl_fw_flag = 0;
+ goto free_buf;
+ }
+ else
+ {
+ memcpy(cfg_cb->total_buf, cfg_cb->fw_buf + entry->patch_offset, entry->patch_length);
+ memcpy(cfg_cb->total_buf + entry->patch_length - 4, &patch->fw_version, 4);
+ memcpy(&entry->svn_version, cfg_cb->total_buf + entry->patch_length - 8, 4);
+ memcpy(&entry->coex_version, cfg_cb->total_buf + entry->patch_length - 12, 4);
+
+ ALOGI("BTCOEX:20%06d-%04x svn_version:%d lmp_subversion:0x%x hci_version:0x%x hci_revision:0x%x chip_type:%d Cut:%d libbt-vendor_uart version:%s, patch->fw_version = %x\n",
+ ((entry->coex_version >> 16) & 0x7ff) + ((entry->coex_version >> 27) * 10000),
+ (entry->coex_version & 0xffff), entry->svn_version, cfg_cb->lmp_subversion, cfg_cb->hci_version, cfg_cb->hci_revision, cfg_cb->chip_type, cfg_cb->eversion+1, RTK_VERSION, patch->fw_version);
+ }
+
+ if (cfg_cb->config_len)
+ {
+ memcpy(cfg_cb->total_buf+entry->patch_length, cfg_cb->config_buf, cfg_cb->config_len);
+ }
+
+ cfg_cb->dl_fw_flag = 1;
+ ALOGI("Fw:%s exists, config file:%s exists", (cfg_cb->fw_len>0)?"":"not", (cfg_cb->config_len>0)?"":"not");
+
+free_buf:
+ if (cfg_cb->fw_len > 0)
+ {
+ free(cfg_cb->fw_buf);
+ cfg_cb->fw_len = 0;
+ }
+
+ if (cfg_cb->config_len > 0)
+ {
+ free(cfg_cb->config_buf);
+ cfg_cb->config_len = 0;
+ }
+
+ if(entry)
+ {
+ free(entry);
+ }
+}
+
+static int usb_hci_download_patch_h4(HC_BT_HDR *p_buf, int index, uint8_t *data, int len)
+{
+ uint8_t retval = FALSE;
+ uint8_t *p = (uint8_t *) (p_buf + 1);
+
+ UINT16_TO_STREAM(p, HCI_VSC_DOWNLOAD_FW_PATCH);
+ *p++ = 1 + len; /* parameter length */
+ *p++ = index;
+ memcpy(p, data, len);
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE + 1+len;
+
+ hw_cfg_cb.state = HW_CFG_DL_FW_PATCH;
+
+ retval = bt_vendor_cbacks->xmit_cb(HCI_VSC_DOWNLOAD_FW_PATCH, p_buf, hw_usb_config_cback);
+ return retval;
+}
+
+static void rtk_usb_get_fw_version(bt_hw_cfg_cb_t* cfg_cb)
+{
+ struct rtk_epatch *patch = (struct rtk_epatch *)cfg_cb->fw_buf;
+
+ if(cfg_cb->lmp_subversion == LMPSUBVERSION_8723a)
+ {
+ cfg_cb->lmp_sub_current = 0;
+ }
+ else
+ {
+ cfg_cb->lmp_sub_current = (uint16_t)patch->fw_version;
+ }
+
+}
+/*******************************************************************************
+**
+** Function hw_usb_config_cback
+**
+** Description Callback function for controller configuration
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_usb_config_cback(void *p_mem)
+{
+ HC_BT_HDR *p_evt_buf = NULL;
+ uint8_t *p = NULL;//, *pp=NULL;
+ uint8_t status = 0;
+ uint16_t opcode = 0;
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t is_proceeding = FALSE;
+ //int i = 0;
+ uint8_t iIndexRx = 0;
+ //patch_info* prtk_patch_file_info = NULL;
+ usb_patch_info* prtk_usb_patch_file_info = NULL;
+ //uint32_t host_baudrate = 0;
+
+#if (USE_CONTROLLER_BDADDR == TRUE)
+ //const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
+#endif
+
+ if(p_mem != NULL)
+ {
+ p_evt_buf = (HC_BT_HDR *) p_mem;
+ status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET);
+ p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE_OFFSET;
+ STREAM_TO_UINT16(opcode,p);
+ }
+
+ /* Ask a new buffer big enough to hold any HCI commands sent in here */
+ /*a cut fc6d status==1*/
+ if (((status == 0) ||(opcode == HCI_VSC_READ_ROM_VERSION)) && bt_vendor_cbacks)
+ p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_MAX_LEN);
+
+ if (p_buf != NULL)
+ {
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+
+ BTVNDDBG("hw_cfg_cb.state = %i", hw_cfg_cb.state);
+ switch (hw_cfg_cb.state)
+ {
+ case HW_CFG_RESET_CHANNEL_CONTROLLER:
+ {
+ usleep(300000);
+ hw_cfg_cb.state = HW_CFG_READ_LOCAL_VER;
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_READ_LMP_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_READ_LMP_VERSION, p_buf, hw_usb_config_cback);
+ break;
+ }
+ case HW_CFG_READ_LOCAL_VER:
+ {
+ if (status == 0)
+ {
+ p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET);
+ STREAM_TO_UINT16(hw_cfg_cb.hci_version, p);
+ p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_REVISION_OFFSET);
+ STREAM_TO_UINT16(hw_cfg_cb.hci_revision, p);
+ p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_LMP_SUBVERSION_OFFSET;
+ STREAM_TO_UINT16(hw_cfg_cb.lmp_subversion, p);
+
+ prtk_usb_patch_file_info = rtk_usb_get_fw_table_entry(hw_cfg_cb.vid, hw_cfg_cb.pid);
+ if((prtk_usb_patch_file_info == NULL) || (prtk_usb_patch_file_info->lmp_sub_default == 0))
+ {
+ ALOGE("get patch entry error");
+ is_proceeding = FALSE;
+ break;
+ }
+ hw_cfg_cb.config_len = rtk_usb_get_bt_config(&hw_cfg_cb.config_buf, prtk_usb_patch_file_info->config_name, prtk_usb_patch_file_info->mac_offset);
+ hw_cfg_cb.fw_len = rtk_get_bt_firmware(&hw_cfg_cb.fw_buf, prtk_usb_patch_file_info->patch_name);
+ rtk_usb_get_fw_version(&hw_cfg_cb);
+
+ hw_cfg_cb.lmp_subversion_default = prtk_usb_patch_file_info->lmp_sub_default;
+ BTVNDDBG("lmp_subversion = 0x%x hw_cfg_cb.hci_version = 0x%x hw_cfg_cb.hci_revision = 0x%x, hw_cfg_cb.lmp_sub_current = 0x%x", hw_cfg_cb.lmp_subversion, hw_cfg_cb.hci_version, hw_cfg_cb.hci_revision, hw_cfg_cb.lmp_sub_current);
+
+ if(prtk_usb_patch_file_info->lmp_sub_default == hw_cfg_cb.lmp_subversion)
+ {
+ BTVNDDBG("%s: Cold BT controller startup", __func__);
+ //hw_cfg_cb.state = HW_CFG_START;
+ //goto CFG_USB_START;
+ hw_cfg_cb.state = HW_CFG_READ_ECO_VER;
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_READ_ROM_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_ROM_VERSION, p_buf, hw_usb_config_cback);
+ }
+ else if (hw_cfg_cb.lmp_subversion != hw_cfg_cb.lmp_sub_current)
+ {
+ BTVNDDBG("%s: Warm BT controller startup with updated lmp", __func__);
+ goto RESET_HW_CONTROLLER;
+ }
+ else
+ {
+ BTVNDDBG("%s: Warm BT controller startup with same lmp", __func__);
+ free(hw_cfg_cb.total_buf);
+ hw_cfg_cb.total_len = 0;
+
+ bt_vendor_cbacks->dealloc(p_buf);
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+ hw_cfg_cb.state = 0;
+ is_proceeding = TRUE;
+ }
+
+ /* if(hw_cfg_cb.lmp_subversion == LMPSUBVERSION_8723a)
+ {
+ hw_cfg_cb.state = HW_CFG_START;
+ goto CFG_USB_START;
+ }
+ else
+ {
+ hw_cfg_cb.state = HW_CFG_READ_ECO_VER;
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_READ_ROM_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_ROM_VERSION, p_buf, hw_usb_config_cback);
+ }*/
+ }
+ break;
+ }
+RESET_HW_CONTROLLER:
+ case HW_RESET_CONTROLLER:
+ {
+ if (status == 0)
+ {
+ //usleep(300000);//300ms
+ userial_vendor_usb_ioctl(RESET_CONTROLLER, NULL);//reset controller
+ hw_cfg_cb.state = HW_CFG_READ_ECO_VER;
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VSC_READ_ROM_VERSION);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+ is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_ROM_VERSION, p_buf, hw_usb_config_cback);
+ }
+ break;
+ }
+ case HW_CFG_READ_ECO_VER:
+ {
+ if(status == 0)
+ {
+ hw_cfg_cb.eversion = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPFC6D_EVERSION_OFFSET);
+ BTVNDDBG("hw_usb_config_cback chip_id of the IC:%d", hw_cfg_cb.eversion+1);
+ }
+ else if(1 == status)
+ {
+ hw_cfg_cb.eversion = 0;
+ }
+ else
+ {
+ is_proceeding = FALSE;
+ break;
+ }
+
+ hw_cfg_cb.state = HW_CFG_START;
+ goto CFG_USB_START;
+
+ }
+CFG_USB_START:
+ case HW_CFG_START:
+ {
+ //get efuse config file and patch code file
+ prtk_usb_patch_file_info = rtk_usb_get_fw_table_entry(hw_cfg_cb.vid, hw_cfg_cb.pid);
+
+ if((prtk_usb_patch_file_info == NULL) || (prtk_usb_patch_file_info->lmp_sub_default == 0))
+ {
+ ALOGE("get patch entry error");
+ is_proceeding = FALSE;
+ break;
+ }
+ hw_cfg_cb.max_patch_size = prtk_usb_patch_file_info->max_patch_size;
+ hw_cfg_cb.config_len = rtk_usb_get_bt_config(&hw_cfg_cb.config_buf, prtk_usb_patch_file_info->config_name, prtk_usb_patch_file_info->mac_offset);
+ if (hw_cfg_cb.config_len < 0)
+ {
+ ALOGE("Get Config file fail, just use efuse settings");
+ hw_cfg_cb.config_len = 0;
+ }
+ rtk_usb_update_altsettings(prtk_usb_patch_file_info, hw_cfg_cb.config_buf, &(hw_cfg_cb.config_len));
+
+ hw_cfg_cb.fw_len = rtk_get_bt_firmware(&hw_cfg_cb.fw_buf, prtk_usb_patch_file_info->patch_name);
+ if (hw_cfg_cb.fw_len < 0)
+ {
+ ALOGE("Get BT firmware fail");
+ hw_cfg_cb.fw_len = 0;
+ }
+ else{
+ //hw_cfg_cb.project_id_mask = prtk_usb_patch_file_info->project_id_mask;
+ rtk_usb_get_bt_final_patch(&hw_cfg_cb);
+ }
+
+ BTVNDDBG("Check total_len(0x%08x) max_patch_size(0x%08x)", hw_cfg_cb.total_len, hw_cfg_cb.max_patch_size);
+ if (hw_cfg_cb.total_len > hw_cfg_cb.max_patch_size)
+ {
+ ALOGE("total length of fw&config(0x%08x) larger than max_patch_size(0x%08x)", hw_cfg_cb.total_len, hw_cfg_cb.max_patch_size);
+ is_proceeding = FALSE;
+ break;
+ }
+
+ if ((hw_cfg_cb.total_len > 0) && hw_cfg_cb.dl_fw_flag)
+ {
+ hw_cfg_cb.patch_frag_cnt = hw_cfg_cb.total_len / PATCH_DATA_FIELD_MAX_SIZE;
+ hw_cfg_cb.patch_frag_tail = hw_cfg_cb.total_len % PATCH_DATA_FIELD_MAX_SIZE;
+ if (hw_cfg_cb.patch_frag_tail)
+ hw_cfg_cb.patch_frag_cnt += 1;
+ else
+ hw_cfg_cb.patch_frag_tail = PATCH_DATA_FIELD_MAX_SIZE;
+ BTVNDDBG("patch fragment count %d, tail len %d", hw_cfg_cb.patch_frag_cnt, hw_cfg_cb.patch_frag_tail);
+ }
+ else
+ {
+ is_proceeding = FALSE;
+ break;
+ }
+
+ goto DOWNLOAD_USB_FW;
+
+ }
+ /* fall through intentionally */
+
+DOWNLOAD_USB_FW:
+ case HW_CFG_DL_FW_PATCH:
+ BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, opcode:0x%x", status, opcode);
+
+ //recv command complete event for patch code download command
+ if(opcode == HCI_VSC_DOWNLOAD_FW_PATCH)
+ {
+ iIndexRx = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET + 1);
+ BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, iIndexRx:%i", status, iIndexRx);
+ hw_cfg_cb.patch_frag_idx++;
+
+ if(iIndexRx&0x80)
+ {
+ BTVNDDBG("vendor lib fwcfg completed");
+ free(hw_cfg_cb.total_buf);
+ hw_cfg_cb.total_len = 0;
+
+ bt_vendor_cbacks->dealloc(p_buf);
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+ hw_cfg_cb.state = 0;
+ is_proceeding = TRUE;
+ break;
+ }
+ }
+
+ if (hw_cfg_cb.patch_frag_idx < hw_cfg_cb.patch_frag_cnt)
+ {
+ iIndexRx = hw_cfg_cb.patch_frag_idx?((hw_cfg_cb.patch_frag_idx-1)%0x7f+1):0;
+ if (hw_cfg_cb.patch_frag_idx == hw_cfg_cb.patch_frag_cnt - 1)
+ {
+ BTVNDDBG("HW_CFG_DL_FW_PATCH: send last fw fragment");
+ iIndexRx |= 0x80;
+ hw_cfg_cb.patch_frag_len = hw_cfg_cb.patch_frag_tail;
+ }
+ else
+ {
+ iIndexRx &= 0x7F;
+ hw_cfg_cb.patch_frag_len = PATCH_DATA_FIELD_MAX_SIZE;
+ }
+ }
+
+ is_proceeding = usb_hci_download_patch_h4(p_buf, iIndexRx,
+ hw_cfg_cb.total_buf+(hw_cfg_cb.patch_frag_idx*PATCH_DATA_FIELD_MAX_SIZE),
+ hw_cfg_cb.patch_frag_len);
+ break;
+ default:
+ break;
+ } // switch(hw_cfg_cb.state)
+ } // if (p_buf != NULL)
+
+ /* Free the RX event buffer */
+ if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
+ bt_vendor_cbacks->dealloc(p_evt_buf);
+
+ if (is_proceeding == FALSE)
+ {
+ ALOGE("vendor lib fwcfg aborted!!!");
+ if (bt_vendor_cbacks)
+ {
+ if (p_buf != NULL)
+ bt_vendor_cbacks->dealloc(p_buf);
+
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ }
+
+ if(hw_cfg_cb.config_len)
+ {
+ free(hw_cfg_cb.config_buf);
+ hw_cfg_cb.config_len = 0;
+ }
+
+ if(hw_cfg_cb.fw_len)
+ {
+ free(hw_cfg_cb.fw_buf);
+ hw_cfg_cb.fw_len= 0;
+ }
+
+ if(hw_cfg_cb.total_len)
+ {
+ free(hw_cfg_cb.total_buf);
+ hw_cfg_cb.total_len = 0;
+ }
+ hw_cfg_cb.state = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function hw__usb_config_start
+**
+** Description Kick off controller initialization process
+**
+** Returns None
+**
+*******************************************************************************/
+void hw_usb_config_start(char transtype, uint32_t usb_id)
+{
+ memset(&hw_cfg_cb, 0, sizeof(bt_hw_cfg_cb_t));
+ hw_cfg_cb.dl_fw_flag = 1;
+ hw_cfg_cb.chip_type = CHIPTYPE_NONE;
+ hw_cfg_cb.pid = usb_id & 0x0000ffff;
+ hw_cfg_cb.vid = (usb_id>>16) & 0x0000ffff;
+ BTVNDDBG("RTKBT_RELEASE_NAME: %s",RTKBT_RELEASE_NAME);
+ BTVNDDBG("\nRealtek libbt-vendor_usb Version %s \n",RTK_VERSION);
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t *p;
+
+ BTVNDDBG("hw_usb_config_start, transtype = 0x%x, pid = 0x%04x, vid = 0x%04x \n", transtype, hw_cfg_cb.pid, hw_cfg_cb.vid);
+
+ if (bt_vendor_cbacks)
+ {
+ /* Must allocate command buffer via HC's alloc API */
+ p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+ HCI_CMD_PREAMBLE_SIZE);
+ if(p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ p = (uint8_t *) (p_buf + 1);
+
+ p = (uint8_t *)(p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_VENDOR_RESET);
+ *p++ = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ hw_cfg_cb.state = HW_CFG_RESET_CHANNEL_CONTROLLER;
+ bt_vendor_cbacks->xmit_cb(HCI_VENDOR_RESET, p_buf, hw_usb_config_cback);
+ }
+ else {
+ ALOGE("%s buffer alloc fail!", __func__);
+ }
+ }
+ else
+ ALOGE("%s call back is null", __func__);
+}
+
#define H5_TRACE_DATA_ENABLE 0//if you want to see data tx and rx, set H5_TRACE_DATA_ENABLE 1
#define H5_LOG_VERBOSE 0
-#define ENABLE_BLEADV_DISCONNECT 1
-
unsigned int h5_log_enable = 1;
#ifndef H5_LOG_BUF_SIZE
/******************************************************************************
** Local type definitions
******************************************************************************/
-
-static const uint16_t msg_evt_table[] =
-{
- MSG_HC_TO_STACK_HCI_ERR, /* H4_TYPE_COMMAND */
- MSG_HC_TO_STACK_HCI_ACL, /* H4_TYPE_ACL_DATA */
- MSG_HC_TO_STACK_HCI_SCO, /* H4_TYPE_SCO_DATA */
- MSG_HC_TO_STACK_HCI_EVT /* H4_TYPE_EVENT */
-};
+//
+//static const uint16_t msg_evt_table[] =
+//{
+// MSG_HC_TO_STACK_HCI_ERR, /* H4_TYPE_COMMAND */
+// MSG_HC_TO_STACK_HCI_ACL, /* H4_TYPE_ACL_DATA */
+// MSG_HC_TO_STACK_HCI_SCO, /* H4_TYPE_SCO_DATA */
+// MSG_HC_TO_STACK_HCI_EVT /* H4_TYPE_EVENT */
+//};
/* Callback function for the returned event of internal issued command */
typedef void (*tTIMER_HANDLE_CBACK)(union sigval sigval_value);
int nRxIndex; // ack index from board
int nNeedRetry; // if no response from board
};
-static struct patch_struct rtk_patch;
+//static struct patch_struct rtk_patch;
/******************************************************************************
** Static function
return;
}
}
-
+/*
static void H5LogMsgVerbose(const char *fmt_str, ...)
{
- static char buffer[H5_LOG_BUF_SIZE];
#if H5_LOG_VERBOSE
+ static char buffer[H5_LOG_BUF_SIZE];
va_list ap;
va_start(ap, fmt_str);
vsnprintf(&buffer[0], H5_LOG_MAX_SIZE, fmt_str, ap);
LOGI0("H5: ", buffer);
#else
+ va_list ap;
+ va_start(ap, fmt_str);
+ va_end(ap);
return;
#endif
-}
+}*/
// reverse bit
static __inline uint8_t bit_rev8(uint8_t byte)
}
struct __una_u16 { uint16_t x; };
-static __inline uint16_t __get_unaligned_cpu16(const void *p)
+/*static __inline uint16_t __get_unaligned_cpu16(const void *p)
{
const struct __una_u16 *ptr = (const struct __una_u16 *)p;
return ptr->x;
-}
-
+}*/
+/*
static __inline uint16_t get_unaligned_be16(const void *p)
{
return __get_unaligned_cpu16((const uint8_t *)p);
-}
+}*/
/**
* Get crc data.
*
* @param fd uart file descriptor
*
*/
-
+/*
static void hci_h5_send_pure_ack(void)
{
//uint16_t bytes_sent = 0;
#endif
return;
-}
+}*/
static void hci_h5_send_sync_req()
{
pthread_cond_signal(&rtk_h5.data_cond);
pthread_mutex_unlock(&rtk_h5.data_mutex);
}
-static uint8_t *acl_pack = NULL;
-static uint32_t acl_len=0;
-int loopbackmode = 0;
-
-static timer_t loopacltimer=0;
-
-static void loop_acl_cb()
-{
- sk_buff *rx_skb;
- rx_skb = skb_alloc_and_init(HCI_ACLDATA_PKT, acl_pack, acl_len);
- pthread_mutex_lock(&rtk_h5.data_mutex);
- skb_queue_tail(rtk_h5.recv_data, rx_skb);
- pthread_cond_signal(&rtk_h5.data_cond);
- pthread_mutex_unlock(&rtk_h5.data_mutex);
-}
-static void loopacl_timer_handler(union sigval sigev_value)
-{
- loop_acl_cb();
-}
-static void start_loopacktimer()
-{
- if(loopacltimer == 0)
- loopacltimer = OsAllocateTimer(loopacl_timer_handler);
- OsStartTimer(loopacltimer, 10, 0);
-
-}
static sk_buff * h5_dequeue()
{
void h5_process_ctl_pkts(void)
{
//process h5 link establish
- int len;
+ //int len;
uint8_t cfg;
- tHCI_H5_CB *p_cb = &rtk_h5;
+ //tHCI_H5_CB *p_cb = &rtk_h5;
sk_buff * skb = rtk_h5.rx_skb;
unsigned char h5sync[2] = {0x01, 0x7E},
h5syncresp[2] = {0x02, 0x7D},
h5conf[3] = {0x03, 0xFC, 0x14},
- h5confresp[2] = {0x04, 0x7B},
- h5InitOk[2] = {0xF1, 0xF1};
+ h5confresp[2] = {0x04, 0x7B};
+ //h5InitOk[2] = {0xF1, 0xF1};
//uint8_t *ph5_payload = NULL;
//ph5_payload = (uint8_t *)(p_cb->p_rcv_msg + 1);
* @param skb socket buffer
*
*/
-#if ENABLE_BLEADV_DISCONNECT
-uint16_t rk_h5_send_cmd(serial_data_type_t type, uint8_t *data, uint16_t length)
-{
- sk_buff * skb = NULL;
- uint16_t bytes_to_send, opcode;
-
-
- skb = skb_alloc_and_init(type, data, length);
- if(!skb) {
- ALOGE("send cmd skb_alloc_and_init fail!");
- return -1;
- }
-
- h5_enqueue(skb);
-
- num_hci_cmd_pkts--;
-
-
- STREAM_TO_UINT16(opcode, data);
- ALOGE("HCI Command opcode(0x%04X)", opcode);
-
- bytes_to_send = h5_wake_up();
- return length;
-}
-
-static void adv_timer_handler(union sigval sigev_value)
-{
- uint8_t sendData[4]={0x0a,0x20,0x01,0x01};
- rk_h5_send_cmd(1, sendData, 4);
-}
-static void start_enableAdvtimer()
-{
- if(loopacltimer == 0)
- loopacltimer = OsAllocateTimer(adv_timer_handler);
- OsStartTimer(loopacltimer, 100, 0);
-
-}
-
-
-static uint16_t bleConHandle = 0x0000;
-static uint8_t bleConnected = 0x00;
-static uint8_t bleAdvEnable = 0x00;
-#endif
static uint8_t hci_recv_frame(sk_buff *skb, uint8_t pkt_type)
{
uint8_t intercepted = 0;
- uint32_t i = 0 ;
+ //uint32_t i = 0 ;
+#if H5_TRACE_DATA_ENABLE
uint8_t *data = skb_get_data(skb);
+#endif
uint32_t data_len = skb_get_data_length(skb);
H5LogMsg("UART H5 RX: length = %d", data_len);
uint8_t event_code;
uint16_t opcode, len;
p = (uint8_t *)skb_get_data(skb);
-#if ENABLE_BLEADV_DISCONNECT
- if(p[0]==0x3e //ble meta
- && p[2]==0x01 //le connect complete
- && p[3]==0x00)//success
- {
- bleConHandle = (uint16_t)p[4] + ((uint16_t)p[5] << 8);
- ALOGE("bleConHandle 0x%x", bleConHandle);
- bleConnected = 0x01;
- }
-
- if(p[0]==0x05 //discon complete
- && p[2]==0x00 //success
- )
- {
- if( bleConnected && bleAdvEnable && bleConHandle == ((uint16_t)p[3] + ((uint16_t)p[4] << 8)) ){
- ALOGE("blediscon restart ble adv");
- bleConnected = 0x00;
- bleConHandle = 0x0000;
- start_enableAdvtimer();
- }
- }
-#endif
event_code = *p++;
len = *p++;
H5LogMsg("hci_recv_frame event_code(0x%x), len = %d", event_code, len);
- if(event_code == HCI_COMMAND_STATUS_EVT && len==0x04 && p[0]==0x01&&p[1]==0x02&&p[2]==0xff&&p[3]==0x3b)
- { *( p-2)=HCI_COMMAND_COMPLETE_EVT ;p[0]=0x02;p[1]=0xff;p[2]=0x3b;p[3]=0x01;}
if (event_code == HCI_COMMAND_COMPLETE_EVT)
{
num_hci_cmd_pkts = *p++;
H5LogMsg("CommandCompleteEvent for command h5_start_wait_controller_baudrate_ready_timer (0x%04X)", opcode);
h5_start_wait_controller_baudrate_ready_timer();
}
- }else if(event_code == 0xff){
- intercepted = 1;
- skb_free(&skb);
-}
+ }
}
int pass_up = 1;
uint16_t eventtype = 0;
uint8_t *h5_hdr = NULL;
- uint8_t complete_pkt = true;
+ //uint8_t complete_pkt = true;
uint8_t pkt_type = 0;
- tHCI_H5_CB *p_cb=&rtk_h5;
+ //tHCI_H5_CB *p_cb=&rtk_h5;
uint8_t status = 0;
//H5LogMsg("HCI 3wire h5_complete_rx_pkt");
/******************************************************************************
** Static functions
******************************************************************************/
-static void h5_data_ready_cb_signal_exit()
-{
-
- pthread_mutex_lock(&rtk_h5.data_mutex);
- pthread_cond_signal(&rtk_h5.data_cond);
- pthread_mutex_unlock(&rtk_h5.data_mutex);
-}
-
-
-static void data_ready_cb_thread(void *arg)
+static void data_ready_cb_thread()
{
sk_buff *skb;
uint8_t pkt_type = 0;
while (h5_data_ready_running)
{
pthread_mutex_lock(&rtk_h5.data_mutex);
- while ((skb_queue_get_length(rtk_h5.recv_data) == 0) && h5_retransfer_running)
+ while ((skb_queue_get_length(rtk_h5.recv_data) == 0))
{
pthread_cond_wait(&rtk_h5.data_cond, &rtk_h5.data_mutex);
}
pthread_mutex_unlock(&rtk_h5.data_mutex);
- if(!h5_retransfer_running)
- break;
-
if((skb = skb_dequeue_head(rtk_h5.recv_data)) != NULL) {
rtk_h5.data_skb = skb;
}
h5_int_hal_callbacks->h5_data_ready_cb(pkt_type, total_length);
}
- ALOGE("data_ready_cb_thread exiting");
+ H5LogMsg("data_ready_cb_thread exiting");
pthread_exit(NULL);
}
-static void data_retransfer_thread(void *arg)
+static void data_retransfer_thread()//(void *arg)
{
uint16_t events;
- uint32_t i = 0;
+ //uint32_t i = 0;
H5LogMsg("data_retransfer_thread started");
}
- ALOGE("data_retransfer_thread exiting");
+ H5LogMsg("data_retransfer_thread exiting");
pthread_exit(NULL);
}
static int create_data_retransfer_thread()
{
- struct sched_param param;
- int policy;
+ //struct sched_param param;
+ //int policy;
pthread_attr_t thread_attr;
static int create_data_ready_cb_thread()
{
- struct sched_param param;
- int policy;
+ //struct sched_param param;
+ //int policy;
pthread_attr_t thread_attr;
*******************************************************************************/
void hci_h5_cleanup(void)
{
- ALOGE("hci_h5_cleanup");
- uint8_t try_cnt=10;
+ H5LogMsg("hci_h5_cleanup");
+ //uint8_t try_cnt=10;
int result;
rtk_h5.cleanuping = 1;
- ms_delay(200);
//btsnoop_cleanup();
if (h5_retransfer_running)
{
h5_retransfer_running = 0;
- h5_data_ready_cb_signal_exit();
- if ((result = pthread_join(rtk_h5.thread_data_ready_cb, NULL)) < 0)
- ALOGE("H5 thread_data_ready_cb pthread_join() FAILED result:%d", result);
-
h5_retransfer_signal_event(H5_EVENT_EXIT);
if ((result = pthread_join(rtk_h5.thread_data_retrans, NULL)) < 0)
ALOGE("H5 pthread_join() FAILED result:%d", result);
ms_delay(200);
-
- pthread_mutex_destroy(&rtk_h5.data_mutex);
- pthread_cond_destroy(&rtk_h5.data_cond);
-
pthread_mutex_destroy(&rtk_h5.mutex);
pthread_cond_destroy(&rtk_h5.cond);
*******************************************************************************/
uint16_t hci_h5_parse_msg(uint8_t *byte, uint16_t count)
{
- uint16_t bytes_needed = 0;
+ //uint16_t bytes_needed = 0;
uint8_t h5_byte;
h5_byte = *byte;
//H5LogMsg("hci_h5_receive_msg byte:%d",h5_byte);
sk_buff * skb = NULL;
uint16_t bytes_to_send, opcode;
-
skb = skb_alloc_and_init(type, data, length);
if(!skb) {
ALOGE("send cmd skb_alloc_and_init fail!");
H5LogMsg("RX HCI RESET Command, stop hw init timer");
h5_stop_hw_init_ready_timer();
}
- if(opcode == 0x1802)
- loopbackmode =1;
-#if ENABLE_BLEADV_DISCONNECT
- if(opcode == 0x200a)//adv enalbe
- {
- ALOGE("setbleAdvEnable %x", data[1]);
- bleAdvEnable = data[1];
- }
-#endif
bytes_to_send = h5_wake_up();
return length;
}
*******************************************************************************/
uint16_t hci_h5_send_acl_data(serial_data_type_t type, uint8_t *data, uint16_t length)
{
- uint16_t bytes_to_send, lay_spec;
+ uint16_t bytes_to_send;//, lay_spec;
sk_buff * skb = NULL;
- if(loopbackmode == 1){
- acl_len = length;
- if(!acl_pack)
- acl_pack = malloc(2050);
- if(acl_len>2050)
- acl_len = 2050;
- memcpy(acl_pack,data,acl_len);
- start_loopacktimer();
- return length;
- }
-
skb = skb_alloc_and_init(type, data, length);
if(!skb) {
ALOGE("hci_h5_send_acl_data, alloc skb buffer fail!");
uint16_t hci_h5_send_sco_data(serial_data_type_t type, uint8_t *data, uint16_t length)
{
sk_buff * skb = NULL;
- uint16_t bytes_to_send, lay_spec;
+ uint16_t bytes_to_send;//, lay_spec;
skb = skb_alloc_and_init(type, data, length);
if(!skb) {
*******************************************************************************/
uint8_t hci_h5_send_sync_cmd(uint16_t opcode, uint8_t *p_buf, uint16_t length)
{
+ if(p_buf != NULL)
+ {
+ H5LogMsg("hci_h5_send_sync_cmd buf is not null");
+ }
if(rtk_h5.link_estab_state == H5_UNINITIALIZED)
{
if(opcode == HCI_VSC_H5_INIT)
}
else if(rtk_h5.link_estab_state == H5_ACTIVE)
{
- H5LogMsg("hci_h5_send_sync_cmd(0x%x), link_estab_state = %d", opcode, rtk_h5.link_estab_state);
+ H5LogMsg("hci_h5_send_sync_cmd(0x%x), link_estab_state = %d, length = %d", opcode, rtk_h5.link_estab_state, length);
return false;
}
return OsStartTimer(timerid, 0, 0);
}
-static void h5_retransfer_timeout_handler(union sigval sigev_value) {
+static void h5_retransfer_timeout_handler(){//(union sigval sigev_value) {
H5LogMsg("h5_retransfer_timeout_handler");
if(rtk_h5.cleanuping)
{
h5_retransfer_signal_event(H5_EVENT_RX);
}
-static void h5_sync_retrans_timeout_handler(union sigval sigev_value) {
+static void h5_sync_retrans_timeout_handler(){//(union sigval sigev_value) {
H5LogMsg("h5_sync_retrans_timeout_handler");
if(rtk_h5.cleanuping)
{
}
-static void h5_conf_retrans_timeout_handler(union sigval sigev_value) {
+static void h5_conf_retrans_timeout_handler(){//(union sigval sigev_value) {
H5LogMsg("h5_conf_retrans_timeout_handler");
if(rtk_h5.cleanuping)
{
}
-static void h5_wait_controller_baudrate_ready_timeout_handler(union sigval sigev_value) {
+static void h5_wait_controller_baudrate_ready_timeout_handler(){//(union sigval sigev_value) {
H5LogMsg("h5_wait_ct_baundrate_ready_timeout_handler");
if(rtk_h5.cleanuping)
{
rtk_h5.internal_skb = NULL;
}
-static void h5_hw_init_ready_timeout_handler(union sigval sigev_value) {
+static void h5_hw_init_ready_timeout_handler(){//(union sigval sigev_value) {
H5LogMsg("h5_hw_init_ready_timeout_handler");
if(rtk_h5.cleanuping)
{
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Realtek Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: rtk_btservice.c
+ *
+ * Description: start unix socketc
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_service"
+#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_rtk.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "rtk_btservice.h"
+#include "upio.h"
+#include <unistd.h>
+#include <sys/eventfd.h>
+#include <semaphore.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/un.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "bt_vendor_lib.h"
+
+
+//HCI VENDOR Command opcode
+#define HCI_VSC_READ_REGISTER 0xFFFF
+
+#define RTKBTSERVICE_SOCKETPATH "@/data/misc/bluedroid/rtkbt_service.sock"
+#define MAX_CONNECTION_NUMBER 10
+
+#define RTK_HCICMD 0x01
+#define RTK_CLOSESOCRET 0x02
+#define RTK_INNER 0x03
+#define OTHER 0xff
+
+#define Rtk_Service_Data_SIZE 259
+#define Rtk_Service_Send_Data_SIZE 259
+
+#define HCICMD_REPLY_TIMEOUT_VALUE 8000 //ms
+#define HCI_CMD_PREAMBLE_SIZE 3
+
+typedef void (*tTIMER_HANDLE_CBACK)(union sigval sigval_value);
+
+
+
+typedef struct Rtk_Btservice_Info
+{
+ int socketfd;
+ pthread_t cmdreadythd;
+ pthread_t epollthd;
+ int current_client_sock;
+ int epoll_fd;
+ int autopair_fd;
+ sem_t cmdqueue_sem;
+ sem_t cmdsend_sem;
+ timer_t timer_hcicmd_reply;
+ RT_LIST_HEAD cmdqueue_list;
+ pthread_mutex_t cmdqueue_mutex;
+ volatile uint8_t cmdqueue_thread_running;
+ volatile uint8_t epoll_thread_running;
+ void (*current_complete_cback)(void *);
+}Rtk_Btservice_Info;
+
+typedef struct Rtk_Service_Data
+{
+ uint16_t opcode;
+ uint8_t parameter_len;
+ uint8_t *parameter;
+ void (*complete_cback)(void *);
+}Rtk_Service_Data;
+
+/*
+typedef struct Rtk_Socket_Data
+{
+ char type; //hci,other,inner
+ uint8_t opcodeh;
+ uint8_t opcodel;
+ uint8_t parameter_len;
+ uint8_t parameter[0];
+}Rtk_Socket_Data;
+*/
+
+typedef struct Rtk_Queue_Data
+{
+ RT_LIST_ENTRY list;
+ int client_sock;
+ uint16_t opcode;
+ uint8_t parameter_len;
+ uint8_t *parameter;
+ void (*complete_cback)(void *);
+}Rtkqueuedata;
+
+static Rtk_Btservice_Info *rtk_btservice;
+static void Rtk_Service_Send_Hwerror_Event();
+//extern void userial_recv_rawdata_hook(unsigned char *, unsigned int);
+static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback)
+{
+ struct sigevent sigev;
+ timer_t timerid;
+
+ memset(&sigev, 0, sizeof(struct sigevent));
+ // Create the POSIX timer to generate signo
+ sigev.sigev_notify = SIGEV_THREAD;
+ //sigev.sigev_notify_thread_id = syscall(__NR_gettid);
+ sigev.sigev_notify_function = timer_callback;
+ sigev.sigev_value.sival_ptr = &timerid;
+
+ ALOGD("OsAllocateTimer bt_service sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
+ //Create the Timer using timer_create signal
+
+ if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == 0)
+ {
+ return timerid;
+ }
+ else
+ {
+ ALOGE("timer_create error!");
+ return (timer_t)-1;
+ }
+}
+
+static int OsFreeTimer(timer_t timerid)
+{
+ int ret = 0;
+ ret = timer_delete(timerid);
+ if(ret != 0)
+ ALOGE("timer_delete fail with errno(%d)", errno);
+
+ return ret;
+}
+
+
+ static int OsStartTimer(timer_t timerid, int msec, int mode)
+ {
+ struct itimerspec itval;
+
+ itval.it_value.tv_sec = msec / 1000;
+ itval.it_value.tv_nsec = (long)(msec % 1000) * (1000000L);
+
+ if (mode == 1)
+
+ {
+ itval.it_interval.tv_sec = itval.it_value.tv_sec;
+ itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
+ }
+ else
+ {
+ itval.it_interval.tv_sec = 0;
+ itval.it_interval.tv_nsec = 0;
+ }
+
+ //Set the Timer when to expire through timer_settime
+
+ if (timer_settime(timerid, 0, &itval, NULL) != 0)
+ {
+ ALOGE("time_settime error!");
+ return -1;
+ }
+
+ return 0;
+
+}
+
+ static int OsStopTimer(timer_t timerid)
+ {
+ return OsStartTimer(timerid, 0, 0);
+ }
+
+static void init_cmdqueue_hash(Rtk_Btservice_Info* rtk_info)
+{
+ RT_LIST_HEAD* head = &rtk_info->cmdqueue_list;
+ ListInitializeHeader(head);
+}
+
+static void delete_cmdqueue_from_hash(Rtkqueuedata* desc)
+{
+ if (desc)
+ {
+ ListDeleteNode(&desc->list);
+ free(desc);
+ desc = NULL;
+ }
+}
+
+static void flush_cmdqueue_hash(Rtk_Btservice_Info* rtk_info)
+{
+ RT_LIST_HEAD* head = &rtk_info->cmdqueue_list;
+ RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+ Rtkqueuedata* desc = NULL;
+
+ pthread_mutex_lock(&rtk_info->cmdqueue_mutex);
+ LIST_FOR_EACH_SAFELY(iter, temp, head)
+ {
+ desc = LIST_ENTRY(iter, Rtkqueuedata, list);
+ delete_cmdqueue_from_hash(desc);
+ }
+ //ListInitializeHeader(head);
+ pthread_mutex_unlock(&rtk_info->cmdqueue_mutex);
+}
+
+static void hcicmd_reply_timeout_handler()//(union sigval sigev_value)
+{
+ Rtk_Service_Send_Hwerror_Event();
+ //return;
+}
+
+static int hcicmd_alloc_reply_timer()
+ {
+ // Create and set the timer when to expire
+ rtk_btservice->timer_hcicmd_reply = OsAllocateTimer(hcicmd_reply_timeout_handler);
+
+ return 0;
+
+ }
+
+static int hcicmd_free_reply_timer()
+{
+ return OsFreeTimer(rtk_btservice->timer_hcicmd_reply);
+}
+
+
+static int hcicmd_start_reply_timer()
+{
+ return OsStartTimer(rtk_btservice->timer_hcicmd_reply, HCICMD_REPLY_TIMEOUT_VALUE, 1);
+}
+
+static int hcicmd_stop_reply_timer()
+{
+ return OsStopTimer(rtk_btservice->timer_hcicmd_reply);
+}
+
+static void Rtk_Client_Cmd_Cback(void *p_mem)
+{
+ HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+ unsigned char *sendbuf=NULL;
+ int len;
+ //ALOGE("%s p_evt_buf = %x,%x,%x,%x,%x!", __func__,p_evt_buf->event,p_evt_buf->len,p_evt_buf->offset,p_evt_buf->layer_specific,p_evt_buf->data[0]);
+ len=8+p_evt_buf->len;
+ if(p_evt_buf != NULL)
+ {
+ sendbuf = (unsigned char *)malloc(sizeof(char)*len);
+ sendbuf = p_mem;
+ if(rtk_btservice->current_client_sock != -1)
+ {
+ write(rtk_btservice->current_client_sock,sendbuf,len);
+ }
+ else
+ {
+ ALOGE("%s current_client_sock is not exist!", __func__);
+ }
+ free(sendbuf);
+ }
+}
+
+void Rtk_Service_Vendorcmd_Hook(Rtk_Service_Data *RtkData, int client_sock)
+{
+ Rtkqueuedata* rtkqueue_data = NULL;
+ pthread_mutex_lock(&rtk_btservice->cmdqueue_mutex);
+ rtkqueue_data = (Rtkqueuedata *)malloc(sizeof(Rtkqueuedata));
+ if (NULL == rtkqueue_data)
+ {
+ ALOGE("rtkqueue_data: allocate error");
+ return;
+ }
+
+ rtkqueue_data->opcode = RtkData->opcode;
+ rtkqueue_data->parameter = RtkData->parameter;
+ rtkqueue_data->parameter_len = RtkData->parameter_len;
+ rtkqueue_data->client_sock = client_sock;
+ rtkqueue_data->complete_cback = RtkData->complete_cback;
+
+ ListAddToTail(&(rtkqueue_data->list), &(rtk_btservice->cmdqueue_list));
+ sem_post(&rtk_btservice->cmdqueue_sem);
+ pthread_mutex_unlock(&rtk_btservice->cmdqueue_mutex);
+}
+
+static void Rtk_Service_Cmd_Event_Cback(void *p_mem)
+{
+ //int i;
+ //unsigned char *a=p_mem;
+ //ALOGE("%s p_mem = %x,%x,%x,%x,%x,%x!", __func__,a[0],a[1],a[2],a[3],a[4],a[5]);
+ if(p_mem != NULL)
+ {
+ if(rtk_btservice->current_complete_cback!=NULL)
+ {
+ rtk_btservice->current_complete_cback(p_mem);
+ }
+ else
+ {
+ ALOGE("%s current_complete_cback is not exist!", __func__);
+ }
+ rtk_btservice->current_complete_cback=NULL;
+ hcicmd_stop_reply_timer();
+ sem_post(&rtk_btservice->cmdsend_sem);
+ }
+}
+
+static void Rtk_Service_Send_Hwerror_Event()
+{
+ unsigned char *p_buf=(unsigned char *)malloc(sizeof(char)*4);
+ int length=4;
+ p_buf[0]=0x04;//event
+ p_buf[1]=0x10;//hardware error
+ p_buf[2]=0x01;//len
+ p_buf[3]=0xfd;//error code
+ userial_recv_rawdata_hook(p_buf,length);
+ free(p_buf);
+}
+
+static void *cmdready_thread()
+{
+ //Rtkqueuedata* rtk_data;
+
+ while(rtk_btservice->cmdqueue_thread_running)
+ {
+ sem_wait(&rtk_btservice->cmdqueue_sem);
+ sem_wait(&rtk_btservice->cmdsend_sem);
+ if(rtk_btservice->cmdqueue_thread_running != 0)
+ {
+ pthread_mutex_lock(&rtk_btservice->cmdqueue_mutex);
+ RT_LIST_ENTRY* iter = ListGetTop(&(rtk_btservice->cmdqueue_list));
+ Rtkqueuedata* desc = NULL;
+ if (iter) {
+ desc = LIST_ENTRY(iter, Rtkqueuedata, list);
+ if (desc)
+ {
+ ListDeleteNode(&desc->list);
+ }
+ }
+
+ pthread_mutex_unlock(&rtk_btservice->cmdqueue_mutex);
+
+ if(desc) {
+ HC_BT_HDR *p_buf = NULL;
+ p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + desc->parameter_len);
+
+ if(NULL == p_buf)
+ {
+ ALOGE("rtk_vendor_cmd_to_fw: HC_BT_HDR alloc error");
+ pthread_exit(0);
+ }
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE + desc->parameter_len;
+ p_buf->layer_specific = 0;
+
+ uint8_t *p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, desc->opcode);
+ *p++ = desc->parameter_len;
+
+ if(desc->opcode == 0xfc77)
+ {
+ rtk_btservice->autopair_fd = desc->client_sock;
+ }
+
+ if(desc->parameter_len > 0)
+ {
+ memcpy(p, desc->parameter, desc->parameter_len);
+ }
+ if(desc->opcode != 0xfc94 )
+ ALOGD("%s, transmit_command Opcode:%x",__func__, desc->opcode);
+ rtk_btservice->current_client_sock = desc->client_sock;
+ rtk_btservice->current_complete_cback = desc->complete_cback;
+ //bt_vendor_cbacks->xmit_cb(desc->opcode, p_buf, desc->complete_cback);
+ if(bt_vendor_cbacks != NULL)
+ {
+ bt_vendor_cbacks->xmit_cb(desc->opcode, p_buf, Rtk_Service_Cmd_Event_Cback);
+ hcicmd_start_reply_timer();
+ }
+ if(desc->parameter_len > 0)
+ free(desc->parameter);
+ }
+
+ free(desc);
+ }
+ }
+ pthread_exit(0);
+}
+
+
+static void Getpacket(int client_sock)
+{
+
+ //unsigned char recvbuf[Rtk_Service_Data_SIZE];
+ unsigned char type=0;
+ unsigned char opcodeh=0;
+ unsigned char opcodel=0;
+ unsigned char parameter_length=0;
+ unsigned char *parameter = NULL;
+ int recvlen=0;
+ Rtk_Service_Data *p_buf;
+ //int i;
+
+
+ recvlen = read(client_sock,&type,1);
+ ALOGD("%s recvlen=%d,type=%d",__func__,recvlen, type);
+ if(recvlen<=0)
+ {
+ close(client_sock);
+ if(client_sock == rtk_btservice->autopair_fd)
+ {
+ rtk_btservice->autopair_fd = -1;
+ }
+ return;
+ }
+
+ switch (type)
+ {
+ case RTK_HCICMD:
+ {
+ recvlen = read(client_sock,&opcodeh,1);
+ if(recvlen<=0)
+ {
+ ALOGE("read opcode high char error");
+ break;
+ }
+ recvlen = read(client_sock,&opcodel,1);
+ if(recvlen<=0)
+ {
+ ALOGE("read opcode low char error");
+ break;
+ }
+ recvlen = read(client_sock,¶meter_length,1);
+ if(recvlen<=0)
+ {
+ ALOGE("read parameter_length char error");
+ break;
+ }
+
+ if(parameter_length>0)
+ {
+ parameter = (unsigned char *)malloc(sizeof(char)*parameter_length);
+ recvlen = read(client_sock,parameter,parameter_length);
+ ALOGD("%s parameter_length=%d,recvlen=%d",__func__,parameter_length, recvlen);
+ if(recvlen<=0 || recvlen!=parameter_length)
+ {
+ ALOGE("read parameter_length char error recvlen=%d,parameter_length=%d\n",recvlen,parameter_length);
+ break;
+ }
+ }
+ p_buf = (Rtk_Service_Data *)malloc(sizeof(Rtk_Service_Data));
+ if (NULL == p_buf)
+ {
+ ALOGE("p_buf: allocate error");
+ return;
+ }
+ p_buf->opcode = ((unsigned short)opcodeh)<<8 | opcodel;
+ p_buf->parameter = parameter;
+ p_buf->parameter_len = parameter_length;
+ p_buf->complete_cback = Rtk_Client_Cmd_Cback;
+ //ALOGE("p_buf->parameter_len: %d",p_buf->parameter_len);
+ //ALOGE("p_buf->opcode: %x",p_buf->opcode);
+ //ALOGE("opcodeh: %x,opcodel: %x",opcodeh,opcodel);
+ //for(i=0;i<p_buf->parameter_len;i++)
+ //{
+ // ALOGE("i=%d,p_buf->parameter: %x",i,p_buf->parameter[i]);
+ //}
+ Rtk_Service_Vendorcmd_Hook(p_buf,client_sock);
+ free(p_buf);
+ break;
+ }
+ case RTK_CLOSESOCRET:
+ {
+ close(client_sock);
+ //pthread_exit(0);
+ break;
+ }
+ default:
+ {
+ ALOGE("%s The RtkSockData type is not found!", __func__);
+ break;
+ }
+ }
+
+}
+
+void rtk_btservice_internal_event_intercept(uint8_t *p_full_msg,uint8_t *p_msg)
+{
+ uint8_t *p = p_msg;
+ uint8_t event_code = *p++;
+ //uint8_t len = *p++;
+ uint8_t subcode;
+ HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_full_msg;
+ if(event_code == 0xff)
+ ALOGD("rtk_btservice_internal_event_intercept event_code=0x%x",event_code);
+ switch (event_code)
+ {
+ case HCI_VENDOR_SPECIFIC_EVT:
+ {
+ STREAM_TO_UINT8(subcode, p);
+ switch(subcode)
+ {
+ case HCI_RTKBT_AUTOPAIR_EVT:
+ {
+
+ ALOGD("p_evt_buf_len=%d",p_evt_buf->len);
+ //for(int i=0;i<p_evt_buf->len;i++)
+ //ALOGE("@jason buf[%d]=0x%x",i,p_evt_buf->data[i]);
+ //
+ if(rtk_btservice->autopair_fd != -1)
+ {
+ write(rtk_btservice->autopair_fd, p_evt_buf, p_evt_buf->len+8);
+ uint8_t p_bluedroid_len = p_evt_buf->len+1;
+ uint8_t *p_bluedroid = malloc(p_bluedroid_len);
+ p_bluedroid[0]=DATA_TYPE_EVENT;
+ memcpy((uint8_t *)(p_bluedroid + 1), p_msg, p_evt_buf->len);
+ p_bluedroid[1]=0x3e; //event_code
+ p_bluedroid[3]=0x02; //subcode
+ userial_recv_rawdata_hook(p_bluedroid, p_bluedroid_len);
+ }
+ }
+
+ default:
+ break;
+ }
+ break;
+ }
+ //case HCI_COMMAND_COMPLETE_EVT:
+ //{
+ //rtkservice_handle_cmd_complete_evt();
+ //}
+ default:
+ break;
+ }
+}
+
+
+static int socket_accept(socketfd)
+{
+ struct sockaddr_un un;
+ socklen_t len;
+ int client_sock=0;
+ len = sizeof(un);
+ struct epoll_event event;
+
+ client_sock=accept(socketfd, (struct sockaddr *)&un, &len);
+ if(client_sock<0)
+ {
+ printf("accept failed\n");
+ return -1;
+ }
+ //pthread_create(&connectthread,NULL,(void *)accept_request_thread,&client_sock);
+
+ event.data.fd=client_sock;
+ event.events=EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+ //list_add(client_sock);
+ if(epoll_ctl(rtk_btservice->epoll_fd,EPOLL_CTL_ADD,client_sock,&event)==-1)
+ {
+ ALOGE("%s unable to register fd %d to epoll set: %s", __func__, client_sock, strerror(errno));
+ close(client_sock);
+ return -1;
+ }
+ return 0;
+}
+
+static void *epoll_thread()
+{
+ struct epoll_event events[64];
+ int nfds=0;
+ int i=0;
+
+ while(rtk_btservice->epoll_thread_running)
+ {
+ nfds=epoll_wait(rtk_btservice->epoll_fd,events,32,500);
+ if(rtk_btservice->epoll_thread_running != 0)
+ {
+ if(nfds>0)
+ {
+ for(i=0;i<nfds;i++)
+ {
+ if(events[i].data.fd == rtk_btservice->socketfd && events[i].events&EPOLLIN)
+ {
+ if(socket_accept(events[i].data.fd)<0)
+ {
+ pthread_exit(0);
+ }
+ }
+ else if(events[i].events&(EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR))
+ {
+ ALOGD("%s events[i].data.fd = %d ", __func__, events[i].data.fd);
+ Getpacket(events[i].data.fd);
+ }
+ }
+ }
+ }
+ }
+ pthread_exit(0);
+}
+
+static int unix_socket_start(const char *servername)
+{
+ int len;
+ struct sockaddr_un un;
+ struct epoll_event event;
+
+ if ((rtk_btservice->socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ ALOGE("%s create AF_UNIX socket fail!", __func__);
+ return -1;
+ }
+
+ memset(&un, 0, sizeof(un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, servername);
+ un.sun_path[0]=0;
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(servername);
+
+ if (bind(rtk_btservice->socketfd, (struct sockaddr *)&un, len) < 0)
+ {
+ ALOGE("%s bind socket fail!", __func__);
+ return -1;
+ }
+
+ if (listen(rtk_btservice->socketfd, MAX_CONNECTION_NUMBER) < 0)
+ {
+ ALOGE("%s listen socket fail!", __func__);
+ return -1;
+ }
+ /*
+ if(chmod(RTKBTSERVICE_SOCKETPATH,0666) != 0)
+ {
+ ALOGE("%s chmod failed");
+ }
+ */
+ event.data.fd=rtk_btservice->socketfd;
+ event.events=EPOLLIN;
+ if(epoll_ctl(rtk_btservice->epoll_fd,EPOLL_CTL_ADD,rtk_btservice->socketfd,&event)==-1)
+ {
+ ALOGE("%s unable to register fd %d to epoll set: %s", __func__, rtk_btservice->socketfd, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int RTK_btservice_thread_start()
+{
+ rtk_btservice->epoll_thread_running=1;
+ if (pthread_create(&rtk_btservice->epollthd, NULL, epoll_thread, NULL)!=0)
+ {
+ ALOGE("pthread_create epoll_thread: %s", strerror(errno));
+ return -1;
+ }
+
+ rtk_btservice->cmdqueue_thread_running=1;
+ if (pthread_create(&rtk_btservice->cmdreadythd, NULL, cmdready_thread, NULL)!=0)
+ {
+ ALOGE("pthread_create cmdready_thread: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+void RTK_btservice_thread_stop()
+{
+ ALOGD("%s !", __func__);
+ rtk_btservice->epoll_thread_running=0;
+ rtk_btservice->cmdqueue_thread_running=0;
+ sem_post(&rtk_btservice->cmdqueue_sem);
+ sem_post(&rtk_btservice->cmdsend_sem);
+ pthread_join(rtk_btservice->cmdreadythd, NULL);
+ pthread_join(rtk_btservice->epollthd, NULL);
+ close(rtk_btservice->epoll_fd);
+ ALOGD("%s end!", __func__);
+}
+
+int RTK_btservice_init()
+{
+ int ret;
+ rtk_btservice=(Rtk_Btservice_Info *)malloc(sizeof(Rtk_Btservice_Info));
+
+ rtk_btservice->current_client_sock = -1;
+ rtk_btservice->current_complete_cback=NULL;
+ rtk_btservice->autopair_fd = -1;
+ ALOGD("%s init start!", __func__);
+ hcicmd_alloc_reply_timer();
+
+ sem_init(&rtk_btservice->cmdqueue_sem, 0, 0);
+ sem_init(&rtk_btservice->cmdsend_sem, 0, 1);
+
+ pthread_mutex_init(&rtk_btservice->cmdqueue_mutex, NULL);
+ init_cmdqueue_hash(rtk_btservice);
+ if(bt_vendor_cbacks == NULL)
+ {
+ ALOGE("%s bt_vendor_cbacks is NULL!", __func__);
+ return -1;
+ }
+
+ rtk_btservice->epoll_fd = epoll_create(64);
+ if (rtk_btservice->epoll_fd == -1) {
+ ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if(unix_socket_start(RTKBTSERVICE_SOCKETPATH) < 0)
+ {
+ ALOGE("%s unix_socket_start fail!", __func__);
+ return -1;
+ }
+
+ ret = RTK_btservice_thread_start();
+ if(ret<0)
+ {
+ ALOGE("%s RTK_btservice_thread_start fail!", __func__);
+ return -1;
+ }
+ ALOGD("%s init done!", __func__);
+ return 0;
+}
+
+void RTK_btservice_destroyed()
+{
+ ALOGD("%s destroyed start!", __func__);
+ RTK_btservice_thread_stop();
+ close(rtk_btservice->socketfd);
+ sem_destroy(&rtk_btservice->cmdqueue_sem);
+ sem_destroy(&rtk_btservice->cmdsend_sem);
+ flush_cmdqueue_hash(rtk_btservice);
+ hcicmd_free_reply_timer();
+ pthread_mutex_destroy(&rtk_btservice->cmdqueue_mutex);
+ rtk_btservice->autopair_fd = -1;
+ rtk_btservice->current_client_sock = -1;
+ free(rtk_btservice);
+ ALOGD("%s destroyed done!", __func__);
+}
+
+
static void rtk_safe_close_(int *fd);
-static void *rtk_listen_fn_(void *context);
+static void *rtk_listen_fn_();
static const char *RTK_LISTEN_THREAD_NAME_ = "rtk_btsnoop_net";
static const int RTK_LOCALHOST_ = 0xC0A80AE2; // 192.168.10.226
void rtk_btsnoop_open()
{
pthread_mutex_init(&btsnoop_log_lock, NULL);
+ char last_log_path[PATH_MAX];
+ uint64_t timestamp;
+ uint32_t usec;
+ uint8_t sec,hour, minus,day;
+
if (hci_btsnoop_fd != -1) {
ALOGE("%s btsnoop log file is already open.", __func__);
return;
}
if(rtk_btsnoop_save_log) {
- char last_log_path[PATH_MAX];
- snprintf(last_log_path, PATH_MAX, "%s.%llu", rtk_btsnoop_path, rtk_btsnoop_timestamp());
+ timestamp = rtk_btsnoop_timestamp() - BTSNOOP_EPOCH_DELTA;
+ usec = (uint32_t)(timestamp % 1000000LL);
+ timestamp /= 1000000LL;
+ sec = (uint8_t)(timestamp % 60LL);
+ timestamp /= 60LL;
+ minus = (uint8_t)(timestamp % 60LL);
+ timestamp /= 60LL;
+ hour = (uint8_t)(timestamp % 24LL);
+ timestamp /= 24LL;
+ day = (uint8_t)(timestamp % 30LL);
+ timestamp /= 30LL;
+ //snprintf(last_log_path, PATH_MAX, "%s.%llu", rtk_btsnoop_path, rtk_btsnoop_timestamp());
+ snprintf(last_log_path, PATH_MAX, "%s.%uY-%dD-%dH-%dM-%dS-%dUS", rtk_btsnoop_path,
+ (uint32_t)timestamp, day, hour, minus, sec, usec);
+ if (!rename(rtk_btsnoop_path, last_log_path) && errno != ENOENT)
+ ALOGE("%s unable to rename '%s' to '%s': %s", __func__, rtk_btsnoop_path, last_log_path, strerror(errno));
+ }
+ else {
+ snprintf(last_log_path, PATH_MAX, "%s.last", rtk_btsnoop_path);
if (!rename(rtk_btsnoop_path, last_log_path) && errno != ENOENT)
ALOGE("%s unable to rename '%s' to '%s': %s", __func__, rtk_btsnoop_path, last_log_path, strerror(errno));
}
pthread_mutex_unlock(&rtk_client_socket_lock_);
}
-static void *rtk_listen_fn_(void *context) {
+static void *rtk_listen_fn_() {
prctl(PR_SET_NAME, (unsigned long)RTK_LISTEN_THREAD_NAME_, 0, 0, 0);
rtk_listen_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
--- /dev/null
+#define LOG_TAG "rtk_heartbeat"
+#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_rtk.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "rtk_btservice.h"
+#include "rtk_poll.h"
+#include "upio.h"
+#include <unistd.h>
+#include <sys/eventfd.h>
+#include <semaphore.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/un.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "bt_vendor_lib.h"
+
+#define RTKBT_HEARTBEAT_CONF_FILE "/vendor/etc/bluetooth/rtkbt_heartbeat.conf"
+
+#define HCI_EVT_HEARTBEAT_STATUS_OFFSET (5)
+#define HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_L (6)
+#define HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_H (7)
+
+static const uint32_t DEFALUT_HEARTBEAT_TIMEOUT_MS = 1000; //send a per sercond
+int heartBeatLog = -1;
+static int heartBeatTimeout= -1;
+static bool heartbeatFlag = false;
+static int heartbeatCount= 0;
+static uint16_t nextSeqNum= 1;
+static uint16_t cleanupFlag = 0;
+
+typedef struct Rtk_Service_Data
+{
+ uint16_t opcode;
+ uint8_t parameter_len;
+ uint8_t *parameter;
+ void (*complete_cback)(void *);
+}Rtk_Service_Data;
+
+#define HCI_CMD_VNDR_HEARTBEAT 0xFC94
+
+extern void Rtk_Service_Vendorcmd_Hook(Rtk_Service_Data *RtkData, int client_sock);
+extern uint8_t get_heartbeat_from_hardware();
+
+static char *rtk_trim(char *str) {
+ while (isspace(*str))
+ ++str;
+
+ if (!*str)
+ return str;
+
+ char *end_str = str + strlen(str) - 1;
+ while (end_str > str && isspace(*end_str))
+ --end_str;
+
+ end_str[1] = '\0';
+ return str;
+}
+
+
+static void load_rtkbt_heartbeat_conf()
+{
+ char *split;
+ FILE *fp = fopen(RTKBT_HEARTBEAT_CONF_FILE, "rt");
+ if (!fp) {
+ ALOGE("%s unable to open file '%s': %s", __func__, RTKBT_HEARTBEAT_CONF_FILE, strerror(errno));
+ return;
+ }
+ int line_num = 0;
+ char line[1024];
+ //char value[1024];
+ while (fgets(line, sizeof(line), fp)) {
+ char *line_ptr = rtk_trim(line);
+ ++line_num;
+
+ // Skip blank and comment lines.
+ if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[')
+ continue;
+
+ split = strchr(line_ptr, '=');
+ if (!split) {
+ ALOGE("%s no key/value separator found on line %d.", __func__, line_num);
+ continue;
+ }
+
+ *split = '\0';
+ char *endptr;
+ if(!strcmp(rtk_trim(line_ptr), "HeartBeatTimeOut")) {
+ heartBeatTimeout = strtol(rtk_trim(split+1), &endptr, 0);
+ }
+ else if(!strcmp(rtk_trim(line_ptr), "HeartBeatLog")) {
+ heartBeatLog = strtol(rtk_trim(split+1), &endptr, 0);
+ }
+ }
+
+ fclose(fp);
+
+}
+
+static void rtkbt_heartbeat_cmpl_cback (void *p_params)
+{
+ uint8_t status = 0;
+ uint16_t seqnum;
+ HC_BT_HDR *p_evt_buf = p_params;
+ //uint8_t *p = NULL;
+ if(p_params != NULL)
+ {
+ p_evt_buf = (HC_BT_HDR *) p_params;
+ status = p_evt_buf->data[HCI_EVT_HEARTBEAT_STATUS_OFFSET];
+ seqnum = p_evt_buf->data[HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_H]<<8 | p_evt_buf->data[HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_L];
+ }
+
+ if(status == 0 && seqnum == nextSeqNum)
+ {
+ nextSeqNum = (seqnum+1);
+ heartbeatCount = 0;
+ }
+ else
+ {
+ ALOGE("rtkbt_heartbeat_cmpl_cback: Current SeqNum = %d,should SeqNum=%d, status = %d", seqnum, nextSeqNum, status);
+ ALOGE("heartbeat event missing: restart bluedroid stack\n");
+ usleep(1000);
+ kill(getpid(), SIGKILL);
+ }
+
+}
+
+
+static void heartbeat_timed_out()//(union sigval arg)
+{
+ Rtk_Service_Data *p_buf;
+
+ heartbeatCount++;
+ if(heartbeatCount >= 3)
+ {
+ if(cleanupFlag == 1)
+ {
+ ALOGW("Already cleanup, ignore.");
+ return;
+ }
+ ALOGE("heartbeat_timed_out: heartbeatCount = %d, expected nextSeqNum = %d",heartbeatCount, nextSeqNum);
+ ALOGE("heartbeat_timed_out,controller may be suspend! Now restart bluedroid stack\n");
+ usleep(1000);
+ kill(getpid(), SIGKILL);
+ return;
+ }
+ if(heartbeatFlag)
+ {
+ p_buf = (Rtk_Service_Data *)malloc(sizeof(Rtk_Service_Data));
+ if (NULL == p_buf)
+ {
+ ALOGE("p_buf: allocate error");
+ return;
+ }
+ p_buf->opcode = HCI_CMD_VNDR_HEARTBEAT;
+ p_buf->parameter = NULL;
+ p_buf->parameter_len = 0;
+ p_buf->complete_cback = rtkbt_heartbeat_cmpl_cback;
+
+ Rtk_Service_Vendorcmd_Hook(p_buf,-1);
+ free(p_buf);
+ poll_timer_flush();
+ }
+}
+
+
+static void rtkbt_heartbeat_beginTimer_func(void)
+{
+ Rtk_Service_Data *p_buf;
+
+ if((heartBeatTimeout != -1) && (heartBeatLog != -1))
+ {
+ poll_init(heartbeat_timed_out,heartBeatTimeout);
+ }
+ else
+ {
+ heartBeatLog = 0;
+ poll_init(heartbeat_timed_out,DEFALUT_HEARTBEAT_TIMEOUT_MS);
+ }
+ poll_enable(TRUE);
+
+ p_buf = (Rtk_Service_Data *)malloc(sizeof(Rtk_Service_Data));
+ if (NULL == p_buf)
+ {
+ ALOGE("p_buf: allocate error");
+ return;
+ }
+ p_buf->opcode = HCI_CMD_VNDR_HEARTBEAT;
+ p_buf->parameter = NULL;
+ p_buf->parameter_len = 0;
+ p_buf->complete_cback = rtkbt_heartbeat_cmpl_cback;
+
+ Rtk_Service_Vendorcmd_Hook(p_buf,-1);
+ free(p_buf);
+
+ //rtkbt_api_callbacks->BTM_VendorSpecificCommand(HCI_CMD_VNDR_HEARTBEAT,0,NULL,rtkbt_heartbeat_cmpl_cback);
+ poll_timer_flush();
+}
+
+void Heartbeat_cleanup()
+{
+ heartbeatFlag = false;
+ nextSeqNum = 1;
+ heartbeatCount = 0;
+ cleanupFlag = 1;
+ poll_enable(FALSE);
+ poll_cleanup();
+}
+
+void Heartbeat_init()
+{
+ int res;
+ ALOGD("Heartbeat_init start");
+ Heartbeat_cleanup();
+ load_rtkbt_heartbeat_conf();
+ heartbeatFlag = true;
+ heartbeatCount = 0;
+ cleanupFlag = 0;
+ res = get_heartbeat_from_hardware();
+ ALOGD("Heartbeat_init res = %x",res);
+ if(res == 1)
+ rtkbt_heartbeat_beginTimer_func();
+ else
+ Heartbeat_cleanup();
+ ALOGD("Heartbeat_init end");
+}
+
*
******************************************************************************/
#define LOG_TAG "rtk_parse"
-#define RTKBT_RELEASE_NAME "Test"
+#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1"
#include <utils/Log.h>
#include <stdlib.h>
profile_max = 8
};
+typedef struct RTK_COEX_INFO {
+ RT_LIST_ENTRY list;
+ HC_BT_HDR * p_buf;
+ uint16_t opcode;
+}tRTK_COEX_INFO;
+
//profile info data
typedef struct RTK_PROF_INFO {
RT_LIST_ENTRY list;
typedef struct RTK_PROF {
RT_LIST_HEAD conn_hash; //hash for connections
RT_LIST_HEAD profile_list; //hash for profile info
+ RT_LIST_HEAD coex_list;
pthread_mutex_t profile_mutex;
+ pthread_mutex_t coex_mutex;
pthread_mutex_t udpsocket_mutex;
pthread_t thread_monitor;
pthread_t thread_data;
uint8_t autoreport_enable;
}tHCI_EVENT_BT_INFO_CONTROL;
+extern void Heartbeat_init();
+
tRTK_PROF rtk_prof;
volatile int poweroff_allowed = 0;
uint8_t coex_log_enable = 0;
+static volatile bool coex_cmd_send = false;
#define BIT(_I) (uint16_t)(1<<(_I))
#define is_profile_connected(profile) ((rtk_prof.profile_bitmap & BIT(profile)) >0)
return NULL;
}
+void init_coex_hash(tRTK_PROF* h5)
+{
+ RT_LIST_HEAD* head = &h5->coex_list;
+ ListInitializeHeader(head);
+}
+
+void delete_coex_from_hash(tRTK_COEX_INFO* desc)
+{
+ if (desc)
+ {
+ ListDeleteNode(&desc->list);
+ free(desc);
+ desc = NULL;
+ }
+}
+
+void flush_coex_hash(tRTK_PROF* h5)
+{
+ RT_LIST_HEAD* head = &h5->coex_list;
+ RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+ tRTK_COEX_INFO* desc = NULL;
+
+ pthread_mutex_lock(&rtk_prof.coex_mutex);
+ LIST_FOR_EACH_SAFELY(iter, temp, head)
+ {
+ desc = LIST_ENTRY(iter, tRTK_COEX_INFO, list);
+ delete_coex_from_hash(desc);
+ }
+ //ListInitializeHeader(head);
+ pthread_mutex_unlock(&rtk_prof.coex_mutex);
+}
+
static void rtk_cmd_complete_cback(void *p_mem)
{
if(p_mem)
bt_vendor_cbacks->dealloc(p_mem);
+ pthread_mutex_lock(&rtk_prof.coex_mutex);
+ RT_LIST_ENTRY* iter = ListGetTop(&(rtk_prof.coex_list));
+ tRTK_COEX_INFO* desc = NULL;
+ if (iter) {
+ desc = LIST_ENTRY(iter, tRTK_COEX_INFO, list);
+ if (desc)
+ {
+ ListDeleteNode(&desc->list);
+ }
+ }
+ else {
+ coex_cmd_send = false;
+ }
+ pthread_mutex_unlock(&rtk_prof.coex_mutex);
+
+ if(desc) {
+ ALOGE("%s, transmit_command Opcode:%x",__func__, desc->opcode);
+ bt_vendor_cbacks->xmit_cb(desc->opcode, desc->p_buf, rtk_cmd_complete_cback);
+ }
+
+ free(desc);
return;
}
void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* parameter)
{
- uint8_t temp = 0;
- HC_BT_HDR *p_buf=NULL;
+ //uint8_t temp = 0;
+ HC_BT_HDR *p_buf = NULL;
if(bt_vendor_cbacks)
p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + parameter_len);
}
if(bt_vendor_cbacks)
{
- ALOGE("transmit_command Opcode:%x",opcode);
+ RtkLogMsg("begin transmit_command Opcode:%x",opcode);
+ pthread_mutex_lock(&rtk_prof.coex_mutex);
+ if(!coex_cmd_send) {
+ coex_cmd_send = true;
+ pthread_mutex_unlock(&rtk_prof.coex_mutex);
bt_vendor_cbacks->xmit_cb(opcode, p_buf, rtk_cmd_complete_cback);
+ }
+ else {
+ tRTK_COEX_INFO* pcoex_info = NULL;
+ pcoex_info = malloc(sizeof(tRTK_COEX_INFO));
+ if (NULL == pcoex_info)
+ {
+ ALOGE("rtk_vendor_cmd_to_fw: allocate error");
+ return;
+ }
+
+ pcoex_info->p_buf = p_buf;
+ pcoex_info->opcode = opcode;
+
+ ListAddToTail(&(pcoex_info->list), &(rtk_prof.coex_list));
+ pthread_mutex_unlock(&rtk_prof.coex_mutex);
+ }
+
}
return ;
}
void packets_count(uint16_t handle, uint16_t scid, uint16_t length, uint8_t direction, uint8_t *user_data)
{
tRTK_PROF_INFO* prof_info = NULL;
- uint8_t profile_type;
+ //uint8_t profile_type;
tRTK_CONN_PROF* hci_conn = find_connection_by_handle(&rtk_prof, handle);
if(NULL == hci_conn)
static void timeout_handler(int signo, siginfo_t * info, void *context)
{
+ if(info == NULL)
+ {
+ RtkLogMsg("info null");
+ }
+ if(context == NULL)
+ {
+ RtkLogMsg("context null");
+ }
if (signo == TIMER_POLLING)
{
RtkLogMsg("polling timeout");
int udpsocket_recv(uint8_t *recv_msg, uint8_t *msg_size)
{
- struct hostent *hostp; /* client host info */
+ //struct hostent *hostp; /* client host info */
char buf[MAX_PAYLOAD]; /* message buf */
- char *hostaddrp; /* dotted decimal host addr string */
+ //char *hostaddrp; /* dotted decimal host addr string */
int n; /* message byte size */
struct sockaddr_in recv_addr;
socklen_t clientlen = sizeof(recv_addr);
static void rtk_handle_bt_coex_control(uint8_t* p)
{
uint8_t opcode = *p++;
+ uint8_t op_len = 0;
RtkLogMsg("receive bt coex control event from wifi, opration is 0x%x", opcode);
switch (opcode)
{
uint8_t opcode_len = *p++;
uint8_t value = *p++;
uint8_t temp_cmd[3];
+ op_len = opcode_len;
temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD;
temp_cmd[1] = 1;
temp_cmd[2] = value;
uint8_t opcode_len = *p++;
uint8_t value = *p++;
uint8_t temp_cmd[3];
+ op_len = opcode_len;
temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT;
temp_cmd[1] = 1;
temp_cmd[2] = value;
uint8_t opcode_len = *p++;
uint8_t power_decrease = *p++;
uint8_t temp_cmd[3];
+ op_len = opcode_len;
temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD;
temp_cmd[1] = 1;
temp_cmd[2] = power_decrease;
uint8_t opcode_len = *p++;
uint8_t psd_mode = *p++;
uint8_t temp_cmd[3];
+ op_len = opcode_len;
temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE;
temp_cmd[1] = 1;
temp_cmd[2] = psd_mode;
{
uint8_t opcode_len = *p++;
uint8_t temp_cmd[5];
+ op_len = opcode_len;
temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD;
temp_cmd[1] = 3;
memcpy(temp_cmd+2, p, 3);//wifi_state, wifi_centralchannel, chnnels_btnotuse
rtk_prof.piconet_id = *p++;
rtk_prof.mode = *p++;
uint8_t temp_cmd[4];
+ op_len = opcode_len;
temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L;
temp_cmd[1] = 2;
temp_cmd[2] = rtk_prof.piconet_id;
{
uint8_t opcode_len = *p++;
uint8_t access_type = *p++;
+ op_len = opcode_len;
if(access_type == 0) //read
{
uint8_t temp_cmd[7];
{
uint8_t *p = msg;
uint8_t event_code = *p++;
-
+ uint8_t total_length = 0;
if(memcmp(msg, invite_rsp, sizeof(invite_rsp)) == 0)
{
#if 0
if(event_code == 0xFE)
{
- uint8_t total_length = *p++;
+ total_length = *p++;
uint8_t extension_event = *p++;
switch(extension_event)
{
pthread_exit(0);
}
-static void udpsocket_receive_thread(void *arg)
+static void udpsocket_receive_thread()//(void *arg)
{
uint8_t msg_recv[MAX_PAYLOAD];
uint8_t recv_length;
actions.sa_flags = 0;
actions.sa_handler = udpsocket_receive_thread_exit_handler;
- int rc = sigaction(SIGUSR2,&actions,NULL);
+ sigaction(SIGUSR2,&actions,NULL);//int rc = sigaction(SIGUSR2,&actions,NULL);
RtkLogMsg("udpsocket_receive_thread started");
prctl(PR_SET_NAME, (unsigned long)"udpsocket_receive_thread", 0, 0, 0);
RtkLogMsg("rtk_profile_init, version: %s", RTK_VERSION);
pthread_mutex_init(&rtk_prof.profile_mutex, NULL);
+ pthread_mutex_init(&rtk_prof.coex_mutex, NULL);
pthread_mutex_init(&rtk_prof.udpsocket_mutex, NULL);
alloc_a2dp_packet_count_timer();
alloc_pan_packet_count_timer();
init_profile_hash(&rtk_prof);
init_connection_hash(&rtk_prof);
+ init_coex_hash(&rtk_prof);
create_udpsocket_socket();
}
flush_connection_hash(&rtk_prof);
flush_profile_hash(&rtk_prof);
pthread_mutex_destroy(&rtk_prof.profile_mutex);
+ flush_coex_hash(&rtk_prof);
+ pthread_mutex_destroy(&rtk_prof.coex_mutex);
stop_udpsocket_receive_thread();
pthread_mutex_destroy(&rtk_prof.udpsocket_mutex);
rtk_handle_vender_mailbox_cmp_evt(p, len);
break;
+ case HCI_SET_EVENT_MASK:
+ Heartbeat_init();
+ break;
+
case HCI_VENDOR_ADD_BITPOOL_FW:
status = *p++;
RtkLogMsg("received cmd complete event for HCI_VENDOR_ADD_BITPOOL_FW status:%d",status);
}
}
-static void rtk_handle_le_connection_complete_evt(uint8_t* p)
+static void rtk_handle_le_connection_complete_evt(uint8_t* p, bool enhanced)
{
uint16_t handle, interval;
uint8_t status;
status = *p++;
STREAM_TO_UINT16 (handle, p);
p += 8; //role, address type, address
+ if(enhanced) {
+ p += 12;
+ }
STREAM_TO_UINT16 (interval, p);
if(status == 0) {
uint8_t sub_event = *p++;
switch (sub_event) {
case HCI_BLE_CONN_COMPLETE_EVT:
- rtk_handle_le_connection_complete_evt(p);
+ rtk_handle_le_connection_complete_evt(p, false);
+ break;
+ case HCI_BLE_ENHANCED_CONN_COMPLETE_EVT:
+ rtk_handle_le_connection_complete_evt(p, true);
break;
-
case HCI_BLE_LL_CONN_PARAM_UPD_EVT:
rtk_handle_le_connection_update_complete_evt(p);
break;
void rtk_add_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map)
{
RtkLogMsg("rtk_add_le_profile, handle is %x, profile_map is %x", handle, profile_map);
-
+ RtkLogMsg("bdaddr[0] = %d", bdaddr[0]);
tRTK_CONN_PROF* hci_conn = find_connection_by_handle(&rtk_prof, handle);
if(hci_conn)
{
void rtk_delete_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map)
{
RtkLogMsg("rtk_delete_le_profile, handle is %x, profile_map is %x", handle, profile_map);
-
+ RtkLogMsg("bdaddr[0] = %d", bdaddr[0]);
pthread_mutex_lock(&rtk_prof.profile_mutex);
tRTK_CONN_PROF* hci_conn = find_connection_by_handle(&rtk_prof, handle);
if(hci_conn == NULL)
}
}
-static const rtk_parse_manager_t parse_interface = {
+static rtk_parse_manager_t parse_interface = {
rtk_parse_internal_event_intercept,
rtk_parse_l2cap_data,
rtk_parse_init,
rtk_add_le_data_count,
};
-const rtk_parse_manager_t *rtk_parse_manager_get_interface() {
+rtk_parse_manager_t *rtk_parse_manager_get_interface() {
return &parse_interface;
}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014-2016 Realtek Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: poll.c
+ *
+ * Description: Contains host & controller handshake implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_poll"
+
+#include <utils/Log.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+#include "bt_hci_bdroid.h"
+//#include "bt_utils.h"
+#include "rtk_poll.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+#ifndef BTPOLL_DBG
+#define BTPOLL_DBG false
+#endif
+
+#if (BTPOLL_DBG == true)
+#define BTPOLLDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
+#else
+#define BTPOLLDBG(param, ...) {}
+#endif
+
+#ifndef ENABLE_BT_POLL_IN_ACTIVE_MODE
+#define ENABLE_BT_POLL_IN_ACTIVE_MODE false
+#endif
+
+#ifndef DEFAULT_POLL_IDLE_TIMEOUT
+#define DEFAULT_POLL_IDLE_TIMEOUT 2500
+#endif
+
+volatile uint32_t rtkbt_heartbeat_noack_num = 0;
+volatile uint32_t rtkbt_heartbeat_evt_seqno = 0xffffffff;
+
+timed_out poll_idle_timeout;
+
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/* Poll state */
+enum {
+ POLL_DISABLED = 0, /* initial state */
+ POLL_ENABLED,
+};
+
+/* poll control block */
+typedef struct
+{
+ uint8_t state; /* poll state */
+ uint8_t timer_created;
+ timer_t timer_id;
+ uint32_t timeout_ms;
+} bt_poll_cb_t;
+
+extern int timer_create(clockid_t clockid, struct sigevent *sevp,
+ timer_t *timerid);
+extern int timer_delete(timer_t timerid);
+
+int timer_settime(timer_t timerid, int flags,
+ const struct itimerspec *new_value,
+ struct itimerspec * old_value);
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static bt_poll_cb_t bt_poll_cb;
+
+/******************************************************************************
+** Poll Static Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function poll_timer_stop
+**
+** Description stop timer if allowed
+**
+** Returns None
+**
+*******************************************************************************/
+static void poll_timer_stop(void)
+{
+ int status;
+ struct itimerspec ts;
+
+ ALOGI("poll_timer_stop: timer_created %d", bt_poll_cb.timer_created);
+
+ if (bt_poll_cb.timer_created == true) {
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ status = timer_settime(bt_poll_cb.timer_id, 0, &ts, 0);
+ if (status == -1)
+ ALOGE("[STOP] Failed to set poll idle timeout");
+ }
+}
+
+/*****************************************************************************
+** POLL Interface Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function poll_init
+**
+** Description Init bt poll
+**
+** Returns None
+**
+*******************************************************************************/
+void poll_init(timed_out ptr_timeout,uint32_t timeout)
+{
+ memset((void*)&bt_poll_cb, 0, sizeof(bt_poll_cb_t));
+ poll_idle_timeout = ptr_timeout;
+ bt_poll_cb.state = POLL_DISABLED;
+ bt_poll_cb.timeout_ms = timeout;
+
+ ALOGI("poll_init: state %d, timeout %d ms,timeout=%d", bt_poll_cb.state, bt_poll_cb.timeout_ms,timeout);
+}
+
+/*******************************************************************************
+**
+** Function poll_cleanup
+**
+** Description Poll clean up
+**
+** Returns None
+**
+*******************************************************************************/
+void poll_cleanup(void)
+{
+ ALOGI("poll_cleanup: timer_created %d", bt_poll_cb.timer_created);
+
+ if (bt_poll_cb.timer_created == true) {
+ timer_delete(bt_poll_cb.timer_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function poll_enable
+**
+** Description Enalbe/Disable poll
+**
+** Returns None
+**
+*******************************************************************************/
+void poll_enable(uint8_t turn_on)
+{
+ ALOGI("poll_enable: turn_on %d, state %d", turn_on, bt_poll_cb.state);
+
+ if ((turn_on == true) && (bt_poll_cb.state == POLL_ENABLED)) {
+ ALOGI("poll_enable: poll is already on!!!");
+ return;
+ } else if ((turn_on == false) && (bt_poll_cb.state == POLL_DISABLED)) {
+ ALOGI("poll_enable: poll is already off!!!");
+ return;
+ }
+
+ if (turn_on == false) {
+ poll_timer_stop();
+ bt_poll_cb.state = POLL_DISABLED;
+ } else {
+ /* start poll timer when poll_timer_flush invoked first time */
+ bt_poll_cb.state = POLL_ENABLED;
+ }
+}
+
+/*******************************************************************************
+**
+** Function poll_timer_flush
+**
+** Description Called to delay notifying Bluetooth chip.
+** Normally this is called when there is data to be sent
+** over HCI.
+**
+** Returns None
+**
+*******************************************************************************/
+void poll_timer_flush(void)
+{
+ int status;
+ struct itimerspec ts;
+ struct sigevent se;
+
+ BTPOLLDBG("poll_timer_flush: state %d", bt_poll_cb.state);
+
+ if (bt_poll_cb.state != POLL_ENABLED)
+ return;
+
+ if (bt_poll_cb.timer_created == false) {
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_value.sival_ptr = &bt_poll_cb.timer_id;
+ se.sigev_notify_function = poll_idle_timeout;
+ se.sigev_notify_attributes = NULL;
+
+ status = timer_create(CLOCK_MONOTONIC, &se, &bt_poll_cb.timer_id);
+
+ if (status == 0)
+ bt_poll_cb.timer_created = true;
+ }
+#if (defined(ENABLE_BT_POLL_IN_ACTIVE_MODE) && (ENABLE_BT_POLL_IN_ACTIVE_MODE == false))
+ if (bt_poll_cb.timer_created == true) {
+ ts.it_value.tv_sec = bt_poll_cb.timeout_ms / 1000;
+ ts.it_value.tv_nsec = 1000 * 1000 * (bt_poll_cb.timeout_ms % 1000);
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ status = timer_settime(bt_poll_cb.timer_id, 0, &ts, 0);
+ if (status == -1)
+ ALOGE("[Flush] Failed to set poll idle timeout");
+ }
+#endif
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Realtek Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: userial_vendor.c
+ *
+ * Description: Contains vendor-specific userial functions
+ *
+ ******************************************************************************/
+#undef NDEBUG
+#define LOG_TAG "rtk_socket"
+
+#include <utils/Log.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include "userial.h"
+#include "userial_vendor.h"
+#include "rtk_socket.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+/******************************************************************************
+** Extern functions
+******************************************************************************/
+
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+
+/******************************************************************************
+** functions
+******************************************************************************/
+uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len)
+{
+ int n_read = 0;
+ struct pollfd pfd;
+
+ if (fd == -1)
+ {
+ return 0;
+ }
+
+ while (n_read < (int)len)
+ {
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP;
+
+ /* make sure there is data prior to attempting read to avoid blocking
+ a read for more than poll timeout */
+
+ int poll_ret;
+ RTK_NO_INTR(poll_ret = poll(&pfd, 1, 100));
+ if (poll_ret == 0)
+ {
+ continue;
+ }
+ if (poll_ret < 0) {
+ ALOGE("%s(): poll() failed: return %d errno %d (%s)",
+ __func__, poll_ret, errno, strerror(errno));
+ break;
+ }
+
+ if (pfd.revents & (POLLHUP|POLLNVAL) )
+ {
+ return 0;
+ }
+
+ ssize_t n;
+ RTK_NO_INTR(n = recv(fd, p_buf + n_read, len - n_read, 0));
+
+ if (n == 0)
+ {
+ ALOGE("Skt_Read : channel detached remotely");
+ return 0;
+ }
+
+ if (n < 0)
+ {
+ ALOGE("Skt_Read : read failed (%s)", strerror(errno));
+ return 0;
+ }
+
+ n_read += n;
+
+ }
+
+ return n_read;
+}
+
+int Skt_Read_noblock(int fd, uint8_t *p_buf, uint32_t len)
+{
+ int n_read = 0;
+ struct pollfd pfd;
+
+ if (fd == -1)
+ {
+ ALOGE("UIPC_Read_noblock closed");
+ return 0;
+ }
+
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP;
+
+ if (poll(&pfd, 1, 0) == 0)
+ {
+ return 0;
+ }
+
+ if (pfd.revents & (POLLHUP|POLLNVAL) )
+ {
+ return 0;
+ }
+
+ n_read = recv(fd, p_buf, len, MSG_DONTWAIT|MSG_NOSIGNAL);
+
+ return n_read;
+}
+
+bool Skt_Send(int fd, uint8_t *p_buf, uint16_t msglen)
+{
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(fd, p_buf, msglen));
+ if (ret < 0) {
+ ALOGE("failed to write (%s)", strerror(errno));
+ }
+
+ return false;
+}
+
+int Skt_Send_noblock(int fd, uint8_t *p_buf, uint16_t msglen)
+{
+ int res = 0;
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = POLLOUT|POLLHUP;
+ if (poll(&pfd, 1, 0) == 0)
+ {
+ return 0;
+ }
+
+ if (pfd.revents & (POLLHUP|POLLNVAL) )
+ {
+ ALOGE("poll : channel detached remotely");
+ return 0;
+ }
+
+ res = send(fd, p_buf, msglen, MSG_DONTWAIT);
+ if (res < 0)
+ {
+ ALOGE("failed to write (%s)", strerror(errno));
+ }
+
+ return res;
+}
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+/*****************************************************************************
+** Helper Functions
+*****************************************************************************/
+
+
** Returns None
**
*******************************************************************************/
-void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
+void upio_set(uint8_t pio, uint8_t action)//(uint8_t pio, uint8_t action, uint8_t polarity)
{
- int rc;
+ //int rc;
#if (BT_WAKE_VIA_PROC == TRUE)
int fd = -1;
char buffer;
#include <sys/eventfd.h>
#include "userial.h"
#include "userial_vendor.h"
+#include "rtk_socket.h"
-#define RTK_SINGLE_CMD_EVENT
+#ifdef CONFIG_SCO_OVER_HCI
+#include "sbc.h"
+#endif
/******************************************************************************
** Constants & Macros
******************************************************************************/
** Extern functions
******************************************************************************/
extern char rtkbt_transtype;
+extern void Heartbeat_cleanup();
/******************************************************************************
** Local type definitions
RTB_QUEUE_HEAD *recv_data;
RTB_QUEUE_HEAD *send_data;
RTB_QUEUE_HEAD *data_order;
+ volatile bool btdriver_state;
} vnd_userial_cb_t;
-#define RTK_NO_INTR(fn) do {} while ((fn) == -1 && errno == EINTR)
+#ifdef CONFIG_SCO_OVER_HCI
+uint16_t btui_msbc_h2[] = {0x0801,0x3801,0xc801,0xf801};
+typedef struct
+{
+ pthread_mutex_t sco_mutex;
+ pthread_cond_t sco_cond;
+ pthread_t thread_socket_sco_id;
+ pthread_t thread_recv_sco_id;
+ pthread_t thread_send_sco_id;
+ uint16_t sco_handle;
+ bool thread_sco_running;
+ uint16_t voice_settings;
+ RTB_QUEUE_HEAD *recv_sco_data;
+ RTB_QUEUE_HEAD *send_sco_data;
+ unsigned char enc_data[480];
+ unsigned int current_pos;
+ uint16_t sco_packet_len;
+ bool msbc_used;
+ int ctrl_fd, data_fd;
+ sbc_t sbc_dec, sbc_enc;
+ uint32_t pcm_enc_seq;
+}sco_cb_t;
+#endif
/******************************************************************************
** Static functions
******************************************************************************/
static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length);
static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) ;
-
+extern void RTK_btservice_destroyed();
/******************************************************************************
** Static variables
******************************************************************************/
+#ifdef CONFIG_SCO_OVER_HCI
+static sco_cb_t sco_cb;
+#endif
static vnd_userial_cb_t vnd_userial;
static const hci_h5_t* h5_int_interface;
static int packet_recv_state = RTKBT_PACKET_IDLE;
static unsigned char coex_resvered_buffer[2048] = {0};
static int coex_resvered_length = 0;
-#ifdef RTK_SINGLE_CMD_EVENT
-static int cmd_packet_recv_state = RTKBT_PACKET_IDLE;
-static int cmd_packet_bytes_need = 0;
-static serial_data_type_t cmd_current_type = 0;
-static unsigned char cmd_resvered_header[10] = {0};
-static int cmd_resvered_length = 0;
+#ifdef RTK_HANDLE_EVENT
+static int received_packet_state = RTKBT_PACKET_IDLE;
+static int received_packet_bytes_need = 0;
+static serial_data_type_t recv_packet_current_type = 0;
+static unsigned char received_resvered_header[2048] = {0};
+static int received_resvered_length = 0;
#endif
static rtk_parse_manager_t * rtk_parse_manager = NULL;
.h5_data_ready_cb = h5_data_ready_cb,
};
+static const uint8_t hci_preamble_sizes[] = {
+ COMMAND_PREAMBLE_SIZE,
+ ACL_PREAMBLE_SIZE,
+ SCO_PREAMBLE_SIZE,
+ EVENT_PREAMBLE_SIZE
+};
+
/*****************************************************************************
** Helper Functions
*****************************************************************************/
vnd_userial.data_order = RtbQueueInit();
vnd_userial.recv_data = RtbQueueInit();
vnd_userial.send_data = RtbQueueInit();
+#ifdef CONFIG_SCO_OVER_HCI
+ sco_cb.recv_sco_data = RtbQueueInit();
+ sco_cb.send_sco_data = RtbQueueInit();
+ pthread_mutex_init(&sco_cb.sco_mutex, NULL);
+ pthread_cond_init(&sco_cb.sco_cond, NULL);
+ memset(&sco_cb.sbc_enc, 0, sizeof(sbc_t));
+ sbc_init(&sco_cb.sbc_enc);//sbc_init(&sco_cb.sbc_enc, 0);
+ memset(&sco_cb.sbc_dec, 0, sizeof(sbc_t));
+ sbc_init(&sco_cb.sbc_dec);//sbc_init(&sco_cb.sbc_enc, 0);
+#endif
}
userial_ioctl_init_bt_wake(vnd_userial.fd);
#endif
+ vnd_userial.btdriver_state = true;
ALOGI("device fd = %d open", vnd_userial.fd);
return vnd_userial.fd;
*******************************************************************************/
void userial_vendor_close(void)
{
- int result;
-
+ //int result;
+ RTK_btservice_destroyed();
if (vnd_userial.fd == -1)
return;
+ if((rtkbt_transtype & RTKBT_TRANS_UART) && (rtkbt_transtype & RTKBT_TRANS_H5)) {
+#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
+ /* de-assert bt_wake BEFORE closing port */
+ ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
+#endif
+ h5_int_interface->h5_int_cleanup();
+ }
vnd_userial.thread_running = false;
userial_socket_close();
userial_uart_close();
userial_coex_close();
+ Heartbeat_cleanup();
vnd_userial.fd = -1;
+ vnd_userial.btdriver_state = false;
if(rtk_parse_manager) {
rtk_parse_manager->rtk_parse_cleanup();
}
rtk_parse_manager = NULL;
-
-
- if((rtkbt_transtype & RTKBT_TRANS_UART) && (rtkbt_transtype & RTKBT_TRANS_H5)) {
-#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
- /* de-assert bt_wake BEFORE closing port */
- ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
+#ifdef CONFIG_SCO_OVER_HCI
+ sbc_finish(&sco_cb.sbc_enc);
+ sbc_finish(&sco_cb.sbc_dec);
#endif
- h5_int_interface->h5_int_cleanup();
-
- }
}
/*******************************************************************************
*******************************************************************************/
void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data)
{
+ if(p_data == NULL)
+ {
+ VNDUSERIALDBG("p_data is null");
+ }
switch(op)
{
#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
*******************************************************************************/
int userial_set_port(char *p_conf_name, char *p_conf_value, int param)
{
+ if(p_conf_name == NULL || param == 0)
+ {
+ VNDUSERIALDBG("p_conf_name is null");
+ }
strcpy(vnd_userial.port_name, p_conf_value);
return 0;
uint16_t length = total_length;
uint16_t transmitted_length = 0;
- while (length > 0) {
+ while (length > 0 && vnd_userial.btdriver_state) {
ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
switch (ret) {
case -1:
case 0:
// If we wrote nothing, don't loop more because we
// can't go to infinity or beyond, ohterwise H5 can resend data
- ALOGE("%s, ret %d", __func__, ret);
+ ALOGE("%s, ret %zd", __func__, ret);
goto done;
default:
transmitted_length += ret;
free(p_buf);
}
-static void userial_coex_handler(void *context)
+static void userial_coex_handler()//(void *context)
{
RTK_BUFFER* skb_data;
RTK_BUFFER* skb_type;
eventfd_t value;
- int read_length = 0;
+ unsigned int read_length = 0;
eventfd_read(vnd_userial.event_fd, &value);
if(!value && !vnd_userial.thread_running) {
return;
}
}
-static void userial_recv_H4_rawdata(void *context)
+#ifdef CONFIG_SCO_OVER_HCI
+//receive sco encode data over hci, we need to decode msbc data to pcm, and send it to sco audio hal
+static void* userial_recv_sco_thread()//(void *arg)
+{
+ RTK_BUFFER* skb_sco_data;
+ unsigned char dec_data[480];
+ unsigned char pcm_data[960];
+ int index = 0;
+ //uint16_t sco_packet_len = 60;
+ uint8_t * p_data = NULL;
+ int res = 0, writen = 0;
+ prctl(PR_SET_NAME, (unsigned long)"userial_recv_sco_thread", 0, 0, 0);
+ /*
+ FILE *file;
+ unsigned char enc_data[60];
+ file = fopen("/data/misc/bluedroid/sco_capture.raw", "rb");
+ FILE *file2;
+ file2 = fopen("/data/misc/bluedroid/sco_capture.pcm", "wb");
+ if (!file) {
+ ALOGE("Unable to create file");
+ return NULL;
+ }
+ */
+ RtbEmptyQueue(sco_cb.recv_sco_data);
+ ALOGE("userial_recv_sco_thread start");
+ while(sco_cb.thread_sco_running) {
+ pthread_mutex_lock(&sco_cb.sco_mutex);
+ while(RtbQueueIsEmpty(sco_cb.recv_sco_data) && sco_cb.thread_sco_running) {
+ pthread_cond_wait(&sco_cb.sco_cond, &sco_cb.sco_mutex);
+ }
+ pthread_mutex_unlock(&sco_cb.sco_mutex);
+ skb_sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
+ if(!skb_sco_data)
+ continue;
+ p_data = skb_sco_data->Data;
+ //if (fwrite(skb_sco_data->Data, 1, 60, file) != 60) {
+ //ALOGE("Error capturing sample");
+ //}
+ /*
+ if(fread(enc_data, 1, 60, file) > 0) {
+ ALOGE("userial_recv_sco_thread, fread data");
+ res = sbc_decode(&sco_cb.sbc_dec, &enc_data[2], 58, dec_data, 240, &writen);
+ }
+ else {
+ fseek(file, 0L, SEEK_SET);
+ if(fread(enc_data, 1, 60, file) > 0) {
+ res = sbc_decode(&sco_cb.sbc_dec, &enc_data[2], 58, dec_data, 240, &writen);
+ }
+ }
+ */
+ res = sbc_decode(&sco_cb.sbc_dec, (p_data+2), 58, dec_data, 240, &writen);
+ if(res > 0) {
+ memcpy(&pcm_data[240 * index], dec_data, 240);
+ //if (fwrite(dec_data, 240, 1, file2) != 240) {
+ //ALOGE("Error capturing sample");
+ //}
+ index = (index + 1) % 4;
+ if(index == 0) {
+ Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+ }
+ }
+ else {
+ ALOGE("msbc decode fail!");
+ }
+ RtbFree(skb_sco_data);
+ }
+ ALOGE("userial_recv_sco_thread exit");
+ RtbEmptyQueue(sco_cb.recv_sco_data);
+ return NULL;
+}
+
+static void* userial_send_sco_thread()//(void *arg)
+{
+ unsigned char enc_data[240];
+ unsigned char pcm_data[960];
+ unsigned char send_data[100];
+ int writen = 0;
+ int num_read;
+ prctl(PR_SET_NAME, (unsigned long)"userial_send_sco_thread", 0, 0, 0);
+ sco_cb.pcm_enc_seq = 0;
+ int i;
+
+ /*
+ FILE *file;
+ file = fopen("/data/misc/bluedroid/sco_playback.raw", "rb");
+ if (!file) {
+ ALOGE("Unable to create file");
+ return NULL;
+ }
+ */
+ ALOGE("userial_send_sco_thread start");
+ while(sco_cb.thread_sco_running) {
+ num_read = Skt_Read(sco_cb.data_fd, pcm_data, 960 * 2);
+ /*
+ for(i = 0; i < 5; i ++) {
+ if(fread(&enc_data[4], 1, 48, file) > 0) {
+ enc_data[0] = DATA_TYPE_SCO;
+ enc_data[3] = 48;
+ *(uint16_t *)&enc_data[1] = sco_cb.sco_handle;
+ h4_int_transmit_data(enc_data, 52);
+ }
+ else {
+ fseek(file, 0L, SEEK_SET);
+ }
+ }
+ userial_enqueue_coex_rawdata(enc_data,52, false);
+ //usleep(7500);
+ continue;
+ */
+ for(i = 0; i < 4; i++) {
+ if(sbc_encode(&sco_cb.sbc_enc, &pcm_data[240*i], 240, &enc_data[i*60 +2], 58, &writen) <= 0) {
+ ALOGE("sbc encode error!");
+ }
+ else {
+ *(uint16_t*)(&(enc_data[i*60])) = btui_msbc_h2[sco_cb.pcm_enc_seq % 4];
+ sco_cb.pcm_enc_seq++;
+ enc_data[i*60 + 59] = 0x00; //padding
+ }
+ }
+ for(i = 0; i < 5; i++) {
+ send_data[0] = DATA_TYPE_SCO;
+ send_data[3] = 48;
+ *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+ memcpy(&send_data[4], &enc_data[i*48], 48);
+ h4_int_transmit_data(send_data, 52);
+ userial_enqueue_coex_rawdata(enc_data, 52, false);
+ }
+ }
+ ALOGE("userial_send_sco_thread exit");
+ return NULL;
+}
+
+static void userial_sco_socket_stop()
+{
+ sco_cb.thread_sco_running = false;
+ pthread_mutex_lock(&sco_cb.sco_mutex);
+ pthread_cond_signal(&sco_cb.sco_cond);
+ pthread_mutex_unlock(&sco_cb.sco_mutex);
+ pthread_join(sco_cb.thread_socket_sco_id, NULL);
+ pthread_join(sco_cb.thread_recv_sco_id, NULL);
+ pthread_join(sco_cb.thread_send_sco_id, NULL);
+}
+
+static void userial_sco_ctrl_skt_handle()
+{
+ uint8_t cmd = 0, ack = 0;;
+ int result = Skt_Read(sco_cb.ctrl_fd, &cmd, 1);
+
+ if(result == 0) {
+ userial_sco_socket_stop();
+ return;
+ }
+
+ ALOGE("%s, cmd = %d, msbc_used = %d", __func__, cmd, sco_cb.msbc_used);
+ switch (cmd) {
+ case SCO_CTRL_CMD_CHECK_READY:
+
+ break;
+
+ case SCO_CTRL_CMD_OUT_START:
+ {
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ if(pthread_create(&sco_cb.thread_send_sco_id, &thread_attr, userial_send_sco_thread, NULL)!= 0 )
+ {
+ ALOGE("pthread_create : %s", strerror(errno));
+ }
+ }
+ break;
+
+ case SCO_CTRL_CMD_IN_START:
+ {
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ if(pthread_create(&sco_cb.thread_recv_sco_id, &thread_attr, userial_recv_sco_thread, NULL)!= 0 )
+ {
+ ALOGE("pthread_create : %s", strerror(errno));
+ }
+ }
+ break;
+
+ case SCO_CTRL_CMD_OUT_STOP:
+
+ break;
+
+ case SCO_CTRL_CMD_SUSPEND:
+
+ break;
+
+ case SCO_CTRL_GET_AUDIO_CONFIG:
+ if(sco_cb.msbc_used) {
+ ack = 2;
+ Skt_Send(sco_cb.ctrl_fd, &ack, 1);
+ }
+ else {
+ ack = 1;
+ Skt_Send(sco_cb.ctrl_fd, &ack, 1);
+ }
+ break;
+
+ default:
+
+ break;
+ }
+}
+
+static void* userial_socket_sco_thread()//(void *arg)
+{
+ struct sockaddr_un addr, remote;
+ socklen_t alen, len = sizeof(struct sockaddr_un);
+ fd_set read_set, active_set;
+ int result, max_fd;
+ int s_ctrl = socket(AF_LOCAL, SOCK_STREAM, 0);
+ int s_data = socket(AF_LOCAL, SOCK_STREAM, 0);
+ prctl(PR_SET_NAME, (unsigned long)"userial_socket_sco_thread", 0, 0, 0);
+
+ //bind sco ctrl socket
+ unlink(SCO_CTRL_PATH);
+ memset(&addr, 0, sizeof(addr));
+ strcpy(addr.sun_path, SCO_CTRL_PATH);
+ addr.sun_family = AF_LOCAL;
+ alen = strlen(addr.sun_path) + offsetof(struct sockaddr_un, sun_path);
+ if (bind(s_ctrl, (struct sockaddr *)&addr, alen) < 0) {
+ ALOGE("userial_socket_sco_thread, bind ctrl socket error : %s", strerror(errno));
+ return NULL;
+ }
+
+ if(listen(s_ctrl, 5) < 0) {
+ ALOGE("userial_socket_sco_thread, listen ctrl socket error : %s", strerror(errno));
+ return NULL;
+ }
+
+ chmod(SCO_CTRL_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ //bind sco data socket
+ unlink(SCO_DATA_PATH);
+ memset(&addr, 0, sizeof(addr));
+ strcpy(addr.sun_path, SCO_DATA_PATH);
+ addr.sun_family = AF_LOCAL;
+ alen = strlen(addr.sun_path) + offsetof(struct sockaddr_un, sun_path);
+ if (bind(s_data, (struct sockaddr *)&addr, alen) < 0) {
+ ALOGE("userial_socket_sco_thread, bind data socket error : %s", strerror(errno));
+ return NULL;
+ }
+
+ if(listen(s_data, 5) < 0) {
+ ALOGE("userial_socket_sco_thread, listen data socket error : %s", strerror(errno));
+ return NULL;
+ }
+ chmod(SCO_DATA_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+ ALOGE("userial_socket_sco_thread");
+ FD_ZERO(&read_set);
+ FD_ZERO(&active_set);
+ FD_SET(s_ctrl, &active_set);
+ FD_SET(s_data, &active_set);
+ max_fd = (MAX(s_ctrl, s_data)) + 1;
+
+ while(sco_cb.thread_sco_running) {
+ read_set = active_set;
+ result = select(max_fd, &read_set, NULL, NULL, NULL);
+ if (result == 0) {
+ ALOGE("select timeout");
+ continue;
+ }
+ if (result < 0) {
+ if (errno != EINTR)
+ ALOGE("select failed %s", strerror(errno));
+ continue;
+ }
+ if(FD_ISSET(s_ctrl, &read_set)) {
+ RTK_NO_INTR(sco_cb.ctrl_fd = accept(s_ctrl, (struct sockaddr *)&remote, &len));
+ if (sco_cb.ctrl_fd == -1) {
+ ALOGE("sock accept failed (%s)", strerror(errno));
+ return NULL;
+ }
+ const int size = (512);
+ setsockopt(sco_cb.ctrl_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+ FD_SET(sco_cb.ctrl_fd, &active_set);
+ max_fd = (MAX(max_fd, sco_cb.ctrl_fd)) + 1;
+ }
+
+ if(FD_ISSET(s_data, &read_set)) {
+ RTK_NO_INTR(sco_cb.data_fd = accept(s_data, (struct sockaddr *)&remote, &len));
+ if (sco_cb.data_fd == -1) {
+ ALOGE("sock accept failed (%s)", strerror(errno));
+ return NULL;
+ }
+ const int size = (30 * 960);
+ int ret = setsockopt(sco_cb.data_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+ ret = setsockopt(sco_cb.data_fd, SOL_SOCKET, SO_SNDBUF, (char*)&size, (int)sizeof(size));
+ }
+
+ if(FD_ISSET(sco_cb.ctrl_fd, &read_set)) {
+ userial_sco_ctrl_skt_handle();
+ }
+ }
+ close(s_ctrl);
+ close(s_data);
+ return NULL;
+}
+
+#endif
+
+#ifdef RTK_HANDLE_CMD
+static void userial_handle_cmd(unsigned char * recv_buffer, int total_length)
+{
+ uint16_t opcode = *(uint16_t*)recv_buffer;
+ uint16_t scan_int, scan_win;
+ static uint16_t voice_settings;
+ if(total_length == 0)
+ {
+ ALOGE("total_length = %d", total_length);
+ }
+ ALOGE("opcode = 0x%x",opcode);
+ switch (opcode) {
+ case HCI_BLE_WRITE_SCAN_PARAMS :
+ scan_int = *(uint16_t*)&recv_buffer[4];
+ scan_win = *(uint16_t*)&recv_buffer[6];
+ ALOGE("scan_int = %d, scan_win = %d",scan_int,scan_win);
+ if(scan_win > 0x10){
+ *(uint16_t*)&recv_buffer[4] = (scan_int * 0x10) / scan_win;
+ *(uint16_t*)&recv_buffer[6] = 0x10;
+ }
+ break;
+
+
+ case HCI_WRITE_VOICE_SETTINGS :
+ voice_settings = *(uint16_t*)&recv_buffer[3];
+ userial_vendor_usb_ioctl(SET_ISO_CFG, &voice_settings);
+#ifdef CONFIG_SCO_OVER_HCI
+ sco_cb.voice_settings = voice_settings;
+#endif
+ break;
+#ifdef CONFIG_SCO_OVER_HCI
+ case HCI_SETUP_ESCO_CONNECTION :
+ sco_cb.voice_settings = *(uint16_t*)&recv_buffer[15];
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ sco_cb.thread_sco_running = true;
+ if(pthread_create(&sco_cb.thread_socket_sco_id, &thread_attr, userial_socket_sco_thread, NULL)!= 0 )
+ {
+ ALOGE("pthread_create : %s", strerror(errno));
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+}
+#endif
+
+
+//This recv data from bt process. The data type only have ACL/SCO/COMMAND
+// direction BT HOST ----> CONTROLLER
+static void userial_recv_H4_rawdata()//(void *context)
{
serial_data_type_t type = 0;
ssize_t bytes_read;
uint16_t opcode;
uint16_t transmitted_length = 0;
- unsigned char *buffer = NULL;
+ //unsigned char *buffer = NULL;
switch (packet_recv_state) {
case RTKBT_PACKET_IDLE:
ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
return;
}
- assert((type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO));
+
if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
ALOGE("%s invalid data type: %d", __func__, type);
+ assert((type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO));
}
else {
packet_bytes_need -= bytes_read;
//fall through
case RTKBT_PACKET_TYPE:
- if(current_type == DATA_TYPE_ACL) {
- packet_bytes_need = 4;
- }
- else {
- packet_bytes_need = 3;
- }
+ packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(current_type)];
h4_read_length = 0;
packet_recv_state = RTKBT_PACKET_HEADER;
//fall through
return;
}
if(!bytes_read && packet_bytes_need) {
- ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
+ ALOGE("%s, state = %d, bytes_read 0, type : %d", __func__, packet_recv_state, current_type);
return;
}
packet_bytes_need -= bytes_read;
packet_recv_state = RTKBT_PACKET_CONTENT;
if(current_type == DATA_TYPE_ACL) {
- packet_bytes_need = *(uint16_t *)&h4_read_buffer[3];
+ packet_bytes_need = *(uint16_t *)&h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
+ } else if(current_type == DATA_TYPE_EVENT) {
+ packet_bytes_need = h4_read_buffer[EVENT_DATA_LENGTH_INDEX];
} else {
- packet_bytes_need = h4_read_buffer[3];
+ packet_bytes_need = h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
}
//fall through
case RTKBT_PACKET_END:
switch (current_type) {
case DATA_TYPE_COMMAND:
+#ifdef RTK_HANDLE_CMD
+ userial_handle_cmd(&h4_read_buffer[1], h4_read_length);
+#endif
if(rtkbt_transtype & RTKBT_TRANS_H4) {
h4_int_transmit_data(h4_read_buffer, (h4_read_length + 1));
}
- else {
+ else {
opcode = *(uint16_t *)&h4_read_buffer[1];
if(opcode == HCI_VSC_H5_INIT) {
h5_int_interface->h5_send_sync_cmd(opcode, NULL, h4_read_length);
}
uint16_t transmitted_length = 0;
- while (length > 0) {
+ while (length > 0 && vnd_userial.btdriver_state) {
ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
switch (ret) {
case -1:
case 0:
// If we wrote nothing, don't loop more because we
// can't go to infinity or beyond, ohterwise H5 can resend data
- ALOGE("%s, ret %d", __func__, ret);
+ ALOGE("%s, ret %zd", __func__, ret);
goto done;
default:
transmitted_length += ret;
}
-static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length)
+#ifdef RTK_HANDLE_EVENT
+static void userial_handle_event(unsigned char * recv_buffer, int total_length)
{
- unsigned char buffer[1028] = {0};
- unsigned length = 0;
- length = h5_int_interface->h5_int_read_data(&buffer[1], total_length);
- buffer[0] = type;
- length++;
- uint16_t transmitted_length = 0;
- while (length > 0) {
- ssize_t ret;
- RTK_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
- switch (ret) {
- case -1:
- ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
- goto done;
- case 0:
- // If we wrote nothing, don't loop more because we
- // can't go to infinity or beyond
- goto done;
- default:
- transmitted_length += ret;
- length -= ret;
- break;
+ uint8_t event;
+ uint8_t *p_data = recv_buffer;
+ event = p_data[0];
+ if(total_length == 0)
+ {
+ ALOGD("total_length %d",total_length);
+ }
+#ifdef CONFIG_SCO_OVER_HCI
+ if(event == HCI_ESCO_CONNECTION_COMP_EVT) {
+ if(p_data[2] != 0) {
+ sco_cb.thread_sco_running = false;
+ pthread_join(sco_cb.thread_recv_sco_id, NULL);
+ pthread_join(sco_cb.thread_send_sco_id, NULL);
}
+ else {
+ sco_cb.sco_handle = *((uint16_t *)&p_data[3]);
+ if(!(sco_cb.voice_settings & 0x0003)) {
+ sco_cb.sco_packet_len = 240;
+ sco_cb.msbc_used = false;
+ }
+ else {
+ sco_cb.sco_packet_len = 60;
+ sco_cb.msbc_used = true;
+ }
+ sco_cb.current_pos = 0;
+ }
+
+ ALOGE("userial_handle_event sco_handle: %d",sco_cb.sco_handle);
}
-done:;
- return;
+ if(event == HCI_DISCONNECTION_COMP_EVT) {
+ if((*((uint16_t *)&p_data[3])) == sco_cb.sco_handle) {
+ sco_cb.sco_handle = 0;
+ sco_cb.msbc_used = false;
+ }
+ }
+#endif
}
+#ifdef CONFIG_SCO_OVER_HCI
+static void userial_enqueue_sco_data(unsigned char * recv_buffer, int total_length)
+{
+ uint16_t sco_handle;
+ uint8_t sco_length;
+ uint8_t *p_data = recv_buffer;
+ RTK_BUFFER* skb_sco_data;
+ int i;
+ sco_handle = *((uint16_t *)p_data);
+ uint16_t current_pos = sco_cb.current_pos;
+ uint16_t sco_packet_len = sco_cb.sco_packet_len;
+ if(total_length == 0)
+ {
+ ALOGD("total_length %d",total_length);
+ }
+ if(sco_handle == sco_cb.sco_handle) {
+ sco_length = p_data[SCO_PREAMBLE_SIZE - 1];
+ p_data += SCO_PREAMBLE_SIZE;
+ if(current_pos) {
+ if((sco_packet_len - current_pos) <= sco_length) {
+ memcpy(&sco_cb.enc_data[current_pos], p_data, (sco_packet_len - current_pos));
+ skb_sco_data = RtbAllocate(sco_packet_len, 0);
+ memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
+ pthread_mutex_lock(&sco_cb.sco_mutex);
+ RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+ pthread_cond_signal(&sco_cb.sco_cond);
+ pthread_mutex_unlock(&sco_cb.sco_mutex);
+
+ sco_cb.current_pos = 0;
+ p_data += (sco_packet_len - current_pos);
+ sco_length -= (sco_packet_len - current_pos);
+ }
+ else {
+ memcpy(&sco_cb.enc_data[current_pos], p_data, sco_length);
+ sco_cb.current_pos += sco_length;
+ return;
+ }
+ }
+
+ if(!sco_cb.msbc_used) {
+ for(i = 0; i < (sco_length/sco_packet_len); i++) {
+ skb_sco_data = RtbAllocate(sco_packet_len, 0);
+ memcpy(skb_sco_data->Data, p_data + i*sco_packet_len, sco_packet_len);
+ RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+ }
+ if((sco_length/sco_packet_len)) {
+ pthread_mutex_lock(&sco_cb.sco_mutex);
+ pthread_cond_signal(&sco_cb.sco_cond);
+ pthread_mutex_unlock(&sco_cb.sco_mutex);
+ }
+
+ i = (sco_length % sco_packet_len);
+ current_pos = sco_length - i;
+ if(i) {
+ memcpy(sco_cb.enc_data, p_data + current_pos, i);
+ sco_cb.current_pos = i;
+ }
+ return;
+ }
+ for(i = 0; i < sco_length; i++) {
+ if((p_data[i] == 0x01) && ((p_data[i+1] & 0x0f) == 0x08) && (p_data[i+2] == 0xAD)) {
+ if((sco_length - i) < sco_packet_len) {
+ memcpy(sco_cb.enc_data, &p_data[i], (sco_length - i));
+ sco_cb.current_pos = sco_length - i;
+ return;
+ }
+ else {
+ memcpy(sco_cb.enc_data, &p_data[i], sco_packet_len); //complete msbc data
+ skb_sco_data = RtbAllocate(sco_packet_len, 0);
+ memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
+ pthread_mutex_lock(&sco_cb.sco_mutex);
+ RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+ pthread_cond_signal(&sco_cb.sco_cond);
+ pthread_mutex_unlock(&sco_cb.sco_mutex);
+
+ sco_cb.current_pos = 0;
+ i += (sco_packet_len - 1);
+ }
+ }
+ }
+ }
+}
+#endif
-#ifdef RTK_SINGLE_CMD_EVENT
-static int userial_handle_cmd_event(unsigned char * recv_buffer, int total_length)
+static int userial_handle_recv_data(unsigned char * recv_buffer, int total_length)
{
serial_data_type_t type = 0;
unsigned char * p_data = recv_buffer;
int length = total_length;
uint8_t event;
- switch (cmd_packet_recv_state) {
+
+ switch (received_packet_state) {
case RTKBT_PACKET_IDLE:
- cmd_packet_bytes_need = 1;
+ received_packet_bytes_need = 1;
while(length) {
type = p_data[0];
length--;
p_data++;
- assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
ALOGE("%s invalid data type: %d", __func__, type);
+ assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
if(!length)
return total_length;
}
break;
}
- cmd_current_type = type;
- cmd_packet_recv_state = RTKBT_PACKET_TYPE;
+ recv_packet_current_type = type;
+ received_packet_state = RTKBT_PACKET_TYPE;
//fall through
case RTKBT_PACKET_TYPE:
- if(cmd_current_type == DATA_TYPE_ACL) {
- cmd_packet_bytes_need = 4;
- }
- else if(cmd_current_type == DATA_TYPE_EVENT) {
- cmd_packet_bytes_need = 2;
- }
- else {
- cmd_packet_bytes_need = 3;
- }
- cmd_resvered_length = 0;
- cmd_packet_recv_state = RTKBT_PACKET_HEADER;
+ received_packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(recv_packet_current_type)];
+ received_resvered_length = 0;
+ received_packet_state = RTKBT_PACKET_HEADER;
//fall through
case RTKBT_PACKET_HEADER:
- if(length >= cmd_packet_bytes_need) {
- memcpy(&cmd_resvered_header[cmd_resvered_length], p_data, cmd_packet_bytes_need);
- cmd_resvered_length += cmd_packet_bytes_need;
- length -= cmd_packet_bytes_need;
- p_data += cmd_packet_bytes_need;
+ if(length >= received_packet_bytes_need) {
+ memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
+ received_resvered_length += received_packet_bytes_need;
+ length -= received_packet_bytes_need;
+ p_data += received_packet_bytes_need;
}
else {
- memcpy(&cmd_resvered_header[cmd_resvered_length], p_data, length);
- cmd_resvered_length += length;
- cmd_packet_bytes_need -= length;
+ memcpy(&received_resvered_header[received_resvered_length], p_data, length);
+ received_resvered_length += length;
+ received_packet_bytes_need -= length;
length = 0;
return total_length;
}
- cmd_packet_recv_state = RTKBT_PACKET_CONTENT;
+ received_packet_state = RTKBT_PACKET_CONTENT;
- if(cmd_current_type == DATA_TYPE_ACL) {
- cmd_packet_bytes_need = *(uint16_t *)&cmd_resvered_header[2];
+ if(recv_packet_current_type == DATA_TYPE_ACL) {
+ received_packet_bytes_need = *(uint16_t *)&received_resvered_header[2];
}
- else if(cmd_current_type == DATA_TYPE_EVENT){
- cmd_packet_bytes_need = cmd_resvered_header[1];
+ else if(recv_packet_current_type == DATA_TYPE_EVENT){
+ received_packet_bytes_need = received_resvered_header[1];
}
else {
- cmd_packet_bytes_need = cmd_resvered_header[2];
+ received_packet_bytes_need = received_resvered_header[2];
}
//fall through
case RTKBT_PACKET_CONTENT:
- if(cmd_current_type == DATA_TYPE_EVENT) {
- event = cmd_resvered_header[0];
- if(cmd_resvered_length == 2) {
- if(event == HCI_COMMAND_COMPLETE_EVT) {
- if(length > 1) {
- *p_data = 1;
- }
- }
- else if(event == HCI_COMMAND_STATUS_EVT) {
- if(length > 2) {
- *(p_data + 1) = 1;
- }
+ if(recv_packet_current_type == DATA_TYPE_EVENT) {
+ event = received_resvered_header[0];
+ if(event == HCI_COMMAND_COMPLETE_EVT) {
+ if(length >= 1) {
+ *p_data = 1;
}
}
- else if(cmd_resvered_length == 3) {
- if(event == HCI_COMMAND_STATUS_EVT) {
- if(length > 1) {
- *p_data = 1;
- }
+ else if(event == HCI_COMMAND_STATUS_EVT) {
+ if(length >= 2) {
+ *(p_data + 1) = 1;
}
-
}
}
- if(length >= cmd_packet_bytes_need) {
- length -= cmd_packet_bytes_need;
- p_data += cmd_packet_bytes_need;
- cmd_resvered_length += cmd_packet_bytes_need;
- cmd_packet_bytes_need = 0;
+ if(length >= received_packet_bytes_need) {
+ memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
+ length -= received_packet_bytes_need;
+ p_data += received_packet_bytes_need;
+ received_resvered_length += received_packet_bytes_need;
+ received_packet_bytes_need = 0;
}
else {
- cmd_resvered_length += length;
- cmd_packet_bytes_need -= length;
+ memcpy(&received_resvered_header[received_resvered_length], p_data, length);
+ received_resvered_length += length;
+ received_packet_bytes_need -= length;
length = 0;
return total_length;
}
- cmd_packet_recv_state = RTKBT_PACKET_END;
+ received_packet_state = RTKBT_PACKET_END;
//fall through
case RTKBT_PACKET_END:
+#ifdef CONFIG_SCO_OVER_HCI
+ switch (recv_packet_current_type) {
+ case DATA_TYPE_EVENT :
+ userial_handle_event(received_resvered_header, received_resvered_length);
+ break;
+
+ case DATA_TYPE_SCO :
+ userial_enqueue_sco_data(received_resvered_header, received_resvered_length);
+ break;
+
+ default :
+ break;
+ }
+#endif
break;
default:
break;
}
- cmd_packet_recv_state = RTKBT_PACKET_IDLE;
- cmd_packet_bytes_need = 0;
- cmd_current_type = 0;
- cmd_resvered_length = 0;
+ received_packet_state = RTKBT_PACKET_IDLE;
+ received_packet_bytes_need = 0;
+ recv_packet_current_type = 0;
+ received_resvered_length = 0;
return (total_length - length);
}
#endif
+static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length)
+{
+ unsigned char buffer[1028] = {0};
+ unsigned int length = 0;
+ length = h5_int_interface->h5_int_read_data(&buffer[1], total_length);
+ buffer[0] = type;
+ length++;
+ uint16_t transmitted_length = 0;
+ unsigned int real_length = length;
+#ifdef RTK_HANDLE_EVENT
+ unsigned int read_length = 0;
+ do {
+ read_length += userial_handle_recv_data(buffer + read_length, real_length - read_length);
+ }while(read_length < total_length);
+#endif
+
+ while (length > 0) {
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
+ switch (ret) {
+ case -1:
+ ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+ goto done;
+ case 0:
+ // If we wrote nothing, don't loop more because we
+ // can't go to infinity or beyond
+ goto done;
+ default:
+ transmitted_length += ret;
+ length -= ret;
+ break;
+ }
+ }
+done:;
+ if(real_length)
+ userial_enqueue_coex_rawdata(buffer, real_length, true);
+ return;
+}
+
+//This recv data from driver which is sent or recv by the controller. The data type have ACL/SCO/EVENT
+// direction CONTROLLER -----> BT HOST
static void userial_recv_uart_rawdata(unsigned char *buffer, unsigned int total_length)
{
unsigned int length = total_length;
uint16_t transmitted_length = 0;
-#ifdef RTK_SINGLE_CMD_EVENT
- int read_length = 0;
+#ifdef RTK_HANDLE_EVENT
+ unsigned int read_length = 0;
do {
- read_length += userial_handle_cmd_event(buffer + read_length, total_length - read_length);
+ read_length += userial_handle_recv_data(buffer + read_length, total_length - read_length);
}while(read_length < total_length);
#endif
return;
}
-static void* userial_recv_socket_thread(void *arg)
+void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length)
+{
+ if(rtkbt_transtype & RTKBT_TRANS_H5) {
+ h5_int_interface->h5_recv_msg(buffer, total_length);
+ }
+ else {
+ userial_recv_uart_rawdata(buffer, total_length);
+ }
+}
+
+static void* userial_recv_socket_thread()//(void *arg)
{
struct epoll_event events[64];
int j;
return NULL;
}
-static void* userial_recv_uart_thread(void *arg)
+static void* userial_recv_uart_thread()//(void *arg)
{
struct pollfd pfd;
pfd.events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
if (pfd.revents & (POLLERR|POLLHUP)) {
ALOGE("%s poll error, fd : %d", __func__, vnd_userial.fd);
- continue;
+ vnd_userial.btdriver_state = false;
+ close(vnd_userial.fd);
+ return NULL;
}
if (ret < 0)
{
return NULL;
}
-static void* userial_coex_thread(void *arg)
+static void* userial_coex_thread()//(void *arg)
{
struct epoll_event events[64];
int j;
vnd_userial.cpoll_fd = epoll_create(64);
assert (vnd_userial.cpoll_fd != -1);
- vnd_userial.event_fd = eventfd(SIZE_MAX, EFD_NONBLOCK);
+ vnd_userial.event_fd = eventfd(10, EFD_NONBLOCK);
assert(vnd_userial.event_fd != -1);
if(vnd_userial.event_fd != -1) {
rtk_coex_object.fd = vnd_userial.event_fd;
return ret;
}
-int userial_vendor_usb_ioctl(int operation)
+int userial_vendor_usb_ioctl(int operation, void* param)
{
int retval;
- retval = ioctl(vnd_userial.fd, operation, NULL);
+ retval = ioctl(vnd_userial.fd, operation, param);
return retval;
}
int userial_vendor_usb_open(void)
{
- if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR)) == -1)
- {
- ALOGE("%s: unable to open %s: %s", __func__, vnd_userial.port_name, strerror(errno));
- return -1;
- }
+ if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR)) == -1)
+ {
+ ALOGE("%s: unable to open %s: %s", __func__, vnd_userial.port_name, strerror(errno));
+ return -1;
+ }
- ALOGI("device fd = %d open", vnd_userial.fd);
+ vnd_userial.btdriver_state = true;
+ ALOGI("device fd = %d open", vnd_userial.fd);
- return vnd_userial.fd;
+ return vnd_userial.fd;
}
--- /dev/null
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES += \
+ rtkcmd.c
+
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := rtkcmd
+LOCAL_PROPRIETARY_MODULE := true
+include $(BUILD_EXECUTABLE)
+
--- /dev/null
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/un.h>
+#include <stddef.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define UNIX_DOMAIN "@/data/misc/bluedroid/rtkbt_service.sock"
+
+typedef struct Rtk_Socket_Data
+{
+ unsigned char type; //hci,other,inner
+ unsigned char opcodeh;
+ unsigned char opcodel;
+ unsigned char parameter_len;
+ unsigned char parameter[0];
+}Rtk_Socket_Data;
+
+/*typedef struct
+{
+ unsigned short event;
+ unsigned short len;
+ unsigned short offset;
+ unsigned short layer_specific;
+ unsigned char data[];
+} HC_BT_HDR;
+*/
+const char shortOptions[] = "f:r:h";
+const struct option longOptions[] = {
+ {"fullhcicmd", required_argument, NULL, 'f'},
+ {"read", required_argument, NULL, 'r'},
+ {"help", no_argument, NULL, 'h'},
+ {0, 0, 0, 0}
+};
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: rtkcmd [options]\n\n"
+ "Options:\n"
+ "-f | --fullhcicmd [opcode,parameter_len,parameter] send hci cmd\n"
+ "-r | --read [address] read register address \n"
+ "-h | --help Print this message\n\n");
+}
+
+int Rtkbt_Sendcmd(int socketfd,char *p)
+{
+ char *token = NULL;
+ int i=0;
+ unsigned short OpCode = 0;
+ unsigned char ParamLen = 0;
+ unsigned char ParamLen_1 = 0;
+ int sendlen = 0;
+ int params_count=0;
+ int ret=0;
+ Rtk_Socket_Data *p_buf = NULL;
+
+ token = strtok(p,",");
+ if (token != NULL) {
+ OpCode = strtol(token, NULL, 0);
+ //printf("OpCode = %x\n",OpCode);
+ params_count++;
+ } else {
+ //ret = FUNCTION_PARAMETER_ERROR;
+ printf("parameter error\n");
+ return -1;
+ }
+
+ token = strtok(NULL, ",");
+ if (token != NULL) {
+ ParamLen = strtol(token, NULL, 0);
+ //printf("ParamLen = %d\n",ParamLen);
+ params_count++;
+ } else {
+ printf("parameter error\n");
+ return -1;
+ }
+
+ p_buf=(Rtk_Socket_Data *)malloc(sizeof(Rtk_Socket_Data) + sizeof(char)*ParamLen);
+ p_buf->type = 0x01;
+ p_buf->opcodeh = OpCode>>8;
+ p_buf->opcodel = OpCode&0xff;
+ p_buf->parameter_len = ParamLen;
+
+ ParamLen_1 = ParamLen;
+ while (ParamLen_1--) {
+ token = strtok(NULL, ",");
+ if (token != NULL) {
+ p_buf->parameter[i++] = strtol(token, NULL, 0);
+ params_count++;
+ } else {
+ printf("parameter error\n");
+ return -1;
+ }
+ }
+
+ if (params_count != ParamLen + 2) {
+ printf("parameter error\n");
+ return -1;
+ }
+
+ sendlen=sizeof(Rtk_Socket_Data)+sizeof(char)*p_buf->parameter_len;
+ ret=write(socketfd,p_buf,sendlen);
+ if(ret!=sendlen)
+ return -1;
+
+ free(p_buf);
+ return 0;
+}
+
+int Rtkbt_Getevent(int sock_fd)
+{
+ unsigned short event=0;
+ unsigned short event_len=0;
+ unsigned short offset=0;
+ unsigned short layer_specific=0;
+ unsigned char *recvbuf = NULL;
+ int ret=0;
+ int i;
+
+ ret = read(sock_fd,&event,2);
+ if(ret<=0)
+ return -1;
+ //printf("event = %x\n",event);
+
+ ret = read(sock_fd,&event_len,2);
+ if(ret<=0)
+ return -1;
+ //printf("event_len = %x\n",event_len);
+
+ ret = read(sock_fd,&offset,2);
+ if(ret<=0)
+ return -1;
+ //printf("offset = %x\n",offset);
+
+ ret = read(sock_fd,&layer_specific,2);
+ if(ret<=0)
+ return -1;
+ //printf("layer_specific = %x\n",layer_specific);
+
+ recvbuf=(unsigned char *)malloc(sizeof(char)*event_len);
+ ret = read(sock_fd,recvbuf,event_len);
+ if(ret < event_len)
+ return -1;
+
+ printf("Event: ");
+ for(i=0;i<event_len-1;i++)
+ printf("0x%02x ",recvbuf[i]);
+ printf("0x%02x\n",recvbuf[event_len-1]);
+
+ free(recvbuf);
+ return 0;
+}
+
+int socketinit()
+{
+ int sock_fd;
+ struct sockaddr_un un;
+ int len;
+ memset(&un, 0, sizeof(un)); /* fill socket address structure with our address */
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, UNIX_DOMAIN);
+ un.sun_path[0]=0;
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(UNIX_DOMAIN);
+
+ sock_fd= socket(AF_UNIX, SOCK_STREAM, 0);
+ if(sock_fd<0)
+ {
+ printf("socket failed %s\n",strerror(errno));
+ return -1;
+ }
+ if(connect(sock_fd,(struct sockaddr *)&un, len)<0)
+ {
+ printf("connect failed %s\n",strerror(errno));
+ close(sock_fd);
+ return -1;
+ }
+
+ return sock_fd;
+}
+
+int main(int argc , char* argv[])
+{
+ int index;
+ int c;
+ int ret;
+ int socketfd;
+
+ socketfd = socketinit();
+ if(socketfd<0)
+ {
+ printf("socketinit failed\n");
+ exit(0);
+ }
+
+ c = getopt_long(argc, argv, shortOptions, longOptions, &index);
+
+ if(c==-1)
+ {
+ usage();
+ }
+ else
+ {
+ switch(c)
+ {
+ case 'f':
+ {
+ printf("Hcicmd %s\n",optarg);
+ ret = Rtkbt_Sendcmd(socketfd,optarg);
+ if(ret>=0)
+ {
+ if(Rtkbt_Getevent(socketfd)<0)
+ printf("Getevent fail\n");
+ }
+ break;
+ }
+ case 'r':
+ {
+ printf("read register %s\n",optarg);
+ //Rtkbt_Readreg(socketfd,optarg);
+ break;
+ }
+ case 'h':
+ {
+ usage();
+ break;
+ }
+ }
+ }
+
+ close(socketfd);
+
+}
\ No newline at end of file
-# RELEASE NAME: 20171107_BT_ANDROID_8.x
+# RELEASE NAME: 20180525_BT_ANDROID_8.1
+# RTKBT_API_VERSION=2.1.1.0
+
+CUR_PATH := hardware/realtek/rtkbt
BOARD_HAVE_BLUETOOTH := true
BOARD_HAVE_BLUETOOTH_RTK := true
BOARD_HAVE_BLUETOOTH_RTK_COEX := true
+ifeq ($(strip $(TARGET_BOARD_PLATFORM_PRODUCT)), box)
+BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := $(CUR_PATH)/bluetooth
+endif
-BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := $(LOCAL_PATH)/bluetooth
-
-
-#PRODUCT_COPY_FILES += \
- $(LOCAL_PATH)/vendor/etc/bluetooth/rtkbt.conf:vendor/etc/bluetooth/rtkbt.conf \
- $(LOCAL_PATH)/vendor/firmware/rtl8703as_config:vendor/firmware/rtl8703as_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8703as_fw:vendor/firmware/rtl8703as_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8703bs_config:vendor/firmware/rtl8703bs_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8703bs_fw:vendor/firmware/rtl8703bs_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8703cs_config:vendor/firmware/rtl8703cs_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8703cs_fw:vendor/firmware/rtl8703cs_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723a_config:vendor/firmware/rtl8723a_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723a_config_addr:vendor/firmware/rtl8723a_config_addr \
- $(LOCAL_PATH)/vendor/firmware/rtl8723a_fw:vendor/firmware/rtl8723a_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723as_config:vendor/firmware/rtl8723as_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723as_fw:vendor/firmware/rtl8723as_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723b_config:vendor/firmware/rtl8723b_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723b_config_2Ant_S0:vendor/firmware/rtl8723b_config_2Ant_S0 \
- $(LOCAL_PATH)/vendor/firmware/rtl8723b_fw:vendor/firmware/rtl8723b_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723bs_config:vendor/firmware/rtl8723bs_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723bs_fw:vendor/firmware/rtl8723bs_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723bs_VQ0_config:vendor/firmware/rtl8723bs_VQ0_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723bs_VQ0_fw:vendor/firmware/rtl8723bs_VQ0_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723bu_config:vendor/firmware/rtl8723bu_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723c_fw:vendor/firmware/rtl8723c_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723cs_cg_config:vendor/firmware/rtl8723cs_cg_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723cs_cg_fw:vendor/firmware/rtl8723cs_cg_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723cs_vf_config:vendor/firmware/rtl8723cs_vf_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723cs_vf_fw:vendor/firmware/rtl8723cs_vf_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723cs_xx_config:vendor/firmware/rtl8723cs_xx_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723cs_xx_fw:vendor/firmware/rtl8723cs_xx_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723d_config:vendor/firmware/rtl8723d_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723d_fw:vendor/firmware/rtl8723d_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8723ds_config:vendor/firmware/rtl8723ds_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8723ds_fw:vendor/firmware/rtl8723ds_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8761a_config:vendor/firmware/rtl8761a_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8761at8192ee_fw:vendor/firmware/rtl8761at8192ee_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8761at_config:vendor/firmware/rtl8761at_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8761at_fw:vendor/firmware/rtl8761at_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8761au8192ee_fw:vendor/firmware/rtl8761au8192ee_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8761au8812ae_fw:vendor/firmware/rtl8761au8812ae_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8761au_fw:vendor/firmware/rtl8761au_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8761aw8192eu_config:vendor/firmware/rtl8761aw8192eu_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8761aw8192eu_fw:vendor/firmware/rtl8761aw8192eu_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8821a_config:vendor/firmware/rtl8821a_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8821a_fw:vendor/firmware/rtl8821a_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8821as_config:vendor/firmware/rtl8821as_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8821as_fw:vendor/firmware/rtl8821as_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8821c_config:vendor/firmware/rtl8821c_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8821c_fw:vendor/firmware/rtl8821c_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8821cs_config:vendor/firmware/rtl8821cs_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8821cs_fw:vendor/firmware/rtl8821cs_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8822b_config:vendor/firmware/rtl8822b_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8822b_fw:vendor/firmware/rtl8822b_fw \
- $(LOCAL_PATH)/vendor/firmware/rtl8822bs_config:vendor/firmware/rtl8822bs_config \
- $(LOCAL_PATH)/vendor/firmware/rtl8822bs_fw:vendor/firmware/rtl8822bs_fw \
-
-CUR_PATH := hardware/realtek/rtkbt
PRODUCT_COPY_FILES += \
$(CUR_PATH)/vendor/etc/bluetooth/rtkbt.conf:vendor/etc/bluetooth/rtkbt.conf
+ifeq ($(strip $(TARGET_BOARD_PLATFORM_PRODUCT)), tablet)
BT_FIRMWARE_FILES := $(shell ls $(CUR_PATH)/vendor/firmware)
PRODUCT_COPY_FILES += \
$(foreach file, $(BT_FIRMWARE_FILES), $(CUR_PATH)/vendor/firmware/$(file):$(TARGET_COPY_OUT_VENDOR)/etc/firmware/$(file))
+else
+BT_FIRMWARE_FILES := $(shell ls $(CUR_PATH)/vendor/firmware_box)
+PRODUCT_COPY_FILES += \
+ $(foreach file, $(BT_FIRMWARE_FILES), $(CUR_PATH)/vendor/firmware_box/$(file):$(TARGET_COPY_OUT_VENDOR)/etc/firmware/$(file))
+endif
PRODUCT_PACKAGES += \
- Bluetooth \
- libbt-vendor \
- android.hardware.bluetooth@1.0-impl \
- android.hidl.memory@1.0-impl \
- android.hardware.bluetooth@1.0-service \
- android.hardware.bluetooth@1.0-service.rc \
- audio.a2dp.default
-
+ libbt-vendor-realtek
PRODUCT_PROPERTY_OVERRIDES += \
persist.bluetooth.btsnoopenable=false \
--- /dev/null
+ FW CUT SVN Coex
+rtl8761au8192ee_fw D 13328 3736
+rtl8761a_fw D 13328 3736
+rtl8761au_fw D 19884 0006
+rtl8761aw8192eu_fw D 19884 0006
+rtl8723ds_fw C 19875 2020
+rtl8822b_fw C 19903 5656
+rtl8821cs_fw B 19894 1d1d
+rtl8761at_fw D 19884 0006
+rtl8761au8812ae_fw D 19648 0006
+rtl8821as_fw B 19292 635d
+rtl8821a_fw B 19292 635d
+rtl8723bs_fw B 19587 6b4e
+rtl8723b_fw B 19587 6b4e
+rtl8821c_fw B 19894 1d1d
+rtl8822bs_fw C 19903 5656
+rtl8723d_fw C 19875 2020
+rtl8723bs_VQ0_fw B 14422 5844