From: Weiguo Hu Date: Mon, 30 Jul 2018 08:30:00 +0000 (+0800) Subject: realtek bt bringup X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=8f97e7642febae707598917c084d3fa5bb257200;p=GitHub%2FLineageOS%2FG12%2Fandroid_hardware_realtek.git realtek bt bringup Change-Id: Iebf72692e2f20657aecfbe3e9e30fed6285f8774 Signed-off-by: Weiguo Hu --- diff --git a/rtkbt/code/libbt-vendor/Android.mk b/rtkbt/code/libbt-vendor/Android.mk old mode 100644 new mode 100755 index 1945150..ea5fdb6 --- a/rtkbt/code/libbt-vendor/Android.mk +++ b/rtkbt/code/libbt-vendor/Android.mk @@ -5,6 +5,8 @@ include $(CLEAR_VARS) 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 \ @@ -13,10 +15,16 @@ LOCAL_SRC_FILES := \ 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 := \ @@ -28,6 +36,5 @@ LOCAL_MODULE := libbt-vendor-realtek LOCAL_MODULE_TAGS := optional LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_CLASS := SHARED_LIBRARIES -LOCAL_CPPFLAGS := -Werror -Wunused-parameter include $(BUILD_SHARED_LIBRARY) diff --git a/rtkbt/code/libbt-vendor/codec/msbc/sbc.c b/rtkbt/code/libbt-vendor/codec/msbc/sbc.c new file mode 100755 index 0000000..e138e9d --- /dev/null +++ b/rtkbt/code/libbt-vendor/codec/msbc/sbc.c @@ -0,0 +1,1763 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2004-2006 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * 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 +#endif + +//#include +#include +#include +//#include +#include +#include + +#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)); +} diff --git a/rtkbt/code/libbt-vendor/codec/msbc/sbc.h b/rtkbt/code/libbt-vendor/codec/msbc/sbc.h new file mode 100755 index 0000000..5e74751 --- /dev/null +++ b/rtkbt/code/libbt-vendor/codec/msbc/sbc.h @@ -0,0 +1,79 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2004-2006 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * 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 */ diff --git a/rtkbt/code/libbt-vendor/codec/msbc/sbc_math.h b/rtkbt/code/libbt-vendor/codec/msbc/sbc_math.h new file mode 100755 index 0000000..d620822 --- /dev/null +++ b/rtkbt/code/libbt-vendor/codec/msbc/sbc_math.h @@ -0,0 +1,70 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2004-2006 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * 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); } diff --git a/rtkbt/code/libbt-vendor/codec/msbc/sbc_tables.h b/rtkbt/code/libbt-vendor/codec/msbc/sbc_tables.h new file mode 100755 index 0000000..f532cec --- /dev/null +++ b/rtkbt/code/libbt-vendor/codec/msbc/sbc_tables.h @@ -0,0 +1,169 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2004-2006 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * 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) } +}; diff --git a/rtkbt/code/libbt-vendor/include/bt_list.h b/rtkbt/code/libbt-vendor/include/bt_list.h old mode 100644 new mode 100755 diff --git a/rtkbt/code/libbt-vendor/include/bt_skbuff.h b/rtkbt/code/libbt-vendor/include/bt_skbuff.h old mode 100644 new mode 100755 index d252976..3a3eca6 --- a/rtkbt/code/libbt-vendor/include/bt_skbuff.h +++ b/rtkbt/code/libbt-vendor/include/bt_skbuff.h @@ -41,6 +41,7 @@ #ifndef BT_SKBUFF_H #define BT_SKBUFF_H #include "bt_list.h" +#include #ifndef EXTERN #define EXTERN @@ -335,12 +336,11 @@ RtbQueueNextNode( /** check whether queue is empty */ -EXTERN unsigned char +EXTERN bool RtbQueueIsEmpty( IN RTB_QUEUE_HEAD* RtkQueueHead ); - //annie_tmp EXTERN unsigned char RtbCheckQueueLen( diff --git a/rtkbt/code/libbt-vendor/include/bt_vendor_rtk.h b/rtkbt/code/libbt-vendor/include/bt_vendor_rtk.h old mode 100644 new mode 100755 index 7146c7a..b027fd9 --- a/rtkbt/code/libbt-vendor/include/bt_vendor_rtk.h +++ b/rtkbt/code/libbt-vendor/include/bt_vendor_rtk.h @@ -78,10 +78,14 @@ #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 */ @@ -110,7 +114,7 @@ * firmware patchram (.hcd) file. */ #ifndef USE_CONTROLLER_BDADDR -#define USE_CONTROLLER_BDADDR FALSE +#define USE_CONTROLLER_BDADDR TRUE //FALSE #endif /* sleep mode diff --git a/rtkbt/code/libbt-vendor/include/hardware.h b/rtkbt/code/libbt-vendor/include/hardware.h new file mode 100755 index 0000000..016d15f --- /dev/null +++ b/rtkbt/code/libbt-vendor/include/hardware.h @@ -0,0 +1,197 @@ +#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 diff --git a/rtkbt/code/libbt-vendor/include/hci_h5_int.h b/rtkbt/code/libbt-vendor/include/hci_h5_int.h old mode 100644 new mode 100755 index 99311c2..6d62c9b --- a/rtkbt/code/libbt-vendor/include/hci_h5_int.h +++ b/rtkbt/code/libbt-vendor/include/hci_h5_int.h @@ -43,6 +43,9 @@ #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);} diff --git a/rtkbt/code/libbt-vendor/include/rtk_btservice.h b/rtkbt/code/libbt-vendor/include/rtk_btservice.h new file mode 100755 index 0000000..f8529bb --- /dev/null +++ b/rtkbt/code/libbt-vendor/include/rtk_btservice.h @@ -0,0 +1,18 @@ +#ifndef RTK_BTSERVICE_H +#define RTK_BTSERVICE_H + +#include +#include + +#define HCI_RTKBT_AUTOPAIR_EVT 0x30 + +#define STREAM_TO_UINT8(u8, p) \ + { \ + (u8) = (uint8_t)(*(p)); \ + (p) += 1; \ + } + + +#endif + + diff --git a/rtkbt/code/libbt-vendor/include/rtk_btsnoop_net.h b/rtkbt/code/libbt-vendor/include/rtk_btsnoop_net.h old mode 100644 new mode 100755 diff --git a/rtkbt/code/libbt-vendor/include/rtk_hcidefs.h b/rtkbt/code/libbt-vendor/include/rtk_hcidefs.h old mode 100644 new mode 100755 diff --git a/rtkbt/code/libbt-vendor/include/rtk_parse.h b/rtkbt/code/libbt-vendor/include/rtk_parse.h old mode 100644 new mode 100755 index f2dcc27..4de047c --- a/rtkbt/code/libbt-vendor/include/rtk_parse.h +++ b/rtkbt/code/libbt-vendor/include/rtk_parse.h @@ -87,7 +87,7 @@ typedef struct rtk_parse_manager_t { }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 { diff --git a/rtkbt/code/libbt-vendor/include/rtk_poll.h b/rtkbt/code/libbt-vendor/include/rtk_poll.h new file mode 100755 index 0000000..c449d24 --- /dev/null +++ b/rtkbt/code/libbt-vendor/include/rtk_poll.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * 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 +#include +#include +#include +#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); diff --git a/rtkbt/code/libbt-vendor/include/rtk_socket.h b/rtkbt/code/libbt-vendor/include/rtk_socket.h new file mode 100755 index 0000000..b878559 --- /dev/null +++ b/rtkbt/code/libbt-vendor/include/rtk_socket.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * 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 +#include +#include +#include +#include +#include +#include + + +#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 diff --git a/rtkbt/code/libbt-vendor/include/unused.h b/rtkbt/code/libbt-vendor/include/unused.h new file mode 100755 index 0000000..d44033e --- /dev/null +++ b/rtkbt/code/libbt-vendor/include/unused.h @@ -0,0 +1,24 @@ +/* + * 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*/ diff --git a/rtkbt/code/libbt-vendor/include/upio.h b/rtkbt/code/libbt-vendor/include/upio.h old mode 100644 new mode 100755 index 20ed9bb..24427a9 --- a/rtkbt/code/libbt-vendor/include/upio.h +++ b/rtkbt/code/libbt-vendor/include/upio.h @@ -101,7 +101,7 @@ int upio_set_bluetooth_power(int on); ** 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); /******************************************************************************* diff --git a/rtkbt/code/libbt-vendor/include/userial_vendor.h b/rtkbt/code/libbt-vendor/include/userial_vendor.h old mode 100644 new mode 100755 index 07bcf7d..573667b --- a/rtkbt/code/libbt-vendor/include/userial_vendor.h +++ b/rtkbt/code/libbt-vendor/include/userial_vendor.h @@ -39,6 +39,8 @@ /****************************************************************************** ** 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 @@ -102,6 +104,20 @@ /****************************************************************************** ** 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 @@ -195,8 +211,13 @@ void userial_vendor_set_hw_fctrl(uint8_t hw_fctrl); 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 */ diff --git a/rtkbt/code/libbt-vendor/include/vnd_buildcfg.h b/rtkbt/code/libbt-vendor/include/vnd_buildcfg.h old mode 100644 new mode 100755 diff --git a/rtkbt/code/libbt-vendor/src/bt_list.c b/rtkbt/code/libbt-vendor/src/bt_list.c old mode 100644 new mode 100755 diff --git a/rtkbt/code/libbt-vendor/src/bt_skbuff.c b/rtkbt/code/libbt-vendor/src/bt_skbuff.c old mode 100644 new mode 100755 index 2396949..8600d0e --- a/rtkbt/code/libbt-vendor/src/bt_skbuff.c +++ b/rtkbt/code/libbt-vendor/src/bt_skbuff.c @@ -77,7 +77,7 @@ typedef struct _RTB_QUEUE_HEAD{ uint32_t QueueLen; pthread_mutex_t Lock; uint8_t Id[RTB_QUEUE_ID_LENGTH]; -}RTB_QUEUE_HEAD, *PRTB_QUEUE_HEAD; +}*PRTB_QUEUE_HEAD; //**************************************************************************** // FUNCTION @@ -87,7 +87,7 @@ typedef struct _RTB_QUEUE_HEAD{ \return : FALSE Queue is not empty TRU Queue is empty */ -unsigned char +bool RtbQueueIsEmpty( IN RTB_QUEUE_HEAD* RtkQueueHead ) diff --git a/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c b/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c old mode 100644 new mode 100755 index 59a551e..78f78d6 --- a/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c +++ b/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c @@ -26,7 +26,7 @@ #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 #include "bt_vendor_rtk.h" #include "upio.h" @@ -44,6 +44,8 @@ extern bool rtk_btsnoop_save_log; 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); @@ -63,7 +65,6 @@ bool rtkbt_auto_restart = false; #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 @@ -197,7 +198,7 @@ static void load_rtkbt_stack_conf() } 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; @@ -263,7 +264,7 @@ static void load_rtkbt_conf() 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; } @@ -280,7 +281,7 @@ static void load_rtkbt_conf() 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; } @@ -296,7 +297,7 @@ static void load_rtkbt_conf() 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; @@ -307,7 +308,7 @@ static void load_rtkbt_conf() } } - 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; @@ -316,12 +317,12 @@ static void load_rtkbt_conf() 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 { @@ -410,20 +411,10 @@ static int op(bt_vendor_opcode_t opcode, void *param) 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; @@ -473,17 +464,16 @@ static int op(bt_vendor_opcode_t opcode, void *param) 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 diff --git a/rtkbt/code/libbt-vendor/src/hardware.c b/rtkbt/code/libbt-vendor/src/hardware.c old mode 100644 new mode 100755 index 28aac2a..7bcfee2 --- a/rtkbt/code/libbt-vendor/src/hardware.c +++ b/rtkbt/code/libbt-vendor/src/hardware.c @@ -27,7 +27,7 @@ ******************************************************************************/ #define LOG_TAG "bt_hwcfg" -#define RTKBT_RELEASE_NAME "20171107_BT_ANDROID_8.x" +#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1" #include #include @@ -48,196 +48,32 @@ #include #include #include +#include #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, @@ -247,291 +83,14 @@ static bt_lpm_param_t lpm_param = 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<hci_version))==0)) - continue; - if((patch_entry->hci_revision_mask!=HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<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<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<hci_version)) == 0)) - continue; - if((patch_entry->hci_revision_mask != HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<hci_revision)) == 0)) - continue; - if((patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL)&&((patch_entry->chip_type_mask&(1<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; @@ -551,246 +110,6 @@ static int getmacaddr(unsigned char * addr) 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; ioffset) == 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; ioffset)) - { - 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; jentry_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}; @@ -869,6 +188,11 @@ uint8_t rtk_get_fw_project_id(uint8_t *p_buf) 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; @@ -917,523 +241,6 @@ struct rtk_epatch_entry *rtk_get_patch_entry(bt_hw_cfg_cb_t *cfg_cb) 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<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 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 ******************************************************************************/ @@ -1465,71 +272,6 @@ void hw_lpm_ctrl_cback(void *p_mem) } -/***************************************************************************** -** 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) /****************************************************************************** * diff --git a/rtkbt/code/libbt-vendor/src/hardware_uart.c b/rtkbt/code/libbt-vendor/src/hardware_uart.c new file mode 100755 index 0000000..d92630b --- /dev/null +++ b/rtkbt/code/libbt-vendor/src/hardware_uart.c @@ -0,0 +1,1233 @@ +#define LOG_TAG "bt_hwcfg_uart" +#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bt_hci_bdroid.h" +#include "bt_vendor_rtk.h" +#include "userial.h" +#include "userial_vendor.h" +#include "upio.h" +#include +#include +#include +#include + +#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<hci_version))==0)) + continue; + if((patch_entry->hci_revision_mask!=HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<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<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<hci_version)) == 0)) + continue; + if((patch_entry->hci_revision_mask != HCI_REVISION_MASK_ALL)&&((patch_entry->hci_revision_mask&(1<hci_revision)) == 0)) + continue; + if((patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL)&&((patch_entry->chip_type_mask&(1<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; ioffset) == 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; ioffset)) + { + 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<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 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__); +} + diff --git a/rtkbt/code/libbt-vendor/src/hardware_usb.c b/rtkbt/code/libbt-vendor/src/hardware_usb.c new file mode 100755 index 0000000..cf8aa77 --- /dev/null +++ b/rtkbt/code/libbt-vendor/src/hardware_usb.c @@ -0,0 +1,930 @@ +#define LOG_TAG "bt_hwcfg_usb" +#define RTKBT_RELEASE_NAME "Test" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bt_hci_bdroid.h" +#include "bt_vendor_rtk.h" +#include "userial.h" +#include "userial_vendor.h" +#include "upio.h" +#include +#include +#include +#include + +#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; ioffset) == 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; ioffset)) + { + 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__); +} + diff --git a/rtkbt/code/libbt-vendor/src/hci_h5.c b/rtkbt/code/libbt-vendor/src/hci_h5.c old mode 100644 new mode 100755 index aae2bb6..d8e5bd8 --- a/rtkbt/code/libbt-vendor/src/hci_h5.c +++ b/rtkbt/code/libbt-vendor/src/hci_h5.c @@ -61,8 +61,6 @@ #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 @@ -140,14 +138,14 @@ unsigned int h5_log_enable = 1; /****************************************************************************** ** 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); @@ -276,7 +274,7 @@ struct patch_struct { 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 @@ -387,11 +385,11 @@ static void H5LogMsg(const char *fmt_str, ...) 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); @@ -399,9 +397,12 @@ static void H5LogMsgVerbose(const char *fmt_str, ...) 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) @@ -581,17 +582,17 @@ static void h5_crc_update(uint16_t *crc, uint8_t d) } 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. * @@ -933,7 +934,7 @@ static void h5_remove_acked_pkt(tHCI_H5_CB *h5) * @param fd uart file descriptor * */ - +/* static void hci_h5_send_pure_ack(void) { //uint16_t bytes_sent = 0; @@ -985,7 +986,7 @@ static void hci_h5_send_pure_ack(void) #endif return; -} +}*/ static void hci_h5_send_sync_req() { @@ -1198,33 +1199,7 @@ static void rtk_notify_hw_h5_init_result(uint8_t status) 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() { @@ -1361,17 +1336,17 @@ static uint16_t h5_wake_up() 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); @@ -1562,54 +1537,13 @@ uint8_t internal_event_intercept_h5(void) * @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); @@ -1636,34 +1570,10 @@ static uint8_t hci_recv_frame(sk_buff *skb, uint8_t pkt_type) 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++; @@ -1676,10 +1586,7 @@ static uint8_t hci_recv_frame(sk_buff *skb, uint8_t pkt_type) 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); -} + } } @@ -1704,9 +1611,9 @@ static uint8_t h5_complete_rx_pkt(tHCI_H5_CB *h5) 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"); @@ -1987,16 +1894,7 @@ static bool h5_recv(tHCI_H5_CB *h5, uint8_t *data, int count) /****************************************************************************** ** 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; @@ -2009,15 +1907,12 @@ static void data_ready_cb_thread(void *arg) 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; } @@ -2027,15 +1922,15 @@ static void data_ready_cb_thread(void *arg) 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"); @@ -2093,7 +1988,7 @@ static void data_retransfer_thread(void *arg) } - ALOGE("data_retransfer_thread exiting"); + H5LogMsg("data_retransfer_thread exiting"); pthread_exit(NULL); } @@ -2108,8 +2003,8 @@ void h5_retransfer_signal_event(uint16_t event) static int create_data_retransfer_thread() { - struct sched_param param; - int policy; + //struct sched_param param; + //int policy; pthread_attr_t thread_attr; @@ -2156,8 +2051,8 @@ static int create_data_retransfer_thread() static int create_data_ready_cb_thread() { - struct sched_param param; - int policy; + //struct sched_param param; + //int policy; pthread_attr_t thread_attr; @@ -2246,12 +2141,11 @@ void hci_h5_int_init(hci_h5_callbacks_t* h5_callbacks) *******************************************************************************/ 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(); @@ -2266,10 +2160,6 @@ void hci_h5_cleanup(void) 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); @@ -2277,10 +2167,6 @@ void hci_h5_cleanup(void) 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); @@ -2305,7 +2191,7 @@ void hci_h5_cleanup(void) *******************************************************************************/ 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); @@ -2374,7 +2260,6 @@ uint16_t hci_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!"); @@ -2396,15 +2281,6 @@ uint16_t hci_h5_send_cmd(serial_data_type_t type, uint8_t *data, uint16_t length 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; } @@ -2421,20 +2297,9 @@ uint16_t hci_h5_send_cmd(serial_data_type_t type, uint8_t *data, uint16_t 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!"); @@ -2460,7 +2325,7 @@ uint16_t hci_h5_send_acl_data(serial_data_type_t type, uint8_t *data, uint16_t l 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) { @@ -2487,6 +2352,10 @@ uint16_t hci_h5_send_sco_data(serial_data_type_t type, uint8_t *data, uint16_t l *******************************************************************************/ 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) @@ -2498,7 +2367,7 @@ uint8_t hci_h5_send_sync_cmd(uint16_t opcode, uint8_t *p_buf, uint16_t length) } 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; } @@ -2581,7 +2450,7 @@ static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback) 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) { @@ -2591,7 +2460,7 @@ static void h5_retransfer_timeout_handler(union sigval sigev_value) { 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) { @@ -2613,7 +2482,7 @@ static void h5_sync_retrans_timeout_handler(union sigval sigev_value) { } -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) { @@ -2637,7 +2506,7 @@ static void h5_conf_retrans_timeout_handler(union sigval sigev_value) { } -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) { @@ -2655,7 +2524,7 @@ static void h5_wait_controller_baudrate_ready_timeout_handler(union sigval sigev 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) { diff --git a/rtkbt/code/libbt-vendor/src/rtk_btservice.c b/rtkbt/code/libbt-vendor/src/rtk_btservice.c new file mode 100755 index 0000000..814427d --- /dev/null +++ b/rtkbt/code/libbt-vendor/src/rtk_btservice.c @@ -0,0 +1,765 @@ +/****************************************************************************** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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;iparameter_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;ilen;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;isocketfd && 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__); +} + + diff --git a/rtkbt/code/libbt-vendor/src/rtk_btsnoop_net.c b/rtkbt/code/libbt-vendor/src/rtk_btsnoop_net.c old mode 100644 new mode 100755 index dcf4636..2de4618 --- a/rtkbt/code/libbt-vendor/src/rtk_btsnoop_net.c +++ b/rtkbt/code/libbt-vendor/src/rtk_btsnoop_net.c @@ -44,7 +44,7 @@ static pthread_mutex_t btsnoop_log_lock; 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 @@ -79,14 +79,36 @@ static uint64_t rtk_btsnoop_timestamp(void) { 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)); } @@ -327,7 +349,7 @@ void rtk_btsnoop_net_write(serial_data_type_t type, uint8_t *data, bool is_recei 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); diff --git a/rtkbt/code/libbt-vendor/src/rtk_heartbeat.c b/rtkbt/code/libbt-vendor/src/rtk_heartbeat.c new file mode 100755 index 0000000..4ace262 --- /dev/null +++ b/rtkbt/code/libbt-vendor/src/rtk_heartbeat.c @@ -0,0 +1,245 @@ +#define LOG_TAG "rtk_heartbeat" +#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); +} + diff --git a/rtkbt/code/libbt-vendor/src/rtk_parse.c b/rtkbt/code/libbt-vendor/src/rtk_parse.c old mode 100644 new mode 100755 index cc9796f..d170472 --- a/rtkbt/code/libbt-vendor/src/rtk_parse.c +++ b/rtkbt/code/libbt-vendor/src/rtk_parse.c @@ -33,7 +33,7 @@ * ******************************************************************************/ #define LOG_TAG "rtk_parse" -#define RTKBT_RELEASE_NAME "Test" +#define RTKBT_RELEASE_NAME "20180525_BT_ANDROID_8.1" #include #include @@ -191,6 +191,12 @@ enum { 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; @@ -214,7 +220,9 @@ typedef struct RTK_CONN_PROF { 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; @@ -263,9 +271,12 @@ typedef struct HCI_EVENT_BT_INFO_CONTROL { 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) @@ -759,17 +770,70 @@ tRTK_PROF_INFO* find_profile_by_handle_dcid_scid(tRTK_PROF* h5, uint16_t handle, 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); @@ -795,8 +859,29 @@ void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* param } 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 ; } @@ -1162,7 +1247,7 @@ uint8_t handle_l2cap_discon_req(uint16_t handle, uint16_t dcid, uint16_t scid, u 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) @@ -1214,6 +1299,14 @@ void packets_count(uint16_t handle, uint16_t scid, uint16_t length, uint8_t dire 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"); @@ -1346,9 +1439,9 @@ int udpsocket_send(char *tx_msg, int msg_size) 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); @@ -1575,6 +1668,7 @@ static void rtk_handle_bt_info_control(uint8_t* p) 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) { @@ -1589,6 +1683,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) 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; @@ -1601,6 +1696,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) 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; @@ -1613,6 +1709,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) 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; @@ -1625,6 +1722,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) 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; @@ -1636,6 +1734,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) { 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 @@ -1649,6 +1748,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) 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; @@ -1661,6 +1761,7 @@ static void rtk_handle_bt_coex_control(uint8_t* p) { uint8_t opcode_len = *p++; uint8_t access_type = *p++; + op_len = opcode_len; if(access_type == 0) //read { uint8_t temp_cmd[7]; @@ -1691,7 +1792,7 @@ void rtk_handle_event_from_wifi(uint8_t* msg) { 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 @@ -1734,7 +1835,7 @@ void rtk_handle_event_from_wifi(uint8_t* msg) if(event_code == 0xFE) { - uint8_t total_length = *p++; + total_length = *p++; uint8_t extension_event = *p++; switch(extension_event) { @@ -1780,7 +1881,7 @@ static void udpsocket_receive_thread_exit_handler(int sig) 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; @@ -1791,7 +1892,7 @@ static void udpsocket_receive_thread(void *arg) 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); @@ -1947,6 +2048,7 @@ void rtk_parse_init(void) 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(); @@ -1955,6 +2057,7 @@ void rtk_parse_init(void) init_profile_hash(&rtk_prof); init_connection_hash(&rtk_prof); + init_coex_hash(&rtk_prof); create_udpsocket_socket(); } @@ -1971,6 +2074,8 @@ void rtk_parse_cleanup() 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); @@ -2161,6 +2266,10 @@ static void rtk_handle_cmd_complete_evt(uint8_t*p, uint8_t len) 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); @@ -2304,7 +2413,7 @@ static void rtk_handle_disconnect_complete_evt(uint8_t* p) } } -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; @@ -2313,6 +2422,9 @@ static void rtk_handle_le_connection_complete_evt(uint8_t* p) 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) { @@ -2366,9 +2478,11 @@ static void rtk_handle_le_meta_evt(uint8_t* p) 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; @@ -2627,7 +2741,7 @@ void rtk_parse_l2cap_data(uint8_t *pp, uint8_t direction) 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) { @@ -2646,7 +2760,7 @@ void rtk_add_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map) 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) @@ -2689,7 +2803,7 @@ void rtk_add_le_data_count(uint8_t data_type) } } -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, @@ -2700,7 +2814,7 @@ static const rtk_parse_manager_t parse_interface = { 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; } diff --git a/rtkbt/code/libbt-vendor/src/rtk_poll.c b/rtkbt/code/libbt-vendor/src/rtk_poll.c new file mode 100755 index 0000000..2ed91c9 --- /dev/null +++ b/rtkbt/code/libbt-vendor/src/rtk_poll.c @@ -0,0 +1,248 @@ +/****************************************************************************** + * + * 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 +#include +#include +#include +#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 +} diff --git a/rtkbt/code/libbt-vendor/src/rtk_socket.c b/rtkbt/code/libbt-vendor/src/rtk_socket.c new file mode 100755 index 0000000..18aa689 --- /dev/null +++ b/rtkbt/code/libbt-vendor/src/rtk_socket.c @@ -0,0 +1,191 @@ +/****************************************************************************** + * + * 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 +#include +#include +#include +#include +#include +#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 +*****************************************************************************/ + + diff --git a/rtkbt/code/libbt-vendor/src/upio.c b/rtkbt/code/libbt-vendor/src/upio.c old mode 100644 new mode 100755 index b7a54a9..9291114 --- a/rtkbt/code/libbt-vendor/src/upio.c +++ b/rtkbt/code/libbt-vendor/src/upio.c @@ -369,9 +369,9 @@ int upio_set_bluetooth_power(int on) ** 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; diff --git a/rtkbt/code/libbt-vendor/src/userial_vendor.c b/rtkbt/code/libbt-vendor/src/userial_vendor.c old mode 100644 new mode 100755 index 9b62d2f..6283c44 --- a/rtkbt/code/libbt-vendor/src/userial_vendor.c +++ b/rtkbt/code/libbt-vendor/src/userial_vendor.c @@ -34,8 +34,11 @@ #include #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 ******************************************************************************/ @@ -60,6 +63,7 @@ ** Extern functions ******************************************************************************/ extern char rtkbt_transtype; +extern void Heartbeat_cleanup(); /****************************************************************************** ** Local type definitions @@ -97,19 +101,45 @@ typedef struct 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; @@ -126,12 +156,12 @@ static serial_data_type_t coex_current_type = 0; 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; @@ -141,6 +171,13 @@ static hci_h5_callbacks_t h5_int_callbacks = { .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 *****************************************************************************/ @@ -252,6 +289,16 @@ void userial_vendor_init(char *bt_device_node) 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 } @@ -357,6 +404,7 @@ int userial_vendor_open(tUSERIAL_CFG *p_cfg) 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; @@ -418,34 +466,37 @@ static void userial_coex_close(void) *******************************************************************************/ 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(); - - } } /******************************************************************************* @@ -486,6 +537,10 @@ void userial_vendor_set_baud(uint8_t userial_baud) *******************************************************************************/ 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) @@ -521,6 +576,10 @@ void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data) *******************************************************************************/ 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; @@ -582,7 +641,7 @@ static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length) { 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: @@ -591,7 +650,7 @@ static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length) { 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; @@ -815,12 +874,12 @@ static void userial_coex_send_data_handler(unsigned char * send_buffer, int tota 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; @@ -853,13 +912,370 @@ static void userial_coex_handler(void *context) } } -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: @@ -874,9 +1290,10 @@ static void userial_recv_H4_rawdata(void *context) 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; @@ -888,12 +1305,7 @@ static void userial_recv_H4_rawdata(void *context) //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 @@ -906,7 +1318,7 @@ static void userial_recv_H4_rawdata(void *context) 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; @@ -915,9 +1327,11 @@ static void userial_recv_H4_rawdata(void *context) 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 @@ -942,10 +1356,13 @@ static void userial_recv_H4_rawdata(void *context) 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); @@ -1002,7 +1419,7 @@ static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, } 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: @@ -1011,7 +1428,7 @@ static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, 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; @@ -1025,53 +1442,148 @@ done:; } -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; @@ -1079,92 +1591,90 @@ static int userial_handle_cmd_event(unsigned char * recv_buffer, int total_lengt } 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: @@ -1172,23 +1682,64 @@ static int userial_handle_cmd_event(unsigned char * recv_buffer, int total_lengt 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 @@ -1215,7 +1766,17 @@ done:; 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; @@ -1243,7 +1804,7 @@ static void* userial_recv_socket_thread(void *arg) 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; @@ -1271,7 +1832,9 @@ static void* userial_recv_uart_thread(void *arg) 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) { @@ -1283,7 +1846,7 @@ static void* userial_recv_uart_thread(void *arg) return NULL; } -static void* userial_coex_thread(void *arg) +static void* userial_coex_thread()//(void *arg) { struct epoll_event events[64]; int j; @@ -1361,7 +1924,7 @@ int userial_socket_open() 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; @@ -1384,23 +1947,24 @@ int userial_socket_open() 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; } diff --git a/rtkbt/code/rtkcmd/Android.mk b/rtkbt/code/rtkcmd/Android.mk new file mode 100755 index 0000000..d4a3905 --- /dev/null +++ b/rtkbt/code/rtkcmd/Android.mk @@ -0,0 +1,12 @@ +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) + diff --git a/rtkbt/code/rtkcmd/rtkcmd.c b/rtkbt/code/rtkcmd/rtkcmd.c new file mode 100755 index 0000000..552c5d7 --- /dev/null +++ b/rtkbt/code/rtkcmd/rtkcmd.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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=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 diff --git a/rtkbt/rtkbt.mk b/rtkbt/rtkbt.mk old mode 100644 new mode 100755 index 41d258c..88c7fe1 --- a/rtkbt/rtkbt.mk +++ b/rtkbt/rtkbt.mk @@ -1,84 +1,31 @@ -# 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 \ diff --git a/rtkbt/vendor/firmware_box/fw_info.txt b/rtkbt/vendor/firmware_box/fw_info.txt new file mode 100755 index 0000000..6305bae --- /dev/null +++ b/rtkbt/vendor/firmware_box/fw_info.txt @@ -0,0 +1,18 @@ + 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 diff --git a/rtkbt/vendor/firmware_box/rtl8723b_config b/rtkbt/vendor/firmware_box/rtl8723b_config new file mode 100755 index 0000000..23fae05 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723b_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8723b_fw b/rtkbt/vendor/firmware_box/rtl8723b_fw new file mode 100755 index 0000000..5a1755d Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723b_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8723bs_VQ0_config b/rtkbt/vendor/firmware_box/rtl8723bs_VQ0_config new file mode 100755 index 0000000..6f3b6a8 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723bs_VQ0_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8723bs_VQ0_fw b/rtkbt/vendor/firmware_box/rtl8723bs_VQ0_fw new file mode 100755 index 0000000..d29f164 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723bs_VQ0_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8723bs_config b/rtkbt/vendor/firmware_box/rtl8723bs_config new file mode 100755 index 0000000..c0f57e7 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723bs_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8723bs_fw b/rtkbt/vendor/firmware_box/rtl8723bs_fw new file mode 100755 index 0000000..580c05c Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723bs_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8723bu_config b/rtkbt/vendor/firmware_box/rtl8723bu_config new file mode 100755 index 0000000..994f6ce Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723bu_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8723d_config b/rtkbt/vendor/firmware_box/rtl8723d_config new file mode 100755 index 0000000..6beca86 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723d_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8723d_fw b/rtkbt/vendor/firmware_box/rtl8723d_fw new file mode 100755 index 0000000..53e9795 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723d_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8723ds_config b/rtkbt/vendor/firmware_box/rtl8723ds_config new file mode 100755 index 0000000..0015d66 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723ds_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8723ds_fw b/rtkbt/vendor/firmware_box/rtl8723ds_fw new file mode 100755 index 0000000..566d674 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8723ds_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8761a_config b/rtkbt/vendor/firmware_box/rtl8761a_config new file mode 100755 index 0000000..8559b4a Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761a_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8761a_fw b/rtkbt/vendor/firmware_box/rtl8761a_fw new file mode 100755 index 0000000..ac99c0c Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761a_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8761at_config b/rtkbt/vendor/firmware_box/rtl8761at_config new file mode 100755 index 0000000..f1904fa Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761at_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8761at_fw b/rtkbt/vendor/firmware_box/rtl8761at_fw new file mode 100755 index 0000000..b34efe5 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761at_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8761au8192ee_fw b/rtkbt/vendor/firmware_box/rtl8761au8192ee_fw new file mode 100755 index 0000000..a4da0e4 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761au8192ee_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8761au8812ae_fw b/rtkbt/vendor/firmware_box/rtl8761au8812ae_fw new file mode 100755 index 0000000..4e3bb84 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761au8812ae_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8761au_fw b/rtkbt/vendor/firmware_box/rtl8761au_fw new file mode 100755 index 0000000..1d79c5e Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761au_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8761aw8192eu_config b/rtkbt/vendor/firmware_box/rtl8761aw8192eu_config new file mode 100755 index 0000000..ea3e50e Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761aw8192eu_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8761aw8192eu_fw b/rtkbt/vendor/firmware_box/rtl8761aw8192eu_fw new file mode 100755 index 0000000..e252afc Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8761aw8192eu_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8821a_config b/rtkbt/vendor/firmware_box/rtl8821a_config new file mode 100755 index 0000000..54309f3 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821a_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8821a_fw b/rtkbt/vendor/firmware_box/rtl8821a_fw new file mode 100755 index 0000000..52c150d Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821a_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8821as_config b/rtkbt/vendor/firmware_box/rtl8821as_config new file mode 100755 index 0000000..eb784a8 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821as_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8821as_fw b/rtkbt/vendor/firmware_box/rtl8821as_fw new file mode 100755 index 0000000..09b8560 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821as_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8821c_config b/rtkbt/vendor/firmware_box/rtl8821c_config new file mode 100755 index 0000000..17f3985 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821c_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8821c_fw b/rtkbt/vendor/firmware_box/rtl8821c_fw new file mode 100755 index 0000000..92b320d Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821c_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8821cs_config b/rtkbt/vendor/firmware_box/rtl8821cs_config new file mode 100755 index 0000000..311ee34 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821cs_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8821cs_fw b/rtkbt/vendor/firmware_box/rtl8821cs_fw new file mode 100755 index 0000000..43cc65e Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8821cs_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8822b_config b/rtkbt/vendor/firmware_box/rtl8822b_config new file mode 100755 index 0000000..17f3985 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8822b_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8822b_fw b/rtkbt/vendor/firmware_box/rtl8822b_fw new file mode 100755 index 0000000..6e3f6ef Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8822b_fw differ diff --git a/rtkbt/vendor/firmware_box/rtl8822bs_config b/rtkbt/vendor/firmware_box/rtl8822bs_config new file mode 100755 index 0000000..311ee34 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8822bs_config differ diff --git a/rtkbt/vendor/firmware_box/rtl8822bs_fw b/rtkbt/vendor/firmware_box/rtl8822bs_fw new file mode 100755 index 0000000..bfe37d2 Binary files /dev/null and b/rtkbt/vendor/firmware_box/rtl8822bs_fw differ