-LOCAL_PATH := $(call my-dir)
-
-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 \
- src/upio.c \
- src/bt_list.c \
- src/bt_skbuff.c \
- src/hci_h5.c \
- src/rtk_parse.c \
- src/rtk_btservice.c \
- src/hardware_uart.c \
- src/hardware_usb.c \
- src/rtk_heartbeat.c \
- src/rtk_poll.c \
- src/rtk_btsnoop_net.c
-
-LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/codec/msbc \
- $(BDROID_DIR)/hci/include
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libutils
-
-LOCAL_MODULE := libbt-vendor-realtek
-LOCAL_MODULE_TAGS := optional
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-
-include $(BUILD_SHARED_LIBRARY)
+include $(call all-subdir-makefiles)
--- /dev/null
+LOCAL_PATH := $(call my-dir)
+
+# libbt-codec.a
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ ./sbc/sbc.c \
+ ./sbc/sbc_primitives.c \
+ ./sbc/sbc_primitives_mmx.c \
+ ./sbc/sbc_primitives_neon.c
+
+LOCAL_C_INCLUDES :=
+LOCAL_CFLAGS := \
+ -Wno-error=unused-parameter \
+ -Wno-ignored-attributes
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SHARED_LIBRARIES := libcutils libc
+LOCAL_MODULE := libbt-codec
+#LOCAL_MULTILIB := 32
+
+include $(BUILD_STATIC_LIBRARY)
+
+++ /dev/null
-/*
- *
- * Bluetooth low-complexity, subband codec (SBC) library
- *
- * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
- * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-/* todo items:
-
- use a log2 table for byte integer scale factors calculation (sum log2 results for high and low bytes)
- fill bitpool by 16 bits instead of one at a time in bits allocation/bitpool generation
- port to the dsp
- don't consume more bytes than passed into the encoder
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-//#include <stdint.h>
-#include <malloc.h>
-#include <string.h>
-//#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/errno.h>
-
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-#include "cutils/log.h"
-
-
-#define SBC_SYNCWORD 0xAD
-#define SBC_POOLTAG 'CBSR'
-
-/* sampling frequency */
-#define SBC_FS_16 0x00
-#define SBC_FS_32 0x01
-#define SBC_FS_44 0x02
-#define SBC_FS_48 0x03
-
-/* nrof_blocks */
-#define SBC_NB_4 0x00
-#define SBC_NB_8 0x01
-#define SBC_NB_12 0x02
-#define SBC_NB_16 0x03
-
-/* channel mode */
-#define SBC_CM_MONO 0x00
-#define SBC_CM_DUAL_CHANNEL 0x01
-#define SBC_CM_STEREO 0x02
-#define SBC_CM_JOINT_STEREO 0x03
-
-/* allocation mode */
-#define SBC_AM_LOUDNESS 0x00
-#define SBC_AM_SNR 0x01
-
-/* subbands */
-#define SBC_SB_4 0x00
-#define SBC_SB_8 0x01
-
-#define SBC_ALIGN_BITS 4
-#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
-
-
-typedef unsigned short uint16_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;
-typedef unsigned int u_int32_t;
-
-#ifndef UINT
-typedef unsigned int UINT;
-#endif
-
-
-#if defined(WIN32) && !defined(__cplusplus)
-
-#define inline __inline
-
-#endif
-
-typedef long long sbc_extended_t;
-/*
-static __inline void sbc_synthesize_four(struct sbc_decoder_state *state,
- struct sbc_frame *frame, int ch, int blk);
-*/
-
-
-/* This structure contains an unpacked SBC frame.
- Yes, there is probably quite some unused space herein */
-struct sbc_frame
-{
- uint16_t sampling_frequency; /* in kHz */
- unsigned char blocks;
- enum {
- MONO = SBC_CM_MONO,
- DUAL_CHANNEL = SBC_CM_DUAL_CHANNEL,
- STEREO = SBC_CM_STEREO,
- JOINT_STEREO = SBC_CM_JOINT_STEREO
- } channel_mode;
- uint8_t channels;
- enum {
- LOUDNESS = SBC_AM_LOUDNESS,
- SNR = SBC_AM_SNR
- } allocation_method;
- uint8_t subbands;
- uint8_t bitpool;
- uint8_t join; /* bit number x set means joint stereo has been used in subband x */
- int scale_factor[2][8]; /* only the lower 4 bits of every element are to be used */
- uint16_t audio_sample[16][2][8]; /* raw integer subband samples in the frame */
-
- int sb_sample_f[16][2][8];
- int sb_sample[16][2][8]; /* modified subband samples */
- short pcm_sample[2][16*8]; /* original pcm audio samples */
-};
-
-struct sbc_decoder_state {
- int subbands;
- long long V[2][170];
- int offset[2][16];
-};
-
-struct sbc_encoder_state {
- int subbands;
- int32_t X[2][80];
-};
-
-/*
- * Calculates the CRC-8 of the first len bits in data
- */
-static const uint8_t crc_table[256] = {
- 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
- 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
- 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
- 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
- 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
- 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
- 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
- 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
- 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
- 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
- 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
- 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
- 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
- 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
- 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
- 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
- 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
- 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
- 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
- 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
- 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
- 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
- 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
- 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
- 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
- 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
- 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
- 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
- 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
- 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
- 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
- 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
-};
-
-static uint8_t sbc_crc8(const uint8_t * data, size_t len)
-{
- uint8_t crc = 0x0f;
- size_t i;
- uint8_t octet;
-
- for (i = 0; i < len / 8; i++)
- crc = crc_table[crc ^ data[i]];
-
- octet = data[i];
- for (i = 0; i < len % 8; i++)
- {
- char bit = ((octet ^ crc) & 0x80) >> 7;
-
- crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
-
- octet = octet << 1;
- }
-
- return crc;
-}
-
-/*
- * Code straight from the spec to calculate the bits array
- * Takes a pointer to the frame in question, a pointer to the bits array and the sampling frequency (as 2 bit integer)
- */
-static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8], uint8_t sf)
-{
- if (frame->channel_mode == MONO || frame->channel_mode == DUAL_CHANNEL)
- {
- int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
- int ch, sb;
-
- for (ch = 0; ch < frame->channels; ch++)
- {
- if (frame->allocation_method == SNR)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- bitneed[ch][sb] = frame->scale_factor[ch][sb];
- }
- }
-
- else
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (frame->scale_factor[ch][sb] == 0)
- {
- bitneed[ch][sb] = -5;
- }
- else
- {
- if (frame->subbands == 4)
- {
- loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
- }
-
- else
- {
- loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
- }
-
- if (loudness > 0)
- {
- bitneed[ch][sb] = loudness / 2;
- }
-
- else
- {
- bitneed[ch][sb] = loudness;
- }
- }
- }
- }
-
- max_bitneed = 0;
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (bitneed[ch][sb] > max_bitneed)
- max_bitneed = bitneed[ch][sb];
- }
-
- bitcount = 0;
- slicecount = 0;
- bitslice = max_bitneed + 1;
- do
- {
- bitslice--;
- bitcount += slicecount;
- slicecount = 0;
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
- {
- slicecount++;
- }
-
- else if (bitneed[ch][sb] == bitslice + 1)
- {
- slicecount += 2;
- }
- }
- } while (bitcount + slicecount < frame->bitpool);
-
- if (bitcount + slicecount == frame->bitpool)
- {
- bitcount += slicecount;
- bitslice--;
- }
-
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (bitneed[ch][sb] < bitslice + 2)
- {
- bits[ch][sb] = 0;
- }
-
- else
- {
- bits[ch][sb] = bitneed[ch][sb] - bitslice;
- if (bits[ch][sb] > 16)
- bits[ch][sb] = 16;
- }
- }
-
- sb = 0;
- while (bitcount < frame->bitpool && sb < frame->subbands)
- {
- if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16))
- {
- bits[ch][sb]++;
- bitcount++;
- }
-
- else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1))
- {
- bits[ch][sb] = 2;
- bitcount += 2;
- }
- sb++;
- }
-
- sb = 0;
- while (bitcount < frame->bitpool && sb < frame->subbands)
- {
- if (bits[ch][sb] < 16)
- {
- bits[ch][sb]++;
- bitcount++;
- }
- sb++;
- }
-
- }
-
- }
-
- else if (frame->channel_mode == STEREO || frame->channel_mode == JOINT_STEREO)
- {
- int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
- int ch, sb;
-
- if (frame->allocation_method == SNR)
- {
- for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- bitneed[ch][sb] = frame->scale_factor[ch][sb];
- }
- }
- }
-
- else
- {
- for (ch = 0; ch < 2; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (frame->scale_factor[ch][sb] == 0)
- {
- bitneed[ch][sb] = -5;
- }
-
- else
- {
- if (frame->subbands == 4)
- {
- loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
- }
-
- else
- {
- loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
- }
-
- if (loudness > 0)
- {
- bitneed[ch][sb] = loudness / 2;
- }
-
- else
- {
- bitneed[ch][sb] = loudness;
- }
- }
- }
- }
- }
-
- max_bitneed = 0;
- for (ch = 0; ch < 2; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (bitneed[ch][sb] > max_bitneed)
- max_bitneed = bitneed[ch][sb];
- }
- }
-
- bitcount = 0;
- slicecount = 0;
- bitslice = max_bitneed + 1;
- do {
- bitslice--;
- bitcount += slicecount;
- slicecount = 0;
- for (ch = 0; ch < 2; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
- {
- slicecount++;
- }
-
- else if (bitneed[ch][sb] == bitslice + 1)
- {
- slicecount += 2;
- }
- }
- }
- } while (bitcount + slicecount < frame->bitpool);
-
- if (bitcount + slicecount == frame->bitpool)
- {
- bitcount += slicecount;
- bitslice--;
- }
-
- for (ch = 0; ch < 2; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (bitneed[ch][sb] < bitslice + 2)
- {
- bits[ch][sb] = 0;
- }
-
- else
- {
- bits[ch][sb] = bitneed[ch][sb] - bitslice;
- if (bits[ch][sb] > 16)
- bits[ch][sb] = 16;
- }
- }
- }
-
- ch = 0;
- sb = 0;
- while ((bitcount < frame->bitpool) && (sb < frame->subbands))
- {
- if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16))
- {
- bits[ch][sb]++;
- bitcount++;
- }
-
- else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1))
- {
- bits[ch][sb] = 2;
- bitcount += 2;
- }
- if (ch == 1)
- {
- ch = 0;
- sb++;
- }
- else
- {
- ch = 1;
- }
- }
-
- ch = 0;
- sb = 0;
- while ((bitcount < frame->bitpool) && (sb < frame->subbands))
- {
- if (bits[ch][sb] < 16)
- {
- bits[ch][sb]++;
- bitcount++;
- }
- if (ch == 1)
- {
- ch = 0;
- sb++;
- }
-
- else
- {
- ch = 1;
- }
- }
-
- }
-}
-
-/*
- * Unpacks a SBC frame at the beginning of the stream in data,
- * which has at most len bytes into frame.
- * Returns the length in bytes of the packed frame, or a negative
- * value on error. The error codes are:
- *
- * -1 Data stream too short
- * -2 Sync byte incorrect
- * -3 CRC8 incorrect
- * -4 Bitpool value out of bounds
- */
-static int sbc_unpack_frame(const uint8_t * data, struct sbc_frame *frame, size_t len)
-{
- UINT consumed;
- /* Will copy the parts of the header that are relevant to crc calculation here */
- uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int crc_pos = 0;
- int32_t temp;
-
- uint8_t sf; /* sampling_frequency, temporarily needed as array index */
-
-// int audio_sample;
- int ch, sb, blk, bit; /* channel, subband, block and bit standard counters */
- int bits[2][8]; /* bits distribution */
- int levels[2][8]; /* levels derived from that */
-
- if (len < 4)
- {
- //DbgPrint("Exit when len < 4\n");
- return -1;
- }
-
- if (data[0] != SBC_SYNCWORD)
- {
- //DbgPrint("Exit when data[0] != SBC_SYNCWORD\n");
- return -2;
- }
-
-#if 0
- sf = (data[1] >> 6) & 0x03;
- switch (sf) {
- case SBC_FS_16:
- frame->sampling_frequency = 16000;
- break;
- case SBC_FS_32:
- frame->sampling_frequency = 32000;
- break;
- case SBC_FS_44:
- frame->sampling_frequency = 44100;
- break;
- case SBC_FS_48:
- frame->sampling_frequency = 48000;
- break;
- }
-
- switch ((data[1] >> 4) & 0x03) {
- case SBC_NB_4:
- frame->blocks = 4;
- break;
- case SBC_NB_8:
- frame->blocks = 8;
- break;
- case SBC_NB_12:
- frame->blocks = 12;
- break;
- case SBC_NB_16:
- frame->blocks = 16;
- break;
- }
-
- frame->channel_mode = (data[1] >> 2) & 0x03;
- switch (frame->channel_mode) {
- case MONO:
- frame->channels = 1;
- break;
- case DUAL_CHANNEL: /* fall-through */
- case STEREO:
- case JOINT_STEREO:
- frame->channels = 2;
- break;
- }
-
- frame->allocation_method = (data[1] >> 1) & 0x01;
- frame->subbands = (data[1] & 0x01) ? 8 : 4;
- frame->bitpool = data[2];
-#endif
-
- frame->sampling_frequency = 16000;
- frame->blocks = 15;
- frame->channel_mode = MONO;
- frame->channels = 1;
- frame->allocation_method = SBC_AM_LOUDNESS;
- frame->subbands = 8;
- frame->bitpool = 26;
-
-
- if (((frame->channel_mode == MONO || frame->channel_mode == DUAL_CHANNEL)
- && frame->bitpool > 16 * frame->subbands)
- || ((frame->channel_mode == STEREO || frame->channel_mode == JOINT_STEREO)
- && frame->bitpool > 32 * frame->subbands))
- {
- //DbgPrint("Exit when frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&"
- // "frame->bitpool > 16 * frame->subbands\n");
- return -4;
- }
-
- /* data[3] is crc, we're checking it later */
- consumed = 32;
-#if 1
- crc_header[0] = data[1];
- crc_header[1] = data[2];
-#endif
-
-#if 0
- crc_header[0] = 0x31;
- crc_header[1] = 0x1a;
-#endif
-
- crc_pos = 16;
-
- if (frame->channel_mode == JOINT_STEREO)
- {
- if (len * 8 < consumed + frame->subbands)
- return -1;
-
- frame->join = 0x00;
- for (sb = 0; sb < frame->subbands - 1; sb++) {
- frame->join |= ((data[4] >> (7 - sb)) & 0x01) << sb;
- }
- if (frame->subbands == 4) {
- crc_header[crc_pos / 8] = data[4] & 0xf0;
- } else {
- crc_header[crc_pos / 8] = data[4];
- }
-
- consumed += frame->subbands;
- crc_pos += frame->subbands;
- }
-
- if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
- {
- //DbgPrint("len * 8 < consumed + (4 * frame->subbands * frame->channels\n");
- return -1;
- }
-
- for (ch = 0; ch < frame->channels; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- /* FIXME assert(consumed % 4 == 0); */
- frame->scale_factor[ch][sb] = (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
- crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
-
- consumed += 4;
- crc_pos += 4;
- }
- }
-
- if (data[3] != sbc_crc8(crc_header, crc_pos))
- {
- ALOGD("sbc_crc %02x -> %02x\n",data[3],sbc_crc8(crc_header, crc_pos));
- return -3;
- }
-
- sf = SBC_FS_16;
- sbc_calculate_bits(frame, bits, sf);
-
- for (ch = 0; ch < frame->channels; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- levels[ch][sb] = (1 << bits[ch][sb]) - 1;
- }
- }
-#if 0
- for (blk = 0; blk < frame->blocks; blk++)
- {
- for (ch = 0; ch < frame->channels; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (levels[ch][sb] > 0)
- {
- audio_sample = 0;
- for (bit = 0; bit < bits[ch][sb]; bit++)
- {
- if (consumed > len * 8)
- {
- LogEvent("Exit when consumed > len * 8\n");
- return -1;
- }
-
- if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
- audio_sample |= 1 << (bits[ch][sb] - bit - 1);
-
- consumed++;
- }
-
- frame->sb_sample[blk][ch][sb] =
- (((audio_sample << 1) | 1) << frame->scale_factor[ch][sb]) /
- levels[ch][sb] - (1 << frame->scale_factor[ch][sb]);
- }
-
- else
- frame->sb_sample[blk][ch][sb] = 0;
- }
- }
- }
-#endif
-
-#if 1
-
- for (blk = 0; blk < frame->blocks; blk++)
- {
- for (ch = 0; ch < frame->channels; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- frame->audio_sample[blk][ch][sb] = 0;
- if (bits[ch][sb] == 0)
- continue;
-
- for (bit = 0; bit < bits[ch][sb]; bit++)
- {
- int b; /* A bit */
- if (consumed > len * 8)
- return -1;
-
- b = (data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01;
- frame->audio_sample[blk][ch][sb] |= b << (bits[ch][sb] - bit - 1);
-
- consumed++;
- }
- }
- }
- }
-
- for (blk = 0; blk < frame->blocks; blk++)
- {
- for (ch = 0; ch < frame->channels; ch++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (levels[ch][sb] > 0)
- {
- frame->sb_sample[blk][ch][sb] =
- (((frame->audio_sample[blk][ch][sb] << 16) | 0x8000) / levels[ch][sb]) - 0x8000;
-
- frame->sb_sample[blk][ch][sb] >>= 3;
- frame->sb_sample[blk][ch][sb] = (frame->sb_sample[blk][ch][sb] << (frame->scale_factor[ch][sb] + 1)); // Q13
- }
- else
- {
- frame->sb_sample[blk][ch][sb] = 0;
- }
- }
- }
- }
-#endif
-
- if (frame->channel_mode == JOINT_STEREO)
- {
- for (blk = 0; blk < frame->blocks; blk++)
- {
- for (sb = 0; sb < frame->subbands; sb++)
- {
- if (frame->join & (0x01 << sb)) {
- temp = frame->sb_sample[blk][0][sb] + frame->sb_sample[blk][1][sb];
- frame->sb_sample[blk][1][sb] = frame->sb_sample[blk][0][sb] - frame->sb_sample[blk][1][sb];
- frame->sb_sample[blk][0][sb] = temp;
- }
- }
- }
- }
-
- if ((consumed & 0x7) != 0)
- consumed += 8 - (consumed & 0x7);
-
-
- return consumed >> 3;
-}
-
-static void sbc_decoder_init(struct sbc_decoder_state *state, const struct sbc_frame *frame)
-{
- int i, ch;
-
- memset(state->V, 0, sizeof(state->V));
- state->subbands = frame->subbands;
-
- for (ch = 0; ch < 2; ch++)
- for (i = 0; i < frame->subbands * 2; i++)
- state->offset[ch][i] = (10 * i + 10);
-}
-
-static __inline void sbc_synthesize_four(struct sbc_decoder_state *state,
- struct sbc_frame *frame, int ch, int blk)
-{
- int i, j, k, idx;
- sbc_extended_t res;
-
- for(i = 0; i < 8; i++) {
- /* Shifting */
- state->offset[ch][i]--;
- if(state->offset[ch][i] < 0) {
- state->offset[ch][i] = 79;
- for(j = 0; j < 9; j++) {
- state->V[ch][j+80] = state->V[ch][j];
- }
- }
- }
-
-
- for(i = 0; i < 8; i++) {
- /* Distribute the new matrix value to the shifted position */
- SBC_FIXED_0(res);
- for (j = 0; j < 4; j++) {
- MULA(res, synmatrix4[i][j], frame->sb_sample[blk][ch][j]);
- }
- state->V[ch][state->offset[ch][i]] = SCALE4_STAGED1(res);
- }
-
- /* Compute the samples */
- for(idx = 0, i = 0; i < 4; i++) {
- k = (i + 4) & 0xf;
- SBC_FIXED_0(res);
- for(j = 0; j < 10; idx++) {
- MULA(res, state->V[ch][state->offset[ch][i]+j++], sbc_proto_4_40m0[idx]);
- MULA(res, state->V[ch][state->offset[ch][k]+j++], sbc_proto_4_40m1[idx]);
- }
- /* Store in output */
- frame->pcm_sample[ch][blk * 4 + i] = (short)SCALE4_STAGED2(res); // Q0
- }
-}
-
-static __inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
- struct sbc_frame *frame, int ch, int blk)
-{
- int i, j, k, idx;
- sbc_extended_t res;
-
- for(i = 0; i < 16; i++) {
- /* Shifting */
- state->offset[ch][i]--;
- if(state->offset[ch][i] < 0) {
- state->offset[ch][i] = 159;
- for(j = 0; j < 9; j++) {
- state->V[ch][j+160] = state->V[ch][j];
- }
- }
- }
-
- for(i = 0; i < 16; i++) {
- /* Distribute the new matrix value to the shifted position */
- SBC_FIXED_0(res);
- for (j = 0; j < 8; j++) {
- MULA(res, synmatrix8[i][j], frame->sb_sample[blk][ch][j]); // Q28 = Q15 * Q13
- }
- state->V[ch][state->offset[ch][i]] = SCALE8_STAGED1(res); // Q10
- }
-
-
- /* Compute the samples */
- for(idx = 0, i = 0; i < 8; i++) {
- k = (i + 8) & 0xf;
- SBC_FIXED_0(res);
- for(j = 0; j < 10; idx++) {
- MULA(res, state->V[ch][state->offset[ch][i]+j++], sbc_proto_8_80m0[idx]);
- MULA(res, state->V[ch][state->offset[ch][k]+j++], sbc_proto_8_80m1[idx]);
- }
- /* Store in output */
- frame->pcm_sample[ch][blk * 8 + i] = (short)SCALE8_STAGED2(res); // Q0
-
- }
-}
-
-static int sbc_synthesize_audio(struct sbc_decoder_state *state, struct sbc_frame *frame)
-{
- int ch, blk;
-
- switch (frame->subbands) {
- case 4:
- for (ch = 0; ch < frame->channels; ch++) {
- for (blk = 0; blk < frame->blocks; blk++)
- sbc_synthesize_four(state, frame, ch, blk);
- }
- return frame->blocks * 4;
-
- case 8:
- for (ch = 0; ch < frame->channels; ch++) {
- for (blk = 0; blk < frame->blocks; blk++)
- sbc_synthesize_eight(state, frame, ch, blk);
- }
- return frame->blocks * 8;
-
- default:
- return -EIO;
- }
-}
-
-static void sbc_encoder_init(struct sbc_encoder_state *state, const struct sbc_frame *frame)
-{
- memset(&state->X, 0, sizeof(state->X));
- state->subbands = frame->subbands;
-}
-
-static __inline void _sbc_analyze_four(const int32_t *in, int32_t *out)
-{
-
- sbc_extended_t res;
- sbc_extended_t t[8];
-
- out[0] = out[1] = out[2] = out[3] = 0;
-
- MUL(res, _sbc_proto_4[0], (in[8] - in[32])); // Q18
- MULA(res, _sbc_proto_4[1], (in[16] - in[24]));
- t[0] = SCALE4_STAGE1(res); // Q8
-
- MUL(res, _sbc_proto_4[2], in[1]);
- MULA(res, _sbc_proto_4[3], in[9]);
- MULA(res, _sbc_proto_4[4], in[17]);
- MULA(res, _sbc_proto_4[5], in[25]);
- MULA(res, _sbc_proto_4[6], in[33]);
- t[1] = SCALE4_STAGE1(res);
-
- MUL(res, _sbc_proto_4[7], in[2]);
- MULA(res, _sbc_proto_4[8], in[10]);
- MULA(res, _sbc_proto_4[9], in[18]);
- MULA(res, _sbc_proto_4[10], in[26]);
- MULA(res, _sbc_proto_4[11], in[34]);
- t[2] = SCALE4_STAGE1(res);
-
- MUL(res, _sbc_proto_4[12], in[3]);
- MULA(res, _sbc_proto_4[13], in[11]);
- MULA(res, _sbc_proto_4[14], in[19]);
- MULA(res, _sbc_proto_4[15], in[27]);
- MULA(res, _sbc_proto_4[16], in[35]);
- t[3] = SCALE4_STAGE1(res);
-
- MUL(res, _sbc_proto_4[17], in[4]);
- MULA(res, _sbc_proto_4[18], (in[12] + in[28]));
- MULA(res, _sbc_proto_4[19], in[20]);
- MULA(res, _sbc_proto_4[17], in[36]);
- t[4] = SCALE4_STAGE1(res);
-
- MUL(res, _sbc_proto_4[16], in[5]);
- MULA(res, _sbc_proto_4[15], in[13]);
- MULA(res, _sbc_proto_4[14], in[21]);
- MULA(res, _sbc_proto_4[13], in[29]);
- MULA(res, _sbc_proto_4[12], in[37]);
- t[5] = SCALE4_STAGE1(res);
-
- MUL(res, _sbc_proto_4[11], in[6]);
- MULA(res, _sbc_proto_4[10], in[14]);
- MULA(res, _sbc_proto_4[9], in[22]);
- MULA(res, _sbc_proto_4[8], in[30]);
- MULA(res, _sbc_proto_4[7], in[38]);
- t[6] = SCALE4_STAGE1(res);
-
- MUL(res, _sbc_proto_4[6], in[7]);
- MULA(res, _sbc_proto_4[5], in[15]);
- MULA(res, _sbc_proto_4[4], in[23]);
- MULA(res, _sbc_proto_4[3], in[31]);
- MULA(res, _sbc_proto_4[2], in[39]);
- t[7] = SCALE4_STAGE1(res);
-
- MUL(res, _anamatrix4[0], t[0]);
- MULA(res, _anamatrix4[1], t[1]);
- MULA(res, _anamatrix4[2], t[2]);
- MULA(res, _anamatrix4[1], t[3]);
- MULA(res, _anamatrix4[0], t[4]);
- MULA(res, _anamatrix4[3], t[5]);
- MULA(res, -_anamatrix4[3], t[7]);
- out[0] = (int)SCALE4_STAGE2(res); // Q0
-
- MUL(res, -_anamatrix4[0], t[0]);
- MULA(res, _anamatrix4[3], t[1]);
- MULA(res, _anamatrix4[2], t[2]);
- MULA(res, _anamatrix4[3], t[3]);
- MULA(res, -_anamatrix4[0], t[4]);
- MULA(res, -_anamatrix4[1], t[5]);
- MULA(res, _anamatrix4[1], t[7]);
- out[1] = (int)SCALE4_STAGE2(res);
-
-
- MUL(res, -_anamatrix4[0], t[0]);
- MULA(res, -_anamatrix4[3], t[1]);
- MULA(res, _anamatrix4[2], t[2]);
- MULA(res, -_anamatrix4[3], t[3]);
- MULA(res, -_anamatrix4[0], t[4]);
- MULA(res, _anamatrix4[1], t[5]);
- MULA(res, -_anamatrix4[1], t[7]);
- out[2] = (int)SCALE4_STAGE2(res);
-
- MUL(res, _anamatrix4[0], t[0]);
- MULA(res, -_anamatrix4[1], t[1]);
- MULA(res, _anamatrix4[2], t[2]);
- MULA(res, -_anamatrix4[1], t[3]);
- MULA(res, _anamatrix4[0], t[4]);
- MULA(res, -_anamatrix4[3], t[5]);
- MULA(res, _anamatrix4[3], t[7]);
- out[3] = (int)SCALE4_STAGE2(res);
-}
-static __inline void sbc_analyze_four(struct sbc_encoder_state *state,
- struct sbc_frame *frame, int ch, int blk)
-{
- int i;
- /* Input 4 New Audio Samples */
- for (i = 39; i >= 4; i--)
- state->X[ch][i] = state->X[ch][i - 4];
- for (i = 3; i >= 0; i--)
- state->X[ch][i] = frame->pcm_sample[ch][blk * 4 + (3 - i)];
- _sbc_analyze_four(state->X[ch], frame->sb_sample_f[blk][ch]);
-}
-
-static __inline void _sbc_analyze_eight(const int32_t *in, int32_t *out)
-{
- sbc_extended_t res;
- sbc_extended_t t[8];
-
- out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = 0;
-
- MUL(res, _sbc_proto_8[0], (in[16] - in[64])); // Q18 = Q18 * Q0
- MULA(res, _sbc_proto_8[1], (in[32] - in[48]));
- MULA(res, _sbc_proto_8[2], in[4]);
- MULA(res, _sbc_proto_8[3], in[20]);
- MULA(res, _sbc_proto_8[4], in[36]);
- MULA(res, _sbc_proto_8[5], in[52]);
- t[0] = SCALE8_STAGE1(res); // Q10
-
- MUL(res, _sbc_proto_8[6], in[2]);
- MULA(res, _sbc_proto_8[7], in[18]);
- MULA(res, _sbc_proto_8[8], in[34]);
- MULA(res, _sbc_proto_8[9], in[50]);
- MULA(res, _sbc_proto_8[10], in[66]);
- t[1] = SCALE8_STAGE1(res);
-
- MUL(res, _sbc_proto_8[11], in[1]);
- MULA(res, _sbc_proto_8[12], in[17]);
- MULA(res, _sbc_proto_8[13], in[33]);
- MULA(res, _sbc_proto_8[14], in[49]);
- MULA(res, _sbc_proto_8[15], in[65]);
- MULA(res, _sbc_proto_8[16], in[3]);
- MULA(res, _sbc_proto_8[17], in[19]);
- MULA(res, _sbc_proto_8[18], in[35]);
- MULA(res, _sbc_proto_8[19], in[51]);
- MULA(res, _sbc_proto_8[20], in[67]);
- t[2] = SCALE8_STAGE1(res);
-
- MUL(res, _sbc_proto_8[21], in[5]);
- MULA(res, _sbc_proto_8[22], in[21]);
- MULA(res, _sbc_proto_8[23], in[37]);
- MULA(res, _sbc_proto_8[24], in[53]);
- MULA(res, _sbc_proto_8[25], in[69]);
- MULA(res, -_sbc_proto_8[15], in[15]);
- MULA(res, -_sbc_proto_8[14], in[31]);
- MULA(res, -_sbc_proto_8[13], in[47]);
- MULA(res, -_sbc_proto_8[12], in[63]);
- MULA(res, -_sbc_proto_8[11], in[79]);
- t[3] = SCALE8_STAGE1(res);
-
- MUL(res, _sbc_proto_8[26], in[6]);
- MULA(res, _sbc_proto_8[27], in[22]);
- MULA(res, _sbc_proto_8[28], in[38]);
- MULA(res, _sbc_proto_8[29], in[54]);
- MULA(res, _sbc_proto_8[30], in[70]);
- MULA(res, -_sbc_proto_8[10], in[14]);
- MULA(res, -_sbc_proto_8[9], in[30]);
- MULA(res, -_sbc_proto_8[8], in[46]);
- MULA(res, -_sbc_proto_8[7], in[62]);
- MULA(res, -_sbc_proto_8[6], in[78]);
- t[4] = SCALE8_STAGE1(res);
-
- MUL(res, _sbc_proto_8[31], in[7]);
- MULA(res, _sbc_proto_8[32], in[23]);
- MULA(res, _sbc_proto_8[33], in[39]);
- MULA(res, _sbc_proto_8[34], in[55]);
- MULA(res, _sbc_proto_8[35], in[71]);
- MULA(res, -_sbc_proto_8[20], in[13]);
- MULA(res, -_sbc_proto_8[19], in[29]);
- MULA(res, -_sbc_proto_8[18], in[45]);
- MULA(res, -_sbc_proto_8[17], in[61]);
- MULA(res, -_sbc_proto_8[16], in[77]);
- t[5] = SCALE8_STAGE1(res);
-
- MUL(res, _sbc_proto_8[36], (in[8] + in[72]));
- MULA(res, _sbc_proto_8[37], in[24]);
- MULA(res, _sbc_proto_8[38], in[40]);
- MULA(res, _sbc_proto_8[37], in[56]);
- MULA(res, -_sbc_proto_8[39], in[12]);
- MULA(res, -_sbc_proto_8[5], in[28]);
- MULA(res, -_sbc_proto_8[4], in[44]);
- MULA(res, -_sbc_proto_8[3], in[60]);
- MULA(res, -_sbc_proto_8[2], in[76]);
- t[6] = SCALE8_STAGE1(res);
-
- MUL(res, _sbc_proto_8[35], in[9]);
- MULA(res, _sbc_proto_8[34], in[25]);
- MULA(res, _sbc_proto_8[33], in[41]);
- MULA(res, _sbc_proto_8[32], in[57]);
- MULA(res, _sbc_proto_8[31], in[73]);
- MULA(res, -_sbc_proto_8[25], in[11]);
- MULA(res, -_sbc_proto_8[24], in[27]);
- MULA(res, -_sbc_proto_8[23], in[43]);
- MULA(res, -_sbc_proto_8[22], in[59]);
- MULA(res, -_sbc_proto_8[21], in[75]);
- t[7] = SCALE8_STAGE1(res);
-
- MUL(res, _anamatrix8[0], t[0]); // = Q14 * Q10
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, _anamatrix8[2], t[2]);
- MULA(res, _anamatrix8[3], t[3]);
- MULA(res, _anamatrix8[6], t[4]);
- MULA(res, _anamatrix8[4], t[5]);
- MULA(res, _anamatrix8[1], t[6]);
- MULA(res, _anamatrix8[5], t[7]);
- out[0] = (int)SCALE8_STAGE2(res); // Q0
-
- MUL(res, _anamatrix8[1], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, _anamatrix8[3], t[2]);
- MULA(res, -_anamatrix8[5], t[3]);
- MULA(res, -_anamatrix8[6], t[4]);
- MULA(res, -_anamatrix8[2], t[5]);
- MULA(res, -_anamatrix8[0], t[6]);
- MULA(res, -_anamatrix8[4], t[7]);
- out[1] = (int)SCALE8_STAGE2(res);
-
- MUL(res, -_anamatrix8[1], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, _anamatrix8[4], t[2]);
- MULA(res, -_anamatrix8[2], t[3]);
- MULA(res, -_anamatrix8[6], t[4]);
- MULA(res, _anamatrix8[5], t[5]);
- MULA(res, _anamatrix8[0], t[6]);
- MULA(res, _anamatrix8[3], t[7]);
- out[2] = (int)SCALE8_STAGE2(res);
-
- MUL(res, -_anamatrix8[0], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, _anamatrix8[5], t[2]);
- MULA(res, -_anamatrix8[4], t[3]);
- MULA(res, _anamatrix8[6], t[4]);
- MULA(res, _anamatrix8[3], t[5]);
- MULA(res, -_anamatrix8[1], t[6]);
- MULA(res, -_anamatrix8[2], t[7]);
- out[3] = (int)SCALE8_STAGE2(res);
-
- MUL(res, -_anamatrix8[0], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, -_anamatrix8[5], t[2]);
- MULA(res, _anamatrix8[4], t[3]);
- MULA(res, _anamatrix8[6], t[4]);
- MULA(res, -_anamatrix8[3], t[5]);
- MULA(res, -_anamatrix8[1], t[6]);
- MULA(res, _anamatrix8[2], t[7]);
- out[4] = (int)SCALE8_STAGE2(res);
-
- MUL(res, -_anamatrix8[1], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, -_anamatrix8[4], t[2]);
- MULA(res, _anamatrix8[2], t[3]);
- MULA(res, -_anamatrix8[6], t[4]);
- MULA(res, -_anamatrix8[5], t[5]);
- MULA(res, _anamatrix8[0], t[6]);
- MULA(res, -_anamatrix8[3], t[7]);
- out[5] = (int)SCALE8_STAGE2(res);
-
- MUL(res, _anamatrix8[1], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, -_anamatrix8[3], t[2]);
- MULA(res, _anamatrix8[5], t[3]);
- MULA(res, -_anamatrix8[6], t[4]);
- MULA(res, _anamatrix8[2], t[5]);
- MULA(res, -_anamatrix8[0], t[6]);
- MULA(res, _anamatrix8[4], t[7]);
- out[6] = (int)SCALE8_STAGE2(res);
-
- MUL(res, _anamatrix8[0], t[0]);
- MULA(res, _anamatrix8[7], t[1]);
- MULA(res, -_anamatrix8[2], t[2]);
- MULA(res, -_anamatrix8[3], t[3]);
- MULA(res, _anamatrix8[6], t[4]);
- MULA(res, -_anamatrix8[4], t[5]);
- MULA(res, _anamatrix8[1], t[6]);
- MULA(res, -_anamatrix8[5], t[7]);
- out[7] = (int)SCALE8_STAGE2(res);
-}
-
-static __inline void sbc_analyze_eight(struct sbc_encoder_state *state,
- struct sbc_frame *frame, int ch, int blk)
-{
- int i;
-
- /* Input 8 Audio Samples */
- for (i = 79; i >= 8; i--)
- state->X[ch][i] = state->X[ch][i - 8];
- for (i = 7; i >= 0; i--)
- state->X[ch][i] = frame->pcm_sample[ch][blk * 8 + (7 - i)];
- _sbc_analyze_eight(state->X[ch], frame->sb_sample_f[blk][ch]);
-}
-
-static int sbc_analyze_audio(struct sbc_encoder_state *state, struct sbc_frame *frame)
-{
- int ch, blk;
-
- switch (frame->subbands)
- {
- case 4:
- for (ch = 0; ch < frame->channels; ch++)
- for (blk = 0; blk < frame->blocks; blk++) {
- sbc_analyze_four(state, frame, ch, blk);
- }
- return frame->blocks * 4;
-
- case 8:
- for (ch = 0; ch < frame->channels; ch++)
- for (blk = 0; blk < frame->blocks; blk++) {
- sbc_analyze_eight(state, frame, ch, blk);
- }
- return frame->blocks * 8;
-
- default:
- return -EIO;
- }
-}
-
-/*
- * Packs the SBC frame from frame into the memory at data. At most len
- * bytes will be used, should more memory be needed an appropriate
- * error code will be returned. Returns the length of the packed frame
- * on success or a negative value on error.
- *
- * The error codes are:
- * -1 Not enough memory reserved
- * -2 Unsupported sampling rate
- * -3 Unsupported number of blocks
- * -4 Unsupported number of subbands
- * -5 Bitpool value out of bounds
- * -99 not implemented
- */
-
-static int sbc_pack_frame(uint8_t * data, struct sbc_frame *frame, size_t len)
-{
- size_t produced;
- /* Will copy the header parts for CRC-8 calculation here */
- uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int crc_pos = 0;
-
- uint8_t sf; /* Sampling frequency as temporary value for table lookup */
-
- int ch, sb, blk, bit; /* channel, subband, block and bit counters */
- int bits[2][8]; /* bits distribution */
- int levels[2][8]; /* levels are derived from that */
-
- u_int32_t scalefactor[2][8]; /* derived from frame->scale_factor */
-
- if (len < 4)
- {
- return -1;
- }
-
- /* Clear first 4 bytes of data (that's the constant length part of the SBC header) */
- memset(data, 0, 4);
-
- data[0] = SBC_SYNCWORD;
-
- if (frame->sampling_frequency == 16000)
- {
- data[1] |= (SBC_FS_16 & 0x03) << 6;
- sf = SBC_FS_16;
- }
- else if (frame->sampling_frequency == 32000)
- {
- data[1] |= (SBC_FS_32 & 0x03) << 6;
- sf = SBC_FS_32;
- }
- else if (frame->sampling_frequency == 44100)
- {
- data[1] |= (SBC_FS_44 & 0x03) << 6;
- sf = SBC_FS_44;
- }
- else if (frame->sampling_frequency == 48000)
- {
- data[1] |= (SBC_FS_48 & 0x03) << 6;
- sf = SBC_FS_48;
- }
- else
- {
- return -2;
- }
-
- switch (frame->blocks)
- {
- case 4:
- data[1] |= (SBC_NB_4 & 0x03) << 4;
- break;
- case 8:
- data[1] |= (SBC_NB_8 & 0x03) << 4;
- break;
- case 12:
- data[1] |= (SBC_NB_12 & 0x03) << 4;
- break;
- case 15:
- data[1] |= (SBC_NB_16 & 0x03) << 4;
- break;
- default:
- return -3;
- break;
- }
-
- data[1] |= (frame->channel_mode & 0x03) << 2;
-
- data[1] |= (frame->allocation_method & 0x01) << 1;
-
- switch (frame->subbands) {
- case 4:
- /* Nothing to do */
- break;
- case 8:
- data[1] |= 0x01;
- break;
- default:
- return -4;
- break;
- }
-
- data[2] = frame->bitpool;
- if (((frame->channel_mode == MONO || frame->channel_mode == DUAL_CHANNEL)
- && frame->bitpool > 16 * frame->subbands)
- || ((frame->channel_mode == STEREO || frame->channel_mode == JOINT_STEREO)
- && frame->bitpool > 32 * frame->subbands)) {
- return -5;
- }
-
- /* Can't fill in crc yet */
-
- produced = 32;
-
- // evan.
- data[1] = 0x00;
- data[2] = 0x00;
-
- crc_header[0] = data[1];
- crc_header[1] = data[2];
- crc_pos = 16;
-
-
- for (ch = 0; ch < frame->channels; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
- frame->scale_factor[ch][sb] = 0;
- scalefactor[ch][sb] = 2;
- for (blk = 0; blk < frame->blocks; blk++) {
- while (scalefactor[ch][sb] < (u_int32_t)fabs(frame->sb_sample_f[blk][ch][sb])) {
- frame->scale_factor[ch][sb]++;
- scalefactor[ch][sb] *= 2;
- }
- }
- }
- }
-
- if (frame->channel_mode == JOINT_STEREO) {
- int32_t sb_sample_j[16][2][7]; /* like frame->sb_sample but joint stereo */
- u_int32_t scalefactor_j[2][7], scale_factor_j[2][7]; /* scalefactor and scale_factor in joint case */
-
- /* Calculate joint stereo signal */
- for (sb = 0; sb < frame->subbands - 1; sb++) {
- for (blk = 0; blk < frame->blocks; blk++) {
- sb_sample_j[blk][0][sb] = (frame->sb_sample_f[blk][0][sb] + frame->sb_sample_f[blk][1][sb]) >> 1;
- sb_sample_j[blk][1][sb] = (frame->sb_sample_f[blk][0][sb] - frame->sb_sample_f[blk][1][sb]) >> 1;
- }
- }
-
- /* calculate scale_factor_j and scalefactor_j for joint case */
- for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands - 1; sb++) {
- scale_factor_j[ch][sb] = 0;
- scalefactor_j[ch][sb] = 2;
- for (blk = 0; blk < frame->blocks; blk++) {
- while (scalefactor_j[ch][sb] < (u_int32_t)fabs(sb_sample_j[blk][ch][sb])) {
- scale_factor_j[ch][sb]++;
- scalefactor_j[ch][sb] *= 2;
- }
- }
- }
- }
-
- /* decide which subbands to join */
- frame->join = 0;
- for (sb = 0; sb < frame->subbands - 1; sb++) {
- if ((scalefactor[0][sb] + scalefactor[1][sb]) >
- (scalefactor_j[0][sb] + scalefactor_j[1][sb]) ) {
- /* use joint stereo for this subband */
- frame->join |= 1 << sb;
- frame->scale_factor[0][sb] = scale_factor_j[0][sb];
- frame->scale_factor[1][sb] = scale_factor_j[1][sb];
- scalefactor[0][sb] = scalefactor_j[0][sb];
- scalefactor[1][sb] = scalefactor_j[1][sb];
- for (blk = 0; blk < frame->blocks; blk++) {
- frame->sb_sample_f[blk][0][sb] = sb_sample_j[blk][0][sb];
- frame->sb_sample_f[blk][1][sb] = sb_sample_j[blk][1][sb];
- }
- }
- }
-
- if (len * 8 < produced + frame->subbands)
- return -1;
-
- data[4] = 0;
- for (sb = 0; sb < frame->subbands - 1; sb++) {
- data[4] |= ((frame->join >> sb) & 0x01) << (7 - sb);
- }
- if (frame->subbands == 4) {
- crc_header[crc_pos / 8] = data[4] & 0xf0;
- } else {
- crc_header[crc_pos / 8] = data[4];
- }
-
- produced += frame->subbands;
- crc_pos += frame->subbands;
- }
-
- if (len * 8 < produced + (4 * frame->subbands * frame->channels))
- return -1;
-
- for (ch = 0; ch < frame->channels; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
- if (produced % 8 == 0)
- data[produced / 8] = 0;
- data[produced / 8] |= ((frame->scale_factor[ch][sb] & 0x0F) << (4 - (produced % 8)));
- crc_header[crc_pos / 8] |= ((frame->scale_factor[ch][sb] & 0x0F) << (4 - (crc_pos % 8)));
-
- produced += 4;
- crc_pos += 4;
- }
- }
-
- data[3] = sbc_crc8(crc_header, crc_pos);
-
-
-
- sbc_calculate_bits(frame, bits, sf);
-
- for (ch = 0; ch < frame->channels; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
- levels[ch][sb] = (1 << bits[ch][sb]) - 1;
- }
- }
-
- for (blk = 0; blk < frame->blocks; blk++) {
- for (ch = 0; ch < frame->channels; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
- if (levels[ch][sb] > 0) {
- frame->audio_sample[blk][ch][sb] =
- (uint16_t) ((((frame->sb_sample_f[blk][ch][sb]*levels[ch][sb]) >> (frame->scale_factor[ch][sb] + 1)) +
- levels[ch][sb]) >> 1);
- } else {
- frame->audio_sample[blk][ch][sb] = 0;
- }
- }
- }
- }
-
- for (blk = 0; blk < frame->blocks; blk++) {
- for (ch = 0; ch < frame->channels; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
- if (bits[ch][sb] != 0) {
- for (bit = 0; bit < bits[ch][sb]; bit++) {
- int b; /* A bit */
- if (produced > len * 8) {
- return -1;
- }
- if (produced % 8 == 0) {
- data[produced / 8] = 0;
- }
- b = ((frame->audio_sample[blk][ch][sb]) >> (bits[ch][sb] - bit -
- 1)) & 0x01;
- data[produced / 8] |= b << (7 - (produced % 8));
- produced++;
- }
- }
- }
- }
- }
-
- if (produced % 8 != 0) {
- produced += 8 - (produced % 8);
- }
-
- return (int)(produced / 8);
-}
-
-struct sbc_priv {
- int init;
- struct sbc_frame frame;
- struct sbc_decoder_state dec_state;
- struct sbc_encoder_state enc_state;
-};
-
-int sbc_init(sbc_t *sbc)//int sbc_init(sbc_t *sbc, unsigned long flags)
-{
- if (!sbc)
- return -EIO;
-
- //flags = flags;
-
- memset(sbc, 0, sizeof(sbc_t));
-
- sbc->priv = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
- if (!sbc->priv)
- return -ENOMEM;
- memset(sbc->priv, 0, sizeof(struct sbc_priv));
-
- sbc->rate = 16000;
- sbc->channels = 1;
- sbc->joint = 0;
- sbc->subbands = 8;
- sbc->blocks = 15;
- sbc->bitpool = 26;
-
- return 0;
-}
-
-int sbc_reinit(sbc_t *sbc)//int sbc_reinit(sbc_t *sbc, unsigned long flags)
-{
- struct sbc_priv *priv;
-
- if (!sbc || !sbc->priv)
- return -EIO;
-
- //flags = flags;
- priv = sbc->priv;
-
- if (priv->init == 1)
- memset(sbc->priv, 0, sizeof(struct sbc_priv));
-
- return 0;
-}
-
-
-int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
- int output_len, int *written)
-{
- struct sbc_priv *priv;
- char *ptr;
- int i, ch, framelen, samples;
-
- if (!sbc)
- {
- //DbgPrint("Exit.when sbc is NULL.\n");
- return -EIO;
- }
-
- if (!sbc && !input)
- {
- //DbgPrint("!sbc && !input\n");
- return -EIO;
- }
-
- priv = sbc->priv;
- if(!priv)
- return -99;
-
- framelen = sbc_unpack_frame(input, &priv->frame, input_len);
-
- if (!priv->init)
- {
- sbc_decoder_init(&priv->dec_state, &priv->frame);
- priv->init = 1;
-
- sbc->rate = priv->frame.sampling_frequency;
- sbc->channels = priv->frame.channels;
- sbc->subbands = priv->frame.subbands;
- sbc->blocks = priv->frame.blocks;
- sbc->bitpool = priv->frame.bitpool;
- }
-
- if (!output)
- {
- //DbgPrint("!output\n");
- return framelen;
- }
-
- if (written)
- *written = 0;
-
- if (framelen <= 0)
- {
- //DbgPrint("Exit when framelen <= 0\n");
- return framelen;
- }
-
- samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
-
- ptr = output;
- if (output_len < samples * priv->frame.channels * 2)
- samples = output_len / (priv->frame.channels * 2);
-
-/*
- if (!sbc->data)
- {
- sbc->size = samples * priv->frame.channels * 2;
- sbc->data = malloc(sbc->size);
- }
-
-
- if (sbc->size < samples * priv->frame.channels * 2)
- {
- sbc->size = samples * priv->frame.channels * 2;
- sbc->data = realloc(sbc->data, sbc->size);
- }
-
- if (!sbc->data)
- {
- sbc->size = 0;
- return -ENOMEM;
- }
-*/
-
- for (i = 0; i < samples; i++)
- {
- for (ch = 0; ch < priv->frame.channels; ch++)
- {
- int16_t s;
- s = priv->frame.pcm_sample[ch][i];
- /*
- *ptr++ = (s & 0xff00) >> 8;
- *ptr++ = (s & 0x00ff);
- */
- *ptr++ = (s & 0x00ff);
- *ptr++ = (s & 0xff00) >> 8;
- }
- }
-
- if (written)
- *written = samples * priv->frame.channels * 2;
-
- return framelen;
-}
-
-int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
- int output_len, int *written)
-{
- struct sbc_priv *priv;
- char *ptr;
- int i, ch, framelen, samples;
-
- if (!sbc)
- {
- //DbgPrint("Exit, when !sbc.\n");
- return -EIO;
- }
-
-
- if (!sbc && !input)
- {
- //DbgPrint("Exit, when !sbc && !input.\n");
- return -EIO;
- }
-
- /// make sure sbc has been initialized
- priv = sbc->priv;
- if(priv == NULL){
- //DbgPrint("priv == NULL\n");
- return -EIO;
- }
-
- if (written)
- *written = 0;
-
- if (!priv->init)
- {
- //DbgPrint("Initial priv->frame ,when priv->init is null\n");
- priv->frame.sampling_frequency = sbc->rate;
- priv->frame.channels = sbc->channels;
- priv->frame.channel_mode = MONO;
- priv->frame.allocation_method = LOUDNESS;
- priv->frame.subbands = sbc->subbands;
- priv->frame.blocks = sbc->blocks;
- priv->frame.bitpool = sbc->bitpool;
-
- sbc_encoder_init(&priv->enc_state, &priv->frame);
- priv->init = 1;
- }
-
- /* input must be large enough to encode a complete frame */
- if (input_len < 240)
- {
- //DbgPrint("Exit, when input_len < priv->frame.codesize..\n");
- return 0;
- }
-
- /* output must be large enough to receive the encoded frame */
- if (!output || output_len < 57)
- {
- //DbgPrint("Exit, when !output || output_len < priv->frame.length\n");
- return -ENOSPC;
- }
-
- ptr = input;
- for (i = 0; i < priv->frame.subbands * priv->frame.blocks; i++)
- {
- for (ch = 0; ch < sbc->channels; ch++)
- {
- // int16_t s = (ptr[0] & 0xff) << 8 | (ptr[1] & 0xff);
- int16_t s = (ptr[1] & 0xff) << 8 | (ptr[0] & 0xff);
- ptr += 2;
- priv->frame.pcm_sample[ch][i] = s;
- }
- }
-
- samples = 0;
- samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
-
- if (!sbc->data)
- {
- sbc->size = 1024;
-// sbc->data = malloc(sbc->size);
- sbc->data = malloc(sbc->size);
- if (!sbc->data)
- {
- //DbgPrint("sbc->data allocate failed!!!\n");
- return -ENOMEM;
- }
- memset(sbc->data, 0, sbc->size);
- }
-
- if (!sbc->data)
- {
- sbc->size = 0;
- //DbgPrint("sbc->data is null, so exit!!!\n");
- return -ENOMEM;
- }
-
- framelen = sbc_pack_frame(output, &priv->frame, output_len);
- if (written)
- {
- *written = (int)framelen;//in 64 bit os, it should be okay.
- }
-
- sbc->len = framelen;
- sbc->duration = (1000000 * priv->frame.subbands * priv->frame.blocks) / sbc->rate;
-
- return samples * sbc->channels * 2;
-}
-
-
-void sbc_finish(sbc_t *sbc)
-{
- if (!sbc)
- return;
-
- if (sbc->data)
- free(sbc->data);
-
-
- if (sbc->priv)
- {
- free(sbc->priv);
- }
- memset(sbc, 0, sizeof(sbc_t));
-}
+++ /dev/null
-/*
- *
- * Bluetooth low-complexity, subband codec (SBC) library
- *
- * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
- * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __SBC_H
-#define __SBC_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-struct sbc_struct {
- unsigned long flags;
- unsigned short rate;
- unsigned char channels;
- unsigned char joint;
- unsigned char blocks;
- unsigned char subbands;
- unsigned char bitpool;
-
- void *data;
- int size;
- int len;
-
- unsigned long duration;
-
- void *priv;
-};
-
-typedef struct sbc_struct sbc_t;
-
-int sbc_init(sbc_t *sbc);//int sbc_init(sbc_t *sbc, unsigned long flags);
-
-int sbc_reinit(sbc_t *sbc);//int sbc_reinit(sbc_t *sbc, unsigned long flags);
-
-
-int sbc_encode(sbc_t *sbc,
- void *input,
- int input_len,
- void *output,
- int output_len,
- int *written);
-
-int sbc_decode(sbc_t *sbc,
- void *input,
- int input_len,
- void *output,
- int output_len,
- int *written);
-
-void sbc_finish(sbc_t *sbc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SBC_H */
+++ /dev/null
-/*
- *
- * Bluetooth low-complexity, subband codec (SBC) library
- *
- * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
- * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#define fabs(x) ((x) < 0 ? -(x) : (x))
-/* C does not provide an explicit arithmetic shift right but this will
- always be correct and every compiler *should* generate optimal code */
-#define ASR(val, bits) ((-2 >> 1 == -1) ? \
- ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
-#define ASR_64(val, bits) ((-2 >> 1 == -1) ? \
- ((long long)(val)) >> (bits) : ((long long) (val)) / (1 << (bits)))
-
-#define SCALE_PROTO4_TBL 15
-#define SCALE_ANA4_TBL 16
-#define SCALE_PROTO8_TBL 15
-#define SCALE_ANA8_TBL 16
-#define SCALE_SPROTO4_TBL 16
-#define SCALE_SPROTO8_TBL 16
-#define SCALE_NPROTO4_TBL 10
-#define SCALE_NPROTO8_TBL 12
-#define SCALE_SAMPLES 14
-#define SCALE4_STAGE1_BITS 10
-#define SCALE4_STAGE2_BITS 21
-#define SCALE4_STAGED1_BITS 18
-#define SCALE4_STAGED2_BITS 23
-#define SCALE8_STAGE1_BITS 8
-#define SCALE8_STAGE2_BITS 24
-#define SCALE8_STAGED1_BITS 18
-#define SCALE8_STAGED2_BITS 23
-
-//typedef int int32_t;
-//typedef int32_t sbc_fixed_t;
-//typedef long long sbc_extended_t;
-
-#define SCALE4_STAGE1(src) ASR_64(src, SCALE4_STAGE1_BITS)
-#define SCALE4_STAGE2(src) ASR_64(src, SCALE4_STAGE2_BITS)
-#define SCALE4_STAGED1(src) ASR_64(src, SCALE4_STAGED1_BITS)
-#define SCALE4_STAGED2(src) ASR_64(src, SCALE4_STAGED2_BITS)
-#define SCALE8_STAGE1(src) ASR_64(src, SCALE8_STAGE1_BITS)
-#define SCALE8_STAGE2(src) ASR_64(src, SCALE8_STAGE2_BITS)
-#define SCALE8_STAGED1(src) ASR_64(src, SCALE8_STAGED1_BITS)
-#define SCALE8_STAGED2(src) ASR_64(src, SCALE8_STAGED2_BITS)
-
-#define SBC_FIXED_0(val) { val = 0; }
-#define ADD(dst, src) { dst += src; }
-#define SUB(dst, src) { dst -= src; }
-#define MUL(dst, a, b) { dst = (sbc_extended_t) (a) * (b); }
-#define MULA(dst, a, b) { dst += (sbc_extended_t) (a) * (b); }
-#define DIV2(dst, src) { dst = ASR(src, 1); }
+++ /dev/null
-/*
- *
- * Bluetooth low-complexity, subband codec (SBC) library
- *
- * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
- * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "sbc_math.h"
-
-/* A2DP specification: Appendix B, page 69 */
-static const int sbc_offset4[4][4] = {
- { -1, 0, 0, 0 },
- { -2, 0, 0, 1 },
- { -2, 0, 0, 1 },
- { -2, 0, 0, 1 }
-};
-
-/* A2DP specification: Appendix B, page 69 */
-static const int sbc_offset8[4][8] = {
- { -2, 0, 0, 0, 0, 0, 0, 1 },
- { -3, 0, 0, 0, 0, 0, 1, 2 },
- { -4, 0, 0, 0, 0, 0, 1, 2 },
- { -4, 0, 0, 0, 0, 0, 1, 2 }
-};
-
-#define SP4(val) ASR(val, SCALE_PROTO4_TBL)
-#define SA4(val) ASR(val, SCALE_ANA4_TBL)
-#define SP8(val) ASR(val, SCALE_PROTO8_TBL)
-#define SA8(val) ASR(val, SCALE_ANA8_TBL)
-#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
-#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
-#define SN4(val) ASR(val, SCALE_NPROTO4_TBL)
-#define SN8(val) ASR(val, SCALE_NPROTO8_TBL)
-
-static const int32_t _sbc_proto_4[20] = {
- SP4(0x02cb3e8c), SP4(0x22b63dc0), SP4(0x002329cc), SP4(0x053b7548),
- SP4(0x31eab940), SP4(0xec1f5e60), SP4(0xff3773a8), SP4(0x0061c5a7),
- SP4(0x07646680), SP4(0x3f239480), SP4(0xf89f23a8), SP4(0x007a4737),
- SP4(0x00b32807), SP4(0x083ddc80), SP4(0x4825e480), SP4(0x0191e578),
- SP4(0x00ff11ca), SP4(0x00fb7991), SP4(0x069fdc58), SP4(0x4b584000)
-};
-
-static const int32_t _anamatrix4[4] = {
- SA4(0x2d413cc0), SA4(0x3b20d780), SA4(0x40000000), SA4(0x187de2a0)
-};
-
-static const int32_t _sbc_proto_8[40] = {
- SP8(0x02e5cd20), SP8(0x22d0c200), SP8(0x006bfe27), SP8(0x07808930),
- SP8(0x3f1c8800), SP8(0xf8810d70), SP8(0x002cfdc6), SP8(0x055acf28),
- SP8(0x31f566c0), SP8(0xebfe57e0), SP8(0xff27c437), SP8(0x001485cc),
- SP8(0x041c6e58), SP8(0x2a7cfa80), SP8(0xe4c4a240), SP8(0xfe359e4c),
- SP8(0x0048b1f8), SP8(0x0686ce30), SP8(0x38eec5c0), SP8(0xf2a1b9f0),
- SP8(0xffe8904a), SP8(0x0095698a), SP8(0x0824a480), SP8(0x443b3c00),
- SP8(0xfd7badc8), SP8(0x00d3e2d9), SP8(0x00c183d2), SP8(0x084e1950),
- SP8(0x4810d800), SP8(0x017f43fe), SP8(0x01056dd8), SP8(0x00e9cb9f),
- SP8(0x07d7d090), SP8(0x4a708980), SP8(0x0488fae8), SP8(0x0113bd20),
- SP8(0x0107b1a8), SP8(0x069fb3c0), SP8(0x4b3db200), SP8(0x00763f48)
-};
-
-static const int32_t sbc_proto_4_40m0[] = {
- SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
- SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
- SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
- SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
- SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
-};
-
-static const int32_t sbc_proto_4_40m1[] = {
- SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
- SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
- SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
- SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
- SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
-};
-
-static const int32_t sbc_proto_8_80m0[] = {
- SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
- SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
- SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
- SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
- SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
- SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
- SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
- SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
- SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
- SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
-};
-
-static const int32_t sbc_proto_8_80m1[] = {
- SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
- SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
- SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
- SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
- SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
- SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
- SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
- SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
- SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
- SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
-};
-
-static const int32_t _anamatrix8[8] = {
- SA8(0x3b20d780), SA8(0x187de2a0), SA8(0x3ec52f80), SA8(0x3536cc40),
- SA8(0x238e7680), SA8(0x0c7c5c20), SA8(0x2d413cc0), SA8(0x40000000)
-};
-
-static const int32_t synmatrix4[8][4] = {
- { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
- { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
- { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
- { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
- { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
- { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
- { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
- { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
-};
-
-static const int32_t synmatrix8[16][8] = {
- { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
- SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
- { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
- SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
- { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
- SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
- { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
- SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
- { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
- SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
- { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
- SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
- { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
- SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
- { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
- SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
- { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
- SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
- { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
- SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
- { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
- SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
- { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
- SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
- { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
- SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
- { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
- SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
- { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
- SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
- { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
- SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
-};
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
+#define LE_SHORT(v) (v)
+#define LE_INT(v) (v)
+#define BE_SHORT(v) bswap_16(v)
+#define BE_INT(v) bswap_32(v)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
+#define LE_SHORT(v) bswap_16(v)
+#define LE_INT(v) bswap_32(v)
+#define BE_SHORT(v) (v)
+#define BE_INT(v) (v)
+#else
+#error "Wrong endian"
+#endif
+
+#define AU_MAGIC COMPOSE_ID('.','s','n','d')
+
+#define AU_FMT_ULAW 1
+#define AU_FMT_LIN8 2
+#define AU_FMT_LIN16 3
+
+struct au_header {
+ uint32_t magic; /* '.snd' */
+ uint32_t hdr_size; /* size of header (min 24) */
+ uint32_t data_size; /* size of data */
+ uint32_t encoding; /* see to AU_FMT_XXXX */
+ uint32_t sample_rate; /* sample rate */
+ uint32_t channels; /* number of channels (voices) */
+};
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
+ * Copyright (C) 2012-2013 Intel Corporation
+ *
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc.h"
+#include "sbc_private.h"
+#include "sbc_primitives.h"
+
+#define SBC_SYNCWORD 0x9C
+
+#define MSBC_SYNCWORD 0xAD
+#define MSBC_BLOCKS 15
+
+#define A2DP_SAMPLING_FREQ_16000 (1 << 3)
+#define A2DP_SAMPLING_FREQ_32000 (1 << 2)
+#define A2DP_SAMPLING_FREQ_44100 (1 << 1)
+#define A2DP_SAMPLING_FREQ_48000 (1 << 0)
+
+#define A2DP_CHANNEL_MODE_MONO (1 << 3)
+#define A2DP_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define A2DP_CHANNEL_MODE_STEREO (1 << 1)
+#define A2DP_CHANNEL_MODE_JOINT_STEREO (1 << 0)
+
+#define A2DP_BLOCK_LENGTH_4 (1 << 3)
+#define A2DP_BLOCK_LENGTH_8 (1 << 2)
+#define A2DP_BLOCK_LENGTH_12 (1 << 1)
+#define A2DP_BLOCK_LENGTH_16 (1 << 0)
+
+#define A2DP_SUBBANDS_4 (1 << 1)
+#define A2DP_SUBBANDS_8 (1 << 0)
+
+#define A2DP_ALLOCATION_SNR (1 << 1)
+#define A2DP_ALLOCATION_LOUDNESS (1 << 0)
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct a2dp_sbc {
+ uint8_t channel_mode:4;
+ uint8_t frequency:4;
+ uint8_t allocation_method:2;
+ uint8_t subbands:2;
+ uint8_t block_length:4;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct a2dp_sbc {
+ uint8_t frequency:4;
+ uint8_t channel_mode:4;
+ uint8_t block_length:4;
+ uint8_t subbands:2;
+ uint8_t allocation_method:2;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+/* This structure contains an unpacked SBC frame.
+ Yes, there is probably quite some unused space herein */
+struct sbc_frame {
+ uint8_t frequency;
+ uint8_t block_mode;
+ uint8_t blocks;
+ enum {
+ MONO = SBC_MODE_MONO,
+ DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL,
+ STEREO = SBC_MODE_STEREO,
+ JOINT_STEREO = SBC_MODE_JOINT_STEREO
+ } mode;
+ uint8_t channels;
+ enum {
+ LOUDNESS = SBC_AM_LOUDNESS,
+ SNR = SBC_AM_SNR
+ } allocation;
+ uint8_t subband_mode;
+ uint8_t subbands;
+ uint8_t bitpool;
+ uint16_t codesize;
+ uint16_t length;
+
+ /* bit number x set means joint stereo has been used in subband x */
+ uint8_t joint;
+
+ /* only the lower 4 bits of every element are to be used */
+ uint32_t SBC_ALIGNED scale_factor[2][8];
+
+ /* raw integer subband samples in the frame */
+ int32_t SBC_ALIGNED sb_sample_f[16][2][8];
+
+ /* modified subband samples */
+ int32_t SBC_ALIGNED sb_sample[16][2][8];
+
+ /* original pcm audio samples */
+ int16_t SBC_ALIGNED pcm_sample[2][16*8];
+};
+
+struct sbc_decoder_state {
+ int subbands;
+ int32_t V[2][170];
+ int offset[2][16];
+};
+
+/*
+ * 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 SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
+ const struct sbc_frame *frame, int (*bits)[8], int subbands)
+{
+ uint8_t sf = frame->frequency;
+
+ if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ max_bitneed = 0;
+ if (frame->allocation == SNR) {
+ for (sb = 0; sb < subbands; sb++) {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ } else {
+ for (sb = 0; sb < subbands; sb++) {
+ if (frame->scale_factor[ch][sb] == 0)
+ bitneed[ch][sb] = -5;
+ else {
+ if (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;
+ }
+ 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 < 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 < 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;
+ }
+ }
+
+ for (sb = 0; bitcount < frame->bitpool &&
+ sb < subbands; sb++) {
+ 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;
+ }
+ }
+
+ for (sb = 0; bitcount < frame->bitpool &&
+ sb < subbands; sb++) {
+ if (bits[ch][sb] < 16) {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ }
+
+ }
+
+ } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ max_bitneed = 0;
+ if (frame->allocation == SNR) {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < subbands; sb++) {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+ } else {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < subbands; sb++) {
+ if (frame->scale_factor[ch][sb] == 0)
+ bitneed[ch][sb] = -5;
+ else {
+ if (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;
+ }
+ 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 < 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 < 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) {
+ 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++;
+ if (sb >= subbands)
+ break;
+ } else
+ ch = 1;
+ }
+
+ ch = 0;
+ sb = 0;
+ while (bitcount < frame->bitpool) {
+ if (bits[ch][sb] < 16) {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ if (ch == 1) {
+ ch = 0;
+ sb++;
+ if (sb >= subbands)
+ break;
+ } else
+ ch = 1;
+ }
+
+ }
+
+}
+
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+ if (frame->subbands == 4)
+ sbc_calculate_bits_internal(frame, bits, 4);
+ else
+ sbc_calculate_bits_internal(frame, bits, 8);
+}
+
+/*
+ * 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_internal(const uint8_t *data,
+ struct sbc_frame *frame, size_t len)
+{
+ unsigned int 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;
+
+ uint32_t audio_sample;
+ int ch, sb, blk, bit; /* channel, subband, block and bit standard
+ counters */
+ int bits[2][8]; /* bits distribution */
+ uint32_t levels[2][8]; /* levels derived from that */
+
+ consumed = 32;
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+ if (frame->mode == JOINT_STEREO) {
+ if (len * 8 < consumed + frame->subbands)
+ return -1;
+
+ frame->joint = 0x00;
+ for (sb = 0; sb < frame->subbands - 1; sb++)
+ frame->joint |= ((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))
+ 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))
+ return -3;
+
+ sbc_calculate_bits(frame, bits);
+
+ 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++) {
+ uint32_t shift;
+
+ if (levels[ch][sb] == 0) {
+ frame->sb_sample[blk][ch][sb] = 0;
+ continue;
+ }
+
+ shift = frame->scale_factor[ch][sb] +
+ 1 + SBCDEC_FIXED_EXTRA_BITS;
+
+ audio_sample = 0;
+ for (bit = 0; bit < bits[ch][sb]; bit++) {
+ if (consumed > len * 8)
+ 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] = (int32_t)
+ (((((uint64_t) audio_sample << 1) | 1) << shift) /
+ levels[ch][sb]) - (1 << shift);
+ }
+ }
+ }
+
+ if (frame->mode == JOINT_STEREO) {
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (frame->joint & (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 int sbc_unpack_frame(const uint8_t *data,
+ struct sbc_frame *frame, size_t len)
+{
+ if (len < 4)
+ return -1;
+
+ if (data[0] != SBC_SYNCWORD)
+ return -2;
+
+ frame->frequency = (data[1] >> 6) & 0x03;
+ frame->block_mode = (data[1] >> 4) & 0x03;
+
+ switch (frame->block_mode) {
+ case SBC_BLK_4:
+ frame->blocks = 4;
+ break;
+ case SBC_BLK_8:
+ frame->blocks = 8;
+ break;
+ case SBC_BLK_12:
+ frame->blocks = 12;
+ break;
+ case SBC_BLK_16:
+ frame->blocks = 16;
+ break;
+ }
+
+ frame->mode = (data[1] >> 2) & 0x03;
+
+ switch (frame->mode) {
+ case MONO:
+ frame->channels = 1;
+ break;
+ case DUAL_CHANNEL: /* fall-through */
+ case STEREO:
+ case JOINT_STEREO:
+ frame->channels = 2;
+ break;
+ }
+
+ frame->allocation = (data[1] >> 1) & 0x01;
+
+ frame->subband_mode = (data[1] & 0x01);
+ frame->subbands = frame->subband_mode ? 8 : 4;
+
+ frame->bitpool = data[2];
+
+ if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+ frame->bitpool > 16 * frame->subbands)
+ return -4;
+
+ if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+ frame->bitpool > 32 * frame->subbands)
+ return -4;
+
+ return sbc_unpack_frame_internal(data, frame, len);
+}
+
+static int msbc_unpack_frame(const uint8_t *data,
+ struct sbc_frame *frame, size_t len)
+{
+ if (len < 4)
+ return -1;
+
+ if (data[0] != MSBC_SYNCWORD)
+ return -2;
+ if (data[1] != 0)
+ return -2;
+ if (data[2] != 0)
+ return -2;
+
+ frame->frequency = SBC_FREQ_16000;
+ frame->block_mode = SBC_BLK_4;
+ frame->blocks = MSBC_BLOCKS;
+ frame->allocation = LOUDNESS;
+ frame->mode = MONO;
+ frame->channels = 1;
+ frame->subband_mode = 1;
+ frame->subbands = 8;
+ frame->bitpool = 26;
+
+ return sbc_unpack_frame_internal(data, frame, len);
+}
+
+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 SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s)
+{
+ if (s > 0x7FFF)
+ return 0x7FFF;
+ else if (s < -0x8000)
+ return -0x8000;
+ else
+ return s;
+}
+
+static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, k, idx;
+ int32_t *v = state->V[ch];
+ int *offset = state->offset[ch];
+
+ for (i = 0; i < 8; i++) {
+ /* Shifting */
+ offset[i]--;
+ if (offset[i] < 0) {
+ offset[i] = 79;
+ memcpy(v + 80, v, 9 * sizeof(*v));
+ }
+
+ /* Distribute the new matrix value to the shifted position */
+ v[offset[i]] = SCALE4_STAGED1(
+ MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0],
+ MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1],
+ MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2],
+ MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3])))));
+ }
+
+ /* Compute the samples */
+ for (idx = 0, i = 0; i < 4; i++, idx += 5) {
+ k = (i + 4) & 0xf;
+
+ /* Store in output, Q0 */
+ frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1(
+ MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
+ MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
+ MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
+ MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1],
+ MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2],
+ MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2],
+ MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
+ MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
+ MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
+ MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4]))))))))))));
+ }
+}
+
+static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, j, k, idx;
+ int *offset = state->offset[ch];
+
+ for (i = 0; i < 16; i++) {
+ /* Shifting */
+ offset[i]--;
+ if (offset[i] < 0) {
+ offset[i] = 159;
+ for (j = 0; j < 9; j++)
+ state->V[ch][j + 160] = state->V[ch][j];
+ }
+
+ /* Distribute the new matrix value to the shifted position */
+ state->V[ch][offset[i]] = SCALE8_STAGED1(
+ MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0],
+ MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1],
+ MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2],
+ MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3],
+ MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4],
+ MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5],
+ MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6],
+ MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7])))))))));
+ }
+
+ /* Compute the samples */
+ for (idx = 0, i = 0; i < 8; i++, idx += 5) {
+ k = (i + 8) & 0xf;
+
+ /* Store in output, Q0 */
+ frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1(
+ MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
+ MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
+ MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
+ MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1],
+ MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2],
+ MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2],
+ MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
+ MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
+ MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
+ MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4]))))))))))));
+ }
+}
+
+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 int sbc_analyze_audio(struct sbc_encoder_state *state,
+ struct sbc_frame *frame)
+{
+ int ch, blk;
+ int16_t *x;
+
+ switch (frame->subbands) {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++) {
+ x = &state->X[ch][state->position - 4 *
+ state->increment + frame->blocks * 4];
+ for (blk = 0; blk < frame->blocks;
+ blk += state->increment) {
+ state->sbc_analyze_4s(
+ state, x,
+ frame->sb_sample_f[blk][ch],
+ frame->sb_sample_f[blk + 1][ch] -
+ frame->sb_sample_f[blk][ch]);
+ x -= 4 * state->increment;
+ }
+ }
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++) {
+ x = &state->X[ch][state->position - 8 *
+ state->increment + frame->blocks * 8];
+ for (blk = 0; blk < frame->blocks;
+ blk += state->increment) {
+ state->sbc_analyze_8s(
+ state, x,
+ frame->sb_sample_f[blk][ch],
+ frame->sb_sample_f[blk + 1][ch] -
+ frame->sb_sample_f[blk][ch]);
+ x -= 8 * state->increment;
+ }
+ }
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+/* Supplementary bitstream writing macros for 'sbc_pack_frame' */
+
+#define PUT_BITS(data_ptr, bits_cache, bits_count, v, n) \
+ do { \
+ bits_cache = (v) | (bits_cache << (n)); \
+ bits_count += (n); \
+ if (bits_count >= 16) { \
+ bits_count -= 8; \
+ *data_ptr++ = (uint8_t) \
+ (bits_cache >> bits_count); \
+ bits_count -= 8; \
+ *data_ptr++ = (uint8_t) \
+ (bits_cache >> bits_count); \
+ } \
+ } while (0)
+
+#define FLUSH_BITS(data_ptr, bits_cache, bits_count) \
+ do { \
+ while (bits_count >= 8) { \
+ bits_count -= 8; \
+ *data_ptr++ = (uint8_t) \
+ (bits_cache >> bits_count); \
+ } \
+ if (bits_count > 0) \
+ *data_ptr++ = (uint8_t) \
+ (bits_cache << (8 - bits_count)); \
+ } while (0)
+
+/*
+ * 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 SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
+ struct sbc_frame *frame, size_t len,
+ int frame_subbands, int frame_channels,
+ int joint)
+{
+ /* Bitstream writer starts from the fourth byte */
+ uint8_t *data_ptr = data + 4;
+ uint32_t bits_cache = 0;
+ uint32_t bits_count = 0;
+
+ /* 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;
+
+ uint32_t audio_sample;
+
+ int ch, sb, blk; /* channel, subband, block and bit counters */
+ int bits[2][8]; /* bits distribution */
+ uint32_t levels[2][8]; /* levels are derived from that */
+ uint32_t sb_sample_delta[2][8];
+
+ /* Can't fill in crc yet */
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+ if (frame->mode == JOINT_STEREO) {
+ PUT_BITS(data_ptr, bits_cache, bits_count,
+ joint, frame_subbands);
+ crc_header[crc_pos >> 3] = joint;
+ crc_pos += frame_subbands;
+ }
+
+ for (ch = 0; ch < frame_channels; ch++) {
+ for (sb = 0; sb < frame_subbands; sb++) {
+ PUT_BITS(data_ptr, bits_cache, bits_count,
+ frame->scale_factor[ch][sb] & 0x0F, 4);
+ crc_header[crc_pos >> 3] <<= 4;
+ crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
+ crc_pos += 4;
+ }
+ }
+
+ /* align the last crc byte */
+ if (crc_pos % 8)
+ crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8);
+
+ data[3] = sbc_crc8(crc_header, crc_pos);
+
+ sbc_calculate_bits(frame, bits);
+
+ for (ch = 0; ch < frame_channels; ch++) {
+ for (sb = 0; sb < frame_subbands; sb++) {
+ levels[ch][sb] = ((1 << bits[ch][sb]) - 1) <<
+ (32 - (frame->scale_factor[ch][sb] +
+ SCALE_OUT_BITS + 2));
+ sb_sample_delta[ch][sb] = (uint32_t) 1 <<
+ (frame->scale_factor[ch][sb] +
+ SCALE_OUT_BITS + 1);
+ }
+ }
+
+ 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)
+ continue;
+
+ audio_sample = ((uint64_t) levels[ch][sb] *
+ (sb_sample_delta[ch][sb] +
+ frame->sb_sample_f[blk][ch][sb])) >> 32;
+
+ PUT_BITS(data_ptr, bits_cache, bits_count,
+ audio_sample, bits[ch][sb]);
+ }
+ }
+ }
+
+ FLUSH_BITS(data_ptr, bits_cache, bits_count);
+
+ return data_ptr - data;
+}
+
+static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
+ int joint)
+{
+ int frame_subbands = 4;
+
+ data[0] = SBC_SYNCWORD;
+
+ data[1] = (frame->frequency & 0x03) << 6;
+ data[1] |= (frame->block_mode & 0x03) << 4;
+ data[1] |= (frame->mode & 0x03) << 2;
+ data[1] |= (frame->allocation & 0x01) << 1;
+
+ data[2] = frame->bitpool;
+
+ if (frame->subbands != 4)
+ frame_subbands = 8;
+
+ if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+ frame->bitpool > frame_subbands << 4)
+ return -5;
+
+ if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+ frame->bitpool > frame_subbands << 5)
+ return -5;
+
+ if (frame->subbands == 4) {
+ if (frame->channels == 1)
+ return sbc_pack_frame_internal(
+ data, frame, len, 4, 1, joint);
+ else
+ return sbc_pack_frame_internal(
+ data, frame, len, 4, 2, joint);
+ } else {
+ data[1] |= 0x01;
+ if (frame->channels == 1)
+ return sbc_pack_frame_internal(
+ data, frame, len, 8, 1, joint);
+ else
+ return sbc_pack_frame_internal(
+ data, frame, len, 8, 2, joint);
+ }
+}
+
+static ssize_t msbc_pack_frame(uint8_t *data, struct sbc_frame *frame,
+ size_t len, int joint)
+{
+ data[0] = MSBC_SYNCWORD;
+ data[1] = 0;
+ data[2] = 0;
+
+ return sbc_pack_frame_internal(data, frame, len, 8, 1, joint);
+}
+
+static void sbc_encoder_init(bool msbc, struct sbc_encoder_state *state,
+ const struct sbc_frame *frame)
+{
+ memset(&state->X, 0, sizeof(state->X));
+ state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
+ if (msbc)
+ state->increment = 1;
+ else
+ state->increment = 4;
+
+ sbc_init_primitives(state);
+}
+
+struct sbc_priv {
+ bool init;
+ bool msbc;
+ struct SBC_ALIGNED sbc_frame frame;
+ struct SBC_ALIGNED sbc_decoder_state dec_state;
+ struct SBC_ALIGNED sbc_encoder_state enc_state;
+ int (*unpack_frame)(const uint8_t *data, struct sbc_frame *frame,
+ size_t len);
+ ssize_t (*pack_frame)(uint8_t *data, struct sbc_frame *frame,
+ size_t len, int joint);
+};
+
+static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
+{
+ struct sbc_priv *priv = sbc->priv;
+
+ if (priv->msbc) {
+ priv->pack_frame = msbc_pack_frame;
+ priv->unpack_frame = msbc_unpack_frame;
+ } else {
+ priv->pack_frame = sbc_pack_frame;
+ priv->unpack_frame = sbc_unpack_frame;
+ }
+
+ sbc->flags = flags;
+ sbc->frequency = SBC_FREQ_44100;
+ sbc->mode = SBC_MODE_STEREO;
+ sbc->subbands = SBC_SB_8;
+ sbc->blocks = SBC_BLK_16;
+ sbc->bitpool = 32;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ sbc->endian = SBC_LE;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ sbc->endian = SBC_BE;
+#else
+#error "Unknown byte order"
+#endif
+}
+
+SBC_EXPORT int sbc_init(sbc_t *sbc, unsigned long flags)
+{
+ if (!sbc)
+ return -EIO;
+
+ memset(sbc, 0, sizeof(sbc_t));
+
+ sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
+ if (!sbc->priv_alloc_base)
+ return -ENOMEM;
+
+ sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base +
+ SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK));
+
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc_set_defaults(sbc, flags);
+
+ return 0;
+}
+
+SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
+{
+ struct sbc_priv *priv;
+
+ if (!sbc)
+ return -EIO;
+
+ memset(sbc, 0, sizeof(sbc_t));
+
+ sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
+ if (!sbc->priv_alloc_base)
+ return -ENOMEM;
+
+ sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base +
+ SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK));
+
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ priv = sbc->priv;
+ priv->msbc = true;
+
+ sbc_set_defaults(sbc, flags);
+
+ sbc->frequency = SBC_FREQ_16000;
+ sbc->blocks = MSBC_BLOCKS;
+ sbc->subbands = SBC_SB_8;
+ sbc->mode = SBC_MODE_MONO;
+ sbc->allocation = SBC_AM_LOUDNESS;
+ sbc->bitpool = 26;
+
+ return 0;
+}
+
+static int sbc_set_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len)
+{
+ const struct a2dp_sbc *a2dp;
+
+ if (conf_len != sizeof(*a2dp))
+ return -EINVAL;
+
+ a2dp = conf;
+
+ switch (a2dp->frequency) {
+ case A2DP_SAMPLING_FREQ_16000:
+ sbc->frequency = SBC_FREQ_16000;
+ break;
+ case A2DP_SAMPLING_FREQ_32000:
+ sbc->frequency = SBC_FREQ_32000;
+ break;
+ case A2DP_SAMPLING_FREQ_44100:
+ sbc->frequency = SBC_FREQ_44100;
+ break;
+ case A2DP_SAMPLING_FREQ_48000:
+ sbc->frequency = SBC_FREQ_48000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->channel_mode) {
+ case A2DP_CHANNEL_MODE_MONO:
+ sbc->mode = SBC_MODE_MONO;
+ break;
+ case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ sbc->mode = SBC_MODE_DUAL_CHANNEL;
+ break;
+ case A2DP_CHANNEL_MODE_STEREO:
+ sbc->mode = SBC_MODE_STEREO;
+ break;
+ case A2DP_CHANNEL_MODE_JOINT_STEREO:
+ sbc->mode = SBC_MODE_JOINT_STEREO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->allocation_method) {
+ case A2DP_ALLOCATION_SNR:
+ sbc->allocation = SBC_AM_SNR;
+ break;
+ case A2DP_ALLOCATION_LOUDNESS:
+ sbc->allocation = SBC_AM_LOUDNESS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->subbands) {
+ case A2DP_SUBBANDS_4:
+ sbc->subbands = SBC_SB_4;
+ break;
+ case A2DP_SUBBANDS_8:
+ sbc->subbands = SBC_SB_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (a2dp->block_length) {
+ case A2DP_BLOCK_LENGTH_4:
+ sbc->blocks = SBC_BLK_4;
+ break;
+ case A2DP_BLOCK_LENGTH_8:
+ sbc->blocks = SBC_BLK_8;
+ break;
+ case A2DP_BLOCK_LENGTH_12:
+ sbc->blocks = SBC_BLK_12;
+ break;
+ case A2DP_BLOCK_LENGTH_16:
+ sbc->blocks = SBC_BLK_16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len)
+{
+ int err;
+
+ err = sbc_init(sbc, flags);
+ if (err < 0)
+ return err;
+
+ err = sbc_set_a2dp(sbc, flags, conf, conf_len);
+ if (err < 0) {
+ sbc_finish(sbc);
+ return err;
+ }
+
+ return 0;
+}
+
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len)
+{
+ int err;
+
+ err = sbc_reinit(sbc, flags);
+ if (err < 0)
+ return err;
+
+ return sbc_set_a2dp(sbc, flags, conf, conf_len);
+}
+
+SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
+{
+ return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
+}
+
+SBC_EXPORT ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
+ void *output, size_t output_len, size_t *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc || !input)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ framelen = priv->unpack_frame(input, &priv->frame, input_len);
+
+ if (!priv->init) {
+ sbc_decoder_init(&priv->dec_state, &priv->frame);
+ priv->init = true;
+
+ sbc->frequency = priv->frame.frequency;
+ sbc->mode = priv->frame.mode;
+ sbc->subbands = priv->frame.subband_mode;
+ sbc->blocks = priv->frame.block_mode;
+ sbc->allocation = priv->frame.allocation;
+ sbc->bitpool = priv->frame.bitpool;
+
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = framelen;
+ } else if (priv->frame.bitpool != sbc->bitpool) {
+ priv->frame.length = framelen;
+ sbc->bitpool = priv->frame.bitpool;
+ }
+
+ if (!output)
+ return framelen;
+
+ if (written)
+ *written = 0;
+
+ if (framelen <= 0)
+ return framelen;
+
+ samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
+
+ ptr = output;
+
+ if (output_len < (size_t) (samples * priv->frame.channels * 2))
+ samples = output_len / (priv->frame.channels * 2);
+
+ for (i = 0; i < samples; i++) {
+ for (ch = 0; ch < priv->frame.channels; ch++) {
+ int16_t s;
+ s = priv->frame.pcm_sample[ch][i];
+
+ if (sbc->endian == SBC_BE) {
+ *ptr++ = (s & 0xff00) >> 8;
+ *ptr++ = (s & 0x00ff);
+ } else {
+ *ptr++ = (s & 0x00ff);
+ *ptr++ = (s & 0xff00) >> 8;
+ }
+ }
+ }
+
+ if (written)
+ *written = samples * priv->frame.channels * 2;
+
+ return framelen;
+}
+
+SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
+ void *output, size_t output_len, ssize_t *written)
+{
+ struct sbc_priv *priv;
+ int samples;
+ ssize_t framelen;
+ int (*sbc_enc_process_input)(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels);
+
+ if (!sbc || !input)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ if (written)
+ *written = 0;
+
+ if (!priv->init) {
+ priv->frame.frequency = sbc->frequency;
+ priv->frame.mode = sbc->mode;
+ priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ priv->frame.allocation = sbc->allocation;
+ priv->frame.subband_mode = sbc->subbands;
+ priv->frame.subbands = sbc->subbands ? 8 : 4;
+ priv->frame.block_mode = sbc->blocks;
+ if (priv->msbc)
+ priv->frame.blocks = MSBC_BLOCKS;
+ else
+ priv->frame.blocks = 4 + (sbc->blocks * 4);
+ priv->frame.bitpool = sbc->bitpool;
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
+
+ sbc_encoder_init(priv->msbc, &priv->enc_state, &priv->frame);
+ priv->init = true;
+ } else if (priv->frame.bitpool != sbc->bitpool) {
+ priv->frame.length = sbc_get_frame_length(sbc);
+ priv->frame.bitpool = sbc->bitpool;
+ }
+
+ /* input must be large enough to encode a complete frame */
+ if (input_len < priv->frame.codesize)
+ return 0;
+
+ /* output must be large enough to receive the encoded frame */
+ if (!output || output_len < priv->frame.length)
+ return -ENOSPC;
+
+ /* Select the needed input data processing function and call it */
+ if (priv->frame.subbands == 8) {
+ if (sbc->endian == SBC_BE)
+ sbc_enc_process_input =
+ priv->enc_state.sbc_enc_process_input_8s_be;
+ else
+ sbc_enc_process_input =
+ priv->enc_state.sbc_enc_process_input_8s_le;
+ } else {
+ if (sbc->endian == SBC_BE)
+ sbc_enc_process_input =
+ priv->enc_state.sbc_enc_process_input_4s_be;
+ else
+ sbc_enc_process_input =
+ priv->enc_state.sbc_enc_process_input_4s_le;
+ }
+
+ priv->enc_state.position = sbc_enc_process_input(
+ priv->enc_state.position, (const uint8_t *) input,
+ priv->enc_state.X, priv->frame.subbands * priv->frame.blocks,
+ priv->frame.channels);
+
+ samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
+
+ if (priv->frame.mode == JOINT_STEREO) {
+ int j = priv->enc_state.sbc_calc_scalefactors_j(
+ priv->frame.sb_sample_f, priv->frame.scale_factor,
+ priv->frame.blocks, priv->frame.subbands);
+ framelen = priv->pack_frame(output,
+ &priv->frame, output_len, j);
+ } else {
+ priv->enc_state.sbc_calc_scalefactors(
+ priv->frame.sb_sample_f, priv->frame.scale_factor,
+ priv->frame.blocks, priv->frame.channels,
+ priv->frame.subbands);
+ framelen = priv->pack_frame(output,
+ &priv->frame, output_len, 0);
+ }
+
+ if (written)
+ *written = framelen;
+
+ return samples * priv->frame.channels * 2;
+}
+
+SBC_EXPORT void sbc_finish(sbc_t *sbc)
+{
+ if (!sbc)
+ return;
+
+ free(sbc->priv_alloc_base);
+
+ memset(sbc, 0, sizeof(sbc_t));
+}
+
+SBC_EXPORT size_t sbc_get_frame_length(sbc_t *sbc)
+{
+ int ret;
+ uint8_t subbands, channels, blocks, joint, bitpool;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (priv->init && priv->frame.bitpool == sbc->bitpool)
+ return priv->frame.length;
+
+ subbands = sbc->subbands ? 8 : 4;
+ if (priv->msbc)
+ blocks = MSBC_BLOCKS;
+ else
+ blocks = 4 + (sbc->blocks * 4);
+ channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
+ bitpool = sbc->bitpool;
+
+ ret = 4 + (4 * subbands * channels) / 8;
+ /* This term is not always evenly divide so we round it up */
+ if (channels == 1 || sbc->mode == SBC_MODE_DUAL_CHANNEL)
+ ret += ((blocks * channels * bitpool) + 7) / 8;
+ else
+ ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8;
+
+ return ret;
+}
+
+SBC_EXPORT unsigned sbc_get_frame_duration(sbc_t *sbc)
+{
+ uint8_t subbands, blocks;
+ uint16_t frequency;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ if (priv->msbc)
+ blocks = MSBC_BLOCKS;
+ else
+ blocks = 4 + (sbc->blocks * 4);
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ }
+
+ switch (sbc->frequency) {
+ case SBC_FREQ_16000:
+ frequency = 16000;
+ break;
+
+ case SBC_FREQ_32000:
+ frequency = 32000;
+ break;
+
+ case SBC_FREQ_44100:
+ frequency = 44100;
+ break;
+
+ case SBC_FREQ_48000:
+ frequency = 48000;
+ break;
+ default:
+ return 0;
+ }
+
+ return (1000000 * blocks * subbands) / frequency;
+}
+
+SBC_EXPORT size_t sbc_get_codesize(sbc_t *sbc)
+{
+ uint16_t subbands, channels, blocks;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ if (priv->msbc)
+ blocks = MSBC_BLOCKS;
+ else
+ blocks = 4 + (sbc->blocks * 4);
+ channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ channels = priv->frame.channels;
+ }
+
+ return subbands * blocks * channels * 2;
+}
+
+SBC_EXPORT const char *sbc_get_implementation_info(sbc_t *sbc)
+{
+ struct sbc_priv *priv;
+
+ if (!sbc)
+ return NULL;
+
+ priv = sbc->priv;
+ if (!priv)
+ return NULL;
+
+ return priv->enc_state.implementation_info;
+}
+
+SBC_EXPORT int sbc_reinit(sbc_t *sbc, unsigned long flags)
+{
+ struct sbc_priv *priv;
+
+ if (!sbc || !sbc->priv)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ if (priv->init)
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc_set_defaults(sbc, flags);
+
+ return 0;
+}
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2012-2014 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_H
+#define __SBC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/* sampling frequency */
+#define SBC_FREQ_16000 0x00
+#define SBC_FREQ_32000 0x01
+#define SBC_FREQ_44100 0x02
+#define SBC_FREQ_48000 0x03
+
+/* blocks */
+#define SBC_BLK_4 0x00
+#define SBC_BLK_8 0x01
+#define SBC_BLK_12 0x02
+#define SBC_BLK_16 0x03
+
+/* channel mode */
+#define SBC_MODE_MONO 0x00
+#define SBC_MODE_DUAL_CHANNEL 0x01
+#define SBC_MODE_STEREO 0x02
+#define SBC_MODE_JOINT_STEREO 0x03
+
+/* allocation method */
+#define SBC_AM_LOUDNESS 0x00
+#define SBC_AM_SNR 0x01
+
+/* subbands */
+#define SBC_SB_4 0x00
+#define SBC_SB_8 0x01
+
+/* data endianess */
+#define SBC_LE 0x00
+#define SBC_BE 0x01
+
+struct sbc_struct {
+ unsigned long flags;
+
+ uint8_t frequency;
+ uint8_t blocks;
+ uint8_t subbands;
+ uint8_t mode;
+ uint8_t allocation;
+ uint8_t bitpool;
+ uint8_t endian;
+
+ void *priv;
+ void *priv_alloc_base;
+};
+
+typedef struct sbc_struct sbc_t;
+
+int sbc_init(sbc_t *sbc, unsigned long flags);
+int sbc_reinit(sbc_t *sbc, unsigned long flags);
+int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
+int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len);
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+ const void *conf, size_t conf_len);
+
+ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
+
+/* Decodes ONE input block into ONE output block */
+ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
+ void *output, size_t output_len, size_t *written);
+
+/* Encodes ONE input block into ONE output block */
+ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
+ void *output, size_t output_len, ssize_t *written);
+
+/* Returns the output block size in bytes */
+size_t sbc_get_frame_length(sbc_t *sbc);
+
+/* Returns the time one input/output block takes to play in msec*/
+unsigned sbc_get_frame_duration(sbc_t *sbc);
+
+/* Returns the input block size in bytes */
+size_t sbc_get_codesize(sbc_t *sbc);
+
+const char *sbc_get_implementation_info(sbc_t *sbc);
+void sbc_finish(sbc_t *sbc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SBC_H */
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define fabs(x) ((x) < 0 ? -(x) : (x))
+/* C does not provide an explicit arithmetic shift right but this will
+ always be correct and every compiler *should* generate optimal code */
+#define ASR(val, bits) ((-2 >> 1 == -1) ? \
+ ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
+
+#define SCALE_SPROTO4_TBL 12
+#define SCALE_SPROTO8_TBL 14
+#define SCALE_NPROTO4_TBL 11
+#define SCALE_NPROTO8_TBL 11
+#define SCALE4_STAGED1_BITS 15
+#define SCALE4_STAGED2_BITS 16
+#define SCALE8_STAGED1_BITS 15
+#define SCALE8_STAGED2_BITS 16
+
+typedef int32_t sbc_fixed_t;
+
+#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS)
+#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS)
+#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS)
+#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS)
+
+#define SBC_FIXED_0(val) { val = 0; }
+#define MUL(a, b) ((a) * (b))
+#if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__))
+#define MULA(a, b, res) ({ \
+ int tmp = res; \
+ __asm__( \
+ "mla %0, %2, %3, %0" \
+ : "=&r" (tmp) \
+ : "0" (tmp), "r" (a), "r" (b)); \
+ tmp; })
+#else
+#define MULA(a, b, res) ((a) * (b) + (res))
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ * Copyright (C) 2012-2013 Intel Corporation
+ *
+ *
+ * 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 <stdint.h>
+#include <limits.h>
+#include <string.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives.h"
+#include "sbc_primitives_mmx.h"
+#include "sbc_primitives_iwmmxt.h"
+#include "sbc_primitives_neon.h"
+#include "sbc_primitives_armv6.h"
+
+/*
+ * A reference C code of analysis filter with SIMD-friendly tables
+ * reordering and code layout. This code can be used to develop platform
+ * specific SIMD optimizations. Also it may be used as some kind of test
+ * for compiler autovectorization capabilities (who knows, if the compiler
+ * is very good at this stuff, hand optimized assembly may be not strictly
+ * needed for some platform).
+ *
+ * Note: It is also possible to make a simple variant of analysis filter,
+ * which needs only a single constants table without taking care about
+ * even/odd cases. This simple variant of filter can be implemented without
+ * input data permutation. The only thing that would be lost is the
+ * possibility to use pairwise SIMD multiplications. But for some simple
+ * CPU cores without SIMD extensions it can be useful. If anybody is
+ * interested in implementing such variant of a filter, sourcecode from
+ * bluez versions 4.26/4.27 can be used as a reference and the history of
+ * the changes in git repository done around that time may be worth checking.
+ */
+
+static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ FIXED_A t1[4];
+ FIXED_T t2[4];
+ int hop = 0;
+
+ /* rounding coefficient */
+ t1[0] = t1[1] = t1[2] = t1[3] =
+ (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1);
+
+ /* low pass polyphase filter */
+ for (hop = 0; hop < 40; hop += 8) {
+ t1[0] += (FIXED_A) in[hop] * consts[hop];
+ t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1];
+ t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2];
+ t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3];
+ t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4];
+ t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5];
+ t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6];
+ t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7];
+ }
+
+ /* scaling */
+ t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE;
+ t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE;
+ t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE;
+ t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE;
+
+ /* do the cos transform */
+ t1[0] = (FIXED_A) t2[0] * consts[40 + 0];
+ t1[0] += (FIXED_A) t2[1] * consts[40 + 1];
+ t1[1] = (FIXED_A) t2[0] * consts[40 + 2];
+ t1[1] += (FIXED_A) t2[1] * consts[40 + 3];
+ t1[2] = (FIXED_A) t2[0] * consts[40 + 4];
+ t1[2] += (FIXED_A) t2[1] * consts[40 + 5];
+ t1[3] = (FIXED_A) t2[0] * consts[40 + 6];
+ t1[3] += (FIXED_A) t2[1] * consts[40 + 7];
+
+ t1[0] += (FIXED_A) t2[2] * consts[40 + 8];
+ t1[0] += (FIXED_A) t2[3] * consts[40 + 9];
+ t1[1] += (FIXED_A) t2[2] * consts[40 + 10];
+ t1[1] += (FIXED_A) t2[3] * consts[40 + 11];
+ t1[2] += (FIXED_A) t2[2] * consts[40 + 12];
+ t1[2] += (FIXED_A) t2[3] * consts[40 + 13];
+ t1[3] += (FIXED_A) t2[2] * consts[40 + 14];
+ t1[3] += (FIXED_A) t2[3] * consts[40 + 15];
+
+ out[0] = t1[0] >>
+ (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+ out[1] = t1[1] >>
+ (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+ out[2] = t1[2] >>
+ (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+ out[3] = t1[3] >>
+ (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+}
+
+static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ FIXED_A t1[8];
+ FIXED_T t2[8];
+ int i, hop;
+
+ /* rounding coefficient */
+ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] =
+ (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1);
+
+ /* low pass polyphase filter */
+ for (hop = 0; hop < 80; hop += 16) {
+ t1[0] += (FIXED_A) in[hop] * consts[hop];
+ t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1];
+ t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2];
+ t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3];
+ t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4];
+ t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5];
+ t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6];
+ t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7];
+ t1[4] += (FIXED_A) in[hop + 8] * consts[hop + 8];
+ t1[4] += (FIXED_A) in[hop + 9] * consts[hop + 9];
+ t1[5] += (FIXED_A) in[hop + 10] * consts[hop + 10];
+ t1[5] += (FIXED_A) in[hop + 11] * consts[hop + 11];
+ t1[6] += (FIXED_A) in[hop + 12] * consts[hop + 12];
+ t1[6] += (FIXED_A) in[hop + 13] * consts[hop + 13];
+ t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14];
+ t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15];
+ }
+
+ /* scaling */
+ t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE;
+ t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE;
+ t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE;
+ t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE;
+ t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE;
+ t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE;
+ t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE;
+ t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE;
+
+
+ /* do the cos transform */
+ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0;
+
+ for (i = 0; i < 4; i++) {
+ t1[0] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 0];
+ t1[0] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 1];
+ t1[1] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 2];
+ t1[1] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 3];
+ t1[2] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 4];
+ t1[2] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 5];
+ t1[3] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 6];
+ t1[3] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 7];
+ t1[4] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 8];
+ t1[4] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 9];
+ t1[5] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 10];
+ t1[5] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 11];
+ t1[6] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 12];
+ t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13];
+ t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14];
+ t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15];
+ }
+
+ for (i = 0; i < 8; i++)
+ out[i] = t1[i] >>
+ (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS);
+}
+
+static inline void sbc_analyze_4b_4s_simd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_four_simd(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_simd(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ sbc_analyze_four_simd(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_simd(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_simd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_eight_simd(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_simd(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ sbc_analyze_eight_simd(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static inline void sbc_analyze_1b_8s_simd_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_simd_odd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_simd(x, out, analysis_consts_fixed8_simd_odd);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_even;
+}
+
+static inline void sbc_analyze_1b_8s_simd_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_simd(x, out, analysis_consts_fixed8_simd_even);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd;
+}
+
+static inline int16_t unaligned16_be(const uint8_t *ptr)
+{
+ return (int16_t) ((ptr[0] << 8) | ptr[1]);
+}
+
+static inline int16_t unaligned16_le(const uint8_t *ptr)
+{
+ return (int16_t) (ptr[0] | (ptr[1] << 8));
+}
+
+/*
+ * Internal helper functions for input data processing. In order to get
+ * optimal performance, it is important to have "nsamples", "nchannels"
+ * and "big_endian" arguments used with this inline function as compile
+ * time constants.
+ */
+
+static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ if (nchannels > 0)
+ memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position],
+ 36 * sizeof(int16_t));
+ if (nchannels > 1)
+ memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position],
+ 36 * sizeof(int16_t));
+ position = SBC_X_BUFFER_SIZE - 40;
+ }
+
+ #define PCM(i) (big_endian ? \
+ unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2))
+
+ /* copy/permutate audio samples */
+ while ((nsamples -= 8) >= 0) {
+ position -= 8;
+ if (nchannels > 0) {
+ int16_t *x = &X[0][position];
+ x[0] = PCM(0 + 7 * nchannels);
+ x[1] = PCM(0 + 3 * nchannels);
+ x[2] = PCM(0 + 6 * nchannels);
+ x[3] = PCM(0 + 4 * nchannels);
+ x[4] = PCM(0 + 0 * nchannels);
+ x[5] = PCM(0 + 2 * nchannels);
+ x[6] = PCM(0 + 1 * nchannels);
+ x[7] = PCM(0 + 5 * nchannels);
+ }
+ if (nchannels > 1) {
+ int16_t *x = &X[1][position];
+ x[0] = PCM(1 + 7 * nchannels);
+ x[1] = PCM(1 + 3 * nchannels);
+ x[2] = PCM(1 + 6 * nchannels);
+ x[3] = PCM(1 + 4 * nchannels);
+ x[4] = PCM(1 + 0 * nchannels);
+ x[5] = PCM(1 + 2 * nchannels);
+ x[6] = PCM(1 + 1 * nchannels);
+ x[7] = PCM(1 + 5 * nchannels);
+ }
+ pcm += 16 * nchannels;
+ }
+ #undef PCM
+
+ return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ if (nchannels > 0)
+ memcpy(&X[0][SBC_X_BUFFER_SIZE - 72], &X[0][position],
+ 72 * sizeof(int16_t));
+ if (nchannels > 1)
+ memcpy(&X[1][SBC_X_BUFFER_SIZE - 72], &X[1][position],
+ 72 * sizeof(int16_t));
+ position = SBC_X_BUFFER_SIZE - 72;
+ }
+
+ #define PCM(i) (big_endian ? \
+ unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2))
+
+ if (position % 16 == 8) {
+ position -= 8;
+ nsamples -= 8;
+ if (nchannels > 0) {
+ int16_t *x = &X[0][position];
+ x[0] = PCM(0 + (15-8) * nchannels);
+ x[2] = PCM(0 + (14-8) * nchannels);
+ x[3] = PCM(0 + (8-8) * nchannels);
+ x[4] = PCM(0 + (13-8) * nchannels);
+ x[5] = PCM(0 + (9-8) * nchannels);
+ x[6] = PCM(0 + (12-8) * nchannels);
+ x[7] = PCM(0 + (10-8) * nchannels);
+ x[8] = PCM(0 + (11-8) * nchannels);
+ }
+ if (nchannels > 1) {
+ int16_t *x = &X[1][position];
+ x[0] = PCM(1 + (15-8) * nchannels);
+ x[2] = PCM(1 + (14-8) * nchannels);
+ x[3] = PCM(1 + (8-8) * nchannels);
+ x[4] = PCM(1 + (13-8) * nchannels);
+ x[5] = PCM(1 + (9-8) * nchannels);
+ x[6] = PCM(1 + (12-8) * nchannels);
+ x[7] = PCM(1 + (10-8) * nchannels);
+ x[8] = PCM(1 + (11-8) * nchannels);
+ }
+
+ pcm += 16 * nchannels;
+ }
+
+ /* copy/permutate audio samples */
+ while (nsamples >= 16) {
+ position -= 16;
+ if (nchannels > 0) {
+ int16_t *x = &X[0][position];
+ x[0] = PCM(0 + 15 * nchannels);
+ x[1] = PCM(0 + 7 * nchannels);
+ x[2] = PCM(0 + 14 * nchannels);
+ x[3] = PCM(0 + 8 * nchannels);
+ x[4] = PCM(0 + 13 * nchannels);
+ x[5] = PCM(0 + 9 * nchannels);
+ x[6] = PCM(0 + 12 * nchannels);
+ x[7] = PCM(0 + 10 * nchannels);
+ x[8] = PCM(0 + 11 * nchannels);
+ x[9] = PCM(0 + 3 * nchannels);
+ x[10] = PCM(0 + 6 * nchannels);
+ x[11] = PCM(0 + 0 * nchannels);
+ x[12] = PCM(0 + 5 * nchannels);
+ x[13] = PCM(0 + 1 * nchannels);
+ x[14] = PCM(0 + 4 * nchannels);
+ x[15] = PCM(0 + 2 * nchannels);
+ }
+ if (nchannels > 1) {
+ int16_t *x = &X[1][position];
+ x[0] = PCM(1 + 15 * nchannels);
+ x[1] = PCM(1 + 7 * nchannels);
+ x[2] = PCM(1 + 14 * nchannels);
+ x[3] = PCM(1 + 8 * nchannels);
+ x[4] = PCM(1 + 13 * nchannels);
+ x[5] = PCM(1 + 9 * nchannels);
+ x[6] = PCM(1 + 12 * nchannels);
+ x[7] = PCM(1 + 10 * nchannels);
+ x[8] = PCM(1 + 11 * nchannels);
+ x[9] = PCM(1 + 3 * nchannels);
+ x[10] = PCM(1 + 6 * nchannels);
+ x[11] = PCM(1 + 0 * nchannels);
+ x[12] = PCM(1 + 5 * nchannels);
+ x[13] = PCM(1 + 1 * nchannels);
+ x[14] = PCM(1 + 4 * nchannels);
+ x[15] = PCM(1 + 2 * nchannels);
+ }
+ pcm += 32 * nchannels;
+ nsamples -= 16;
+ }
+
+ if (nsamples == 8) {
+ position -= 8;
+ if (nchannels > 0) {
+ int16_t *x = &X[0][position];
+ x[-7] = PCM(0 + 7 * nchannels);
+ x[1] = PCM(0 + 3 * nchannels);
+ x[2] = PCM(0 + 6 * nchannels);
+ x[3] = PCM(0 + 0 * nchannels);
+ x[4] = PCM(0 + 5 * nchannels);
+ x[5] = PCM(0 + 1 * nchannels);
+ x[6] = PCM(0 + 4 * nchannels);
+ x[7] = PCM(0 + 2 * nchannels);
+ }
+ if (nchannels > 1) {
+ int16_t *x = &X[1][position];
+ x[-7] = PCM(1 + 7 * nchannels);
+ x[1] = PCM(1 + 3 * nchannels);
+ x[2] = PCM(1 + 6 * nchannels);
+ x[3] = PCM(1 + 0 * nchannels);
+ x[4] = PCM(1 + 5 * nchannels);
+ x[5] = PCM(1 + 1 * nchannels);
+ x[6] = PCM(1 + 4 * nchannels);
+ x[7] = PCM(1 + 2 * nchannels);
+ }
+ }
+ #undef PCM
+
+ return position;
+}
+
+/*
+ * Input data processing functions. The data is endian converted if needed,
+ * channels are deintrleaved and audio samples are reordered for use in
+ * SIMD-friendly analysis filter function. The results are put into "X"
+ * array, getting appended to the previous data (or it is better to say
+ * prepended, as the buffer is filled from top to bottom). Old data is
+ * discarded when neededed, but availability of (10 * nrof_subbands)
+ * contiguous samples is always guaranteed for the input to the analysis
+ * filter. This is achieved by copying a sufficient part of old data
+ * to the top of the buffer on buffer wraparound.
+ */
+
+static int sbc_enc_process_input_4s_le(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ if (nchannels > 1)
+ return sbc_encoder_process_input_s4_internal(
+ position, pcm, X, nsamples, 2, 0);
+ else
+ return sbc_encoder_process_input_s4_internal(
+ position, pcm, X, nsamples, 1, 0);
+}
+
+static int sbc_enc_process_input_4s_be(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ if (nchannels > 1)
+ return sbc_encoder_process_input_s4_internal(
+ position, pcm, X, nsamples, 2, 1);
+ else
+ return sbc_encoder_process_input_s4_internal(
+ position, pcm, X, nsamples, 1, 1);
+}
+
+static int sbc_enc_process_input_8s_le(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ if (nchannels > 1)
+ return sbc_encoder_process_input_s8_internal(
+ position, pcm, X, nsamples, 2, 0);
+ else
+ return sbc_encoder_process_input_s8_internal(
+ position, pcm, X, nsamples, 1, 0);
+}
+
+static int sbc_enc_process_input_8s_be(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ if (nchannels > 1)
+ return sbc_encoder_process_input_s8_internal(
+ position, pcm, X, nsamples, 2, 1);
+ else
+ return sbc_encoder_process_input_s8_internal(
+ position, pcm, X, nsamples, 1, 1);
+}
+
+/* Supplementary function to count the number of leading zeros */
+
+static inline int sbc_clz(uint32_t x)
+{
+#ifdef __GNUC__
+ return __builtin_clz(x);
+#else
+ /* TODO: this should be replaced with something better if good
+ * performance is wanted when using compilers other than gcc */
+ int cnt = 0;
+ while (x) {
+ cnt++;
+ x >>= 1;
+ }
+ return 32 - cnt;
+#endif
+}
+
+static void sbc_calc_scalefactors(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ int ch, sb, blk;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb++) {
+ uint32_t x = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ int32_t tmp = fabs(sb_sample_f[blk][ch][sb]);
+ if (tmp != 0)
+ x |= tmp - 1;
+ }
+ scale_factor[ch][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(x);
+ }
+ }
+}
+
+static int sbc_calc_scalefactors_j(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands)
+{
+ int blk, joint = 0;
+ int32_t tmp0, tmp1;
+ uint32_t x, y;
+
+ /* last subband does not use joint stereo */
+ int sb = subbands - 1;
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = fabs(sb_sample_f[blk][0][sb]);
+ tmp1 = fabs(sb_sample_f[blk][1][sb]);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+ scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+ /* the rest of subbands can use joint stereo */
+ while (--sb >= 0) {
+ int32_t sb_sample_j[16][2];
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = sb_sample_f[blk][0][sb];
+ tmp1 = sb_sample_f[blk][1][sb];
+ sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1);
+ sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1);
+ tmp0 = fabs(tmp0);
+ tmp1 = fabs(tmp1);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ scale_factor[0][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(x);
+ scale_factor[1][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(y);
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = fabs(sb_sample_j[blk][0]);
+ tmp1 = fabs(sb_sample_j[blk][1]);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ x = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+ y = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+ /* decide whether to use joint stereo for this subband */
+ if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) {
+ joint |= 1 << (subbands - 1 - sb);
+ scale_factor[0][sb] = x;
+ scale_factor[1][sb] = y;
+ for (blk = 0; blk < blocks; blk++) {
+ sb_sample_f[blk][0][sb] = sb_sample_j[blk][0];
+ sb_sample_f[blk][1][sb] = sb_sample_j[blk][1];
+ }
+ }
+ }
+
+ /* bitmask with the information about subbands using joint stereo */
+ return joint;
+}
+
+/*
+ * Detect CPU features and setup function pointers
+ */
+void sbc_init_primitives(struct sbc_encoder_state *state)
+{
+ /* Default implementation for analyze functions */
+ state->sbc_analyze_4s = sbc_analyze_4b_4s_simd;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_simd;
+
+ /* Default implementation for input reordering / deinterleaving */
+ state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le;
+ state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be;
+ state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le;
+ state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be;
+
+ /* Default implementation for scale factors calculation */
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors;
+ state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j;
+ state->implementation_info = "Generic C";
+
+ /* X86/AMD64 optimizations */
+#ifdef SBC_BUILD_WITH_MMX_SUPPORT
+ sbc_init_primitives_mmx(state);
+#endif
+
+ /* ARM optimizations */
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+ sbc_init_primitives_armv6(state);
+#endif
+#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
+ sbc_init_primitives_iwmmxt(state);
+#endif
+#ifdef SBC_BUILD_WITH_NEON_SUPPORT
+ sbc_init_primitives_neon(state);
+
+ if (state->increment == 1) {
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd;
+ state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le;
+ state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be;
+ state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le;
+ state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be;
+ }
+#endif
+}
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_H
+#define __SBC_PRIMITIVES_H
+
+#define SCALE_OUT_BITS 15
+#define SBC_X_BUFFER_SIZE 328
+
+#ifdef __GNUC__
+#define SBC_ALWAYS_INLINE inline __attribute__((always_inline))
+#else
+#define SBC_ALWAYS_INLINE inline
+#endif
+
+struct SBC_ALIGNED sbc_encoder_state {
+ int position;
+ /* Number of consecutive blocks handled by the encoder */
+ uint8_t increment;
+ int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE];
+ /* Polyphase analysis filter for 4 subbands configuration,
+ * it handles "increment" blocks at once */
+ void (*sbc_analyze_4s)(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride);
+ /* Polyphase analysis filter for 8 subbands configuration,
+ * it handles "increment" blocks at once */
+ void (*sbc_analyze_8s)(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride);
+ /* Process input data (deinterleave, endian conversion, reordering),
+ * depending on the number of subbands and input data byte order */
+ int (*sbc_enc_process_input_4s_le)(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels);
+ int (*sbc_enc_process_input_4s_be)(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels);
+ int (*sbc_enc_process_input_8s_le)(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels);
+ int (*sbc_enc_process_input_8s_be)(int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels);
+ /* Scale factors calculation */
+ void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands);
+ /* Scale factors calculation with joint stereo support */
+ int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands);
+ const char *implementation_info;
+};
+
+/*
+ * Initialize pointers to the functions which are the basic "building bricks"
+ * of SBC codec. Best implementation is selected based on target CPU
+ * capabilities.
+ */
+void sbc_init_primitives(struct sbc_encoder_state *encoder_state);
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_armv6.h"
+
+/*
+ * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline.
+ */
+
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+
+static void __attribute__((naked)) sbc_analyze_four_armv6()
+{
+ /* r0 = in, r1 = out, r2 = consts */
+ __asm__ volatile (
+ "push {r1, r4-r7, lr}\n"
+ "push {r8-r11}\n"
+ "ldrd r4, r5, [r0, #0]\n"
+ "ldrd r6, r7, [r2, #0]\n"
+ "ldrd r8, r9, [r0, #16]\n"
+ "ldrd r10, r11, [r2, #16]\n"
+ "mov r14, #0x8000\n"
+ "smlad r3, r4, r6, r14\n"
+ "smlad r12, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #32]\n"
+ "ldrd r6, r7, [r2, #32]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #48]\n"
+ "ldrd r10, r11, [r2, #48]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #64]\n"
+ "ldrd r6, r7, [r2, #64]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #8]\n"
+ "ldrd r10, r11, [r2, #8]\n"
+ "smlad r3, r4, r6, r3\n" /* t1[0] is done */
+ "smlad r12, r5, r7, r12\n" /* t1[1] is done */
+ "ldrd r4, r5, [r0, #24]\n"
+ "ldrd r6, r7, [r2, #24]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */
+ "smlad r12, r8, r10, r14\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #40]\n"
+ "ldrd r10, r11, [r2, #40]\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #56]\n"
+ "ldrd r6, r7, [r2, #56]\n"
+ "smlad r12, r8, r10, r12\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #72]\n"
+ "ldrd r10, r11, [r2, #72]\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r2, #80]\n" /* start loading cos table */
+ "smlad r12, r8, r10, r12\n" /* t1[2] is done */
+ "smlad r14, r9, r11, r14\n" /* t1[3] is done */
+ "ldrd r6, r7, [r2, #88]\n"
+ "ldrd r8, r9, [r2, #96]\n"
+ "ldrd r10, r11, [r2, #104]\n" /* cos table fully loaded */
+ "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+ "smuad r4, r3, r4\n"
+ "smuad r5, r3, r5\n"
+ "smlad r4, r12, r8, r4\n"
+ "smlad r5, r12, r9, r5\n"
+ "smuad r6, r3, r6\n"
+ "smuad r7, r3, r7\n"
+ "smlad r6, r12, r10, r6\n"
+ "smlad r7, r12, r11, r7\n"
+ "pop {r8-r11}\n"
+ "stmia r1, {r4, r5, r6, r7}\n"
+ "pop {r1, r4-r7, pc}\n"
+ );
+}
+
+#define sbc_analyze_four(in, out, consts) \
+ ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+ sbc_analyze_four_armv6)((in), (out), (consts))
+
+static void __attribute__((naked)) sbc_analyze_eight_armv6()
+{
+ /* r0 = in, r1 = out, r2 = consts */
+ __asm__ volatile (
+ "push {r1, r4-r7, lr}\n"
+ "push {r8-r11}\n"
+ "ldrd r4, r5, [r0, #24]\n"
+ "ldrd r6, r7, [r2, #24]\n"
+ "ldrd r8, r9, [r0, #56]\n"
+ "ldrd r10, r11, [r2, #56]\n"
+ "mov r14, #0x8000\n"
+ "smlad r3, r4, r6, r14\n"
+ "smlad r12, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #88]\n"
+ "ldrd r6, r7, [r2, #88]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #120]\n"
+ "ldrd r10, r11, [r2, #120]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #152]\n"
+ "ldrd r6, r7, [r2, #152]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #16]\n"
+ "ldrd r10, r11, [r2, #16]\n"
+ "smlad r3, r4, r6, r3\n" /* t1[6] is done */
+ "smlad r12, r5, r7, r12\n" /* t1[7] is done */
+ "ldrd r4, r5, [r0, #48]\n"
+ "ldrd r6, r7, [r2, #48]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[6] and t1[7] */
+ "str r3, [sp, #-4]!\n" /* save to stack */
+ "smlad r3, r8, r10, r14\n"
+ "smlad r12, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #80]\n"
+ "ldrd r10, r11, [r2, #80]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #112]\n"
+ "ldrd r6, r7, [r2, #112]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #144]\n"
+ "ldrd r10, r11, [r2, #144]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #0]\n"
+ "ldrd r6, r7, [r2, #0]\n"
+ "smlad r3, r8, r10, r3\n" /* t1[4] is done */
+ "smlad r12, r9, r11, r12\n" /* t1[5] is done */
+ "ldrd r8, r9, [r0, #32]\n"
+ "ldrd r10, r11, [r2, #32]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[4] and t1[5] */
+ "str r3, [sp, #-4]!\n" /* save to stack */
+ "smlad r3, r4, r6, r14\n"
+ "smlad r12, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #64]\n"
+ "ldrd r6, r7, [r2, #64]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #96]\n"
+ "ldrd r10, r11, [r2, #96]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #128]\n"
+ "ldrd r6, r7, [r2, #128]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #8]\n"
+ "ldrd r10, r11, [r2, #8]\n"
+ "smlad r3, r4, r6, r3\n" /* t1[0] is done */
+ "smlad r12, r5, r7, r12\n" /* t1[1] is done */
+ "ldrd r4, r5, [r0, #40]\n"
+ "ldrd r6, r7, [r2, #40]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */
+ "smlad r12, r8, r10, r14\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #72]\n"
+ "ldrd r10, r11, [r2, #72]\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #104]\n"
+ "ldrd r6, r7, [r2, #104]\n"
+ "smlad r12, r8, r10, r12\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #136]\n"
+ "ldrd r10, r11, [r2, #136]!\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r2, #(160 - 136 + 0)]\n"
+ "smlad r12, r8, r10, r12\n" /* t1[2] is done */
+ "smlad r14, r9, r11, r14\n" /* t1[3] is done */
+ "ldrd r6, r7, [r2, #(160 - 136 + 8)]\n"
+ "smuad r4, r3, r4\n"
+ "smuad r5, r3, r5\n"
+ "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+ /* r3 = t2[0:1] */
+ /* r12 = t2[2:3] */
+ "pop {r0, r14}\n" /* t2[4:5], t2[6:7] */
+ "ldrd r8, r9, [r2, #(160 - 136 + 32)]\n"
+ "smuad r6, r3, r6\n"
+ "smuad r7, r3, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 40)]\n"
+ "smlad r4, r12, r8, r4\n"
+ "smlad r5, r12, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 64)]\n"
+ "smlad r6, r12, r10, r6\n"
+ "smlad r7, r12, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 72)]\n"
+ "smlad r4, r0, r8, r4\n"
+ "smlad r5, r0, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 96)]\n"
+ "smlad r6, r0, r10, r6\n"
+ "smlad r7, r0, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 104)]\n"
+ "smlad r4, r14, r8, r4\n"
+ "smlad r5, r14, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 0)]\n"
+ "smlad r6, r14, r10, r6\n"
+ "smlad r7, r14, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 8)]\n"
+ "stmia r1!, {r4, r5}\n"
+ "smuad r4, r3, r8\n"
+ "smuad r5, r3, r9\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 32)]\n"
+ "stmia r1!, {r6, r7}\n"
+ "smuad r6, r3, r10\n"
+ "smuad r7, r3, r11\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 40)]\n"
+ "smlad r4, r12, r8, r4\n"
+ "smlad r5, r12, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 64)]\n"
+ "smlad r6, r12, r10, r6\n"
+ "smlad r7, r12, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 72)]\n"
+ "smlad r4, r0, r8, r4\n"
+ "smlad r5, r0, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 96)]\n"
+ "smlad r6, r0, r10, r6\n"
+ "smlad r7, r0, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 104)]\n"
+ "smlad r4, r14, r8, r4\n"
+ "smlad r5, r14, r9, r5\n"
+ "smlad r6, r14, r10, r6\n"
+ "smlad r7, r14, r11, r7\n"
+ "pop {r8-r11}\n"
+ "stmia r1!, {r4, r5, r6, r7}\n"
+ "pop {r1, r4-r7, pc}\n"
+ );
+}
+
+#define sbc_analyze_eight(in, out, consts) \
+ ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+ sbc_analyze_eight_armv6)((in), (out), (consts))
+
+static void sbc_analyze_4b_4s_armv6(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static void sbc_analyze_4b_8s_armv6(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static inline void sbc_analyze_1b_8s_armv6_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_armv6_odd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_armv6(x, out, analysis_consts_fixed8_simd_odd);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6_even;
+}
+
+static inline void sbc_analyze_1b_8s_armv6_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_armv6(x, out, analysis_consts_fixed8_simd_even);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6_odd;
+}
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
+{
+ state->sbc_analyze_4s = sbc_analyze_4b_4s_armv6;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6_odd;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_armv6;
+ state->implementation_info = "ARMv6 SIMD";
+}
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_ARMV6_H
+#define __SBC_PRIMITIVES_ARMV6_H
+
+#include "sbc_primitives.h"
+
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+ defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
+ defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
+ defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
+ defined(__ARM_ARCH_7M__)
+#define SBC_HAVE_ARMV6 1
+#endif
+
+#if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
+ defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
+ defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \
+ (!defined(__thumb__) || defined(__thumb2__))
+
+#define SBC_BUILD_WITH_ARMV6_SUPPORT
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_iwmmxt.h"
+
+/*
+ * IWMMXT optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
+
+static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ __asm__ volatile (
+ "wldrd wr0, [%0]\n"
+ "tbcstw wr4, %2\n"
+ "wldrd wr2, [%1]\n"
+ "wldrd wr1, [%0, #8]\n"
+ "wldrd wr3, [%1, #8]\n"
+ "wmadds wr0, wr2, wr0\n"
+ " wldrd wr6, [%0, #16]\n"
+ "wmadds wr1, wr3, wr1\n"
+ " wldrd wr7, [%0, #24]\n"
+ "waddwss wr0, wr0, wr4\n"
+ " wldrd wr8, [%1, #16]\n"
+ "waddwss wr1, wr1, wr4\n"
+ " wldrd wr9, [%1, #24]\n"
+ " wmadds wr6, wr8, wr6\n"
+ " wldrd wr2, [%0, #32]\n"
+ " wmadds wr7, wr9, wr7\n"
+ " wldrd wr3, [%0, #40]\n"
+ " waddwss wr0, wr6, wr0\n"
+ " wldrd wr4, [%1, #32]\n"
+ " waddwss wr1, wr7, wr1\n"
+ " wldrd wr5, [%1, #40]\n"
+ " wmadds wr2, wr4, wr2\n"
+ "wldrd wr6, [%0, #48]\n"
+ " wmadds wr3, wr5, wr3\n"
+ "wldrd wr7, [%0, #56]\n"
+ " waddwss wr0, wr2, wr0\n"
+ "wldrd wr8, [%1, #48]\n"
+ " waddwss wr1, wr3, wr1\n"
+ "wldrd wr9, [%1, #56]\n"
+ "wmadds wr6, wr8, wr6\n"
+ " wldrd wr2, [%0, #64]\n"
+ "wmadds wr7, wr9, wr7\n"
+ " wldrd wr3, [%0, #72]\n"
+ "waddwss wr0, wr6, wr0\n"
+ " wldrd wr4, [%1, #64]\n"
+ "waddwss wr1, wr7, wr1\n"
+ " wldrd wr5, [%1, #72]\n"
+ " wmadds wr2, wr4, wr2\n"
+ "tmcr wcgr0, %4\n"
+ " wmadds wr3, wr5, wr3\n"
+ " waddwss wr0, wr2, wr0\n"
+ " waddwss wr1, wr3, wr1\n"
+ "\n"
+ "wsrawg wr0, wr0, wcgr0\n"
+ " wldrd wr4, [%1, #80]\n"
+ "wsrawg wr1, wr1, wcgr0\n"
+ " wldrd wr5, [%1, #88]\n"
+ "wpackwss wr0, wr0, wr0\n"
+ " wldrd wr6, [%1, #96]\n"
+ "wpackwss wr1, wr1, wr1\n"
+ "wmadds wr2, wr5, wr0\n"
+ " wldrd wr7, [%1, #104]\n"
+ "wmadds wr0, wr4, wr0\n"
+ "\n"
+ " wmadds wr3, wr7, wr1\n"
+ " wmadds wr1, wr6, wr1\n"
+ " waddwss wr2, wr3, wr2\n"
+ " waddwss wr0, wr1, wr0\n"
+ "\n"
+ "wstrd wr0, [%3]\n"
+ "wstrd wr2, [%3, #8]\n"
+ :
+ : "r" (in), "r" (consts),
+ "r" (1 << (SBC_PROTO_FIXED4_SCALE - 1)), "r" (out),
+ "r" (SBC_PROTO_FIXED4_SCALE)
+ : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+ "wr8", "wr9", "wcgr0", "memory");
+}
+
+static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ __asm__ volatile (
+ "wldrd wr0, [%0]\n"
+ "tbcstw wr15, %2\n"
+ "wldrd wr1, [%0, #8]\n"
+ "wldrd wr2, [%0, #16]\n"
+ "wldrd wr3, [%0, #24]\n"
+ "wldrd wr4, [%1]\n"
+ "wldrd wr5, [%1, #8]\n"
+ "wldrd wr6, [%1, #16]\n"
+ "wldrd wr7, [%1, #24]\n"
+ "wmadds wr0, wr0, wr4\n"
+ " wldrd wr8, [%1, #32]\n"
+ "wmadds wr1, wr1, wr5\n"
+ " wldrd wr9, [%1, #40]\n"
+ "wmadds wr2, wr2, wr6\n"
+ " wldrd wr10, [%1, #48]\n"
+ "wmadds wr3, wr3, wr7\n"
+ " wldrd wr11, [%1, #56]\n"
+ "waddwss wr0, wr0, wr15\n"
+ " wldrd wr4, [%0, #32]\n"
+ "waddwss wr1, wr1, wr15\n"
+ " wldrd wr5, [%0, #40]\n"
+ "waddwss wr2, wr2, wr15\n"
+ " wldrd wr6, [%0, #48]\n"
+ "waddwss wr3, wr3, wr15\n"
+ " wldrd wr7, [%0, #56]\n"
+ " wmadds wr4, wr4, wr8\n"
+ " wldrd wr12, [%0, #64]\n"
+ " wmadds wr5, wr5, wr9\n"
+ " wldrd wr13, [%0, #72]\n"
+ " wmadds wr6, wr6, wr10\n"
+ " wldrd wr14, [%0, #80]\n"
+ " wmadds wr7, wr7, wr11\n"
+ " wldrd wr15, [%0, #88]\n"
+ " waddwss wr0, wr4, wr0\n"
+ " wldrd wr8, [%1, #64]\n"
+ " waddwss wr1, wr5, wr1\n"
+ " wldrd wr9, [%1, #72]\n"
+ " waddwss wr2, wr6, wr2\n"
+ " wldrd wr10, [%1, #80]\n"
+ " waddwss wr3, wr7, wr3\n"
+ " wldrd wr11, [%1, #88]\n"
+ " wmadds wr12, wr12, wr8\n"
+ "wldrd wr4, [%0, #96]\n"
+ " wmadds wr13, wr13, wr9\n"
+ "wldrd wr5, [%0, #104]\n"
+ " wmadds wr14, wr14, wr10\n"
+ "wldrd wr6, [%0, #112]\n"
+ " wmadds wr15, wr15, wr11\n"
+ "wldrd wr7, [%0, #120]\n"
+ " waddwss wr0, wr12, wr0\n"
+ "wldrd wr8, [%1, #96]\n"
+ " waddwss wr1, wr13, wr1\n"
+ "wldrd wr9, [%1, #104]\n"
+ " waddwss wr2, wr14, wr2\n"
+ "wldrd wr10, [%1, #112]\n"
+ " waddwss wr3, wr15, wr3\n"
+ "wldrd wr11, [%1, #120]\n"
+ "wmadds wr4, wr4, wr8\n"
+ " wldrd wr12, [%0, #128]\n"
+ "wmadds wr5, wr5, wr9\n"
+ " wldrd wr13, [%0, #136]\n"
+ "wmadds wr6, wr6, wr10\n"
+ " wldrd wr14, [%0, #144]\n"
+ "wmadds wr7, wr7, wr11\n"
+ " wldrd wr15, [%0, #152]\n"
+ "waddwss wr0, wr4, wr0\n"
+ " wldrd wr8, [%1, #128]\n"
+ "waddwss wr1, wr5, wr1\n"
+ " wldrd wr9, [%1, #136]\n"
+ "waddwss wr2, wr6, wr2\n"
+ " wldrd wr10, [%1, #144]\n"
+ " waddwss wr3, wr7, wr3\n"
+ " wldrd wr11, [%1, #152]\n"
+ " wmadds wr12, wr12, wr8\n"
+ "tmcr wcgr0, %4\n"
+ " wmadds wr13, wr13, wr9\n"
+ " wmadds wr14, wr14, wr10\n"
+ " wmadds wr15, wr15, wr11\n"
+ " waddwss wr0, wr12, wr0\n"
+ " waddwss wr1, wr13, wr1\n"
+ " waddwss wr2, wr14, wr2\n"
+ " waddwss wr3, wr15, wr3\n"
+ "\n"
+ "wsrawg wr0, wr0, wcgr0\n"
+ "wsrawg wr1, wr1, wcgr0\n"
+ "wsrawg wr2, wr2, wcgr0\n"
+ "wsrawg wr3, wr3, wcgr0\n"
+ "\n"
+ "wpackwss wr0, wr0, wr0\n"
+ "wpackwss wr1, wr1, wr1\n"
+ " wldrd wr4, [%1, #160]\n"
+ "wpackwss wr2, wr2, wr2\n"
+ " wldrd wr5, [%1, #168]\n"
+ "wpackwss wr3, wr3, wr3\n"
+ " wldrd wr6, [%1, #192]\n"
+ " wmadds wr4, wr4, wr0\n"
+ " wldrd wr7, [%1, #200]\n"
+ " wmadds wr5, wr5, wr0\n"
+ " wldrd wr8, [%1, #224]\n"
+ " wmadds wr6, wr6, wr1\n"
+ " wldrd wr9, [%1, #232]\n"
+ " wmadds wr7, wr7, wr1\n"
+ " waddwss wr4, wr6, wr4\n"
+ " waddwss wr5, wr7, wr5\n"
+ " wmadds wr8, wr8, wr2\n"
+ "wldrd wr6, [%1, #256]\n"
+ " wmadds wr9, wr9, wr2\n"
+ "wldrd wr7, [%1, #264]\n"
+ "waddwss wr4, wr8, wr4\n"
+ " waddwss wr5, wr9, wr5\n"
+ "wmadds wr6, wr6, wr3\n"
+ "wmadds wr7, wr7, wr3\n"
+ "waddwss wr4, wr6, wr4\n"
+ "waddwss wr5, wr7, wr5\n"
+ "\n"
+ "wstrd wr4, [%3]\n"
+ "wstrd wr5, [%3, #8]\n"
+ "\n"
+ "wldrd wr6, [%1, #176]\n"
+ "wldrd wr5, [%1, #184]\n"
+ "wmadds wr5, wr5, wr0\n"
+ "wldrd wr8, [%1, #208]\n"
+ "wmadds wr0, wr6, wr0\n"
+ "wldrd wr9, [%1, #216]\n"
+ "wmadds wr9, wr9, wr1\n"
+ "wldrd wr6, [%1, #240]\n"
+ "wmadds wr1, wr8, wr1\n"
+ "wldrd wr7, [%1, #248]\n"
+ "waddwss wr0, wr1, wr0\n"
+ "waddwss wr5, wr9, wr5\n"
+ "wmadds wr7, wr7, wr2\n"
+ "wldrd wr8, [%1, #272]\n"
+ "wmadds wr2, wr6, wr2\n"
+ "wldrd wr9, [%1, #280]\n"
+ "waddwss wr0, wr2, wr0\n"
+ "waddwss wr5, wr7, wr5\n"
+ "wmadds wr9, wr9, wr3\n"
+ "wmadds wr3, wr8, wr3\n"
+ "waddwss wr0, wr3, wr0\n"
+ "waddwss wr5, wr9, wr5\n"
+ "\n"
+ "wstrd wr0, [%3, #16]\n"
+ "wstrd wr5, [%3, #24]\n"
+ :
+ : "r" (in), "r" (consts),
+ "r" (1 << (SBC_PROTO_FIXED8_SCALE - 1)), "r" (out),
+ "r" (SBC_PROTO_FIXED8_SCALE)
+ : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+ "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
+ "wcgr0", "memory");
+}
+
+static inline void sbc_analyze_4b_4s_iwmmxt(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_four_iwmmxt(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_iwmmxt(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ sbc_analyze_four_iwmmxt(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_iwmmxt(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_iwmmxt(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_eight_iwmmxt(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_iwmmxt(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ sbc_analyze_eight_iwmmxt(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static inline void sbc_analyze_1b_8s_iwmmxt_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_iwmmxt_odd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_iwmmxt(x, out, analysis_consts_fixed8_simd_odd);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt_even;
+}
+
+static inline void sbc_analyze_1b_8s_iwmmxt_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_iwmmxt(x, out, analysis_consts_fixed8_simd_even);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt_odd;
+}
+
+void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state)
+{
+ state->sbc_analyze_4s = sbc_analyze_4b_4s_iwmmxt;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt_odd;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_iwmmxt;
+ state->implementation_info = "IWMMXT";
+}
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_IWMMXT_H
+#define __SBC_PRIMITIVES_IWMMXT_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && defined(__IWMMXT__) && \
+ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_IWMMXT_SUPPORT
+
+void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_mmx.h"
+
+/*
+ * MMX optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_MMX_SUPPORT
+
+static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ static const SBC_ALIGNED int32_t round_c[2] = {
+ 1 << (SBC_PROTO_FIXED4_SCALE - 1),
+ 1 << (SBC_PROTO_FIXED4_SCALE - 1),
+ };
+ __asm__ volatile (
+ "movq (%0), %%mm0\n"
+ "movq 8(%0), %%mm1\n"
+ "pmaddwd (%1), %%mm0\n"
+ "pmaddwd 8(%1), %%mm1\n"
+ "paddd (%2), %%mm0\n"
+ "paddd (%2), %%mm1\n"
+ "\n"
+ "movq 16(%0), %%mm2\n"
+ "movq 24(%0), %%mm3\n"
+ "pmaddwd 16(%1), %%mm2\n"
+ "pmaddwd 24(%1), %%mm3\n"
+ "paddd %%mm2, %%mm0\n"
+ "paddd %%mm3, %%mm1\n"
+ "\n"
+ "movq 32(%0), %%mm2\n"
+ "movq 40(%0), %%mm3\n"
+ "pmaddwd 32(%1), %%mm2\n"
+ "pmaddwd 40(%1), %%mm3\n"
+ "paddd %%mm2, %%mm0\n"
+ "paddd %%mm3, %%mm1\n"
+ "\n"
+ "movq 48(%0), %%mm2\n"
+ "movq 56(%0), %%mm3\n"
+ "pmaddwd 48(%1), %%mm2\n"
+ "pmaddwd 56(%1), %%mm3\n"
+ "paddd %%mm2, %%mm0\n"
+ "paddd %%mm3, %%mm1\n"
+ "\n"
+ "movq 64(%0), %%mm2\n"
+ "movq 72(%0), %%mm3\n"
+ "pmaddwd 64(%1), %%mm2\n"
+ "pmaddwd 72(%1), %%mm3\n"
+ "paddd %%mm2, %%mm0\n"
+ "paddd %%mm3, %%mm1\n"
+ "\n"
+ "psrad %4, %%mm0\n"
+ "psrad %4, %%mm1\n"
+ "packssdw %%mm0, %%mm0\n"
+ "packssdw %%mm1, %%mm1\n"
+ "\n"
+ "movq %%mm0, %%mm2\n"
+ "pmaddwd 80(%1), %%mm0\n"
+ "pmaddwd 88(%1), %%mm2\n"
+ "\n"
+ "movq %%mm1, %%mm3\n"
+ "pmaddwd 96(%1), %%mm1\n"
+ "pmaddwd 104(%1), %%mm3\n"
+ "paddd %%mm1, %%mm0\n"
+ "paddd %%mm3, %%mm2\n"
+ "\n"
+ "movq %%mm0, (%3)\n"
+ "movq %%mm2, 8(%3)\n"
+ :
+ : "r" (in), "r" (consts), "r" (&round_c), "r" (out),
+ "i" (SBC_PROTO_FIXED4_SCALE)
+ : "cc", "memory");
+}
+
+static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ static const SBC_ALIGNED int32_t round_c[2] = {
+ 1 << (SBC_PROTO_FIXED8_SCALE - 1),
+ 1 << (SBC_PROTO_FIXED8_SCALE - 1),
+ };
+ __asm__ volatile (
+ "movq (%0), %%mm0\n"
+ "movq 8(%0), %%mm1\n"
+ "movq 16(%0), %%mm2\n"
+ "movq 24(%0), %%mm3\n"
+ "pmaddwd (%1), %%mm0\n"
+ "pmaddwd 8(%1), %%mm1\n"
+ "pmaddwd 16(%1), %%mm2\n"
+ "pmaddwd 24(%1), %%mm3\n"
+ "paddd (%2), %%mm0\n"
+ "paddd (%2), %%mm1\n"
+ "paddd (%2), %%mm2\n"
+ "paddd (%2), %%mm3\n"
+ "\n"
+ "movq 32(%0), %%mm4\n"
+ "movq 40(%0), %%mm5\n"
+ "movq 48(%0), %%mm6\n"
+ "movq 56(%0), %%mm7\n"
+ "pmaddwd 32(%1), %%mm4\n"
+ "pmaddwd 40(%1), %%mm5\n"
+ "pmaddwd 48(%1), %%mm6\n"
+ "pmaddwd 56(%1), %%mm7\n"
+ "paddd %%mm4, %%mm0\n"
+ "paddd %%mm5, %%mm1\n"
+ "paddd %%mm6, %%mm2\n"
+ "paddd %%mm7, %%mm3\n"
+ "\n"
+ "movq 64(%0), %%mm4\n"
+ "movq 72(%0), %%mm5\n"
+ "movq 80(%0), %%mm6\n"
+ "movq 88(%0), %%mm7\n"
+ "pmaddwd 64(%1), %%mm4\n"
+ "pmaddwd 72(%1), %%mm5\n"
+ "pmaddwd 80(%1), %%mm6\n"
+ "pmaddwd 88(%1), %%mm7\n"
+ "paddd %%mm4, %%mm0\n"
+ "paddd %%mm5, %%mm1\n"
+ "paddd %%mm6, %%mm2\n"
+ "paddd %%mm7, %%mm3\n"
+ "\n"
+ "movq 96(%0), %%mm4\n"
+ "movq 104(%0), %%mm5\n"
+ "movq 112(%0), %%mm6\n"
+ "movq 120(%0), %%mm7\n"
+ "pmaddwd 96(%1), %%mm4\n"
+ "pmaddwd 104(%1), %%mm5\n"
+ "pmaddwd 112(%1), %%mm6\n"
+ "pmaddwd 120(%1), %%mm7\n"
+ "paddd %%mm4, %%mm0\n"
+ "paddd %%mm5, %%mm1\n"
+ "paddd %%mm6, %%mm2\n"
+ "paddd %%mm7, %%mm3\n"
+ "\n"
+ "movq 128(%0), %%mm4\n"
+ "movq 136(%0), %%mm5\n"
+ "movq 144(%0), %%mm6\n"
+ "movq 152(%0), %%mm7\n"
+ "pmaddwd 128(%1), %%mm4\n"
+ "pmaddwd 136(%1), %%mm5\n"
+ "pmaddwd 144(%1), %%mm6\n"
+ "pmaddwd 152(%1), %%mm7\n"
+ "paddd %%mm4, %%mm0\n"
+ "paddd %%mm5, %%mm1\n"
+ "paddd %%mm6, %%mm2\n"
+ "paddd %%mm7, %%mm3\n"
+ "\n"
+ "psrad %4, %%mm0\n"
+ "psrad %4, %%mm1\n"
+ "psrad %4, %%mm2\n"
+ "psrad %4, %%mm3\n"
+ "\n"
+ "packssdw %%mm0, %%mm0\n"
+ "packssdw %%mm1, %%mm1\n"
+ "packssdw %%mm2, %%mm2\n"
+ "packssdw %%mm3, %%mm3\n"
+ "\n"
+ "movq %%mm0, %%mm4\n"
+ "movq %%mm0, %%mm5\n"
+ "pmaddwd 160(%1), %%mm4\n"
+ "pmaddwd 168(%1), %%mm5\n"
+ "\n"
+ "movq %%mm1, %%mm6\n"
+ "movq %%mm1, %%mm7\n"
+ "pmaddwd 192(%1), %%mm6\n"
+ "pmaddwd 200(%1), %%mm7\n"
+ "paddd %%mm6, %%mm4\n"
+ "paddd %%mm7, %%mm5\n"
+ "\n"
+ "movq %%mm2, %%mm6\n"
+ "movq %%mm2, %%mm7\n"
+ "pmaddwd 224(%1), %%mm6\n"
+ "pmaddwd 232(%1), %%mm7\n"
+ "paddd %%mm6, %%mm4\n"
+ "paddd %%mm7, %%mm5\n"
+ "\n"
+ "movq %%mm3, %%mm6\n"
+ "movq %%mm3, %%mm7\n"
+ "pmaddwd 256(%1), %%mm6\n"
+ "pmaddwd 264(%1), %%mm7\n"
+ "paddd %%mm6, %%mm4\n"
+ "paddd %%mm7, %%mm5\n"
+ "\n"
+ "movq %%mm4, (%3)\n"
+ "movq %%mm5, 8(%3)\n"
+ "\n"
+ "movq %%mm0, %%mm5\n"
+ "pmaddwd 176(%1), %%mm0\n"
+ "pmaddwd 184(%1), %%mm5\n"
+ "\n"
+ "movq %%mm1, %%mm7\n"
+ "pmaddwd 208(%1), %%mm1\n"
+ "pmaddwd 216(%1), %%mm7\n"
+ "paddd %%mm1, %%mm0\n"
+ "paddd %%mm7, %%mm5\n"
+ "\n"
+ "movq %%mm2, %%mm7\n"
+ "pmaddwd 240(%1), %%mm2\n"
+ "pmaddwd 248(%1), %%mm7\n"
+ "paddd %%mm2, %%mm0\n"
+ "paddd %%mm7, %%mm5\n"
+ "\n"
+ "movq %%mm3, %%mm7\n"
+ "pmaddwd 272(%1), %%mm3\n"
+ "pmaddwd 280(%1), %%mm7\n"
+ "paddd %%mm3, %%mm0\n"
+ "paddd %%mm7, %%mm5\n"
+ "\n"
+ "movq %%mm0, 16(%3)\n"
+ "movq %%mm5, 24(%3)\n"
+ :
+ : "r" (in), "r" (consts), "r" (&round_c), "r" (out),
+ "i" (SBC_PROTO_FIXED8_SCALE)
+ : "cc", "memory");
+}
+
+static inline void sbc_analyze_4b_4s_mmx(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_four_mmx(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_mmx(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ sbc_analyze_four_mmx(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_mmx(x + 0, out, analysis_consts_fixed4_simd_even);
+
+ __asm__ volatile ("emms\n");
+}
+
+static inline void sbc_analyze_4b_8s_mmx(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_eight_mmx(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_mmx(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ sbc_analyze_eight_mmx(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_mmx(x + 0, out, analysis_consts_fixed8_simd_even);
+
+ __asm__ volatile ("emms\n");
+}
+
+static inline void sbc_analyze_1b_8s_mmx_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_mmx_odd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_mmx(x, out, analysis_consts_fixed8_simd_odd);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx_even;
+
+ __asm__ volatile ("emms\n");
+}
+
+static inline void sbc_analyze_1b_8s_mmx_even(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ sbc_analyze_eight_mmx(x, out, analysis_consts_fixed8_simd_even);
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx_odd;
+
+ __asm__ volatile ("emms\n");
+}
+
+static void sbc_calc_scalefactors_mmx(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ static const SBC_ALIGNED int32_t consts[2] = {
+ 1 << SCALE_OUT_BITS,
+ 1 << SCALE_OUT_BITS,
+ };
+ int ch, sb;
+ intptr_t blk;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb += 2) {
+ blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]));
+ __asm__ volatile (
+ "movq (%4), %%mm0\n"
+ "1:\n"
+ "movq (%1, %0), %%mm1\n"
+ "pxor %%mm2, %%mm2\n"
+ "pcmpgtd %%mm2, %%mm1\n"
+ "paddd (%1, %0), %%mm1\n"
+ "pcmpgtd %%mm1, %%mm2\n"
+ "pxor %%mm2, %%mm1\n"
+
+ "por %%mm1, %%mm0\n"
+
+ "sub %2, %0\n"
+ "jns 1b\n"
+
+ "movd %%mm0, %k0\n"
+ "psrlq $32, %%mm0\n"
+ "bsrl %k0, %k0\n"
+ "subl %5, %k0\n"
+ "movl %k0, (%3)\n"
+
+ "movd %%mm0, %k0\n"
+ "bsrl %k0, %k0\n"
+ "subl %5, %k0\n"
+ "movl %k0, 4(%3)\n"
+ : "+r" (blk)
+ : "r" (&sb_sample_f[0][ch][sb]),
+ "i" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ "r" (&scale_factor[ch][sb]),
+ "r" (&consts),
+ "i" (SCALE_OUT_BITS)
+ : "cc", "memory");
+ }
+ }
+ __asm__ volatile ("emms\n");
+}
+
+static int check_mmx_support(void)
+{
+#ifdef __amd64__
+ return 1; /* We assume that all 64-bit processors have MMX support */
+#else
+ int cpuid_feature_information;
+ __asm__ volatile (
+ /* According to Intel manual, CPUID instruction is supported
+ * if the value of ID bit (bit 21) in EFLAGS can be modified */
+ "pushf\n"
+ "movl (%%esp), %0\n"
+ "xorl $0x200000, (%%esp)\n" /* try to modify ID bit */
+ "popf\n"
+ "pushf\n"
+ "xorl (%%esp), %0\n" /* check if ID bit changed */
+ "jz 1f\n"
+ "push %%eax\n"
+ "push %%ebx\n"
+ "push %%ecx\n"
+ "mov $1, %%eax\n"
+ "cpuid\n"
+ "pop %%ecx\n"
+ "pop %%ebx\n"
+ "pop %%eax\n"
+ "1:\n"
+ "popf\n"
+ : "=d" (cpuid_feature_information)
+ :
+ : "cc");
+ return cpuid_feature_information & (1 << 23);
+#endif
+}
+
+void sbc_init_primitives_mmx(struct sbc_encoder_state *state)
+{
+ if (check_mmx_support()) {
+ state->sbc_analyze_4s = sbc_analyze_4b_4s_mmx;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx_odd;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_mmx;
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
+ state->implementation_info = "MMX";
+ }
+}
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_MMX_H
+#define __SBC_PRIMITIVES_MMX_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__)) && \
+ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_MMX_SUPPORT
+
+void sbc_init_primitives_mmx(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_neon.h"
+
+/*
+ * ARM NEON optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_NEON_SUPPORT
+
+static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ /* TODO: merge even and odd cases (or even merge all four calls to this
+ * function) in order to have only aligned reads from 'in' array
+ * and reduce number of load instructions */
+ __asm__ volatile (
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmull.s16 q0, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmull.s16 q1, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q1, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q1, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q1, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d4, d8\n"
+ "vmlal.s16 q1, d5, d9\n"
+
+ "vpadd.s32 d0, d0, d1\n"
+ "vpadd.s32 d1, d2, d3\n"
+
+ "vrshrn.s32 d0, q0, %3\n"
+
+ "vld1.16 {d2, d3, d4, d5}, [%1, :128]!\n"
+
+ "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */
+ "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */
+
+ "vmull.s16 q3, d2, d0\n"
+ "vmull.s16 q4, d3, d0\n"
+ "vmlal.s16 q3, d4, d1\n"
+ "vmlal.s16 q4, d5, d1\n"
+
+ "vpadd.s32 d0, d6, d7\n" /* TODO: can be eliminated */
+ "vpadd.s32 d1, d8, d9\n" /* TODO: can be eliminated */
+
+ "vst1.32 {d0, d1}, [%2, :128]\n"
+ : "+r" (in), "+r" (consts)
+ : "r" (out),
+ "i" (SBC_PROTO_FIXED4_SCALE)
+ : "memory",
+ "d0", "d1", "d2", "d3", "d4", "d5",
+ "d6", "d7", "d8", "d9", "d10", "d11");
+}
+
+static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ /* TODO: merge even and odd cases (or even merge all four calls to this
+ * function) in order to have only aligned reads from 'in' array
+ * and reduce number of load instructions */
+ __asm__ volatile (
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmull.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmull.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmull.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmull.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmlal.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmlal.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmlal.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+
+ "vmlal.s16 q8, d6, d10\n"
+ "vmlal.s16 q9, d7, d11\n"
+
+ "vpadd.s32 d0, d12, d13\n"
+ "vpadd.s32 d1, d14, d15\n"
+ "vpadd.s32 d2, d16, d17\n"
+ "vpadd.s32 d3, d18, d19\n"
+
+ "vrshr.s32 q0, q0, %3\n"
+ "vrshr.s32 q1, q1, %3\n"
+ "vmovn.s32 d0, q0\n"
+ "vmovn.s32 d1, q1\n"
+
+ "vdup.i32 d3, d1[1]\n" /* TODO: can be eliminated */
+ "vdup.i32 d2, d1[0]\n" /* TODO: can be eliminated */
+ "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */
+ "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmull.s16 q6, d4, d0\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmull.s16 q7, d5, d0\n"
+ "vmull.s16 q8, d6, d0\n"
+ "vmull.s16 q9, d7, d0\n"
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmlal.s16 q6, d4, d1\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmlal.s16 q7, d5, d1\n"
+ "vmlal.s16 q8, d6, d1\n"
+ "vmlal.s16 q9, d7, d1\n"
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmlal.s16 q6, d4, d2\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmlal.s16 q7, d5, d2\n"
+ "vmlal.s16 q8, d6, d2\n"
+ "vmlal.s16 q9, d7, d2\n"
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmlal.s16 q6, d4, d3\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmlal.s16 q7, d5, d3\n"
+ "vmlal.s16 q8, d6, d3\n"
+ "vmlal.s16 q9, d7, d3\n"
+
+ "vpadd.s32 d0, d12, d13\n" /* TODO: can be eliminated */
+ "vpadd.s32 d1, d14, d15\n" /* TODO: can be eliminated */
+ "vpadd.s32 d2, d16, d17\n" /* TODO: can be eliminated */
+ "vpadd.s32 d3, d18, d19\n" /* TODO: can be eliminated */
+
+ "vst1.32 {d0, d1, d2, d3}, [%2, :128]\n"
+ : "+r" (in), "+r" (consts)
+ : "r" (out),
+ "i" (SBC_PROTO_FIXED8_SCALE)
+ : "memory",
+ "d0", "d1", "d2", "d3", "d4", "d5",
+ "d6", "d7", "d8", "d9", "d10", "d11",
+ "d12", "d13", "d14", "d15", "d16", "d17",
+ "d18", "d19");
+}
+
+static inline void sbc_analyze_4b_4s_neon(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ _sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ _sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ _sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ _sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_neon(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ _sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ _sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ _sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ _sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static void sbc_calc_scalefactors_neon(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ int ch, sb;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb += 4) {
+ int blk = blocks;
+ int32_t *in = &sb_sample_f[0][ch][sb];
+ __asm__ volatile (
+ "vmov.s32 q0, #0\n"
+ "vmov.s32 q1, %[c1]\n"
+ "vmov.s32 q14, #1\n"
+ "vmov.s32 q15, %[c2]\n"
+ "vadd.s32 q1, q1, q14\n"
+ "1:\n"
+ "vld1.32 {d16, d17}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q8, q8\n"
+ "vld1.32 {d18, d19}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q9, q9\n"
+ "vld1.32 {d20, d21}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q10, q10\n"
+ "vld1.32 {d22, d23}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q11, q11\n"
+ "vmax.s32 q0, q0, q8\n"
+ "vmax.s32 q1, q1, q9\n"
+ "vmax.s32 q0, q0, q10\n"
+ "vmax.s32 q1, q1, q11\n"
+ "subs %[blk], %[blk], #4\n"
+ "bgt 1b\n"
+ "vmax.s32 q0, q0, q1\n"
+ "vsub.s32 q0, q0, q14\n"
+ "vclz.s32 q0, q0\n"
+ "vsub.s32 q0, q15, q0\n"
+ "vst1.32 {d0, d1}, [%[out], :128]\n"
+ :
+ [blk] "+r" (blk),
+ [in] "+r" (in)
+ :
+ [inc] "r" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ [out] "r" (&scale_factor[ch][sb]),
+ [c1] "i" (1 << SCALE_OUT_BITS),
+ [c2] "i" (31 - SCALE_OUT_BITS)
+ : "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23", "d24", "d25", "d26",
+ "d27", "d28", "d29", "d30", "d31", "cc", "memory");
+ }
+ }
+}
+
+int sbc_calc_scalefactors_j_neon(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands)
+{
+ static SBC_ALIGNED int32_t joint_bits_mask[8] = {
+ 8, 4, 2, 1, 128, 64, 32, 16
+ };
+ int joint, i;
+ int32_t *in0, *in1;
+ int32_t *in = &sb_sample_f[0][0][0];
+ uint32_t *out0, *out1;
+ uint32_t *out = &scale_factor[0][0];
+ int32_t *consts = joint_bits_mask;
+
+ i = subbands;
+
+ __asm__ volatile (
+ /*
+ * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
+ * input: q0 = ((1 << SCALE_OUT_BITS) + 1)
+ * %[in0] - samples for channel 0
+ * %[in1] - samples for shannel 1
+ * output: q0, q1 - scale factors without joint stereo
+ * q2, q3 - scale factors with joint stereo
+ * q15 - joint stereo selection mask
+ */
+ ".macro calc_scalefactors\n"
+ "vmov.s32 q1, q0\n"
+ "vmov.s32 q2, q0\n"
+ "vmov.s32 q3, q0\n"
+ "mov %[i], %[blocks]\n"
+ "1:\n"
+ "vld1.32 {d18, d19}, [%[in1], :128], %[inc]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d16, d17}, [%[in0], :128], %[inc]\n"
+ "vhadd.s32 q10, q8, q11\n"
+ "vhsub.s32 q11, q8, q11\n"
+ "vabs.s32 q8, q8\n"
+ "vabs.s32 q9, q9\n"
+ "vabs.s32 q10, q10\n"
+ "vabs.s32 q11, q11\n"
+ "vmax.s32 q0, q0, q8\n"
+ "vmax.s32 q1, q1, q9\n"
+ "vmax.s32 q2, q2, q10\n"
+ "vmax.s32 q3, q3, q11\n"
+ "subs %[i], %[i], #1\n"
+ "bgt 1b\n"
+ "vsub.s32 q0, q0, q14\n"
+ "vsub.s32 q1, q1, q14\n"
+ "vsub.s32 q2, q2, q14\n"
+ "vsub.s32 q3, q3, q14\n"
+ "vclz.s32 q0, q0\n"
+ "vclz.s32 q1, q1\n"
+ "vclz.s32 q2, q2\n"
+ "vclz.s32 q3, q3\n"
+ "vsub.s32 q0, q13, q0\n"
+ "vsub.s32 q1, q13, q1\n"
+ "vsub.s32 q2, q13, q2\n"
+ "vsub.s32 q3, q13, q3\n"
+ ".endm\n"
+ /*
+ * constants: q14 = 1
+ * input: q15 - joint stereo selection mask
+ * %[in0] - value set by calc_scalefactors macro
+ * %[in1] - value set by calc_scalefactors macro
+ */
+ ".macro update_joint_stereo_samples\n"
+ "sub %[out1], %[in1], %[inc]\n"
+ "sub %[out0], %[in0], %[inc]\n"
+ "sub %[in1], %[in1], %[inc], asl #1\n"
+ "sub %[in0], %[in0], %[inc], asl #1\n"
+ "vld1.32 {d18, d19}, [%[in1], :128]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d16, d17}, [%[in0], :128]\n"
+ "vld1.32 {d2, d3}, [%[out1], :128]\n"
+ "vbic.s32 q3, q1, q14\n"
+ "vld1.32 {d0, d1}, [%[out0], :128]\n"
+ "vhsub.s32 q10, q8, q11\n"
+ "vhadd.s32 q11, q8, q11\n"
+ "vhsub.s32 q2, q0, q3\n"
+ "vhadd.s32 q3, q0, q3\n"
+ "vbif.s32 q10, q9, q15\n"
+ "vbif.s32 d22, d16, d30\n"
+ "sub %[inc], %[zero], %[inc], asl #1\n"
+ "sub %[i], %[blocks], #2\n"
+ "2:\n"
+ "vbif.s32 d23, d17, d31\n"
+ "vst1.32 {d20, d21}, [%[in1], :128], %[inc]\n"
+ "vbif.s32 d4, d2, d30\n"
+ "vld1.32 {d18, d19}, [%[in1], :128]\n"
+ "vbif.s32 d5, d3, d31\n"
+ "vst1.32 {d22, d23}, [%[in0], :128], %[inc]\n"
+ "vbif.s32 d6, d0, d30\n"
+ "vld1.32 {d16, d17}, [%[in0], :128]\n"
+ "vbif.s32 d7, d1, d31\n"
+ "vst1.32 {d4, d5}, [%[out1], :128], %[inc]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d2, d3}, [%[out1], :128]\n"
+ "vst1.32 {d6, d7}, [%[out0], :128], %[inc]\n"
+ "vbic.s32 q3, q1, q14\n"
+ "vld1.32 {d0, d1}, [%[out0], :128]\n"
+ "vhsub.s32 q10, q8, q11\n"
+ "vhadd.s32 q11, q8, q11\n"
+ "vhsub.s32 q2, q0, q3\n"
+ "vhadd.s32 q3, q0, q3\n"
+ "vbif.s32 q10, q9, q15\n"
+ "vbif.s32 d22, d16, d30\n"
+ "subs %[i], %[i], #2\n"
+ "bgt 2b\n"
+ "sub %[inc], %[zero], %[inc], asr #1\n"
+ "vbif.s32 d23, d17, d31\n"
+ "vst1.32 {d20, d21}, [%[in1], :128]\n"
+ "vbif.s32 q2, q1, q15\n"
+ "vst1.32 {d22, d23}, [%[in0], :128]\n"
+ "vbif.s32 q3, q0, q15\n"
+ "vst1.32 {d4, d5}, [%[out1], :128]\n"
+ "vst1.32 {d6, d7}, [%[out0], :128]\n"
+ ".endm\n"
+
+ "vmov.s32 q14, #1\n"
+ "vmov.s32 q13, %[c2]\n"
+
+ "cmp %[i], #4\n"
+ "bne 8f\n"
+
+ "4:\n" /* 4 subbands */
+ "add %[in0], %[in], #0\n"
+ "add %[in1], %[in], #32\n"
+ "add %[out0], %[out], #0\n"
+ "add %[out1], %[out], #32\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 0, 1, 2 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* calculate and save to memory 'joint' variable */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ " vpadd.s32 d16, d16, d16\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vst1.32 {d16[0]}, [%[joint]]\n"
+
+ "update_joint_stereo_samples\n"
+ "b 9f\n"
+
+ "8:\n" /* 8 subbands */
+ "add %[in0], %[in], #16\n\n"
+ "add %[in1], %[in], #48\n"
+ "add %[out0], %[out], #16\n\n"
+ "add %[out1], %[out], #48\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 4, 5, 6 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* calculate part of 'joint' variable and save it to d24 */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vpadd.s32 d24, d16, d16\n"
+
+ "update_joint_stereo_samples\n"
+
+ "add %[in0], %[in], #0\n"
+ "add %[in1], %[in], #32\n"
+ "add %[out0], %[out], #0\n\n"
+ "add %[out1], %[out], #32\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 0, 1, 2, 3 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* combine last part of 'joint' with d24 and save to memory */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ " vpadd.s32 d16, d16, d16\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ " vadd.s32 d16, d16, d24\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vst1.32 {d16[0]}, [%[joint]]\n"
+
+ "update_joint_stereo_samples\n"
+ "9:\n"
+ ".purgem calc_scalefactors\n"
+ ".purgem update_joint_stereo_samples\n"
+ :
+ [i] "+&r" (i),
+ [in] "+&r" (in),
+ [in0] "=&r" (in0),
+ [in1] "=&r" (in1),
+ [out] "+&r" (out),
+ [out0] "=&r" (out0),
+ [out1] "=&r" (out1),
+ [consts] "+&r" (consts)
+ :
+ [inc] "r" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ [blocks] "r" (blocks),
+ [joint] "r" (&joint),
+ [c1] "i" (1 << SCALE_OUT_BITS),
+ [c2] "i" (31 - SCALE_OUT_BITS),
+ [zero] "r" (0)
+ : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+ "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+ "d30", "d31", "cc", "memory");
+
+ return joint;
+}
+
+#define PERM_BE(a, b, c, d) { \
+ (a * 2) + 1, (a * 2) + 0, \
+ (b * 2) + 1, (b * 2) + 0, \
+ (c * 2) + 1, (c * 2) + 0, \
+ (d * 2) + 1, (d * 2) + 0 \
+ }
+#define PERM_LE(a, b, c, d) { \
+ (a * 2) + 0, (a * 2) + 1, \
+ (b * 2) + 0, (b * 2) + 1, \
+ (c * 2) + 0, (c * 2) + 1, \
+ (d * 2) + 0, (d * 2) + 1 \
+ }
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ static SBC_ALIGNED uint8_t perm_be[2][8] = {
+ PERM_BE(7, 3, 6, 4),
+ PERM_BE(0, 2, 1, 5)
+ };
+ static SBC_ALIGNED uint8_t perm_le[2][8] = {
+ PERM_LE(7, 3, 6, 4),
+ PERM_LE(0, 2, 1, 5)
+ };
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
+ int16_t *src = &X[0][position];
+ __asm__ volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0}, [%[src], :64]!\n"
+ "vst1.16 {d0}, [%[dst], :64]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ if (nchannels > 1) {
+ dst = &X[1][SBC_X_BUFFER_SIZE - 40];
+ src = &X[1][position];
+ __asm__ volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0}, [%[src], :64]!\n"
+ "vst1.16 {d0}, [%[dst], :64]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ }
+ position = SBC_X_BUFFER_SIZE - 40;
+ }
+
+ if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+ /* poor 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ __asm__ volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[y], %[y], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld1.8 {d4, d5}, [%[pcm]]!\n"
+ "vuzp.16 d4, d5\n"
+ "vld1.8 {d20, d21}, [%[pcm]]!\n"
+ "vuzp.16 d20, d21\n"
+ "vswp d5, d20\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vtbl.8 d18, {d20, d21}, d0\n"
+ "vtbl.8 d19, {d20, d21}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "vst1.16 {d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else if (nchannels > 1) {
+ /* proper 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ __asm__ volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[y], %[y], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld2.16 {d4, d5}, [%[pcm]]!\n"
+ "vld2.16 {d20, d21}, [%[pcm]]!\n"
+ "vswp d5, d20\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vtbl.8 d18, {d20, d21}, d0\n"
+ "vtbl.8 d19, {d20, d21}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "vst1.16 {d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else {
+ int16_t *x = &X[0][position];
+ __asm__ volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld1.8 {d4, d5}, [%[pcm]]!\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+ }
+ return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ static SBC_ALIGNED uint8_t perm_be[4][8] = {
+ PERM_BE(15, 7, 14, 8),
+ PERM_BE(13, 9, 12, 10),
+ PERM_BE(11, 3, 6, 0),
+ PERM_BE(5, 1, 4, 2)
+ };
+ static SBC_ALIGNED uint8_t perm_le[4][8] = {
+ PERM_LE(15, 7, 14, 8),
+ PERM_LE(13, 9, 12, 10),
+ PERM_LE(11, 3, 6, 0),
+ PERM_LE(5, 1, 4, 2)
+ };
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
+ int16_t *src = &X[0][position];
+ __asm__ volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1}, [%[dst], :128]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ if (nchannels > 1) {
+ dst = &X[1][SBC_X_BUFFER_SIZE - 72];
+ src = &X[1][position];
+ __asm__ volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1}, [%[dst], :128]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ }
+ position = SBC_X_BUFFER_SIZE - 72;
+ }
+
+ if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+ /* poor 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ __asm__ volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[y], %[y], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vuzp.16 q2, q3\n"
+ "vld1.8 {d20, d21, d22, d23}, [%[pcm]]!\n"
+ "vuzp.16 q10, q11\n"
+ "vswp q3, q10\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "vtbl.8 d16, {d20, d21, d22, d23}, d0\n"
+ "vtbl.8 d17, {d20, d21, d22, d23}, d1\n"
+ "vtbl.8 d18, {d20, d21, d22, d23}, d2\n"
+ "vtbl.8 d19, {d20, d21, d22, d23}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else if (nchannels > 1) {
+ /* proper 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ __asm__ volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[y], %[y], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld2.16 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vld2.16 {d20, d21, d22, d23}, [%[pcm]]!\n"
+ "vswp q3, q10\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "vtbl.8 d16, {d20, d21, d22, d23}, d0\n"
+ "vtbl.8 d17, {d20, d21, d22, d23}, d1\n"
+ "vtbl.8 d18, {d20, d21, d22, d23}, d2\n"
+ "vtbl.8 d19, {d20, d21, d22, d23}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else {
+ int16_t *x = &X[0][position];
+ __asm__ volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+ }
+ return position;
+}
+
+#undef PERM_BE
+#undef PERM_LE
+
+static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_4s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_4s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 0);
+}
+
+static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_8s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_8s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 0);
+}
+
+void sbc_init_primitives_neon(struct sbc_encoder_state *state)
+{
+ state->sbc_analyze_4s = sbc_analyze_4b_4s_neon;
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_neon;
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
+ state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
+ state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
+ state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
+ state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
+ state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
+ state->implementation_info = "NEON";
+}
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_NEON_H
+#define __SBC_PRIMITIVES_NEON_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && defined(__ARM_NEON__) && \
+ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_NEON_SUPPORT
+
+void sbc_init_primitives_neon(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 SBC_EXPORT __attribute__ ((visibility("default")))
--- /dev/null
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* 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 }
+};
+
+/* extra bits of precision for the synthesis filter input data */
+#define SBCDEC_FIXED_EXTRA_BITS 2
+
+#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
+#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
+#define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
+#define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
+
+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 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) }
+};
+
+#ifdef SBC_HIGH_PRECISION
+#define FIXED_A int64_t /* data type for fixed point accumulator */
+#define FIXED_T int32_t /* data type for fixed point constants */
+#define SBC_FIXED_EXTRA_BITS 16
+#else
+#define FIXED_A int32_t /* data type for fixed point accumulator */
+#define FIXED_T int16_t /* data type for fixed point constants */
+#define SBC_FIXED_EXTRA_BITS 0
+#endif
+
+/* A2DP specification: Section 12.8 Tables
+ *
+ * Original values are premultiplied by 2 for better precision (that is the
+ * maximum which is possible without overflows)
+ *
+ * Note: in each block of 8 numbers sign was changed for elements 2 and 7
+ * in order to compensate the same change applied to cos_table_fixed_4
+ */
+#define SBC_PROTO_FIXED4_SCALE \
+ ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
+#define F_PROTO4(x) (FIXED_A) ((x * 2) * \
+ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_PROTO4(x)
+static const FIXED_T _sbc_proto_fixed4[40] = {
+ F(0.00000000E+00), F(5.36548976E-04),
+ -F(1.49188357E-03), F(2.73370904E-03),
+ F(3.83720193E-03), F(3.89205149E-03),
+ F(1.86581691E-03), F(3.06012286E-03),
+
+ F(1.09137620E-02), F(2.04385087E-02),
+ -F(2.88757392E-02), F(3.21939290E-02),
+ F(2.58767811E-02), F(6.13245186E-03),
+ -F(2.88217274E-02), F(7.76463494E-02),
+
+ F(1.35593274E-01), F(1.94987841E-01),
+ -F(2.46636662E-01), F(2.81828203E-01),
+ F(2.94315332E-01), F(2.81828203E-01),
+ F(2.46636662E-01), -F(1.94987841E-01),
+
+ -F(1.35593274E-01), -F(7.76463494E-02),
+ F(2.88217274E-02), F(6.13245186E-03),
+ F(2.58767811E-02), F(3.21939290E-02),
+ F(2.88757392E-02), -F(2.04385087E-02),
+
+ -F(1.09137620E-02), -F(3.06012286E-03),
+ -F(1.86581691E-03), F(3.89205149E-03),
+ F(3.83720193E-03), F(2.73370904E-03),
+ F(1.49188357E-03), -F(5.36548976E-04),
+};
+#undef F
+
+/*
+ * To produce this cosine matrix in Octave:
+ *
+ * b = zeros(4, 8);
+ * for i = 0:3
+ * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4))
+ * endfor
+ * endfor;
+ * printf("%.10f, ", b');
+ *
+ * Note: in each block of 8 numbers sign was changed for elements 2 and 7
+ *
+ * Change of sign for element 2 allows to replace constant 1.0 (not
+ * representable in Q15 format) with -1.0 (fine with Q15).
+ * Changed sign for element 7 allows to have more similar constants
+ * and simplify subband filter function code.
+ */
+#define SBC_COS_TABLE_FIXED4_SCALE \
+ ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
+#define F_COS4(x) (FIXED_A) ((x) * \
+ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_COS4(x)
+static const FIXED_T cos_table_fixed_4[32] = {
+ F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325),
+ F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324),
+
+ -F(0.7071067812), F(0.3826834324), -F(1.0000000000), F(0.3826834324),
+ -F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325),
+
+ -F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324),
+ -F(0.7071067812), F(0.9238795325), F(0.0000000000), F(0.9238795325),
+
+ F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325),
+ F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324),
+};
+#undef F
+
+/* A2DP specification: Section 12.8 Tables
+ *
+ * Original values are premultiplied by 4 for better precision (that is the
+ * maximum which is possible without overflows)
+ *
+ * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
+ * in order to compensate the same change applied to cos_table_fixed_8
+ */
+#define SBC_PROTO_FIXED8_SCALE \
+ ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
+#define F_PROTO8(x) (FIXED_A) ((x * 2) * \
+ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_PROTO8(x)
+static const FIXED_T _sbc_proto_fixed8[80] = {
+ F(0.00000000E+00), F(1.56575398E-04),
+ F(3.43256425E-04), F(5.54620202E-04),
+ -F(8.23919506E-04), F(1.13992507E-03),
+ F(1.47640169E-03), F(1.78371725E-03),
+ F(2.01182542E-03), F(2.10371989E-03),
+ F(1.99454554E-03), F(1.61656283E-03),
+ F(9.02154502E-04), F(1.78805361E-04),
+ F(1.64973098E-03), F(3.49717454E-03),
+
+ F(5.65949473E-03), F(8.02941163E-03),
+ F(1.04584443E-02), F(1.27472335E-02),
+ -F(1.46525263E-02), F(1.59045603E-02),
+ F(1.62208471E-02), F(1.53184106E-02),
+ F(1.29371806E-02), F(8.85757540E-03),
+ F(2.92408442E-03), -F(4.91578024E-03),
+ -F(1.46404076E-02), F(2.61098752E-02),
+ F(3.90751381E-02), F(5.31873032E-02),
+
+ F(6.79989431E-02), F(8.29847578E-02),
+ F(9.75753918E-02), F(1.11196689E-01),
+ -F(1.23264548E-01), F(1.33264415E-01),
+ F(1.40753505E-01), F(1.45389847E-01),
+ F(1.46955068E-01), F(1.45389847E-01),
+ F(1.40753505E-01), F(1.33264415E-01),
+ F(1.23264548E-01), -F(1.11196689E-01),
+ -F(9.75753918E-02), -F(8.29847578E-02),
+
+ -F(6.79989431E-02), -F(5.31873032E-02),
+ -F(3.90751381E-02), -F(2.61098752E-02),
+ F(1.46404076E-02), -F(4.91578024E-03),
+ F(2.92408442E-03), F(8.85757540E-03),
+ F(1.29371806E-02), F(1.53184106E-02),
+ F(1.62208471E-02), F(1.59045603E-02),
+ F(1.46525263E-02), -F(1.27472335E-02),
+ -F(1.04584443E-02), -F(8.02941163E-03),
+
+ -F(5.65949473E-03), -F(3.49717454E-03),
+ -F(1.64973098E-03), -F(1.78805361E-04),
+ -F(9.02154502E-04), F(1.61656283E-03),
+ F(1.99454554E-03), F(2.10371989E-03),
+ F(2.01182542E-03), F(1.78371725E-03),
+ F(1.47640169E-03), F(1.13992507E-03),
+ F(8.23919506E-04), -F(5.54620202E-04),
+ -F(3.43256425E-04), -F(1.56575398E-04),
+};
+#undef F
+
+/*
+ * To produce this cosine matrix in Octave:
+ *
+ * b = zeros(8, 16);
+ * for i = 0:7
+ * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8))
+ * endfor endfor;
+ * printf("%.10f, ", b');
+ *
+ * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
+ *
+ * Change of sign for element 4 allows to replace constant 1.0 (not
+ * representable in Q15 format) with -1.0 (fine with Q15).
+ * Changed signs for elements 13, 14, 15 allow to have more similar constants
+ * and simplify subband filter function code.
+ */
+#define SBC_COS_TABLE_FIXED8_SCALE \
+ ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
+#define F_COS8(x) (FIXED_A) ((x) * \
+ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_COS8(x)
+static const FIXED_T cos_table_fixed_8[128] = {
+ F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804),
+ -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123),
+ F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220),
+ F(0.0000000000), F(0.1950903220), F(0.3826834324), F(0.5555702330),
+
+ -F(0.7071067812), -F(0.1950903220), F(0.3826834324), F(0.8314696123),
+ -F(1.0000000000), F(0.8314696123), F(0.3826834324), -F(0.1950903220),
+ -F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330),
+ -F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804),
+
+ -F(0.7071067812), -F(0.9807852804), -F(0.3826834324), F(0.5555702330),
+ -F(1.0000000000), F(0.5555702330), -F(0.3826834324), -F(0.9807852804),
+ -F(0.7071067812), F(0.1950903220), F(0.9238795325), F(0.8314696123),
+ F(0.0000000000), F(0.8314696123), F(0.9238795325), F(0.1950903220),
+
+ F(0.7071067812), -F(0.5555702330), -F(0.9238795325), F(0.1950903220),
+ -F(1.0000000000), F(0.1950903220), -F(0.9238795325), -F(0.5555702330),
+ F(0.7071067812), F(0.8314696123), -F(0.3826834324), -F(0.9807852804),
+ -F(0.0000000000), -F(0.9807852804), -F(0.3826834324), F(0.8314696123),
+
+ F(0.7071067812), F(0.5555702330), -F(0.9238795325), -F(0.1950903220),
+ -F(1.0000000000), -F(0.1950903220), -F(0.9238795325), F(0.5555702330),
+ F(0.7071067812), -F(0.8314696123), -F(0.3826834324), F(0.9807852804),
+ F(0.0000000000), F(0.9807852804), -F(0.3826834324), -F(0.8314696123),
+
+ -F(0.7071067812), F(0.9807852804), -F(0.3826834324), -F(0.5555702330),
+ -F(1.0000000000), -F(0.5555702330), -F(0.3826834324), F(0.9807852804),
+ -F(0.7071067812), -F(0.1950903220), F(0.9238795325), -F(0.8314696123),
+ -F(0.0000000000), -F(0.8314696123), F(0.9238795325), -F(0.1950903220),
+
+ -F(0.7071067812), F(0.1950903220), F(0.3826834324), -F(0.8314696123),
+ -F(1.0000000000), -F(0.8314696123), F(0.3826834324), F(0.1950903220),
+ -F(0.7071067812), F(0.9807852804), -F(0.9238795325), F(0.5555702330),
+ -F(0.0000000000), F(0.5555702330), -F(0.9238795325), F(0.9807852804),
+
+ F(0.7071067812), -F(0.8314696123), F(0.9238795325), -F(0.9807852804),
+ -F(1.0000000000), -F(0.9807852804), F(0.9238795325), -F(0.8314696123),
+ F(0.7071067812), -F(0.5555702330), F(0.3826834324), -F(0.1950903220),
+ -F(0.0000000000), -F(0.1950903220), F(0.3826834324), -F(0.5555702330),
+};
+#undef F
+
+/*
+ * Enforce 16 byte alignment for the data, which is supposed to be used
+ * with SIMD optimized code.
+ */
+
+#define SBC_ALIGN_BITS 4
+#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
+
+#ifdef __GNUC__
+#define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS))))
+#else
+#define SBC_ALIGNED
+#endif
+
+/*
+ * Constant tables for the use in SIMD optimized analysis filters
+ * Each table consists of two parts:
+ * 1. reordered "proto" table
+ * 2. reordered "cos" table
+ *
+ * Due to non-symmetrical reordering, separate tables for "even"
+ * and "odd" cases are needed
+ */
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] = {
+#define C0 1.0932568993
+#define C1 1.3056875580
+#define C2 1.3056875580
+#define C3 1.6772280856
+
+#define F(x) F_PROTO4(x)
+ F(0.00000000E+00 * C0), F(3.83720193E-03 * C0),
+ F(5.36548976E-04 * C1), F(2.73370904E-03 * C1),
+ F(3.06012286E-03 * C2), F(3.89205149E-03 * C2),
+ F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3),
+ F(1.09137620E-02 * C0), F(2.58767811E-02 * C0),
+ F(2.04385087E-02 * C1), F(3.21939290E-02 * C1),
+ F(7.76463494E-02 * C2), F(6.13245186E-03 * C2),
+ F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3),
+ F(1.35593274E-01 * C0), F(2.94315332E-01 * C0),
+ F(1.94987841E-01 * C1), F(2.81828203E-01 * C1),
+ -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2),
+ F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3),
+ -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0),
+ -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1),
+ -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2),
+ F(0.00000000E+00 * C3), F(2.88217274E-02 * C3),
+ -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0),
+ -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1),
+ -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2),
+ F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3),
+#undef F
+#define F(x) F_COS4(x)
+ F(0.7071067812 / C0), F(0.9238795325 / C1),
+ -F(0.7071067812 / C0), F(0.3826834324 / C1),
+ -F(0.7071067812 / C0), -F(0.3826834324 / C1),
+ F(0.7071067812 / C0), -F(0.9238795325 / C1),
+ F(0.3826834324 / C2), -F(1.0000000000 / C3),
+ -F(0.9238795325 / C2), -F(1.0000000000 / C3),
+ F(0.9238795325 / C2), -F(1.0000000000 / C3),
+ -F(0.3826834324 / C2), -F(1.0000000000 / C3),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+};
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] = {
+#define C0 1.3056875580
+#define C1 1.6772280856
+#define C2 1.0932568993
+#define C3 1.3056875580
+
+#define F(x) F_PROTO4(x)
+ F(2.73370904E-03 * C0), F(5.36548976E-04 * C0),
+ -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1),
+ F(3.83720193E-03 * C2), F(1.09137620E-02 * C2),
+ F(3.89205149E-03 * C3), F(3.06012286E-03 * C3),
+ F(3.21939290E-02 * C0), F(2.04385087E-02 * C0),
+ -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1),
+ F(2.58767811E-02 * C2), F(1.35593274E-01 * C2),
+ F(6.13245186E-03 * C3), F(7.76463494E-02 * C3),
+ F(2.81828203E-01 * C0), F(1.94987841E-01 * C0),
+ -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1),
+ F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2),
+ F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3),
+ F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0),
+ F(2.88217274E-02 * C1), F(0.00000000E+00 * C1),
+ F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2),
+ F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3),
+ F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0),
+ -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1),
+ F(3.83720193E-03 * C2), F(0.00000000E+00 * C2),
+ F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3),
+#undef F
+#define F(x) F_COS4(x)
+ F(0.9238795325 / C0), -F(1.0000000000 / C1),
+ F(0.3826834324 / C0), -F(1.0000000000 / C1),
+ -F(0.3826834324 / C0), -F(1.0000000000 / C1),
+ -F(0.9238795325 / C0), -F(1.0000000000 / C1),
+ F(0.7071067812 / C2), F(0.3826834324 / C3),
+ -F(0.7071067812 / C2), -F(0.9238795325 / C3),
+ -F(0.7071067812 / C2), F(0.9238795325 / C3),
+ F(0.7071067812 / C2), -F(0.3826834324 / C3),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+};
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] = {
+#define C0 2.7906148894
+#define C1 2.4270044280
+#define C2 2.8015616024
+#define C3 3.1710363741
+#define C4 2.5377944043
+#define C5 2.4270044280
+#define C6 2.8015616024
+#define C7 3.1710363741
+
+#define F(x) F_PROTO8(x)
+ F(0.00000000E+00 * C0), F(2.01182542E-03 * C0),
+ F(1.56575398E-04 * C1), F(1.78371725E-03 * C1),
+ F(3.43256425E-04 * C2), F(1.47640169E-03 * C2),
+ F(5.54620202E-04 * C3), F(1.13992507E-03 * C3),
+ -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4),
+ F(2.10371989E-03 * C5), F(3.49717454E-03 * C5),
+ F(1.99454554E-03 * C6), F(1.64973098E-03 * C6),
+ F(1.61656283E-03 * C7), F(1.78805361E-04 * C7),
+ F(5.65949473E-03 * C0), F(1.29371806E-02 * C0),
+ F(8.02941163E-03 * C1), F(1.53184106E-02 * C1),
+ F(1.04584443E-02 * C2), F(1.62208471E-02 * C2),
+ F(1.27472335E-02 * C3), F(1.59045603E-02 * C3),
+ -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4),
+ F(8.85757540E-03 * C5), F(5.31873032E-02 * C5),
+ F(2.92408442E-03 * C6), F(3.90751381E-02 * C6),
+ -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7),
+ F(6.79989431E-02 * C0), F(1.46955068E-01 * C0),
+ F(8.29847578E-02 * C1), F(1.45389847E-01 * C1),
+ F(9.75753918E-02 * C2), F(1.40753505E-01 * C2),
+ F(1.11196689E-01 * C3), F(1.33264415E-01 * C3),
+ -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4),
+ F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
+ F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
+ F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
+ -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0),
+ -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1),
+ -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2),
+ -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
+ F(1.46404076E-02 * C4), F(0.00000000E+00 * C4),
+ F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
+ F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
+ F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
+ -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0),
+ -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1),
+ -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2),
+ -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3),
+ -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4),
+ F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
+ F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
+ F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
+#undef F
+#define F(x) F_COS8(x)
+ F(0.7071067812 / C0), F(0.8314696123 / C1),
+ -F(0.7071067812 / C0), -F(0.1950903220 / C1),
+ -F(0.7071067812 / C0), -F(0.9807852804 / C1),
+ F(0.7071067812 / C0), -F(0.5555702330 / C1),
+ F(0.7071067812 / C0), F(0.5555702330 / C1),
+ -F(0.7071067812 / C0), F(0.9807852804 / C1),
+ -F(0.7071067812 / C0), F(0.1950903220 / C1),
+ F(0.7071067812 / C0), -F(0.8314696123 / C1),
+ F(0.9238795325 / C2), F(0.9807852804 / C3),
+ F(0.3826834324 / C2), F(0.8314696123 / C3),
+ -F(0.3826834324 / C2), F(0.5555702330 / C3),
+ -F(0.9238795325 / C2), F(0.1950903220 / C3),
+ -F(0.9238795325 / C2), -F(0.1950903220 / C3),
+ -F(0.3826834324 / C2), -F(0.5555702330 / C3),
+ F(0.3826834324 / C2), -F(0.8314696123 / C3),
+ F(0.9238795325 / C2), -F(0.9807852804 / C3),
+ -F(1.0000000000 / C4), F(0.5555702330 / C5),
+ -F(1.0000000000 / C4), -F(0.9807852804 / C5),
+ -F(1.0000000000 / C4), F(0.1950903220 / C5),
+ -F(1.0000000000 / C4), F(0.8314696123 / C5),
+ -F(1.0000000000 / C4), -F(0.8314696123 / C5),
+ -F(1.0000000000 / C4), -F(0.1950903220 / C5),
+ -F(1.0000000000 / C4), F(0.9807852804 / C5),
+ -F(1.0000000000 / C4), -F(0.5555702330 / C5),
+ F(0.3826834324 / C6), F(0.1950903220 / C7),
+ -F(0.9238795325 / C6), -F(0.5555702330 / C7),
+ F(0.9238795325 / C6), F(0.8314696123 / C7),
+ -F(0.3826834324 / C6), -F(0.9807852804 / C7),
+ -F(0.3826834324 / C6), F(0.9807852804 / C7),
+ F(0.9238795325 / C6), -F(0.8314696123 / C7),
+ -F(0.9238795325 / C6), F(0.5555702330 / C7),
+ F(0.3826834324 / C6), -F(0.1950903220 / C7),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+#undef C4
+#undef C5
+#undef C6
+#undef C7
+};
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] = {
+#define C0 2.5377944043
+#define C1 2.4270044280
+#define C2 2.8015616024
+#define C3 3.1710363741
+#define C4 2.7906148894
+#define C5 2.4270044280
+#define C6 2.8015616024
+#define C7 3.1710363741
+
+#define F(x) F_PROTO8(x)
+ F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0),
+ F(1.56575398E-04 * C1), F(1.78371725E-03 * C1),
+ F(3.43256425E-04 * C2), F(1.47640169E-03 * C2),
+ F(5.54620202E-04 * C3), F(1.13992507E-03 * C3),
+ F(2.01182542E-03 * C4), F(5.65949473E-03 * C4),
+ F(2.10371989E-03 * C5), F(3.49717454E-03 * C5),
+ F(1.99454554E-03 * C6), F(1.64973098E-03 * C6),
+ F(1.61656283E-03 * C7), F(1.78805361E-04 * C7),
+ F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0),
+ F(8.02941163E-03 * C1), F(1.53184106E-02 * C1),
+ F(1.04584443E-02 * C2), F(1.62208471E-02 * C2),
+ F(1.27472335E-02 * C3), F(1.59045603E-02 * C3),
+ F(1.29371806E-02 * C4), F(6.79989431E-02 * C4),
+ F(8.85757540E-03 * C5), F(5.31873032E-02 * C5),
+ F(2.92408442E-03 * C6), F(3.90751381E-02 * C6),
+ -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7),
+ F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0),
+ F(8.29847578E-02 * C1), F(1.45389847E-01 * C1),
+ F(9.75753918E-02 * C2), F(1.40753505E-01 * C2),
+ F(1.11196689E-01 * C3), F(1.33264415E-01 * C3),
+ F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4),
+ F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
+ F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
+ F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
+ F(0.00000000E+00 * C0), F(1.46404076E-02 * C0),
+ -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1),
+ -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2),
+ -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
+ F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4),
+ F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
+ F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
+ F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
+ F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0),
+ -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1),
+ -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2),
+ -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3),
+ F(2.01182542E-03 * C4), F(0.00000000E+00 * C4),
+ F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
+ F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
+ F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
+#undef F
+#define F(x) F_COS8(x)
+ -F(1.0000000000 / C0), F(0.8314696123 / C1),
+ -F(1.0000000000 / C0), -F(0.1950903220 / C1),
+ -F(1.0000000000 / C0), -F(0.9807852804 / C1),
+ -F(1.0000000000 / C0), -F(0.5555702330 / C1),
+ -F(1.0000000000 / C0), F(0.5555702330 / C1),
+ -F(1.0000000000 / C0), F(0.9807852804 / C1),
+ -F(1.0000000000 / C0), F(0.1950903220 / C1),
+ -F(1.0000000000 / C0), -F(0.8314696123 / C1),
+ F(0.9238795325 / C2), F(0.9807852804 / C3),
+ F(0.3826834324 / C2), F(0.8314696123 / C3),
+ -F(0.3826834324 / C2), F(0.5555702330 / C3),
+ -F(0.9238795325 / C2), F(0.1950903220 / C3),
+ -F(0.9238795325 / C2), -F(0.1950903220 / C3),
+ -F(0.3826834324 / C2), -F(0.5555702330 / C3),
+ F(0.3826834324 / C2), -F(0.8314696123 / C3),
+ F(0.9238795325 / C2), -F(0.9807852804 / C3),
+ F(0.7071067812 / C4), F(0.5555702330 / C5),
+ -F(0.7071067812 / C4), -F(0.9807852804 / C5),
+ -F(0.7071067812 / C4), F(0.1950903220 / C5),
+ F(0.7071067812 / C4), F(0.8314696123 / C5),
+ F(0.7071067812 / C4), -F(0.8314696123 / C5),
+ -F(0.7071067812 / C4), -F(0.1950903220 / C5),
+ -F(0.7071067812 / C4), F(0.9807852804 / C5),
+ F(0.7071067812 / C4), -F(0.5555702330 / C5),
+ F(0.3826834324 / C6), F(0.1950903220 / C7),
+ -F(0.9238795325 / C6), -F(0.5555702330 / C7),
+ F(0.9238795325 / C6), F(0.8314696123 / C7),
+ -F(0.3826834324 / C6), -F(0.9807852804 / C7),
+ -F(0.3826834324 / C6), F(0.9807852804 / C7),
+ F(0.9238795325 / C6), -F(0.8314696123 / C7),
+ -F(0.9238795325 / C6), F(0.5555702330 / C7),
+ F(0.3826834324 / C6), -F(0.1950903220 / C7),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+#undef C4
+#undef C5
+#undef C6
+#undef C7
+};
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#define BT_VENDOR_RTK_H
#include "bt_vendor_lib.h"
-#include "vnd_buildcfg.h"
#include "rtk_btsnoop_net.h"
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <cutils/properties.h>
+#include "rtk_common.h"
-
+#define RTK_VERSION "5.0.1"
/******************************************************************************
** Constants & Macros
******************************************************************************/
#define RTKBT_TRANS_H4 0x20
#define RTKBT_TRANS_H5 0x10
#define RTKBT_TRANS_UART 0x01
-#define RTKBT_TRANS_USB 0x20
-
+#define RTKBT_TRANS_USB 0x02
#ifndef FALSE
#define FALSE 0
#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)
+#define DOWN_FW_CFG _IOW('E', 176, int)
+#define SET_ISO_CFG _IOW('E', 177, int)
+#define RESET_CONTROLLER _IOW('E', 178, int)
+#define DWFW_CMPLT _IOW('E', 179, int)
+
+#define GET_USB_INFO _IOR('E', 180, int)
+
/* Device port name where Bluetooth controller attached */
#ifndef BLUETOOTH_UART_DEVICE_PORT
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2018 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.
+ *
+ ******************************************************************************/
+
#ifndef HARDWARE_H
#define HARDWARE_H
#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;
#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 CONFIG_MAC_OFFSET_GEN_4PLUS (0x30) //MAC's OFFSET in config/efuse for rtk generation 4+ 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 ROM_LMP_8723b 0x8723
#define ROM_LMP_8821a 0X8821
#define ROM_LMP_8761a 0X8761
+#define ROM_LMP_8761b 0X8761
#define ROM_LMP_8703a 0x8723
#define ROM_LMP_8763a 0x8763
#define ROM_LMP_8703b 0x8703
#define ROM_LMP_8822b 0x8822
#define ROM_LMP_8723d 0x8723
#define ROM_LMP_8821c 0x8821
+#define ROM_LMP_8822c 0x8822
struct rtk_epatch_entry{
uint16_t chip_id;
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
******************************************************************************/
+
#ifndef RTK_HCI_H5_INT_H
#define RTK_HCI_H5_INT_H
#include <stdio.h>
#include <stdlib.h>
#include "rtk_hcidefs.h"
+#include "rtk_common.h"
//HCI Command opcodes
#define HCI_LE_READ_BUFFER_SIZE 0x2002
#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);}
-#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
-#define STREAM_TO_UINT32(u32, p) {u32 = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + ((((uint32_t)(*((p) + 2)))) << 16) + ((((uint32_t)(*((p) + 3)))) << 24)); (p) += 4;}
-#define UINT8_TO_STREAM(p, u8) {*(p)++ = (uint8_t)(u8);}
-
void ms_delay (uint32_t timeout);
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2018 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.
+ *
+ ******************************************************************************/
#ifndef RTK_BTSERVICE_H
#define RTK_BTSERVICE_H
#define HCI_RTKBT_AUTOPAIR_EVT 0x30
-#define STREAM_TO_UINT8(u8, p) \
- { \
- (u8) = (uint8_t)(*(p)); \
- (p) += 1; \
- }
-
-
#endif
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2018 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.
+ *
+ ******************************************************************************/
+#ifndef RTK_COMMON_H
+#define RTK_COMMON_H
+
+#define RTK_UNUSED(x) (void)(x)
+
+#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);}
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
+#define STREAM_TO_UINT32(u32, p) {u32 = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + ((((uint32_t)(*((p) + 2)))) << 16) + ((((uint32_t)(*((p) + 3)))) << 24)); (p) += 4;}
+#define UINT8_TO_STREAM(p, u8) {*(p)++ = (uint8_t)(u8);}
+#define STREAM_TO_UINT8(u8, p) {u8 = (uint8_t)(*(p)); (p) += 1;}
+
+
+#define STREAM_SKIP_UINT8(p) \
+ do { \
+ (p) += 1; \
+ } while (0)
+#define STREAM_SKIP_UINT16(p) \
+ do { \
+ (p) += 2; \
+ } while (0)
+
+#endif
/******************************************************************************
*
- * Copyright (C) 1999-2014 Broadcom Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*
******************************************************************************/
-
#ifndef HCIDEFS_H
#define HCIDEFS_H
#define HCI_PROTO_VERSION_4_0 0x06 /* Version for BT spec 4.0 */
#define HCI_PROTO_VERSION_4_1 0x07 /* Version for BT spec 4.1 */
#define HCI_PROTO_VERSION_4_2 0x08 /* Version for BT spec 4.2 */
+#define HCI_PROTO_VERSION_5_0 0x09 /* Version for BT spec 5.0 */
+
/*
** Definitions for HCI groups
#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL (0x002C | HCI_GRP_BLE_CMDS)
#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE (0x002D | HCI_GRP_BLE_CMDS)
#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT (0x002E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_MAXIMUM_DATA_LENGTH (0x002F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_PHY (0x0030 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_DEFAULT_PHY (0x0031 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PHY (0x0032 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENH_RECEIVER_TEST (0x0033 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENH_TRANSMITTER_TEST (0x0034 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_RANDOM_ADDRESS (0x35 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_PARAM (0x36 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_DATA (0x37 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_SCAN_RESP (0x38 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_ENABLE (0x39 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH (0x003A | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS \
+ (0x003B | HCI_GRP_BLE_CMDS)
+#define HCI_LE_REMOVE_ADVERTISING_SET (0x003C | HCI_GRP_BLE_CMDS)
+#define HCI_LE_CLEAR_ADVERTISING_SETS (0x003D | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_PARAM (0x003E | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_DATA (0x003F | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE (0x0040 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXTENDED_SCAN_PARAMETERS (0x0041 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXTENDED_SCAN_ENABLE (0x0042 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_EXTENDED_CREATE_CONNECTION (0x0043 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_CREATE_SYNC (0x0044 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL \
+ (0x0045 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC \
+ (0x0046 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST \
+ (0x0047 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST \
+ (0x0048 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_PERIODIC_ADVERTISING_LIST (0x0049 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE (0x004A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_TRANSMIT_POWER (0x004B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RF_COMPENS_POWER (0x004C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RF_COMPENS_POWER (0x004D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS)
/* LE Get Vendor Capabilities Command OCF */
#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
/* tracking sub event */
#define HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT 0x56 /* Tracking event */
+/* debug info sub event */
+#define HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT 0x57
+
/* LE supported states definition */
#define HCI_LE_ADV_STATE 0x00000001
#define HCI_LE_SCAN_STATE 0x00000002
#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF 33
#define HCI_LE_RC_CONN_PARAM_UPD_NEG_RPY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF] & HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK)
+
+#define HCI_DATA_EVENT_MASK 3
+#define HCI_DATA_EVENT_OFFSET 12
+
+#define RTK_HANDLE_MASK 0x0FFF
+#define RTK_NONF_START_PACKET_BOUNDARY 0
+#define RTK_START_PACKET_BOUNDARY 2
+#define RTK_CONTINUATION_PACKET_BOUNDARY 1
+#define RTK_L2CAP_HEADER_PDU_LEN_SIZE 2
+#define RTK_L2CAP_HEADER_CID_SIZE 2
+#define RTK_L2CAP_HEADER_SIZE (RTK_L2CAP_HEADER_PDU_LEN_SIZE + RTK_L2CAP_HEADER_CID_SIZE)
+
+#define RTK_GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
+
+ // 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
+
+typedef struct {
+ uint8_t hci_version;
+ uint16_t hci_revision;
+ uint8_t lmp_version;
+ uint16_t manufacturer;
+ uint16_t lmp_subversion;
+} rtkbt_version_t;
+
+typedef struct {
+ uint8_t adverting_type;
+ bool adverting_enable;
+ bool adverting_start;
+ bool connetion_enable;
+} rtkbt_lescn_t;
+
#endif
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void (*rtk_add_le_data_count)(uint8_t data_type);
+ void (*rtk_set_bt_on)(uint8_t bt_on);
+
}rtk_parse_manager_t;
rtk_parse_manager_t *rtk_parse_manager_get_interface();
/******************************************************************************
*
- * Copyright (C) 2014 Realtek, Inc.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*
******************************************************************************/
-
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
SCO_CTRL_CMD_SUSPEND,
SCO_CTRL_GET_AUDIO_CONFIG,
SCO_CTRL_CMD_OFFLOAD_START,
+ SCO_CTRL_CMD_CLOSE,
} tSCO_CTRL_CMD;
#define SCO_SAMPLE_RATE_8K 1
** Constants & Macros
******************************************************************************/
-uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len);
+uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len, bool* condition);
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);
-/*
- * 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
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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:
*
- * 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
- */
+ * 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.
+ *
+ ******************************************************************************/
#ifndef BT_UNUSED_H
#define BT_UNUSED_H
#ifdef __GNUC__
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
** Returns None
**
*******************************************************************************/
-void upio_set(uint8_t pio, uint8_t action);//void upio_set(uint8_t pio, uint8_t action, uint8_t polarity);
+void upio_set(uint8_t pio, uint8_t action, uint8_t polarity);
/*******************************************************************************
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <assert.h>
#include "rtk_parse.h"
#include "bt_skbuff.h"
+#include "rtk_common.h"
/******************************************************************************
** 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
-
/**** baud rates ****/
#define USERIAL_BAUD_300 0
#define USERIAL_BAUD_600 1
/******************************************************************************
** 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
{
#define RTK_HANDLE_EVENT
#define RTK_HANDLE_CMD
-#define CONFIG_SCO_OVER_HCI
+//#define CONFIG_SCO_OVER_HCI
#endif /* USERIAL_VENDOR_H */
--- /dev/null
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+BDROID_DIR := $(TOP_DIR)system/bt
+
+LOCAL_SRC_FILES := \
+ rtk_socket.c \
+ bt_vendor_rtk.c \
+ hardware.c \
+ userial_vendor.c \
+ upio.c \
+ bt_list.c \
+ bt_skbuff.c \
+ hci_h5.c \
+ rtk_parse.c \
+ rtk_btservice.c \
+ hardware_uart.c \
+ hardware_usb.c \
+ rtk_heartbeat.c \
+ rtk_poll.c \
+ rtk_btsnoop_net.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../codec/sbc \
+ $(BDROID_DIR)/hci/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ liblog
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libbt-codec
+
+LOCAL_MODULE := libbt-vendor-realtek
+LOCAL_MODULE_TAGS := optional
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+include $(BUILD_SHARED_LIBRARY)
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
)
{
RTB_QUEUE_HEAD* RtbQueue = NULL;
-
+ int ret = 0;
RtbQueue = malloc(sizeof(RTB_QUEUE_HEAD));
if(RtbQueue)
{
- pthread_mutex_init(&RtbQueue->Lock, NULL);
- ListInitializeHeader(&RtbQueue->List);
- RtbQueue->QueueLen = 0;
- return RtbQueue;
+ ret = pthread_mutex_init(&RtbQueue->Lock, NULL);
+ if(!ret) {
+ ListInitializeHeader(&RtbQueue->List);
+ RtbQueue->QueueLen = 0;
+ return RtbQueue;
+ }
}
//error code comes here
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#undef NDEBUG
#define LOG_TAG "libbt_vendor"
-#define RTKBT_RELEASE_NAME "20180702_BT_ANDROID_9.0"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include "bt_vendor_rtk.h"
#include "upio.h"
if (!split) {
ALOGE("%s no key/value separator found on line %d.", __func__, line_num);
strcpy(rtkbt_device_node,"/dev/rtkbt_dev");
+ fclose(fp);
return;
}
}
else {
rtkbt_transtype |= RTKBT_TRANS_USB;
+ rtkbt_transtype |= RTKBT_TRANS_H4;
+ }
+}
+
+static void byte_reverse(unsigned char* data, int len)
+{
+ int i;
+ int tmp;
+
+ for(i = 0; i < len/2; i++) {
+ tmp = len - i - 1;
+ data[i] ^= data[tmp];
+ data[tmp] ^= data[i];
+ data[i] ^= data[tmp];
}
}
/* This is handed over from the stack */
memcpy(vnd_local_bd_addr, local_bdaddr, 6);
+ byte_reverse(vnd_local_bd_addr, 6);
if(rtk_btsnoop_dump)
rtk_btsnoop_open();
hw_config_start(rtkbt_transtype);
}
else {
- retval = userial_vendor_usb_ioctl(GET_USB_INFO, NULL);
- hw_usb_config_start(RTKBT_TRANS_H4,retval);
+ int usb_info = 0;
+ retval = userial_vendor_usb_ioctl(GET_USB_INFO, &usb_info);
+ if(retval == -1) {
+ ALOGE("get usb info fail");
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ return retval;
+ }
+ else
+ hw_usb_config_start(RTKBT_TRANS_H4, usb_info);
}
RTK_btservice_init();
}
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
******************************************************************************/
#define LOG_TAG "bt_hwcfg"
-#define RTKBT_RELEASE_NAME "20180702_BT_ANDROID_9.0"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include <sys/types.h>
/******************************************************************************
** Constants & Macros
******************************************************************************/
-#define RTK_VERSION "4.1.1"
/******************************************************************************
** Externs
char data[256], *str;
int addr_fd;
- if ((addr_fd = open("/data/misc/bluetooth/bdaddr", O_RDONLY)) != -1)
- {
- memset(data, 0, sizeof(data));
- read(addr_fd, data, 17);
- for (i = 0,str = data; i < 6; i++) {
- addr[5-i] = (unsigned char)strtoul(str, &str, 16);
- str++;
+ char property[100] = {0};
+ if (property_get("persist.vendor.rtkbt.bdaddr_path", property, "none")) {
+ if(strcmp(property, "none") == 0) {
+ return -1;
+ }
+ else if(strcmp(property, "default") == 0) {
+ memcpy(addr, vnd_local_bd_addr, BD_ADDR_LEN);
+ return 0;
+
+ }
+ else if ((addr_fd = open(property, O_RDONLY)) != -1)
+ {
+ memset(data, 0, sizeof(data));
+ int ret = read(addr_fd, data, 17);
+ if(ret < 17) {
+ ALOGE("%s, read length = %d", __func__, ret);
+ close(addr_fd);
+ return -1;
+ }
+ for (i = 0,str = data; i < 6; i++) {
+ addr[5-i] = (unsigned char)strtoul(str, &str, 16);
+ str++;
+ }
+ close(addr_fd);
+ return 0;
}
- close(addr_fd);
- return 0;
}
return -1;
}
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2018 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.
+ *
+ ******************************************************************************/
+
#define LOG_TAG "bt_hwcfg_uart"
-#define RTKBT_RELEASE_NAME "Test"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include <sys/types.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 int rtk_get_bt_firmware(uint8_t** fw_buf, char* fw_short_name);
extern volatile int h5_init_datatrans_flag;
+#define EXTRA_CONFIG_FILE "/vendor/etc/bluetooth/rtk_btconfig.txt"
+static struct rtk_bt_vendor_config_entry *extra_extry;
+static struct rtk_bt_vendor_config_entry *extra_entry_inx = NULL;
/******************************************************************************
{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
+// {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
+ {0x8761, HCI_VERSION_MASK_ALL, ~(1<<0xb), CHIP_TYPE_MASK_ALL, 1<<3, "rtl8761at_fw", "rtl8761at_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8761AW
+ {0x8761, HCI_VERSION_MASK_ALL, (1<<0xb), CHIP_TYPE_MASK_ALL, 1<<14, "rtl8761bt_fw", "rtl8761bt_config", CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, //Rtl8761BW
+
{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
+// {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
+ {0x8822, HCI_VERSION_MASK_ALL, ~(1<<0xc), CHIP_TYPE_MASK_ALL, 1<<8, "rtl8822bs_fw", "rtl8822bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8822BS
+ {0x8822, HCI_VERSION_MASK_ALL, (1<<0xc), CHIP_TYPE_MASK_ALL, 1<<13, "rtl8822cs_fw", "rtl8822cs_config", CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, //Rtl8822CS
{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
}
*/
+static void line_process(char *buf, unsigned short *offset, int *t)
+{
+ char *head = buf;
+ char *ptr = buf;
+ char *argv[32];
+ int argc = 0;
+ unsigned char len = 0;
+ int i = 0;
+ static int alt_size = 0;
+
+ if(buf[0] == '\0' || buf[0] == '#' || buf[0] == '[')
+ return;
+ if(alt_size > MAX_ALT_CONFIG_SIZE-4)
+ {
+ ALOGW("Extra Config file is too large");
+ return;
+ }
+ if(extra_entry_inx == NULL)
+ extra_entry_inx = extra_extry;
+ ALOGI("line_process:%s", buf);
+ while((ptr = strsep(&head, ", \t")) != NULL)
+ {
+ if(!ptr[0])
+ continue;
+ argv[argc++] = ptr;
+ if(argc >= 32) {
+ ALOGW("Config item is too long");
+ break;
+ }
+ }
+
+ if(argc <4) {
+ ALOGE("Invalid Config item, ignore");
+ return;
+ }
+
+ offset[(*t)] = (unsigned short)((strtoul(argv[0], NULL, 16)) | (strtoul(argv[1], NULL, 16) << 8));
+ ALOGI("Extra Config offset %04x", offset[(*t)]);
+ extra_entry_inx->offset = offset[(*t)];
+ (*t)++;
+ len = (unsigned char)strtoul(argv[2], NULL, 16);
+ if(len != (unsigned char)(argc - 3)) {
+ ALOGE("Extra Config item len %d is not match, we assume the actual len is %d", len, (argc-3));
+ len = argc -3;
+ }
+ extra_entry_inx->entry_len = len;
+
+ alt_size += len + sizeof(struct rtk_bt_vendor_config_entry);
+ if(alt_size > MAX_ALT_CONFIG_SIZE)
+ {
+ ALOGW("Extra Config file is too large");
+ extra_entry_inx->offset = 0;
+ extra_entry_inx->entry_len = 0;
+ alt_size -= (len + sizeof(struct rtk_bt_vendor_config_entry));
+ return;
+ }
+ for(i = 0; i < len; i++)
+ {
+ extra_entry_inx->entry_data[i] = (uint8_t)strtoul(argv[3+i], NULL, 16);
+ ALOGI("data[%d]:%02x", i, extra_entry_inx->entry_data[i]);
+ }
+ extra_entry_inx = (struct rtk_bt_vendor_config_entry *)((uint8_t *)extra_entry_inx + len + sizeof(struct rtk_bt_vendor_config_entry));
+}
+
+static void parse_extra_config(const char *path, patch_info *patch_entry, unsigned short *offset, int *t)
+{
+ int fd, ret;
+ unsigned char buf[1024];
+
+ fd = open(path, O_RDONLY);
+ if(fd == -1) {
+ ALOGI("Couldn't open extra config %s, err:%s", path, strerror(errno));
+ return;
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+ if(ret == -1) {
+ ALOGE("Couldn't read %s, err:%s", path, strerror(errno));
+ close(fd);
+ return;
+ }
+ else if(ret == 0) {
+ ALOGE("%s is empty", path);
+ close(fd);
+ return;
+ }
+
+ if(ret > 1022) {
+ ALOGE("Extra config file is too big");
+ close(fd);
+ return;
+ }
+ buf[ret++] = '\n';
+ buf[ret++] = '\0';
+ close(fd);
+ char *head = (void *)buf;
+ char *ptr = (void *)buf;
+ ptr = strsep(&head, "\n\r");
+ if(strncmp(ptr, patch_entry->config_name, strlen(ptr)))
+ {
+ ALOGW("Extra config file not set for %s, ignore", patch_entry->config_name);
+ return;
+ }
+ while((ptr = strsep(&head, "\n\r")) != NULL)
+ {
+ if(!ptr[0])
+ continue;
+ line_process(ptr, offset, t);
+ }
+}
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;
+ else
+ return n;
/*
//sample code, add special settings
offset[n++] = 0x15B;
*/
+ if(extra_extry)
+ parse_extra_config(EXTRA_CONFIG_FILE, patch_entry, offset, &n);
+
return n;
}
static inline int getAltSettingVal(patch_info *patch_entry, unsigned short offset, unsigned char * val)
{
int res = 0;
+ int i = 0;
+ struct rtk_bt_vendor_config_entry *ptr = extra_extry;
- switch(offset)
+ while(ptr->offset)
{
+ if(ptr->offset == offset)
+ {
+ if(offset != patch_entry->mac_offset)
+ {
+ memcpy(val, ptr->entry_data, ptr->entry_len);
+ res = ptr->entry_len;
+ ALOGI("Get Extra offset:%04x, val:", offset);
+ for(i = 0; i < ptr->entry_len; i++)
+ ALOGI("%02x", ptr->entry_data[i]);
+ }
+ break;
+ }
+ ptr = (struct rtk_bt_vendor_config_entry *)((uint8_t *)ptr + ptr->entry_len + sizeof(struct rtk_bt_vendor_config_entry));
+ }
/*
+ switch(offset)
+ {
+
//sample code, add special settings
case 0x15B:
val[0] = 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){
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;
+ int count = 0,temp = 0, j;
+
+ if((extra_extry = (struct rtk_bt_vendor_config_entry *)malloc(MAX_ALT_CONFIG_SIZE)) == NULL)
+ {
+ ALOGE("malloc buffer for extra_extry failed");
+ }
+ else
+ memset(extra_extry, 0, MAX_ALT_CONFIG_SIZE);
ALOGI("ORG Config len=%08zx:\n", config_len);
for(i=0;i<=config_len;i+=0x10)
for(j = 0; j < count;j++)
{
if(le16_to_cpu(entry->offset) == offset[j])
- offset[j] = 0;
+ {
+ if(offset[j] == patch_entry->mac_offset)
+ offset[j] = 0;
+ else
+ {
+ struct rtk_bt_vendor_config_entry *t = extra_extry;
+ while(t->offset) {
+ if(t->offset == le16_to_cpu(entry->offset))
+ {
+ if(t->entry_len == entry->entry_len)
+ offset[j] = 0;
+ break;
+ }
+ t = (struct rtk_bt_vendor_config_entry *)((uint8_t *)t + t->entry_len + sizeof(struct rtk_bt_vendor_config_entry));
+ }
+ }
+ }
}
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);
config->data_len = cpu_to_le16(i);
*config_len_ptr = i+sizeof(struct rtk_bt_vendor_config);
+ if(extra_extry)
+ {
+ free(extra_extry);
+ extra_extry = NULL;
+ extra_entry_inx = NULL;
+ }
+
ALOGI("NEW Config len=%08zx:\n", *config_len_ptr);
for(i=0;i<=(*config_len_ptr);i+=0x10)
{
//uint32_t config_has_bdaddr = 0;
uint8_t *p;
- ALOGD("bt_addr = %x", bt_addr[0]);
+ 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);
}
case 0x01be:
{
- if(mac_offset == CONFIG_MAC_OFFSET_GEN_3PLUS)
+ if(mac_offset == CONFIG_MAC_OFFSET_GEN_3PLUS || mac_offset == CONFIG_MAC_OFFSET_GEN_4PLUS)
{
p = (uint8_t *)entry->entry_data;
STREAM_TO_UINT8(heartbeat_buf, p);
}
break;
}
-#if (USE_CONTROLLER_BDADDR == FALSE)
- case 0x44:
- case 0x3c:
- {
- int j=0;
- for (j=0; j<entry->entry_len; j++)
- entry->entry_data[j] = bt_addr[entry->entry_len - 1- j];
- ALOGI("rtk_parse_config_file: DO NOT USE_CONTROLLER_BDADDR, config has bdaddr");
- ALOGI("rtk_parse_config_file : CONFIG_ADDR is: %02X:%02X:%02X:%02X:%02X:%02X",
- bt_addr[0], bt_addr[1],
- bt_addr[2], bt_addr[3],
- bt_addr[4], bt_addr[5]);
- break;
- }
-#endif
default:
ALOGI("config offset(0x%x),length(0x%x)", entry->offset, entry->entry_len);
break;
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;
+ return 0;
}
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;
+ return 0;
}
if ((fd = open(bt_config_file_name, O_RDONLY)) < 0)
{
ALOGE("Can't open bt config file");
- return -1;
+ return 0;
}
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;
+ return 0;
}
if (read(fd, *config_buf, filelen) < (ssize_t)filelen)
ALOGE("Can't load bt config file");
free(*config_buf);
close(fd);
- return -1;
+ return 0;
}
*config_baud_rate = rtk_parse_config_file(config_buf, &filelen, vnd_local_bd_addr, mac_offset);
if(status != 0) {
ALOGE("%s, status = %d", __func__, status);
if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
- bt_vendor_cbacks->dealloc(p_evt_buf);
+ bt_vendor_cbacks->dealloc(p_evt_buf);
if(rtkbt_auto_restart) {
- bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ if(bt_vendor_cbacks)
+ bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
kill(getpid(), SIGKILL);
}
return;
}
case HW_CFG_READ_LOCAL_VER:
{
- if (status == 0)
+ if (status == 0 && p_evt_buf)
{
p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET);
STREAM_TO_UINT16(hw_cfg_cb.hci_version, p);
}
case HW_CFG_READ_ECO_VER:
{
- if(status == 0)
+ if(status == 0 && p_evt_buf)
{
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);
}
case HW_CFG_READ_CHIP_TYPE:
{
+ if(!p_evt_buf) {
+ ALOGE("%s, buffer is null", __func__);
+ is_proceeding = FALSE;
+ break;
+ }
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++)
}
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)
+ if (hw_cfg_cb.config_len == 0)
{
ALOGE("Get Config file fail, just use efuse settings");
- hw_cfg_cb.config_len = 0;
+ //hw_cfg_cb.config_len = 0;
}
rtk_update_altsettings(prtk_patch_file_info, hw_cfg_cb.config_buf, &(hw_cfg_cb.config_len));
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2018 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.
+ *
+ ******************************************************************************/
+
#define LOG_TAG "bt_hwcfg_usb"
-#define RTKBT_RELEASE_NAME "Test"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include <sys/types.h>
#include "bt_vendor_lib.h"
#include "hardware.h"
+#include "rtk_common.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 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);
+#define EXTRA_CONFIG_FILE "/vendor/etc/bluetooth/rtk_btconfig.txt"
+static struct rtk_bt_vendor_config_entry *extra_extry;
+static struct rtk_bt_vendor_config_entry *extra_entry_inx = NULL;
/******************************************************************************
** Static variables
{ 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, 0x8771, 0x8761, 0, 0, "mp_rtl8761b_fw", "rtl8761b_fw", "rtl8761b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8761BU */
+{ 0x0BDA, 0xa725, 0x8761, 0, 0, "mp_rtl8725a_fw", "rtl8725a_fw", "rtl8725a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8725AU */
{ 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, 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 */
+{ 0x0BDA, 0xC82C, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CU */
+{ 0x0BDA, 0xC822, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CE */
/* 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 */
ROM_LMP_8822b,
ROM_LMP_8723d,
ROM_LMP_8821c,
+ ROM_LMP_NONE,
+ ROM_LMP_NONE,
+ ROM_LMP_8822c,
+ ROM_LMP_8761b,
ROM_LMP_NONE
};
//signature: realtech
//Extension Section IGNATURE:0x77FD0451
static const uint8_t EXTENSION_SECTION_SIGNATURE[4]={0x51,0x04,0xFD,0x77};
+static void usb_line_process(char *buf, unsigned short *offset, int *t)
+{
+ char *head = buf;
+ char *ptr = buf;
+ char *argv[32];
+ int argc = 0;
+ unsigned char len = 0;
+ int i = 0;
+ static int alt_size = 0;
+
+ if(buf[0] == '\0' || buf[0] == '#' || buf[0] == '[')
+ return;
+ if(alt_size > MAX_ALT_CONFIG_SIZE-4)
+ {
+ ALOGW("Extra Config file is too large");
+ return;
+ }
+ if(extra_entry_inx == NULL)
+ extra_entry_inx = extra_extry;
+ ALOGI("line_process:%s", buf);
+ while((ptr = strsep(&head, ", \t")) != NULL)
+ {
+ if(!ptr[0])
+ continue;
+ argv[argc++] = ptr;
+ if(argc >= 32) {
+ ALOGW("Config item is too long");
+ break;
+ }
+ }
+
+ if(argc <4) {
+ ALOGE("Invalid Config item, ignore");
+ return;
+ }
+
+ offset[(*t)] = (unsigned short)((strtoul(argv[0], NULL, 16)) | (strtoul(argv[1], NULL, 16) << 8));
+ ALOGI("Extra Config offset %04x", offset[(*t)]);
+ extra_entry_inx->offset = offset[(*t)];
+ (*t)++;
+ len = (unsigned char)strtoul(argv[2], NULL, 16);
+ if(len != (unsigned char)(argc - 3)) {
+ ALOGE("Extra Config item len %d is not match, we assume the actual len is %d", len, (argc-3));
+ len = argc -3;
+ }
+ extra_entry_inx->entry_len = len;
+
+ alt_size += len + sizeof(struct rtk_bt_vendor_config_entry);
+ if(alt_size > MAX_ALT_CONFIG_SIZE)
+ {
+ ALOGW("Extra Config file is too large");
+ extra_entry_inx->offset = 0;
+ extra_entry_inx->entry_len = 0;
+ alt_size -= (len + sizeof(struct rtk_bt_vendor_config_entry));
+ return;
+ }
+ for(i = 0; i < len; i++)
+ {
+ extra_entry_inx->entry_data[i] = (uint8_t)strtoul(argv[3+i], NULL, 16);
+ ALOGI("data[%d]:%02x", i, extra_entry_inx->entry_data[i]);
+ }
+ extra_entry_inx = (struct rtk_bt_vendor_config_entry *)((uint8_t *)extra_entry_inx + len + sizeof(struct rtk_bt_vendor_config_entry));
+}
+
+static void usb_parse_extra_config(const char *path, usb_patch_info *patch_entry, unsigned short *offset, int *t)
+{
+ int fd, ret;
+ unsigned char buf[1024];
+
+ fd = open(path, O_RDONLY);
+ if(fd == -1) {
+ ALOGI("Couldn't open extra config %s, err:%s", path, strerror(errno));
+ return;
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+ if(ret == -1) {
+ ALOGE("Couldn't read %s, err:%s", path, strerror(errno));
+ close(fd);
+ return;
+ }
+ else if(ret == 0) {
+ ALOGE("%s is empty", path);
+ close(fd);
+ return;
+ }
+
+ if(ret > 1022) {
+ ALOGE("Extra config file is too big");
+ close(fd);
+ return;
+ }
+ buf[ret++] = '\n';
+ buf[ret++] = '\0';
+ close(fd);
+ char *head = (void *)buf;
+ char *ptr = (void *)buf;
+ ptr = strsep(&head, "\n\r");
+ if(strncmp(ptr, patch_entry->config_name, strlen(ptr)))
+ {
+ ALOGW("Extra config file not set for %s, ignore", patch_entry->config_name);
+ return;
+ }
+ while((ptr = strsep(&head, "\n\r")) != NULL)
+ {
+ if(!ptr[0])
+ continue;
+ usb_line_process(ptr, offset, t);
+ }
+}
+
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;
+ else
+ return n;
/*
//sample code, add special settings
offset[n++] = 0x15B;
*/
+ if(extra_extry)
+ usb_parse_extra_config(EXTRA_CONFIG_FILE, patch_entry, offset, &n);
+
return n;
}
{
int res = 0;
- switch(offset)
+ int i = 0;
+ struct rtk_bt_vendor_config_entry *ptr = extra_extry;
+
+ while(ptr->offset)
+ {
+ if(ptr->offset == offset)
+ {
+ if(offset != patch_entry->mac_offset)
+ {
+ memcpy(val, ptr->entry_data, ptr->entry_len);
+ res = ptr->entry_len;
+ ALOGI("Get Extra offset:%04x, val:", offset);
+ for(i = 0; i < ptr->entry_len; i++)
+ ALOGI("%02x", ptr->entry_data[i]);
+ }
+ break;
+ }
+ ptr = (struct rtk_bt_vendor_config_entry *)((uint8_t *)ptr + ptr->entry_len + sizeof(struct rtk_bt_vendor_config_entry));
+ }
+
+/* switch(offset)
{
-/*
//sample code, add special settings
case 0x15B:
val[0] = 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){
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;
+ int count = 0,temp = 0, j;
+
+ if((extra_extry = (struct rtk_bt_vendor_config_entry *)malloc(MAX_ALT_CONFIG_SIZE)) == NULL)
+ {
+ ALOGE("malloc buffer for extra_extry failed");
+ }
+ else
+ memset(extra_extry, 0, MAX_ALT_CONFIG_SIZE);
ALOGI("ORG Config len=%08zx:\n", config_len);
- for(i=0;i<=config_len;i+=0x10)
+ 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], \
return;
}
- for (i=0; i<data_len;)
+ for (i = 0; i < data_len;)
{
for(j = 0; j < count;j++)
{
- if(le16_to_cpu(entry->offset) == offset[j])
- offset[j] = 0;
+ if(le16_to_cpu(entry->offset) == offset[j]) {
+ if(offset[j] == patch_entry->mac_offset)
+ offset[j] = 0;
+ else
+ {
+ struct rtk_bt_vendor_config_entry *t = extra_extry;
+ while(t->offset) {
+ if(t->offset == le16_to_cpu(entry->offset))
+ {
+ if(t->entry_len == entry->entry_len)
+ offset[j] = 0;
+ break;
+ }
+ t = (struct rtk_bt_vendor_config_entry *)((uint8_t *)t + t->entry_len + sizeof(struct rtk_bt_vendor_config_entry));
+ }
+ }
+ }
}
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);
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 = (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);
+ *config_len_ptr = i + sizeof(struct rtk_bt_vendor_config);
+
+ if(extra_extry)
+ {
+ free(extra_extry);
+ extra_extry = NULL;
+ extra_entry_inx = NULL;
+ }
ALOGI("NEW Config len=%08zx:\n", *config_len_ptr);
- for(i=0;i<=(*config_len_ptr);i+=0x10)
+ 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], \
//uint32_t config_has_bdaddr = 0;
uint8_t *p;
- ALOGD("bt_addr = %x", bt_addr[0]);
+ 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);
}
hw_cfg_cb.heartbeat = 0;
- for (i=0; i<config_len;)
+ for (i = 0; i < config_len;)
{
switch(le16_to_cpu(entry->offset))
{
}
case 0x01be:
{
- if(mac_offset == CONFIG_MAC_OFFSET_GEN_3PLUS)
+ if(mac_offset == CONFIG_MAC_OFFSET_GEN_3PLUS || mac_offset == CONFIG_MAC_OFFSET_GEN_4PLUS)
{
p = (uint8_t *)entry->entry_data;
STREAM_TO_UINT8(heartbeat_buf, p);
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;
+ return 0;
}
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;
+ return 0;
}
if ((fd = open(bt_config_file_name, O_RDONLY)) < 0)
{
ALOGE("Can't open bt config file");
- return -1;
+ return 0;
}
- if ((*config_buf = malloc(MAX_ORG_CONFIG_SIZE+MAX_ALT_CONFIG_SIZE)) == NULL)
+ 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;
+ return 0;
}
if (read(fd, *config_buf, filelen) < (ssize_t)filelen)
ALOGE("Can't load bt config file");
free(*config_buf);
close(fd);
- return -1;
+ return 0;
}
rtk_usb_parse_config_file(config_buf, &filelen, vnd_local_bd_addr, mac_offset);
}
case HW_CFG_READ_LOCAL_VER:
{
- if (status == 0)
+ if (status == 0 && p_evt_buf)
{
p = ((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OP1001_HCI_VERSION_OFFSET);
STREAM_TO_UINT16(hw_cfg_cb.hci_version, p);
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))
{
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);
+ 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)
{
else
{
BTVNDDBG("%s: Warm BT controller startup with same lmp", __func__);
+ userial_vendor_usb_ioctl(DWFW_CMPLT, &hw_cfg_cb.lmp_sub_current);
free(hw_cfg_cb.total_buf);
hw_cfg_cb.total_len = 0;
hw_cfg_cb.state = 0;
is_proceeding = TRUE;
}
-
+
/* if(hw_cfg_cb.lmp_subversion == LMPSUBVERSION_8723a)
{
hw_cfg_cb.state = HW_CFG_START;
is_proceeding = bt_vendor_cbacks->xmit_cb(HCI_VSC_READ_ROM_VERSION, p_buf, hw_usb_config_cback);
}*/
}
+ else {
+ ALOGE("status = %d, or p_evt_buf is NULL", status);
+ }
break;
}
RESET_HW_CONTROLLER:
}
case HW_CFG_READ_ECO_VER:
{
- if(status == 0)
+ if(status == 0 && p_evt_buf)
{
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);
}
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)
+ if (hw_cfg_cb.config_len)
{
- ALOGE("Get Config file fail, just use efuse settings");
- hw_cfg_cb.config_len = 0;
+ ALOGE("update altsettings");
+ rtk_usb_update_altsettings(prtk_usb_patch_file_info, hw_cfg_cb.config_buf, &(hw_cfg_cb.config_len));
}
- 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;
+ is_proceeding = FALSE;
+ break;
}
else{
//hw_cfg_cb.project_id_mask = prtk_usb_patch_file_info->project_id_mask;
BTVNDDBG("bt vendor lib: HW_CFG_DL_FW_PATCH status:%i, iIndexRx:%i", status, iIndexRx);
hw_cfg_cb.patch_frag_idx++;
- if(iIndexRx&0x80)
+ if(iIndexRx & 0x80)
{
BTVNDDBG("vendor lib fwcfg completed");
+ userial_vendor_usb_ioctl(DWFW_CMPLT, &hw_cfg_cb.lmp_sub_current);
free(hw_cfg_cb.total_buf);
hw_cfg_cb.total_len = 0;
if (p_buf != NULL)
bt_vendor_cbacks->dealloc(p_buf);
+ userial_vendor_usb_ioctl(DWFW_CMPLT, &hw_cfg_cb.lmp_sub_current);
bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
}
*******************************************************************************/
void hw_usb_config_start(char transtype, uint32_t usb_id)
{
+ RTK_UNUSED(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;
hw_cfg_cb.pid = usb_id & 0x0000ffff;
- hw_cfg_cb.vid = (usb_id>>16) & 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;
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
-#include <pthread.h>
#include <signal.h>
#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <arpa/inet.h>
#include <string.h>
#include <linux/wait.h>
-#include <unistd.h>
#include "hci_h5_int.h"
#include "bt_skbuff.h"
/* Num of allowed outstanding HCI CMD packets */
volatile int num_hci_cmd_pkts = 1;
extern unsigned int rtkbt_h5logfilter;
+extern void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length);
/******************************************************************************
** Static variables
return;
}
}
-/*
-static void H5LogMsgVerbose(const char *fmt_str, ...)
-{
-#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);
- va_end(ap);
-
- LOGI0("H5: ", buffer);
-#else
- va_list ap;
- va_start(ap, fmt_str);
- va_end(ap);
- return;
-#endif
-}*/
+
+static void rtkbt_h5_send_hw_error()
+{
+ unsigned char p_buf[100];
+ const char *str = "host stack: h5 send error";
+ int length = strlen(str) + 1 + 4;
+ p_buf[0] = HCIT_TYPE_EVENT;//event
+ p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+ p_buf[2] = strlen(str) + 2;//len
+ p_buf[3] = 0x01;// host log opcode
+ strcpy((char *)&p_buf[4], str);
+ userial_recv_rawdata_hook(p_buf,length);
+
+ length = 4;
+ p_buf[0] = HCIT_TYPE_EVENT;//event
+ p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+ p_buf[2] = 0x01;//len
+ p_buf[3] = 0xfb;//h5 error code
+ userial_recv_rawdata_hook(p_buf,length);
+}
// reverse bit
static __inline uint8_t bit_rev8(uint8_t byte)
case H5_ACK_PKT:
case H5_VDRSPEC_PKT:
case H5_LINK_CTL_PKT:
+ case HCI_SCODATA_PKT:
rel = H5_UNRELIABLE_PKT;// unreliable
break;
default:
sk_buff *rx_skb;
rx_skb = skb_alloc_and_init(HCI_EVENT_PKT, sync_event, sizeof(sync_event));
+ if(!rx_skb) {
+ ALOGE("%s, rx_skb alloc fail!", __func__);
+ return;
+ }
pthread_mutex_lock(&rtk_h5.data_mutex);
skb_queue_tail(rtk_h5.recv_data, rx_skb);
pthread_cond_signal(&rtk_h5.data_cond);
case H5_LINK_CTL_PKT:
case H5_ACK_PKT:
case H5_VDRSPEC_PKT:
+ case HCI_SCODATA_PKT:
skb_queue_tail(rtk_h5.unrel, skb);/* 3-wire LinkEstablishment*/
break;
default:
if (!memcmp(skb_get_data(skb), h5sync, 0x2)) {
H5LogMsg("H5: <<<---recv sync req in H5_ACTIVE");
- kill(getpid(), SIGKILL);
+ rtkbt_h5_send_hw_error();
+ //kill(getpid(), SIGKILL);
hci_h5_send_sync_resp();
H5LogMsg("H5 : H5_ACTIVE transit to H5_UNINITIALIZED");
rtk_h5.link_estab_state = H5_UNINITIALIZED;
}
-
-/*******************************************************************************
-**
-** Function internal_event_intercept_h5
-**
-** Description This function is called to parse received HCI event and
-** - update the Num_HCI_Command_Packets
-** - intercept the event if it is the result of an early
-** issued internal command.
-**
-** Returns TRUE : if the event had been intercepted for internal process
-** FALSE : send this event to core stack
-**
-*******************************************************************************/
-uint8_t internal_event_intercept_h5(void)
-{
- bool h5_int_command = 0;//if it the H5 int command like H5 vendor cmd or Coex cmd h5_int_command=1;
- tHCI_H5_CB *p_cb = &rtk_h5;
- sk_buff * skb = rtk_h5.rx_skb;
- //uint8_t *ph5_payload = NULL;
- //ph5_payload = (uint8_t *)(p_cb->p_rcv_msg + 1);
-
- //process fw change baudrate and patch download
- uint8_t *p;
- uint8_t event_code;
- uint16_t opcode, len;
- p = (uint8_t *)(p_cb->p_rcv_msg + 1);
-
- event_code = *p++;
- len = *p++;
- H5LogMsg("event_code(0x%x), len = %d", event_code, len);
- if (event_code == HCI_COMMAND_COMPLETE_EVT)
- {
- num_hci_cmd_pkts = *p++;
- STREAM_TO_UINT16(opcode, p);
- H5LogMsg("event_code(0x%x) opcode (0x%x) p_cb->int_cmd_rsp_pending %d", event_code,opcode,p_cb->int_cmd_rsp_pending);
-
- if (p_cb->int_cmd_rsp_pending > 0)
- {
- H5LogMsg("CommandCompleteEvent for command (0x%04X)", opcode);
- if (opcode == p_cb->int_cmd[p_cb->int_cmd_rd_idx].opcode)
- {
- //ONLY HANDLE H5 INIT CMD COMMAND COMPLETE EVT
- h5_int_command = 1;
- if(opcode == HCI_VSC_UPDATE_BAUDRATE)
- {
- //need to set a timer, add wait for retransfer packet from controller.
- //if there is no packet rx from controller, we can assure baudrate change success.
- H5LogMsg("CommandCompleteEvent for command 2 h5_start_wait_controller_baudrate_ready_timer (0x%04X)", opcode);
- h5_start_wait_controller_baudrate_ready_timer();
- }
- else
- {
-
- if (p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback != NULL)
- {
- H5LogMsg("CommandCompleteEvent for command (0x%04X) p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback(p_cb->p_rcv_msg)", opcode);
- p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback(p_cb->p_rcv_msg);
- }
- else
- {
- H5LogMsg("CommandCompleteEvent for command Missing cback function buffer_allocator->free(p_cb->p_rcv_msg) (0x%04X)", opcode);
- free(p_cb->p_rcv_msg);
- }
- }
-
- p_cb->int_cmd_rd_idx = ((p_cb->int_cmd_rd_idx+1) & INT_CMD_PKT_IDX_MASK);
- p_cb->int_cmd_rsp_pending--;
- }
- }
- else {
- if(opcode == HCI_VSC_UPDATE_BAUDRATE)
- {
- h5_int_command |= 0x80;
- rtk_h5.internal_skb = skb;
- //need to set a timer, add wait for retransfer packet from controller.
- //if there is no packet rx from controller, we can assure baudrate change success.
- H5LogMsg("CommandCompleteEvent for command 2 h5_start_wait_controller_baudrate_ready_timer (0x%04X)", opcode);
- h5_start_wait_controller_baudrate_ready_timer();
- }
- }
- }
-
- return h5_int_command;
-
-}
-
-
-/**
+/*****************************************************************************
* Check if it's a hci frame, if it is, complete it with response or parse the cmd complete event
*
* @param skb socket buffer
pthread_cond_signal(&rtk_h5.data_cond);
pthread_mutex_unlock(&rtk_h5.data_mutex);
}
+
+
+static uint16_t encHandle = 0x0000;
+
+static void send_fake_enc_keysize(uint16_t handle,uint8_t keysize){
+ sk_buff *rx_skb;
+ uint8_t pack[9]={0x0e, 0x07, 0x01, 0x08, 0x14, 0x00, 0x03, 0x00, 0x10};
+ pack[6]=(uint8_t)handle;pack[7]=(uint8_t)(handle>>8);
+ pack[8] = keysize;
+ rx_skb = skb_alloc_and_init(HCI_EVENT_PKT, pack, 9);
+
+ 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);
+}
+
+
#endif
static uint8_t hci_recv_frame(sk_buff *skb, uint8_t pkt_type)
{
p[4]=0x05;
p[7]=0x05;
}
+ if(event_code == HCI_COMMAND_COMPLETE_EVT
+ && len==0x44 && p[0]==0x02 && p[1]==0x02 && p[2]==0x10){
+ p[24]|=0x10;
+ }
if(event_code == HCI_COMMAND_COMPLETE_EVT && len==0x0e && p[0]==0x02 && p[1]==0x04 && p[2]==0x10 ){
if(p[4]==0x00)
p[10]|=0x40;
if(p[4]==0x01)
p[6]|=0x02;
}
+ if(event_code == HCI_COMMAND_COMPLETE_EVT && len==0x04 && p[1]==0x08 &&p[2]==0x14){
+ skb_free(&skb);
+ intercepted = 1;
+ send_fake_enc_keysize(encHandle,0x10);
+ }
if(event_code == HCI_COMMAND_STATUS_EVT && len==0x04 && p[0]==0x01 && p[1]==0x02 && p[2]==0x0f &&p[3]==0x20){
skb_free(&skb);
intercepted = 1;
/******************************************************************************
** 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()
+static void data_ready_cb_thread(void *arg)
{
+ RTK_UNUSED(arg);
sk_buff *skb;
uint8_t pkt_type = 0;
unsigned int total_length = 0;
while (h5_data_ready_running)
{
pthread_mutex_lock(&rtk_h5.data_mutex);
- while ((skb_queue_get_length(rtk_h5.recv_data) == 0) && h5_retransfer_running)
+ while (h5_data_ready_running && (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) {
+ if(h5_data_ready_running && (skb = skb_dequeue_head(rtk_h5.recv_data)) != NULL) {
rtk_h5.data_skb = skb;
}
+ else
+ continue;
pkt_type = skb_get_pkt_type(rtk_h5.data_skb);
total_length = skb_get_data_length(rtk_h5.data_skb);
h5_int_hal_callbacks->h5_data_ready_cb(pkt_type, total_length);
}
- ALOGE("data_ready_cb_thread exiting");
+ H5LogMsg("data_ready_cb_thread exiting");
pthread_exit(NULL);
}
-static void data_retransfer_thread()//(void *arg)
+static void data_retransfer_thread(void *arg)
{
+ RTK_UNUSED(arg);
uint16_t events;
- //uint32_t i = 0;
uint16_t data_retrans_counts = DATA_RETRANS_COUNT;
H5LogMsg("data_retransfer_thread started");
if(rtk_h5.data_retrans_count < data_retrans_counts)
{
+ pthread_mutex_lock(&h5_wakeup_mutex);
while ((skb = skb_dequeue_tail(rtk_h5.unack)) != NULL)
{
#if H5_TRACE_DATA_ENABLE
skb_queue_head(rtk_h5.rel, skb);
}
+ pthread_mutex_unlock(&h5_wakeup_mutex);
rtk_h5.data_retrans_count++;
h5_wake_up();
{
//do not put packet to rel queue, and do not send
//Kill bluetooth
- kill(getpid(), SIGKILL);
+ rtkbt_h5_send_hw_error();
+ //kill(getpid(), SIGKILL);
}
}
}
- ALOGE("data_retransfer_thread exiting");
+ H5LogMsg("data_retransfer_thread exiting");
pthread_exit(NULL);
}
*******************************************************************************/
void hci_h5_cleanup(void)
{
- ALOGE("hci_h5_cleanup");
+ H5LogMsg("hci_h5_cleanup");
//uint8_t try_cnt=10;
int result;
rtk_h5.cleanuping = 1;
- ms_delay(200);
//btsnoop_cleanup();
h5_free_wait_controller_baudrate_ready_timer();
h5_free_hw_init_ready_timer();
+ if(h5_data_ready_running) {
+ h5_data_ready_running = 0;
+ pthread_mutex_lock(&rtk_h5.data_mutex);
+ pthread_cond_signal(&rtk_h5.data_cond);
+ pthread_mutex_unlock(&rtk_h5.data_mutex);
+ if ((result = pthread_join(rtk_h5.thread_data_ready_cb, NULL)) < 0)
+ ALOGE("H5 thread_data_ready_cb pthread_join() FAILED result:%d", result);
+ }
if (h5_retransfer_running)
{
h5_retransfer_running = 0;
- h5_data_ready_cb_signal_exit();
- if ((result = pthread_join(rtk_h5.thread_data_ready_cb, NULL)) < 0)
- ALOGE("H5 thread_data_ready_cb pthread_join() FAILED result:%d", result);
-
h5_retransfer_signal_event(H5_EVENT_EXIT);
if ((result = pthread_join(rtk_h5.thread_data_retrans, NULL)) < 0)
ALOGE("H5 pthread_join() FAILED result:%d", result);
}
- ms_delay(200);
-
-
- pthread_mutex_destroy(&rtk_h5.data_mutex);
- pthread_cond_destroy(&rtk_h5.data_cond);
+ //ms_delay(200);
pthread_mutex_destroy(&rtk_h5.mutex);
+ pthread_mutex_destroy(&rtk_h5.data_mutex);
pthread_cond_destroy(&rtk_h5.cond);
+ pthread_cond_destroy(&rtk_h5.data_cond);
RtbQueueFree(rtk_h5.unack);
RtbQueueFree(rtk_h5.rel);
rtk_h5.internal_skb = NULL;
}
-
-/*******************************************************************************
-**
-** Function hci_h5_parse_msg
-**
-** Description Construct HCI EVENT/ACL packets and send them to stack once
-** complete packet has been received.
-**
-** Returns Number of need to be red bytes
-**
-*******************************************************************************/
-uint16_t hci_h5_parse_msg(uint8_t *byte, uint16_t count)
-{
- //uint16_t bytes_needed = 0;
- uint8_t h5_byte;
- h5_byte = *byte;
- //H5LogMsg("hci_h5_receive_msg byte:%d",h5_byte);
- h5_recv(&rtk_h5, &h5_byte, count);
- return 1;
-}
-
-
/*******************************************************************************
**
** Function hci_h5_receive_msg
sk_buff * skb = NULL;
uint16_t bytes_to_send, opcode;
+ if(type != DATA_TYPE_COMMAND) {
+ ALOGE("%s Receive wrong type type : %d", __func__, type);
+ return -1;
+ }
+
skb = skb_alloc_and_init(type, data, length);
if(!skb) {
ALOGE("send cmd skb_alloc_and_init fail!");
}
if(opcode == HCI_WRITE_LOOPBACK_MODE)
loopbackmode = 0x01;
+ #if ENABLE_BLE_8703
+ if(opcode == 0x1408)//enc key size
+ encHandle = (uint16_t)data[1] + ((uint16_t)data[2] << 8);
+
+ #endif
bytes_to_send = h5_wake_up();
return length;
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) {
+ RTK_UNUSED(sigev_value);
H5LogMsg("h5_retransfer_timeout_handler");
if(rtk_h5.cleanuping)
{
h5_retransfer_signal_event(H5_EVENT_RX);
}
-static void h5_sync_retrans_timeout_handler(){//(union sigval sigev_value) {
+static void h5_sync_retrans_timeout_handler(union sigval sigev_value) {
+ RTK_UNUSED(sigev_value);
H5LogMsg("h5_sync_retrans_timeout_handler");
if(rtk_h5.cleanuping)
{
}
-static void h5_conf_retrans_timeout_handler(){//(union sigval sigev_value) {
+static void h5_conf_retrans_timeout_handler(union sigval sigev_value) {
+ RTK_UNUSED(sigev_value);
H5LogMsg("h5_conf_retrans_timeout_handler");
if(rtk_h5.cleanuping)
{
}
-static void h5_wait_controller_baudrate_ready_timeout_handler(){//(union sigval sigev_value) {
+static void h5_wait_controller_baudrate_ready_timeout_handler(union sigval sigev_value) {
+ RTK_UNUSED(sigev_value);
H5LogMsg("h5_wait_ct_baundrate_ready_timeout_handler");
if(rtk_h5.cleanuping)
{
rtk_h5.internal_skb = NULL;
}
-static void h5_hw_init_ready_timeout_handler(){//(union sigval sigev_value) {
+static void h5_hw_init_ready_timeout_handler(union sigval sigev_value) {
+ RTK_UNUSED(sigev_value);
H5LogMsg("h5_hw_init_ready_timeout_handler");
if(rtk_h5.cleanuping)
{
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
******************************************************************************/
#define LOG_TAG "bt_service"
-#define RTKBT_RELEASE_NAME "Test"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include <sys/types.h>
typedef struct Rtk_Btservice_Info
{
int socketfd;
+ int sig_fd[2];
pthread_t cmdreadythd;
pthread_t epollthd;
int current_client_sock;
void (*complete_cback)(void *);
}Rtkqueuedata;
-static Rtk_Btservice_Info *rtk_btservice;
+extern void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* parameter, tINT_CMD_CBACK p_cback);
+static Rtk_Btservice_Info *rtk_btservice = NULL;
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)
static void Rtk_Client_Cmd_Cback(void *p_mem)
{
HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
- unsigned char *sendbuf=NULL;
+ 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);
+ len = 8 + p_evt_buf->len;
sendbuf = p_mem;
if(rtk_btservice->current_client_sock != -1)
{
{
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;
+ if(!rtk_btservice) {
+ ALOGE("rtkbt service is null");
+ return;
+ }
+
pthread_mutex_lock(&rtk_btservice->cmdqueue_mutex);
rtkqueue_data = (Rtkqueuedata *)malloc(sizeof(Rtkqueuedata));
if (NULL == rtkqueue_data)
{
ALOGE("rtkqueue_data: allocate error");
+ if(RtkData->parameter_len > 0) {
+ free(RtkData->parameter);
+ }
return;
}
//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)
+ if(rtk_btservice->current_complete_cback != NULL)
{
- rtk_btservice->current_complete_cback(p_mem);
+ (*rtk_btservice->current_complete_cback)(p_mem);
}
else
{
ALOGE("%s current_complete_cback is not exist!", __func__);
}
- rtk_btservice->current_complete_cback=NULL;
+ 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
+ unsigned char p_buf[4];
+ int length = 4;
+ p_buf[0] = 0x04;//event
+ p_buf[1] = 0x10;//hardware error
+ p_buf[2] = 0x01;//len
+ p_buf[3] = 0xfd;//rtkbtservice error code
userial_recv_rawdata_hook(p_buf,length);
- free(p_buf);
+
}
-static void *cmdready_thread()
+static void* cmdready_thread()
{
//Rtkqueuedata* rtk_data;
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 )
+ 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();
- }
+ rtk_vendor_cmd_to_fw(desc->opcode, desc->parameter_len, desc->parameter, Rtk_Service_Cmd_Event_Cback);
+ hcicmd_start_reply_timer();
if(desc->parameter_len > 0)
free(desc->parameter);
}
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 = NULL;
int recvlen=0;
Rtk_Service_Data *p_buf;
- //int i;
-
- recvlen = read(client_sock,&type,1);
+ recvlen = read(client_sock, &type, 1);
ALOGD("%s recvlen=%d,type=%d",__func__,recvlen, type);
- if(recvlen<=0)
+ if(recvlen <= 0)
{
close(client_sock);
if(client_sock == rtk_btservice->autopair_fd)
case RTK_HCICMD:
{
recvlen = read(client_sock,&opcodeh,1);
- if(recvlen<=0)
+ if(recvlen <= 0)
{
ALOGE("read opcode high char error");
break;
}
recvlen = read(client_sock,&opcodel,1);
- if(recvlen<=0)
+ if(recvlen <= 0)
{
ALOGE("read opcode low char error");
break;
}
recvlen = read(client_sock,¶meter_length,1);
- if(recvlen<=0)
+ if(recvlen <= 0)
{
ALOGE("read parameter_length char error");
break;
}
- if(parameter_length>0)
+ if(parameter_length > 0)
{
parameter = (unsigned char *)malloc(sizeof(char)*parameter_length);
- recvlen = read(client_sock,parameter,parameter_length);
+ if(!parameter) {
+ ALOGE("%s parameter alloc fail!", __func__);
+ return;
+ }
+ recvlen = read(client_sock, parameter, parameter_length);
ALOGD("%s parameter_length=%d,recvlen=%d",__func__,parameter_length, recvlen);
- if(recvlen<=0 || recvlen!=parameter_length)
+ if(recvlen <= 0 || recvlen != parameter_length)
{
ALOGE("read parameter_length char error recvlen=%d,parameter_length=%d\n",recvlen,parameter_length);
+ free(parameter);
break;
}
}
if (NULL == p_buf)
{
ALOGE("p_buf: allocate error");
+ if(parameter)
+ free(parameter);
return;
}
+
p_buf->opcode = ((unsigned short)opcodeh)<<8 | opcodel;
p_buf->parameter = parameter;
p_buf->parameter_len = parameter_length;
p_buf->complete_cback = Rtk_Client_Cmd_Cback;
- //ALOGE("p_buf->parameter_len: %d",p_buf->parameter_len);
- //ALOGE("p_buf->opcode: %x",p_buf->opcode);
- //ALOGE("opcodeh: %x,opcodel: %x",opcodeh,opcodel);
- //for(i=0;i<p_buf->parameter_len;i++)
- //{
- // ALOGE("i=%d,p_buf->parameter: %x",i,p_buf->parameter[i]);
- //}
Rtk_Service_Vendorcmd_Hook(p_buf,client_sock);
free(p_buf);
break;
}
-void rtk_btservice_internal_event_intercept(uint8_t *p_full_msg,uint8_t *p_msg)
+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++;
{
ALOGD("p_evt_buf_len=%d",p_evt_buf->len);
- //for(int i=0;i<p_evt_buf->len;i++)
- //ALOGE("@jason buf[%d]=0x%x",i,p_evt_buf->data[i]);
- //
if(rtk_btservice->autopair_fd != -1)
{
write(rtk_btservice->autopair_fd, p_evt_buf, p_evt_buf->len+8);
uint8_t p_bluedroid_len = p_evt_buf->len+1;
- uint8_t *p_bluedroid = malloc(p_bluedroid_len);
- p_bluedroid[0]=DATA_TYPE_EVENT;
+ uint8_t p_bluedroid[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
+ p_bluedroid[1] = 0x3e; //event_code
+ p_bluedroid[3] = 0x02; //subcode
userial_recv_rawdata_hook(p_bluedroid, p_bluedroid_len);
}
}
}
break;
}
- //case HCI_COMMAND_COMPLETE_EVT:
- //{
- //rtkservice_handle_cmd_complete_evt();
- //}
default:
break;
}
{
struct sockaddr_un un;
socklen_t len;
- int client_sock=0;
+ int client_sock = 0;
len = sizeof(un);
struct epoll_event event;
}
//pthread_create(&connectthread,NULL,(void *)accept_request_thread,&client_sock);
- event.data.fd=client_sock;
- event.events=EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+ 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)
+ 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);
while(rtk_btservice->epoll_thread_running)
{
- nfds=epoll_wait(rtk_btservice->epoll_fd,events,32,500);
+ nfds = epoll_wait(rtk_btservice->epoll_fd,events, 32, 500);
if(rtk_btservice->epoll_thread_running != 0)
{
- if(nfds>0)
+ if(nfds > 0)
{
- for(i=0;i<nfds;i++)
+ for(i = 0; i < nfds; i++)
{
- if(events[i].data.fd == rtk_btservice->socketfd && events[i].events&EPOLLIN)
+ if(events[i].data.fd == rtk_btservice->sig_fd[1]) {
+ ALOGE("epoll_thread , receive exit signal");
+ continue;
+ }
+
+ if(events[i].data.fd == rtk_btservice->socketfd && events[i].events & EPOLLIN)
{
- if(socket_accept(events[i].data.fd)<0)
+ if(socket_accept(events[i].data.fd) < 0)
{
pthread_exit(0);
}
}
- else if(events[i].events&(EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR))
+ 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);
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)
+ 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;
}
+ event.data.fd = rtk_btservice->sig_fd[1];
+ event.events = EPOLLIN;
+ if(epoll_ctl(rtk_btservice->epoll_fd, EPOLL_CTL_ADD, rtk_btservice->sig_fd[1], &event) == -1)
+ {
+ ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, rtk_btservice->sig_fd[1], strerror(errno));
+ return -1;
+ }
return 0;
}
+void RTK_btservice_send_close_signal(void)
+{
+ unsigned char close_signal = 1;
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(rtk_btservice->sig_fd[0], &close_signal, 1));
+}
+
int RTK_btservice_thread_start()
{
rtk_btservice->epoll_thread_running=1;
return -1;
}
- rtk_btservice->cmdqueue_thread_running=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));
void RTK_btservice_thread_stop()
{
- ALOGD("%s !", __func__);
rtk_btservice->epoll_thread_running=0;
rtk_btservice->cmdqueue_thread_running=0;
+ RTK_btservice_send_close_signal();
sem_post(&rtk_btservice->cmdqueue_sem);
sem_post(&rtk_btservice->cmdsend_sem);
pthread_join(rtk_btservice->cmdreadythd, NULL);
int RTK_btservice_init()
{
int ret;
- rtk_btservice=(Rtk_Btservice_Info *)malloc(sizeof(Rtk_Btservice_Info));
+ rtk_btservice = (Rtk_Btservice_Info *)malloc(sizeof(Rtk_Btservice_Info));
+ if(rtk_btservice)
+ memset(rtk_btservice, 0, sizeof(Rtk_Btservice_Info));
+ else {
+ ALOGE("%s, alloc fail", __func__);
+ return -1;
+ }
rtk_btservice->current_client_sock = -1;
- rtk_btservice->current_complete_cback=NULL;
+ 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);
return -1;
}
+ if((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, rtk_btservice->sig_fd)) < 0) {
+ ALOGE("%s, errno : %s", __func__, strerror(errno));
+ return ret;
+ }
+
rtk_btservice->epoll_fd = epoll_create(64);
if (rtk_btservice->epoll_fd == -1) {
ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
}
ret = RTK_btservice_thread_start();
- if(ret<0)
+ if(ret < 0)
{
ALOGE("%s RTK_btservice_thread_start fail!", __func__);
return -1;
void RTK_btservice_destroyed()
{
- ALOGD("%s destroyed start!", __func__);
+ if(!rtk_btservice)
+ return;
RTK_btservice_thread_stop();
close(rtk_btservice->socketfd);
+ rtk_btservice->socketfd = -1;
+ close(rtk_btservice->sig_fd[0]);
+ close(rtk_btservice->sig_fd[1]);
sem_destroy(&rtk_btservice->cmdqueue_sem);
sem_destroy(&rtk_btservice->cmdsend_sem);
flush_cmdqueue_hash(rtk_btservice);
rtk_btservice->autopair_fd = -1;
rtk_btservice->current_client_sock = -1;
free(rtk_btservice);
+ rtk_btservice = NULL;
ALOGD("%s destroyed done!", __func__);
}
/******************************************************************************
*
- * Copyright (C) 2013 Google, Inc.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*
******************************************************************************/
-
#define LOG_TAG "rtk_btsnoop_net"
#include "rtk_btsnoop_net.h"
#include <unistd.h>
+#define RTK_NO_INTR(fn) do {} while ((fn) == -1 && errno == EINTR)
+
#define DATA_DIRECT_2_ELLISY 1
#define HCI_COMMAND 0x01
static void rtk_safe_close_(int *fd);
-static void *rtk_listen_fn_();
+static void *rtk_listen_fn_(void *context);
static const char *RTK_LISTEN_THREAD_NAME_ = "rtk_btsnoop_net";
static const int RTK_LOCALHOST_ = 0xC0A80AE2; // 192.168.10.226
client_addr.sin_addr.s_addr = htonl(RTK_REMOTEHOST_);
client_addr.sin_port = htons(RTK_REMOTE_PORT_);
pthread_mutex_lock(&rtk_client_socket_lock_);
- sendto(rtk_listen_socket_, buffer, (length+i), 0,(struct sockaddr*)&client_addr, sizeof(struct sockaddr_in));
+ int ret;
+ RTK_NO_INTR(ret = sendto(rtk_listen_socket_, buffer, (length+i), 0,(struct sockaddr*)&client_addr, sizeof(struct sockaddr_in)));
//sendto(rtk_listen_socket_, buffer, 25, 0,(struct sockaddr*)&client_addr, sizeof(struct sockaddr_in));
pthread_mutex_unlock(&rtk_client_socket_lock_);
}
-static void *rtk_listen_fn_() {
+static void *rtk_listen_fn_(void *context) {
+ RTK_UNUSED(context);
prctl(PR_SET_NAME, (unsigned long)RTK_LISTEN_THREAD_NAME_, 0, 0, 0);
rtk_listen_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2018 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.
+ *
+ ******************************************************************************/
#define LOG_TAG "rtk_heartbeat"
-#define RTKBT_RELEASE_NAME "Test"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include <sys/types.h>
#include <semaphore.h>
#include <endian.h>
#include <byteswap.h>
-#include <sys/un.h>
+#include <sys/un.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/types.h>
static int heartbeatCount= 0;
static uint16_t nextSeqNum= 1;
static uint16_t cleanupFlag = 0;
+static pthread_mutex_t heartbeat_mutex;
typedef struct Rtk_Service_Data
{
}
+static void rtkbt_heartbeat_send_hw_error(uint8_t status, uint16_t seqnum, uint16_t next_seqnum, int heartbeatCnt)
+{
+ if(!heartbeatFlag)
+ return;
+ unsigned char p_buf[100];
+ int length;
+ p_buf[0] = HCIT_TYPE_EVENT;//event
+ p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+ p_buf[3] = 0x01;// host log opcode
+ length = sprintf((char *)&p_buf[4], "host stack: heartbeat hw error: %d:%d:%d:%d",
+ status, seqnum, next_seqnum, heartbeatCnt);
+ p_buf[2] = length + 2;//len
+ length = length + 1 + 4;
+ userial_recv_rawdata_hook(p_buf,length);
+
+ length = 4;
+ p_buf[0] = HCIT_TYPE_EVENT;//event
+ p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+ p_buf[2] = 0x01;//len
+ p_buf[3] = 0xfc;//heartbeat error code
+ userial_recv_rawdata_hook(p_buf,length);
+}
+
static void rtkbt_heartbeat_cmpl_cback (void *p_params)
{
uint8_t status = 0;
- uint16_t seqnum;
+ uint16_t seqnum = 0;
HC_BT_HDR *p_evt_buf = p_params;
//uint8_t *p = NULL;
+
+ if(!heartbeatFlag)
+ return;
+
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);
+ nextSeqNum = (seqnum + 1);
+ pthread_mutex_lock(&heartbeat_mutex);
heartbeatCount = 0;
+ pthread_mutex_unlock(&heartbeat_mutex);
}
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);
+ rtkbt_heartbeat_send_hw_error(status, seqnum, nextSeqNum, heartbeatCount);
}
-
+
}
static void heartbeat_timed_out()//(union sigval arg)
{
Rtk_Service_Data *p_buf;
-
+ int count;
+
+ if(!heartbeatFlag)
+ return;
+ pthread_mutex_lock(&heartbeat_mutex);
heartbeatCount++;
if(heartbeatCount >= 3)
{
if(cleanupFlag == 1)
{
ALOGW("Already cleanup, ignore.");
+ pthread_mutex_unlock(&heartbeat_mutex);
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");
+ count = heartbeatCount;
+ pthread_mutex_unlock(&heartbeat_mutex);
usleep(1000);
+ rtkbt_heartbeat_send_hw_error(0,0,nextSeqNum,count);
+
//kill(getpid(), SIGKILL);
return;
}
+ pthread_mutex_unlock(&heartbeat_mutex);
if(heartbeatFlag)
{
p_buf = (Rtk_Service_Data *)malloc(sizeof(Rtk_Service_Data));
p_buf->parameter_len = 0;
p_buf->complete_cback = rtkbt_heartbeat_cmpl_cback;
- Rtk_Service_Vendorcmd_Hook(p_buf,-1);
+ Rtk_Service_Vendorcmd_Hook(p_buf, -1);
free(p_buf);
poll_timer_flush();
}
p_buf->parameter = NULL;
p_buf->parameter_len = 0;
p_buf->complete_cback = rtkbt_heartbeat_cmpl_cback;
-
- Rtk_Service_Vendorcmd_Hook(p_buf,-1);
+
+ 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()
{
+ if(!heartbeatFlag)
+ return;
heartbeatFlag = false;
nextSeqNum = 1;
heartbeatCount = 0;
ALOGD("Heartbeat_init start");
Heartbeat_cleanup();
load_rtkbt_heartbeat_conf();
+ pthread_mutex_init(&heartbeat_mutex, NULL);
heartbeatFlag = true;
heartbeatCount = 0;
cleanupFlag = 0;
/******************************************************************************
*
- * Copyright (C) 2016 Realtek Corporation.
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*
******************************************************************************/
+
/******************************************************************************
*
* Module Name:
*
******************************************************************************/
#define LOG_TAG "rtk_parse"
-#define RTKBT_RELEASE_NAME "20180702_BT_ANDROID_9.0"
+#define RTKBT_RELEASE_NAME "20190520_BT_ANDROID_9.0"
#include <utils/Log.h>
#include <stdlib.h>
#include "rtk_parse.h"
#include <sys/syscall.h>
-#define RTK_VERSION "2.1"
+#define RTK_COEX_VERSION "3.0"
char invite_req[] = "INVITE_REQ";
char invite_rsp[] = "INVITE_RSP";
//vendor cmd to wifi driver
#define HCI_OP_HCI_EXTENSION_VERSION_NOTIFY (0x0100 | HCI_GRP_VENDOR_SPECIFIC)
#define HCI_OP_BT_OPERATION_NOTIFY (0x0102 | HCI_GRP_VENDOR_SPECIFIC)
-#define HCI_OP_HCI_BT_INFO_NOTIFY (0x0106 | HCI_GRP_VENDOR_SPECIFIC)
-#define HCI_OP_HCI_BT_COEX_NOTIFY (0x0107 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_INFO_NOTIFY (0x0106 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_COEX_NOTIFY (0x0107 | HCI_GRP_VENDOR_SPECIFIC)
#define HCI_OP_HCI_BT_PATCH_VER_NOTIFY (0x0108 | HCI_GRP_VENDOR_SPECIFIC)
#define HCI_OP_HCI_BT_AFH_MAP_NOTIFY (0x0109 | HCI_GRP_VENDOR_SPECIFIC)
#define HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY (0x010a | HCI_GRP_VENDOR_SPECIFIC)
RT_LIST_ENTRY list;
HC_BT_HDR * p_buf;
uint16_t opcode;
+ tINT_CMD_CBACK p_cback;
}tRTK_COEX_INFO;
//profile info data
RT_LIST_HEAD conn_hash; //hash for connections
RT_LIST_HEAD profile_list; //hash for profile info
RT_LIST_HEAD coex_list;
+ tINT_CMD_CBACK current_cback;
pthread_mutex_t profile_mutex;
pthread_mutex_t coex_mutex;
- pthread_mutex_t udpsocket_mutex;
+ pthread_mutex_t btwifi_mutex;
pthread_t thread_monitor;
pthread_t thread_data;
timer_t timer_a2dp_packet_count;
uint8_t autoreport;
uint8_t polling_enable;
uint8_t polling_interval;
- volatile uint8_t udpsocket_recv_thread_running;
+ volatile uint8_t coex_recv_thread_running;
//int32_t nlsocket;
- int32_t udpsocket;
+ int32_t btcoex_chr;
+ int32_t udpsocket;
uint8_t piconet_id;
uint8_t mode;
uint8_t afh_map[10];
uint16_t hci_reversion;
uint16_t lmp_subversion;
uint8_t wifi_on;
+ uint8_t bt_on;
//uint8_t le_profile_index;
}tRTK_PROF;
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;
#define is_profile_busy(profile) ((rtk_prof.profile_status & BIT(profile)) >0)
static void timeout_handler(int signo, siginfo_t * info, void *context);
+static void notify_func(union sigval sig);
+
+static int coex_msg_send(char *tx_msg, int msg_size);
+static int coex_msg_recv(uint8_t *recv_msg, uint8_t *msg_size);
#ifndef RTK_PARSE_LOG_BUF_SIZE
#define RTK_PARSE_LOG_BUF_SIZE 1024
timer_t timerid = (timer_t)-1;
// Create the POSIX timer to generate signo
- sigev.sigev_notify = SIGEV_THREAD_ID;
- sigev.sigev_notify_thread_id = syscall(__NR_gettid);
- sigev.sigev_signo = signo;
- sigev.sigev_value.sival_ptr = &timerid;
+ //sigev.sigev_notify = SIGEV_THREAD_ID;
+ //sigev.sigev_notify_thread_id = syscall(__NR_gettid);
+ //sigev.sigev_signo = signo;
+ //sigev.sigev_value.sival_ptr = &timerid;
+
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.sigev_notify = SIGEV_THREAD;
+ sigev.sigev_notify_function = notify_func;
+ sigev.sigev_value.sival_int = signo;
//ALOGE("OsAllocateTimer rtk_parse sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
int alloc_polling_timer()
{
+/*
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
ALOGE("alloc_polling_timer, sigaction failed");
return -1;
}
-
+*/
// Create and set the timer when to expire
rtk_prof.timer_polling= OsAllocateTimer(TIMER_POLLING);
RtkLogMsg("alloc polling timer");
int alloc_hogp_packet_count_timer()
{
+/*
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
ALOGE("alloc_hogp_packet_count_timer, sigaction failed");
return -1;
}
-
+*/
// Create and set the timer when to expire
rtk_prof.timer_hogp_packet_count= OsAllocateTimer(TIMER_HOGP_PACKET_COUNT);
RtkLogMsg("alloc hogp packet");
int alloc_a2dp_packet_count_timer()
{
+/*
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
ALOGE("alloc_a2dp_packet_count_timer, sigaction failed");
return -1;
}
-
+*/
// Create and set the timer when to expire
rtk_prof.timer_a2dp_packet_count= OsAllocateTimer(TIMER_A2DP_PACKET_COUNT);
RtkLogMsg("alloc a2dp packet");
int alloc_pan_packet_count_timer()
{
+/*
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
ALOGE("alloc_pan_packet_count_timer, sigaction failed");
return -1;
}
-
+*/
// Create and set the timer when to expire
rtk_prof.timer_pan_packet_count= OsAllocateTimer(TIMER_PAN_PACKET_COUNT);
void delete_profile_from_hash(tRTK_PROF_INFO* desc)
{
- RtkLogMsg("delete profile for handle: %x, psm:%x, dcid:%x, scid:%x", desc->handle, desc->psm, desc->dcid, desc->scid);
+ //RtkLogMsg("delete profile for handle: %x, psm:%x, dcid:%x, scid:%x", desc->handle, desc->psm, desc->dcid, desc->scid);
if (desc)
{
ListDeleteNode(&desc->list);
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;
}
pthread_mutex_unlock(&rtk_prof.coex_mutex);
+ if(rtk_prof.current_cback) {
+ rtk_prof.current_cback(p_mem);
+ rtk_prof.current_cback = NULL;
+ }
+
+ if(p_mem)
+ bt_vendor_cbacks->dealloc(p_mem);
+
if(desc) {
ALOGE("%s, transmit_command Opcode:%x",__func__, desc->opcode);
+ rtk_prof.current_cback = desc->p_cback;
bt_vendor_cbacks->xmit_cb(desc->opcode, desc->p_buf, rtk_cmd_complete_cback);
}
return;
}
-void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* parameter)
+void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* parameter, tINT_CMD_CBACK p_cback)
{
- //uint8_t temp = 0;
HC_BT_HDR *p_buf = NULL;
+ if(!rtk_prof.bt_on)
+ return;
+
if(bt_vendor_cbacks)
p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + parameter_len);
ALOGE("rtk_vendor_cmd_to_fw: HC_BT_HDR alloc error");
return;
}
+ memset(p_buf, 0, (BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + parameter_len));
p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
p_buf->offset = 0;
p_buf->len = HCI_CMD_PREAMBLE_SIZE + parameter_len;
uint8_t *p = (uint8_t *) (p_buf + 1);
UINT16_TO_STREAM(p, opcode);
- RtkLogMsg("rtk_vendor_cmd_to_fw: Opcode:%x",opcode);
+ *p++ = parameter_len;
+ RtkLogMsg("rtk_vendor_cmd_to_fw: Opcode:%x, parameter_len = %d",opcode, parameter_len);
if(parameter_len > 0)
{
- *p++ = parameter_len;
memcpy(p, parameter, parameter_len);
}
if(bt_vendor_cbacks)
{
- RtkLogMsg("begin transmit_command Opcode:%x",opcode);
pthread_mutex_lock(&rtk_prof.coex_mutex);
if(!coex_cmd_send) {
coex_cmd_send = true;
+ RtkLogMsg("begin transmit_command Opcode:%x",opcode);
pthread_mutex_unlock(&rtk_prof.coex_mutex);
+ rtk_prof.current_cback = p_cback;
bt_vendor_cbacks->xmit_cb(opcode, p_buf, rtk_cmd_complete_cback);
}
else {
if (NULL == pcoex_info)
{
ALOGE("rtk_vendor_cmd_to_fw: allocate error");
+ pthread_mutex_unlock(&rtk_prof.coex_mutex);
return;
}
pcoex_info->p_buf = p_buf;
pcoex_info->opcode = opcode;
+ pcoex_info->p_cback = p_cback;
ListAddToTail(&(pcoex_info->list), &(rtk_prof.coex_list));
pthread_mutex_unlock(&rtk_prof.coex_mutex);
*p++ = rtk_prof.profile_status;
RtkLogMsg("rtk_notify_profileinfo_to_fw, profile_status is %x",rtk_prof.profile_status);
- rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size, p_buf);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size, p_buf, NULL);
free(p_buf);
bitpool = sbc_header->bitpool;
print_sbc_header(sbc_header);
RtkLogMsg("rtp: v %u, cc %u, pt %u", rtph->v, rtph->cc, rtph->pt);
- rtk_vendor_cmd_to_fw(HCI_VENDOR_ADD_BITPOOL_FW, 1, &bitpool);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_ADD_BITPOOL_FW, 1, &bitpool, NULL);
}
rtk_prof.a2dp_packet_count++;
}
static void timeout_handler(int signo, siginfo_t * info, void *context)
{
- if(info == NULL)
- {
- RtkLogMsg("info null");
- }
- if(context == NULL)
- {
- RtkLogMsg("context null");
- }
+ RTK_UNUSED(info);
+ RTK_UNUSED(context);
if (signo == TIMER_POLLING)
{
RtkLogMsg("polling timeout");
{
uint8_t temp_cmd[1];
temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 1, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 1, temp_cmd, NULL);
}
}
else if (signo == TIMER_A2DP_PACKET_COUNT)
}
}
+static void notify_func(union sigval sig)
+{
+ int signo = sig.sival_int;
+ timeout_handler(signo, NULL, NULL);
+}
+
#if 0
int netlink_send(int nlsk, char *buffer)
{
bzero(buf, MAX_PAYLOAD);
while (poll(&pfd, 1, 1000) <= 0) {
- if (rtk_prof.udpsocket_recv_thread_running ==0) {
- RtkLogMsg("SIGUSR2 should have caught us before this");
+ if (rtk_prof.coex_recv_thread_running ==0) {
+ RtkLogMsg("%s, SIGUSR2 should have caught us before this", __func__);
return -1;
}
}
return 0;
}
+
+int btcoex_chr_send(char *tx_msg, int msg_size)
+{
+ int n; /* message byte size */
+
+ RtkLogMsg("btcoex_chr_send tx_msg:%s",tx_msg);
+ RTK_NO_INTR (n = write(rtk_prof.btcoex_chr, tx_msg, msg_size));
+ if (n < 0)
+ {
+ ALOGE("ERROR in write");
+ return -1;
+ }
+ return n;
+}
+
+int btcoex_chr_recv(uint8_t *recv_msg, uint8_t *msg_size)
+{
+ char buf[MAX_PAYLOAD]; /* message buf */
+ int n = -1; /* message byte size */
+ struct pollfd pfd = {
+ .events = POLLPRI|POLLIN|POLLHUP|POLLERR|POLLRDHUP,
+ .revents = 0,
+ .fd = rtk_prof.btcoex_chr
+ };
+
+ bzero(buf, MAX_PAYLOAD);
+
+ while (poll(&pfd, 1, 1000) <= 0) {
+ if (rtk_prof.coex_recv_thread_running == 0) {
+ RtkLogMsg("%s, SIGUSR2 should have caught us before this", __func__);
+ return -1;
+ }
+ }
+
+ if (pfd.revents & POLLIN) {
+ RTK_NO_INTR(n = read(rtk_prof.btcoex_chr, buf, MAX_PAYLOAD));
+ if (n < 0) {
+ ALOGE("ERROR in recvfrom");
+ return -1;
+ } else {
+ *msg_size = n;
+ memcpy(recv_msg, buf, n);
+ }
+ }
+ else {
+ ALOGE("rtk_btcoex is wrong");
+ return -1;
+ }
+ return 0;
+}
+
void rtk_notify_extension_version_to_wifi()
{
uint8_t para_length = 2;
*p++ = para_length;
UINT16_TO_STREAM(p, HCI_EXTENSION_VERSION);
RtkLogMsg("extension version is 0x%x", HCI_EXTENSION_VERSION);
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_extension_version_to_wifi: udpsocket send error");
}
UINT16_TO_STREAM(p, rtk_prof.lmp_subversion);
RtkLogMsg("btpatch_version, length is 0x%x, hci_reversion is 0x%x, lmp_subversion is %x", para_length, rtk_prof.hci_reversion, rtk_prof.lmp_subversion);
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_btpatch_version_to_wifi: udpsocket send error");
}
for(kk=0; kk < 10; kk++)
RtkLogMsg("afhmap data[%d] is 0x%x", kk, rtk_prof.afh_map[kk]);
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_afhmap_to_wifi: udpsocket send error");
}
RtkLogMsg("btcoex, opcode is 0x%x, status is 0x%x", opcode, status);
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_btcoex_to_wifi: udpsocket send error");
}
RtkLogMsg("append data is 0x%x", *(append_data+kk));
}
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_btoperation_to_wifi: udpsocket send error");
}
RtkLogMsg("bt info[%d]: %02x", i, report_info[i]);
}
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_info_to_wifi: udpsocket send error");
}
RtkLogMsg("bt register, register offset is %x", reg->offset);
RtkLogMsg("bt register, register value is %x", reg->value);
- if(udpsocket_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+ if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
ALOGE("rtk_notify_regester_to_wifi: udpsocket send error");
}
temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE;
temp_cmd[1] = 1;
temp_cmd[2] = info->autoreport_enable;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
rtk_notify_info_to_wifi(HOST_RESPONSE, 0, NULL);
}
temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD;
temp_cmd[1] = 1;
temp_cmd[2] = value;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
break;
}
temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT;
temp_cmd[1] = 1;
temp_cmd[2] = value;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
break;
}
temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD;
temp_cmd[1] = 1;
temp_cmd[2] = power_decrease;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
break;
}
temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE;
temp_cmd[1] = 1;
temp_cmd[2] = psd_mode;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
break;
}
temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD;
temp_cmd[1] = 3;
memcpy(temp_cmd+2, p, 3);//wifi_state, wifi_centralchannel, chnnels_btnotuse
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 5, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 5, temp_cmd, NULL);
break;
}
temp_cmd[1] = 2;
temp_cmd[2] = rtk_prof.piconet_id;
temp_cmd[3] = rtk_prof.mode;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd, NULL);
break;
}
temp_cmd[1] = 5;
temp_cmd[2] = *p++;
memcpy(temp_cmd+3, p, 4);
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 7, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 7, temp_cmd, NULL);
}
else //write
{
temp_cmd[1] = 5;
temp_cmd[2] = *p++;
memcpy(temp_cmd+3, p, 8);
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 11, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 11, temp_cmd, NULL);
}
break;
}
{
uint8_t *p = msg;
uint8_t event_code = *p++;
- uint8_t total_length = 0;
+ uint8_t total_length = 0;
+
+ RtkLogMsg("receive invite rsp from wifi msg : %s", msg);
if(memcmp(msg, invite_rsp, sizeof(invite_rsp)) == 0)
{
#if 0
{
RtkLogMsg("receive attend req from wifi, wifi turn on");
rtk_prof.wifi_on = 1;
- udpsocket_send(attend_ack, sizeof(attend_ack));
+ coex_msg_send(attend_ack, sizeof(attend_ack));
rtk_notify_extension_version_to_wifi();
}
{
RtkLogMsg("receive wifi leave from wifi, wifi turn off");
rtk_prof.wifi_on = 0;
- udpsocket_send(leave_ack, sizeof(leave_ack));
+ coex_msg_send(leave_ack, sizeof(leave_ack));
if(rtk_prof.polling_enable)
{
rtk_prof.polling_enable = 0;
}
}
-static void udpsocket_receive_thread_exit_handler(int sig)
+static void coex_receive_thread_exit_handler(int sig)
{
RtkLogMsg("USR2, this signal is %d \n", sig);
usleep(100);
pthread_exit(0);
}
-static void udpsocket_receive_thread()//(void *arg)
+static void btwifi_coex_receive_thread(void *arg)
{
+ RTK_UNUSED(arg);
uint8_t msg_recv[MAX_PAYLOAD];
uint8_t recv_length;
struct sigaction actions;
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
- actions.sa_handler = udpsocket_receive_thread_exit_handler;
+ actions.sa_handler = coex_receive_thread_exit_handler;
sigaction(SIGUSR2,&actions,NULL);//int rc = sigaction(SIGUSR2,&actions,NULL);
- RtkLogMsg("udpsocket_receive_thread started");
- prctl(PR_SET_NAME, (unsigned long)"udpsocket_receive_thread", 0, 0, 0);
+ RtkLogMsg("btwifi_coex_receive_thread started");
+ prctl(PR_SET_NAME, (unsigned long)"btwifi_coex_receive_thread", 0, 0, 0);
- while(rtk_prof.udpsocket_recv_thread_running)
+ while(rtk_prof.coex_recv_thread_running)
{
memset(msg_recv, 0 , MAX_PAYLOAD);
- if (udpsocket_recv(msg_recv, &recv_length) == 0)
+ if (coex_msg_recv(msg_recv, &recv_length) == 0)
rtk_handle_event_from_wifi(msg_recv);
}
- RtkLogMsg("udpsocket_receive_thread exiting");
+ RtkLogMsg("btwifi_coex_receive_thread exiting");
pthread_exit(NULL);
}
RtkLogMsg("create udpsocket port: %d\n", portno);
- pthread_mutex_lock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_lock(&rtk_prof.btwifi_mutex);
pthread_attr_t thread_attr_data;
- if (rtk_prof.udpsocket_recv_thread_running)
+ if (rtk_prof.coex_recv_thread_running)
{
ALOGE("udp_receive_thread already exit");
- pthread_mutex_unlock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
return -1 ;
}
- rtk_prof.udpsocket_recv_thread_running = 1;
+ rtk_prof.coex_recv_thread_running = 1;
rtk_prof.udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
RtkLogMsg("create socket %d", rtk_prof.udpsocket);
if (rtk_prof.udpsocket < 0)
{
ALOGE("create udpsocket error...%s\n", strerror(errno));
- rtk_prof.udpsocket_recv_thread_running = 0;
- close(rtk_prof.udpsocket);
+ rtk_prof.coex_recv_thread_running = 0;
RtkLogMsg("close socket %d", rtk_prof.udpsocket);
- pthread_mutex_unlock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
return -1 ;
}
rtk_prof.client_addr.sin_port = htons(CONNECT_PORT_WIFI);
optval = 1;
- setsockopt(rtk_prof.udpsocket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
+ int ret = setsockopt(rtk_prof.udpsocket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
+ if(ret == -1){
+ ALOGE("%s, setsockopt error: %s", __func__, strerror(errno));
+ }
if (bind(rtk_prof.udpsocket, (struct sockaddr *)&rtk_prof.server_addr, sizeof(rtk_prof.server_addr)) < 0)
{
ALOGE("bind udpsocket error...%s\n", strerror(errno));
- rtk_prof.udpsocket_recv_thread_running = 0;
+ rtk_prof.coex_recv_thread_running = 0;
close(rtk_prof.udpsocket);
RtkLogMsg("close socket %d", rtk_prof.udpsocket);
- pthread_mutex_unlock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
return -1 ;
}
pthread_attr_init(&thread_attr_data);
- if (pthread_create(&rtk_prof.thread_data, &thread_attr_data, (void*)udpsocket_receive_thread, NULL) != 0)
+ if (pthread_create(&rtk_prof.thread_data, &thread_attr_data, (void*)btwifi_coex_receive_thread, NULL) != 0)
{
ALOGE("pthread_create failed!");
pthread_attr_destroy(&thread_attr_data);
- rtk_prof.udpsocket_recv_thread_running = 0;
- pthread_mutex_unlock(&rtk_prof.udpsocket_mutex);
+ rtk_prof.coex_recv_thread_running = 0;
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
return -1 ;
}
pthread_attr_destroy(&thread_attr_data);
- pthread_mutex_unlock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
return 0;
}
-int stop_udpsocket_receive_thread()
+int stop_btwifi_coex_receive_thread()
{
- pthread_mutex_lock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_lock(&rtk_prof.btwifi_mutex);
int result = 0;
RtkLogMsg("notify wifi bt turn off");
if(rtk_prof.wifi_on)
- udpsocket_send(bt_leave, sizeof(bt_leave));
+ coex_msg_send(bt_leave, sizeof(bt_leave));
- if (rtk_prof.udpsocket_recv_thread_running)
+ if (rtk_prof.coex_recv_thread_running)
{
RtkLogMsg("data thread is running, stop it");
{
ALOGE("error cancelling data thread");
}
- rtk_prof.udpsocket_recv_thread_running = 0;
+ rtk_prof.coex_recv_thread_running = 0;
if ((result = pthread_join(rtk_prof.thread_data, NULL)) < 0)
{
ALOGE( "data thread pthread_join() failed result:%d", result);
}
- RtkLogMsg("close socket %d", rtk_prof.udpsocket);
- if((result = close(rtk_prof.udpsocket)) != 0)
- {
- ALOGE("close socket error!");
+ if(rtk_prof.udpsocket > 0) {
+ RtkLogMsg("close socket %d", rtk_prof.udpsocket);
+ if((result = close(rtk_prof.udpsocket)) != 0)
+ {
+ ALOGE("close socket error!");
+ }
+ }
+ else if(rtk_prof.btcoex_chr > 0) {
+ RtkLogMsg("close char device %d", rtk_prof.btcoex_chr);
+ if((result = close(rtk_prof.btcoex_chr)) != 0)
+ {
+ ALOGE("close char device error!");
+ }
}
}
- pthread_mutex_unlock(&rtk_prof.udpsocket_mutex);
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
return 0;
}
}
#endif
+int open_btcoex_chrdev()
+{
+ RtkLogMsg("open_btcoex_chrdev\n");
+
+ pthread_mutex_lock(&rtk_prof.btwifi_mutex);
+
+ pthread_attr_t thread_attr_data;
+ if (rtk_prof.coex_recv_thread_running)
+ {
+ ALOGE("udp_receive_thread already exit");
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
+ return -1 ;
+ }
+
+ rtk_prof.coex_recv_thread_running = 1;
+ if ((rtk_prof.btcoex_chr = open("/dev/rtk_btcoex", O_RDWR)) < 0)
+ {
+ ALOGE("open rtk_btcoex error...%s\n", strerror(errno));
+ rtk_prof.coex_recv_thread_running = 0;
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
+ return -1 ;
+ }
+
+ pthread_attr_init(&thread_attr_data);
+ if (pthread_create(&rtk_prof.thread_data, &thread_attr_data, (void*)btwifi_coex_receive_thread, NULL) != 0)
+ {
+ ALOGE("create coexchr_receive_thread failed!");
+ pthread_attr_destroy(&thread_attr_data);
+ rtk_prof.coex_recv_thread_running = 0;
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
+ return -1 ;
+ }
+ pthread_attr_destroy(&thread_attr_data);
+ pthread_mutex_unlock(&rtk_prof.btwifi_mutex);
+ return 0;
+}
+
void rtk_parse_init(void)
{
ALOGI("RTKBT_RELEASE_NAME: %s",RTKBT_RELEASE_NAME);
- RtkLogMsg("rtk_profile_init, version: %s", RTK_VERSION);
+ RtkLogMsg("rtk_profile_init, version: %s", RTK_COEX_VERSION);
+ memset(&rtk_prof, 0, sizeof(rtk_prof));
pthread_mutex_init(&rtk_prof.profile_mutex, NULL);
pthread_mutex_init(&rtk_prof.coex_mutex, NULL);
- pthread_mutex_init(&rtk_prof.udpsocket_mutex, NULL);
+ pthread_mutex_init(&rtk_prof.btwifi_mutex, NULL);
alloc_a2dp_packet_count_timer();
alloc_pan_packet_count_timer();
alloc_hogp_packet_count_timer();
init_connection_hash(&rtk_prof);
init_coex_hash(&rtk_prof);
- create_udpsocket_socket();
+ if(create_udpsocket_socket() < 0) {
+ ALOGE("UDP socket fail, try to use rtk_btcoex chrdev");
+ open_btcoex_chrdev();
+ }
}
void rtk_parse_cleanup()
{
RtkLogMsg("rtk_profile_cleanup");
- int kk = 0;
free_a2dp_packet_count_timer();
free_pan_packet_count_timer();
free_hogp_packet_count_timer();
flush_coex_hash(&rtk_prof);
pthread_mutex_destroy(&rtk_prof.coex_mutex);
- stop_udpsocket_receive_thread();
- pthread_mutex_destroy(&rtk_prof.udpsocket_mutex);
+ stop_btwifi_coex_receive_thread();
+ pthread_mutex_destroy(&rtk_prof.btwifi_mutex);
- rtk_prof.polling_enable = 0;
- rtk_prof.profile_bitmap = 0;
- rtk_prof.profile_status = 0;
- for(kk = 0; kk < 8; kk++)
- rtk_prof.profile_refcount[kk] = 0;
+ memset(&rtk_prof, 0, sizeof(rtk_prof));
}
static void rtk_handle_vender_mailbox_cmp_evt(uint8_t* p, uint8_t len)
temp_cmd[1] = 2;
temp_cmd[2] = rtk_prof.piconet_id;
temp_cmd[3] = rtk_prof.mode;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd, NULL);
}
else //fail
{
temp_cmd[1] = 2;
temp_cmd[2] = rtk_prof.piconet_id;
temp_cmd[3] = rtk_prof.mode;
- rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd);
+ rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd, NULL);
}
else //fail
{
case HCI_RESET:
{
RtkLogMsg("bt start ok");
- udpsocket_send(invite_req, sizeof(invite_req));
+ coex_msg_send(invite_req, sizeof(invite_req));
#if 0
if(create_netlink_socket() == 0)
{
else
RtkLogMsg("wifi is off when bt turn on, wait for wifi turning on...");
#endif
- uint8_t ttmp[1] = {1};
- rtk_vendor_cmd_to_fw(0xfc1b, 1, ttmp);
break;
}
rtk_handle_vender_mailbox_cmp_evt(p, len);
break;
- case HCI_SET_EVENT_MASK:
- Heartbeat_init();
- break;
-
case HCI_VENDOR_ADD_BITPOOL_FW:
status = *p++;
RtkLogMsg("received cmd complete event for HCI_VENDOR_ADD_BITPOOL_FW status:%d",status);
}
}
+static int coex_msg_send(char *tx_msg, int msg_size)
+{
+ int ret = -1;
+ if(rtk_prof.udpsocket > 0) {
+ ret = udpsocket_send(tx_msg, msg_size);
+ }
+ else if(rtk_prof.btcoex_chr > 0) {
+ ret = btcoex_chr_send(tx_msg, msg_size);
+ }
+ return ret;
+
+}
+
+static int coex_msg_recv(uint8_t *recv_msg, uint8_t *msg_size)
+{
+ int ret = -1;
+ if(rtk_prof.udpsocket > 0) {
+ ret = udpsocket_recv(recv_msg, msg_size);
+ }
+ else if(rtk_prof.btcoex_chr > 0) {
+ ret = btcoex_chr_recv(recv_msg, msg_size);
+ }
+ return ret;
+}
void rtk_parse_internal_event_intercept(uint8_t *p_msg)
{
//ALOGE("in rtk_parse_internal_event_intercept, *p= %x", *p);
void rtk_parse_command(uint8_t *pp)
{
- uint8_t *p =pp;
+ uint8_t *p = pp;
uint16_t cmd;
STREAM_TO_UINT16(cmd, p);
uint16_t handle, total_len, pdu_len, channel_ID, command_len, psm, scid, dcid, result, status;
uint8_t flag, code, identifier;
STREAM_TO_UINT16 (handle, pp);
- flag = handle >> 12;
+ flag = (handle >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK;
handle = handle & 0x0FFF;
STREAM_TO_UINT16 (total_len, pp);
STREAM_TO_UINT16 (pdu_len, pp);
STREAM_TO_UINT16 (channel_ID, pp);
+ if(flag != RTK_START_PACKET_BOUNDARY)
+ return;
+
if(channel_ID == 0x0001)
{
code = (uint8_t)(*pp++);
void rtk_add_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map)
{
+ RTK_UNUSED(bdaddr);
RtkLogMsg("rtk_add_le_profile, handle is %x, profile_map is %x", handle, profile_map);
- RtkLogMsg("bdaddr[0] = %d", bdaddr[0]);
+
tRTK_CONN_PROF* hci_conn = find_connection_by_handle(&rtk_prof, handle);
if(hci_conn)
{
void rtk_delete_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map)
{
+ RTK_UNUSED(bdaddr);
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)
}
}
+void rtk_set_bt_on(uint8_t bt_on) {
+ RtkLogMsg("bt stack is init");
+ rtk_prof.bt_on = bt_on;
+ uint8_t ttmp[1] = {1};
+ rtk_vendor_cmd_to_fw(0xfc1b, 1, ttmp, NULL);
+}
+
static rtk_parse_manager_t parse_interface = {
rtk_parse_internal_event_intercept,
rtk_parse_l2cap_data,
rtk_add_le_profile,
rtk_delete_le_profile,
rtk_add_le_data_count,
+ rtk_set_bt_on,
};
rtk_parse_manager_t *rtk_parse_manager_get_interface() {
/******************************************************************************
*
- * Copyright (C) 2014-2016 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*
******************************************************************************/
-
/******************************************************************************
*
* Filename: poll.c
struct itimerspec ts;
struct sigevent se;
+ memset(&se, 0, sizeof(struct sigevent));
BTPOLLDBG("poll_timer_flush: state %d", bt_poll_cb.state);
if (bt_poll_cb.state != POLL_ENABLED)
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*
******************************************************************************/
-
/******************************************************************************
*
* Filename: userial_vendor.c
/******************************************************************************
** functions
******************************************************************************/
-uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len)
+uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len, bool* condition)
{
int n_read = 0;
struct pollfd pfd;
while (n_read < (int)len)
{
+ if(condition && !(*condition))
+ return n_read;
pfd.fd = fd;
- pfd.events = POLLIN|POLLHUP;
+ pfd.events = POLLIN|POLLHUP|POLLNVAL|POLLRDHUP;
/* make sure there is data prior to attempting read to avoid blocking
a read for more than poll timeout */
break;
}
- if (pfd.revents & (POLLHUP|POLLNVAL) )
+ if (pfd.revents & (POLLHUP|POLLNVAL|POLLRDHUP) )
{
return 0;
}
}
pfd.fd = fd;
- pfd.events = POLLIN|POLLHUP;
+ pfd.events = POLLIN|POLLHUP|POLLRDHUP;
if (poll(&pfd, 1, 0) == 0)
{
return 0;
}
- if (pfd.revents & (POLLHUP|POLLNVAL) )
+ if (pfd.revents & (POLLHUP|POLLNVAL|POLLRDHUP) )
{
return 0;
}
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
break;
}
}
-
+
asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
return 0;
}
** Returns None
**
*******************************************************************************/
-void upio_set(uint8_t pio, uint8_t action)//(uint8_t pio, uint8_t action, uint8_t polarity)
+void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
{
//int rc;
+ RTK_UNUSED(polarity);
#if (BT_WAKE_VIA_PROC == TRUE)
int fd = -1;
char buffer;
case UPIO_LPM_MODE:
if (upio_state[UPIO_LPM_MODE] == action)
{
+ RTK_UNUSED(lpm_mode[action]);
UPIODBG("LPM is %s already", lpm_mode[action]);
return;
}
case UPIO_BT_WAKE:
if (upio_state[UPIO_BT_WAKE] == action)
{
+ RTK_UNUSED(lpm_state[action]);
UPIODBG("BT_WAKE is %s already", lpm_state[action]);
#if (BT_WAKE_VIA_PROC == TRUE)
/******************************************************************************
*
- * Copyright (C) 2009-2012 Realtek Corporation
+ * Copyright (C) 2009-2018 Realtek Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "userial.h"
#include "userial_vendor.h"
#include "rtk_socket.h"
+#include <cutils/sockets.h>
+
#ifdef CONFIG_SCO_OVER_HCI
#include "sbc.h"
******************************************************************************/
extern char rtkbt_transtype;
extern void Heartbeat_cleanup();
+extern void Heartbeat_init();
/******************************************************************************
** Local type definitions
{
int fd; /* fd to Bluetooth device */
int uart_fd[2];
+ int signal_fd[2];
int epoll_fd;
int cpoll_fd;
int event_fd;
uint16_t btui_msbc_h2[] = {0x0801,0x3801,0xc801,0xf801};
typedef struct
{
- pthread_mutex_t sco_mutex;
- pthread_cond_t sco_cond;
+ pthread_mutex_t sco_recv_mutex;
+ pthread_cond_t sco_recv_cond;
+ pthread_mutex_t sco_send_mutex;
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;
+ bool thread_recv_sco_running;
+ bool thread_send_sco_running;
uint16_t voice_settings;
RTB_QUEUE_HEAD *recv_sco_data;
RTB_QUEUE_HEAD *send_sco_data;
int ctrl_fd, data_fd;
sbc_t sbc_dec, sbc_enc;
uint32_t pcm_enc_seq;
+ int signal_fd[2];
}sco_cb_t;
#endif
#ifdef RTK_HANDLE_EVENT
static int received_packet_state = RTKBT_PACKET_IDLE;
-static int received_packet_bytes_need = 0;
+static unsigned 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;
+static rtkbt_version_t rtkbt_version;
+static rtkbt_lescn_t rtkbt_adv_con;
#endif
static rtk_parse_manager_t * rtk_parse_manager = NULL;
*******************************************************************************/
void userial_vendor_init(char *bt_device_node)
{
+ memset(&rtkbt_adv_con, 0, sizeof(rtkbt_lescn_t));
+ memset(&vnd_userial, 0, sizeof(vnd_userial_cb_t));
vnd_userial.fd = -1;
char value[100];
snprintf(vnd_userial.port_name, VND_PORT_NAME_MAXLEN, "%s", \
h5_int_interface->h5_int_init(&h5_int_callbacks);
}
rtk_parse_manager = NULL;
- property_get("persist.bluetooth.rtkcoex", value, "true");
+ property_get("persist.vendor.bluetooth.rtkcoex", value, "true");
if(strncmp(value, "true", 4) == 0) {
rtk_parse_manager = rtk_parse_manager_get_interface();
rtk_parse_manager->rtk_parse_init();
vnd_userial.data_order = RtbQueueInit();
vnd_userial.recv_data = RtbQueueInit();
vnd_userial.send_data = RtbQueueInit();
+
+ //reset coex gloable variables
+ coex_packet_recv_state = RTKBT_PACKET_IDLE;
+ coex_packet_bytes_need = 0;
+ coex_current_type = 0;
+ coex_resvered_length = 0;
+
+#ifdef RTK_HANDLE_EVENT
+ //reset handle event gloable variables
+ received_packet_state = RTKBT_PACKET_IDLE;
+ received_packet_bytes_need = 0;
+ recv_packet_current_type = 0;
+ received_resvered_length = 0;
+#endif
+
#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);
+ pthread_mutex_init(&sco_cb.sco_recv_mutex, NULL);
+ pthread_cond_init(&sco_cb.sco_recv_cond, NULL);
+ pthread_mutex_init(&sco_cb.sco_send_mutex, NULL);
memset(&sco_cb.sbc_enc, 0, sizeof(sbc_t));
- sbc_init(&sco_cb.sbc_enc);//sbc_init(&sco_cb.sbc_enc, 0);
+ sbc_init_msbc(&sco_cb.sbc_enc, 0L);
+ sco_cb.sbc_enc.endian = SBC_LE;
memset(&sco_cb.sbc_dec, 0, sizeof(sbc_t));
- sbc_init(&sco_cb.sbc_dec);//sbc_init(&sco_cb.sbc_enc, 0);
+ sbc_init_msbc(&sco_cb.sbc_dec, 0L);
+ sco_cb.sbc_dec.endian = SBC_LE;
#endif
}
{
int result;
- if ((result = close(vnd_userial.uart_fd[0])) < 0)
+ if ((vnd_userial.uart_fd[0] > 0) && (result = close(vnd_userial.uart_fd[0])) < 0)
ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[0], result);
if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.uart_fd[1], NULL) == -1)
ALOGE("%s unable to unregister fd %d from epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
- if ((result = close(vnd_userial.uart_fd[1])) < 0)
+ if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
+ ALOGE("%s unable to unregister signal fd %d from epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+
+ if ((vnd_userial.uart_fd[1] > 0) && (result = close(vnd_userial.uart_fd[1])) < 0)
ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[1], result);
- pthread_join(vnd_userial.thread_socket_id, NULL);
- close(vnd_userial.epoll_fd);
+ if(vnd_userial.thread_socket_id != -1)
+ pthread_join(vnd_userial.thread_socket_id, NULL);
+
+ if(vnd_userial.epoll_fd > 0)
+ close(vnd_userial.epoll_fd);
+
+ if ((vnd_userial.signal_fd[0] > 0) && (result = close(vnd_userial.signal_fd[0])) < 0)
+ ALOGE( "%s (signal fd[0]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[0], result);
+ if ((vnd_userial.signal_fd[1] > 0) && (result = close(vnd_userial.signal_fd[1])) < 0)
+ ALOGE( "%s (signal fd[1]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[1], result);
+
vnd_userial.epoll_fd = -1;
vnd_userial.uart_fd[0] = -1;
vnd_userial.uart_fd[1] = -1;
+ vnd_userial.signal_fd[0] = -1;
+ vnd_userial.signal_fd[1] = -1;
}
static void userial_uart_close(void)
{
int result;
- if ((result = close(vnd_userial.fd)) < 0)
+ if ((vnd_userial.fd > 0) && (result = close(vnd_userial.fd)) < 0)
ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.fd, result);
- pthread_join(vnd_userial.thread_uart_id, NULL);
+ if(vnd_userial.thread_uart_id != -1)
+ pthread_join(vnd_userial.thread_uart_id, NULL);
}
static void userial_coex_close(void)
int result;
if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_DEL, vnd_userial.event_fd, NULL) == -1)
- ALOGE("%s unable to unregister fd %d from epoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
+ ALOGE("%s unable to unregister fd %d from cpoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
+
+ if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
+ ALOGE("%s unable to unregister fd %d from cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
if ((result = close(vnd_userial.event_fd)) < 0)
ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.event_fd, result);
close(vnd_userial.cpoll_fd);
- pthread_join(vnd_userial.thread_coex_id, NULL);
+ if(vnd_userial.thread_coex_id != -1)
+ pthread_join(vnd_userial.thread_coex_id, NULL);
vnd_userial.cpoll_fd = -1;
vnd_userial.event_fd = -1;
}
+void userial_send_close_signal(void)
+{
+ unsigned char close_signal = 1;
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(vnd_userial.signal_fd[0], &close_signal, 1));
+}
/*******************************************************************************
**
*******************************************************************************/
void userial_vendor_close(void)
{
- //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();
+#ifdef CONFIG_SCO_OVER_HCI
+ if(sco_cb.thread_sco_running) {
+ sco_cb.thread_sco_running = false;
+ unsigned char close_signal = 1;
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
+ pthread_join(sco_cb.thread_socket_sco_id, NULL);
+ }
+#endif
+ Heartbeat_cleanup();
+ RTK_btservice_destroyed();
+ userial_send_close_signal();
userial_uart_close();
userial_coex_close();
- Heartbeat_cleanup();
-
+ userial_socket_close();
+
+ if((rtkbt_transtype & RTKBT_TRANS_UART) && (rtkbt_transtype & RTKBT_TRANS_H5)) {
+ h5_int_interface->h5_int_cleanup();
+ }
vnd_userial.fd = -1;
vnd_userial.btdriver_state = false;
sbc_finish(&sco_cb.sbc_enc);
sbc_finish(&sco_cb.sbc_dec);
#endif
- 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();
-
- }
+ ALOGD( "%s finish", __func__);
}
/*******************************************************************************
*******************************************************************************/
void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data)
{
- if(p_data == NULL)
- {
- VNDUSERIALDBG("p_data is null");
- }
+ RTK_UNUSED(p_data);
switch(op)
{
#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
*******************************************************************************/
int userial_set_port(char *p_conf_name, char *p_conf_value, int param)
{
- if(p_conf_name == NULL || param == 0)
- {
- VNDUSERIALDBG("p_conf_name is null");
- }
+ RTK_UNUSED(p_conf_name);
+ RTK_UNUSED(param);
strcpy(vnd_userial.port_name, p_conf_value);
return 0;
}
}
+static void userial_send_cmd_to_controller(unsigned char * recv_buffer, int total_length)
+{
+ if(rtkbt_transtype & RTKBT_TRANS_H4) {
+ h4_int_transmit_data(recv_buffer, total_length);
+ }
+ else {
+ h5_int_interface->h5_send_cmd(DATA_TYPE_COMMAND, &recv_buffer[1], (total_length - 1));
+ }
+ userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+static void userial_send_acl_to_controller(unsigned char * recv_buffer, int total_length)
+{
+ if(rtkbt_transtype & RTKBT_TRANS_H4) {
+ h4_int_transmit_data(recv_buffer, total_length);
+ }
+ else {
+ h5_int_interface->h5_send_acl_data(DATA_TYPE_ACL, &recv_buffer[1], (total_length - 1));
+ }
+ userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+static void userial_send_sco_to_controller(unsigned char * recv_buffer, int total_length)
+{
+ if(rtkbt_transtype & RTKBT_TRANS_H4) {
+ h4_int_transmit_data(recv_buffer, total_length);
+ }
+ else {
+ h5_int_interface->h5_send_sco_data(DATA_TYPE_SCO, &recv_buffer[1], (total_length - 1));
+ }
+ userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+
static int userial_coex_recv_data_handler(unsigned char * recv_buffer, int total_length)
{
serial_data_type_t type = 0;
//fall through
case RTKBT_PACKET_END:
+ {
len = BT_HC_HDR_SIZE + coex_resvered_length;
- p_buf = (HC_BT_HDR *) malloc(len);
+ uint8_t packet[len];
+ p_buf = (HC_BT_HDR *) packet;
p_buf->offset = 0;
p_buf->layer_specific = 0;
p_buf->len = coex_resvered_length;
acl_length = *(uint16_t *)&coex_resvered_buffer[2];
l2cap_length = *(uint16_t *)&coex_resvered_buffer[4];
boundary_flag = RTK_GET_BOUNDARY_FLAG(handle);
- if (boundary_flag == RTK_START_PACKET_BOUNDARY) {
- if(rtk_parse_manager)
- rtk_parse_manager->rtk_parse_l2cap_data(coex_resvered_buffer, 0);
- }
+ if(rtk_parse_manager)
+ rtk_parse_manager->rtk_parse_l2cap_data(coex_resvered_buffer, 0);
break;
case DATA_TYPE_SCO:
break;
}
rtk_btsnoop_capture(p_buf, true);
- free(p_buf);
+ }
break;
default:
uint16_t len, handle, acl_length, l2cap_length;
len = BT_HC_HDR_SIZE + (length - 1);
- p_buf = (HC_BT_HDR *) malloc(len);
+ uint8_t packet[len];
+ p_buf = (HC_BT_HDR *) packet;
p_buf->offset = 0;
p_buf->layer_specific = 0;
p_buf->len = total_length -1;
acl_length = *(uint16_t *)&send_buffer[3];
l2cap_length = *(uint16_t *)&send_buffer[5];
boundary_flag = RTK_GET_BOUNDARY_FLAG(handle);
- if (boundary_flag == RTK_START_PACKET_BOUNDARY) {
- if(rtk_parse_manager)
- rtk_parse_manager->rtk_parse_l2cap_data(&send_buffer[1], 1);
- }
+ if(rtk_parse_manager)
+ rtk_parse_manager->rtk_parse_l2cap_data(&send_buffer[1], 1);
break;
break;
}
rtk_btsnoop_capture(p_buf, false);
- free(p_buf);
}
-static void userial_coex_handler()//(void *context)
+static void userial_coex_handler(void *context)
{
+ RTK_UNUSED(context);
RTK_BUFFER* skb_data;
RTK_BUFFER* skb_type;
eventfd_t value;
}
#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)
+//receive sco encode or non-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_UNUSED(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;
+ int res = 0;
+ size_t writen = 0;
prctl(PR_SET_NAME, (unsigned long)"userial_recv_sco_thread", 0, 0, 0);
/*
FILE *file;
return NULL;
}
*/
- RtbEmptyQueue(sco_cb.recv_sco_data);
+ //RtbEmptyQueue(sco_cb.recv_sco_data);
+ pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+ while(RtbGetQueueLen(sco_cb.recv_sco_data) > 60) {
+ RTK_BUFFER* sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
+ if(sco_data)
+ RtbFree(sco_data);
+ }
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+
ALOGE("userial_recv_sco_thread start");
- while(sco_cb.thread_sco_running) {
- pthread_mutex_lock(&sco_cb.sco_mutex);
+ while(sco_cb.thread_recv_sco_running) {
+ pthread_mutex_lock(&sco_cb.sco_recv_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_cond_wait(&sco_cb.sco_recv_cond, &sco_cb.sco_recv_mutex);
}
- pthread_mutex_unlock(&sco_cb.sco_mutex);
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
skb_sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
if(!skb_sco_data)
continue;
p_data = skb_sco_data->Data;
+
+ if(!sco_cb.msbc_used) {
+ res = Skt_Send_noblock(sco_cb.data_fd, p_data, sco_cb.sco_packet_len);
+ if(res < 0) {
+ ALOGE("userial_recv_sco_thread, send noblock error");
+ }
+ }
+ else {
//if (fwrite(skb_sco_data->Data, 1, 60, file) != 60) {
//ALOGE("Error capturing sample");
//}
}
}
*/
- 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) {
+ 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);
+ //}
+ index = (index + 1) % 4;
+ if(index == 0) {
+ Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+ }
+ }
+ else {
+ ALOGE("msbc decode fail!");
}
- }
- else {
- ALOGE("msbc decode fail!");
}
RtbFree(skb_sco_data);
}
return NULL;
}
-static void* userial_send_sco_thread()//(void *arg)
+static void* userial_send_sco_thread(void *arg)
{
+ RTK_UNUSED(arg);
unsigned char enc_data[240];
- unsigned char pcm_data[960];
+ unsigned char pcm_data[960 * 2];
unsigned char send_data[100];
int writen = 0;
int num_read;
return NULL;
}
*/
+ //when start sco send thread, first send 6 sco data to controller
+ if(!sco_cb.msbc_used) {
+ memset(pcm_data, 0, (48*6));
+ for(i = 0; i < 6; i++) {
+ send_data[0] = DATA_TYPE_SCO;
+ send_data[3] = 48;
+ *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+ memcpy(&send_data[4], &pcm_data[i*48], 48);
+ userial_send_sco_to_controller(send_data, 52);
+ }
+ }
ALOGE("userial_send_sco_thread start");
- while(sco_cb.thread_sco_running) {
- num_read = Skt_Read(sco_cb.data_fd, pcm_data, 960 * 2);
+ while(sco_cb.thread_send_sco_running) {
+ if(!sco_cb.msbc_used) {
+ num_read = Skt_Read(sco_cb.data_fd, pcm_data, 48 * 5, &sco_cb.thread_send_sco_running);
+ if(!num_read)
+ continue;
+ 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], &pcm_data[i*48], 48);
+ userial_send_sco_to_controller(send_data, 52);
+ }
+ }
+ else {
+ num_read = Skt_Read(sco_cb.data_fd, pcm_data, 960, &sco_cb.thread_send_sco_running);
/*
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);
+ userial_send_sco_to_controller(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!");
+ if(!num_read)
+ 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, (ssize_t *)&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
+ }
}
- 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);
+ userial_send_sco_to_controller(send_data, 52);
}
}
- 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_send_socket_stop()
+{
+ ALOGE("%s", __func__);
+ pthread_mutex_lock(&sco_cb.sco_send_mutex);
+ if(sco_cb.thread_send_sco_running) {
+ sco_cb.thread_send_sco_running = false;
+ }
+ else {
+ pthread_mutex_unlock(&sco_cb.sco_send_mutex);
+ return;
+ }
+ pthread_mutex_unlock(&sco_cb.sco_send_mutex);
+
+ if(sco_cb.thread_send_sco_id != -1) {
+ pthread_join(sco_cb.thread_send_sco_id, NULL);
+ sco_cb.thread_send_sco_id = -1;
+ }
+}
+
+static void userial_sco_recv_socket_stop()
+{
+ ALOGE("%s", __func__);
+ pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+ if(sco_cb.thread_recv_sco_running) {
+ sco_cb.thread_recv_sco_running = false;
+ pthread_cond_signal(&sco_cb.sco_recv_cond);
+ }
+ else {
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+ return;
+
+ }
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+
+ if(sco_cb.thread_recv_sco_id != -1) {
+ pthread_join(sco_cb.thread_recv_sco_id, NULL);
+ sco_cb.thread_recv_sco_id = -1;
+ }
+
+}
+
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);
+ ALOGE("%s", __func__);
+ userial_sco_send_socket_stop();
+ userial_sco_recv_socket_stop();
+ if(sco_cb.ctrl_fd > 0) {
+ close(sco_cb.ctrl_fd);
+ sco_cb.ctrl_fd = -1;
+ }
+ if(sco_cb.data_fd > 0) {
+ close(sco_cb.data_fd);
+ sco_cb.data_fd = -1;
+ }
+ RtbEmptyQueue(sco_cb.recv_sco_data);
}
static void userial_sco_ctrl_skt_handle()
{
uint8_t cmd = 0, ack = 0;;
- int result = Skt_Read(sco_cb.ctrl_fd, &cmd, 1);
+ int result = Skt_Read(sco_cb.ctrl_fd, &cmd, 1, NULL);
if(result == 0) {
userial_sco_socket_stop();
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ sco_cb.thread_send_sco_running = true;
if(pthread_create(&sco_cb.thread_send_sco_id, &thread_attr, userial_send_sco_thread, NULL)!= 0 )
{
ALOGE("pthread_create : %s", strerror(errno));
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ sco_cb.thread_recv_sco_running = true;
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:
+ userial_sco_send_socket_stop();
+ break;
+
+ case SCO_CTRL_CMD_IN_STOP:
+ userial_sco_recv_socket_stop();
break;
}
break;
+ case SCO_CTRL_CMD_CLOSE:
+ userial_sco_socket_stop();
+ break;
+
default:
break;
}
}
-static void* userial_socket_sco_thread()//(void *arg)
+static void* userial_socket_sco_thread(void *arg)
{
+ RTK_UNUSED(arg);
struct sockaddr_un addr, remote;
- socklen_t alen, len = sizeof(struct sockaddr_un);
+ //socklen_t alen;
+ socklen_t len = sizeof(struct sockaddr_un);
fd_set read_set, active_set;
int result, max_fd;
int s_ctrl = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(s_ctrl < 0) {
+ ALOGE("ctrl socket create fail");
+ return NULL;
+ }
int s_data = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(s_data < 0) {
+ ALOGE("data socket create fail");
+ close(s_ctrl);
+ return NULL;
+ }
prctl(PR_SET_NAME, (unsigned long)"userial_socket_sco_thread", 0, 0, 0);
+ if((socketpair(AF_UNIX, SOCK_STREAM, 0, sco_cb.signal_fd)) < 0) {
+ ALOGE("%s, errno : %s", __func__, strerror(errno));
+ goto socket_close;
+ }
+
//bind sco ctrl socket
- unlink(SCO_CTRL_PATH);
+ //unlink(SCO_CTRL_PATH);
+
+#if 0
memset(&addr, 0, sizeof(addr));
strcpy(addr.sun_path, SCO_CTRL_PATH);
- addr.sun_family = AF_LOCAL;
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = 0;
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;
}
+#else
+ if(socket_local_server_bind(s_ctrl, SCO_CTRL_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0)
+ {
+ ALOGE("ctrl socket failed to create (%s)", strerror(errno));
+ goto signal_close;
+ }
+#endif
if(listen(s_ctrl, 5) < 0) {
ALOGE("userial_socket_sco_thread, listen ctrl socket error : %s", strerror(errno));
- return NULL;
+ goto signal_close;
}
- chmod(SCO_CTRL_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ int res = chmod(SCO_CTRL_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if(res < 0) {
+ ALOGE("chmod ctrl path fail");
+ }
//bind sco data socket
- unlink(SCO_DATA_PATH);
+ //unlink(SCO_DATA_PATH);
+#if 0
memset(&addr, 0, sizeof(addr));
strcpy(addr.sun_path, SCO_DATA_PATH);
- addr.sun_family = AF_LOCAL;
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = 0;
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;
}
+#else
+ if(socket_local_server_bind(s_data, SCO_DATA_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0)
+ {
+ ALOGE("data socket failed to create (%s)", strerror(errno));
+ goto signal_close;
+ }
+
+#endif
if(listen(s_data, 5) < 0) {
ALOGE("userial_socket_sco_thread, listen data socket error : %s", strerror(errno));
- return NULL;
+ goto signal_close;
+ }
+ res = chmod(SCO_DATA_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if(res < 0) {
+ ALOGE("chmod data path fail");
}
- 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;
-
+ FD_SET(sco_cb.signal_fd[1], &active_set);
+ max_fd = MAX(s_ctrl, s_data);
+ max_fd = MAX(max_fd, sco_cb.signal_fd[1]) + 1;
while(sco_cb.thread_sco_running) {
read_set = active_set;
result = select(max_fd, &read_set, NULL, NULL, NULL);
continue;
}
if(FD_ISSET(s_ctrl, &read_set)) {
+ if(sco_cb.ctrl_fd > 0) {
+ ALOGE("Already has connect a control fd: %d", sco_cb.ctrl_fd);
+ FD_SET(sco_cb.ctrl_fd, &read_set);
+ close(sco_cb.ctrl_fd);
+ }
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;
+ continue;
}
const int size = (512);
setsockopt(sco_cb.ctrl_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
}
if(FD_ISSET(s_data, &read_set)) {
+ if(sco_cb.data_fd > 0) {
+ ALOGE("Already has connect a control fd: %d", sco_cb.data_fd);
+ close(sco_cb.data_fd);
+ }
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;
+ ALOGE("socket accept failed (%s)", strerror(errno));
+ continue;
}
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)) {
+ if(sco_cb.ctrl_fd > 0 && FD_ISSET(sco_cb.ctrl_fd, &read_set)) {
userial_sco_ctrl_skt_handle();
}
}
+
+ userial_sco_socket_stop();
+signal_close:
+ close(sco_cb.signal_fd[0]);
+ close(sco_cb.signal_fd[1]);
+socket_close:
close(s_ctrl);
close(s_data);
+
+ memset(&addr, 0, sizeof(addr));
+ strcpy((addr.sun_path + 1), SCO_DATA_PATH);
+ addr.sun_path[0] = 0;
+ unlink(addr.sun_path);
+
+ memset(&addr, 0, sizeof(addr));
+ strcpy((addr.sun_path + 1), SCO_CTRL_PATH);
+ addr.sun_path[0] = 0;
+ unlink(addr.sun_path);
+ ALOGE("userial_socket_sco_thread exit");
return NULL;
}
#ifdef RTK_HANDLE_CMD
static void userial_handle_cmd(unsigned char * recv_buffer, int total_length)
{
+ RTK_UNUSED(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);
+ char prop_value[100];
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;
+ if(scan_win > 20){
+ if((scan_int/scan_win) > 2) {
+ *(uint16_t*)&recv_buffer[4] = (scan_int * 20) / scan_win;
+ *(uint16_t*)&recv_buffer[6] = 20;
+ }
+ else {
+ *(uint16_t*)&recv_buffer[4] = 40;
+ *(uint16_t*)&recv_buffer[6] = 20;
+ }
+ }
+ else if(scan_win == scan_int) {
+ *(uint16_t*)&recv_buffer[4] = (scan_int * 5) & 0xFE;
+ }
+ else if((scan_int/scan_win) <= 2) {
+ *(uint16_t*)&recv_buffer[4] = (scan_int * 3) & 0xFE;
}
break;
+ case HCI_LE_SET_EXTENDED_SCAN_PARAMETERS:
+ scan_int = *(uint16_t*)&recv_buffer[7];
+ scan_win = *(uint16_t*)&recv_buffer[9];
+ if(scan_win > 20){
+ if((scan_int/scan_win) > 2) {
+ *(uint16_t*)&recv_buffer[7] = (scan_int * 20) / scan_win;
+ *(uint16_t*)&recv_buffer[9] = 20;
+ }
+ else {
+ *(uint16_t*)&recv_buffer[7] = 40;
+ *(uint16_t*)&recv_buffer[9] = 20;
+ }
+ }
+ else if(scan_win == scan_int) {
+ *(uint16_t*)&recv_buffer[7] = (scan_int * 5) & 0xFE;
+ }
+ else if((scan_int/scan_win) <= 2) {
+ *(uint16_t*)&recv_buffer[9] = (scan_int * 3) & 0xFE;
+ }
+
+ break;
case HCI_WRITE_VOICE_SETTINGS :
voice_settings = *(uint16_t*)&recv_buffer[3];
- userial_vendor_usb_ioctl(SET_ISO_CFG, &voice_settings);
+ if(rtkbt_transtype & RTKBT_TRANS_USB) {
+ userial_vendor_usb_ioctl(SET_ISO_CFG, &voice_settings);
+ }
#ifdef CONFIG_SCO_OVER_HCI
sco_cb.voice_settings = voice_settings;
#endif
#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));
- }
+ sco_cb.ctrl_fd = -1;
+ sco_cb.data_fd = -1;
break;
#endif
+ case HCI_SET_EVENT_MASK:
+ ALOGE("set event mask, it should bt stack init, set coex bt on");
+ if(rtk_parse_manager) {
+ rtk_parse_manager->rtk_set_bt_on(1);
+ }
+ Heartbeat_init();
+ break;
+
+ case HCI_ACCEPT_CONNECTION_REQUEST:
+ property_get("persist.vendor.bluetooth.prefferedrole", prop_value, "none");
+ if(strcmp(prop_value, "none") != 0) {
+ int role = recv_buffer[9];
+ if(role == 0x01 && (strcmp(prop_value, "master") == 0))
+ recv_buffer[9] = 0x00;
+ else if(role == 0x00 && (strcmp(prop_value, "slave") == 0))
+ recv_buffer[9] = 0x01;
+ }
+ break;
+
+ case HCI_BLE_WRITE_ADV_PARAMS:
+ {
+ if(rtkbt_version.hci_version> HCI_PROTO_VERSION_4_2) {
+ break;
+ }
+ rtkbt_adv_con.adverting_type = recv_buffer[7];
+ property_get("persist.vendor.rtkbtadvdisable", prop_value, "false");
+ if(rtkbt_adv_con.adverting_type == 0x00 && (strcmp(prop_value, "true") == 0)) {
+ recv_buffer[7] = 0x03;
+ rtkbt_adv_con.adverting_type = 0x03;
+ }
+ }
+ break;
+ case HCI_BLE_WRITE_ADV_ENABLE:
+ {
+ if(rtkbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+ break;
+ }
+ if(recv_buffer[2] == 0x01) {
+ rtkbt_adv_con.adverting_start = TRUE;
+ }
+ else if(recv_buffer[2] == 0x00) {
+ rtkbt_adv_con.adverting_type = 0;
+ rtkbt_adv_con.adverting_enable = FALSE;
+ rtkbt_adv_con.adverting_start = FALSE;
+ }
+ }
+ break;
+ case HCI_BLE_CREATE_LL_CONN:
+ if(rtkbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+ break;
+ }
+ if(rtkbt_adv_con.adverting_enable &&
+ ((rtkbt_adv_con.adverting_type == 0x00) ||
+ (rtkbt_adv_con.adverting_type == 0x01) ||
+ (rtkbt_adv_con.adverting_type == 0x04))) {
+ uint8_t disable_adv_cmd[5] = {0x01, 0x0A, 0x20, 0x01, 0x00};
+ rtkbt_adv_con.adverting_enable = FALSE;
+ userial_send_cmd_to_controller(disable_adv_cmd, 5);
+ }
+ break;
default:
break;
}
//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)
+static void userial_recv_H4_rawdata(void *context)
{
+ RTK_UNUSED(context);
serial_data_type_t type = 0;
ssize_t bytes_read;
uint16_t opcode;
transmitted_length = h5_int_interface->h5_send_cmd(type, &h4_read_buffer[1], h4_read_length);
}
}
+ userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
break;
case DATA_TYPE_ACL:
- if(rtkbt_transtype & RTKBT_TRANS_H4) {
- h4_int_transmit_data(h4_read_buffer, (h4_read_length + 1));
- }
- else {
- transmitted_length = h5_int_interface->h5_send_acl_data(type, &h4_read_buffer[1], h4_read_length);
- }
+ userial_send_acl_to_controller(h4_read_buffer, (h4_read_length + 1));
break;
case DATA_TYPE_SCO:
- if(rtkbt_transtype & RTKBT_TRANS_H4) {
- h4_int_transmit_data(h4_read_buffer, (h4_read_length + 1));
- }
- else {
- transmitted_length = h5_int_interface->h5_send_sco_data(type, &h4_read_buffer[1], h4_read_length);
- }
+ userial_send_sco_to_controller(h4_read_buffer, (h4_read_length + 1));
break;
default:
ALOGE("%s invalid data type: %d", __func__, current_type);
+ userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
break;
}
-
- userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
break;
default:
#ifdef RTK_HANDLE_EVENT
static void userial_handle_event(unsigned char * recv_buffer, int total_length)
{
+ RTK_UNUSED(total_length);
uint8_t event;
uint8_t *p_data = recv_buffer;
event = p_data[0];
- if(total_length == 0)
+ switch (event) {
+ case HCI_COMMAND_COMPLETE_EVT:
{
- ALOGD("total_length %d",total_length);
+ uint16_t opcode = *((uint16_t*)&p_data[3]);
+ uint8_t* stream = &p_data[6];
+ if(opcode == HCI_READ_LOCAL_VERSION_INFO) {
+ STREAM_TO_UINT8(rtkbt_version.hci_version, stream);
+ STREAM_TO_UINT16(rtkbt_version.hci_revision, stream);
+ STREAM_TO_UINT8(rtkbt_version.lmp_version, stream);
+ STREAM_TO_UINT16(rtkbt_version.manufacturer, stream);
+ STREAM_TO_UINT16(rtkbt_version.lmp_subversion, stream);
+ }
+ else if(opcode == HCI_BLE_WRITE_ADV_ENABLE){
+ if(rtkbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+ break;
+ }
+ if(rtkbt_adv_con.adverting_start &&(p_data[5] == HCI_SUCCESS)) {
+ rtkbt_adv_con.adverting_enable = TRUE;
+ rtkbt_adv_con.adverting_start = FALSE;
+ }
+ }
}
+ break;
#ifdef CONFIG_SCO_OVER_HCI
- if(event == HCI_ESCO_CONNECTION_COMP_EVT) {
+ case 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);
+ sco_cb.thread_recv_sco_running = false;
+ sco_cb.thread_send_sco_running = false;
+ sco_cb.data_fd = -1;
+ sco_cb.ctrl_fd = -1;
}
else {
sco_cb.sco_handle = *((uint16_t *)&p_data[3]);
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ sco_cb.thread_sco_running = true;
+ sco_cb.thread_recv_sco_running = false;
+ sco_cb.thread_send_sco_running = false;
+ sco_cb.data_fd = -1;
+ sco_cb.ctrl_fd = -1;
+ if(pthread_create(&sco_cb.thread_socket_sco_id, &thread_attr, userial_socket_sco_thread, NULL)!= 0 )
+ {
+ ALOGE("pthread_create : %s", strerror(errno));
+ }
+
+ RtbEmptyQueue(sco_cb.recv_sco_data);
if(!(sco_cb.voice_settings & 0x0003)) {
- sco_cb.sco_packet_len = 240;
+ sco_cb.sco_packet_len = 240; //every 5 cvsd packets form a sco pcm data
sco_cb.msbc_used = false;
}
else {
ALOGE("userial_handle_event sco_handle: %d",sco_cb.sco_handle);
}
- if(event == HCI_DISCONNECTION_COMP_EVT) {
+ break;
+
+ case HCI_DISCONNECTION_COMP_EVT: {
if((*((uint16_t *)&p_data[3])) == sco_cb.sco_handle) {
sco_cb.sco_handle = 0;
sco_cb.msbc_used = false;
+ RtbEmptyQueue(sco_cb.recv_sco_data);
+ if(sco_cb.thread_sco_running) {
+ sco_cb.thread_sco_running = false;
+ unsigned char close_signal = 1;
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
+ }
}
}
+ break;
#endif
+ default :
+ break;
+ }
}
#ifdef CONFIG_SCO_OVER_HCI
-static void userial_enqueue_sco_data(unsigned char * recv_buffer, int total_length)
+static void userial_enqueue_recv_sco_data(unsigned char * recv_buffer, int total_length)
{
+ RTK_UNUSED(total_length);
uint16_t sco_handle;
uint8_t sco_length;
uint8_t *p_data = recv_buffer;
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);
+ RtbAddTail(skb_sco_data, sco_packet_len);
+ pthread_mutex_lock(&sco_cb.sco_recv_mutex);
RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
- pthread_cond_signal(&sco_cb.sco_cond);
- pthread_mutex_unlock(&sco_cb.sco_mutex);
+ pthread_cond_signal(&sco_cb.sco_recv_cond);
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
sco_cb.current_pos = 0;
p_data += (sco_packet_len - current_pos);
}
}
+ //if use cvsd codec
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);
+ RtbAddTail(skb_sco_data, 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);
+ pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+ pthread_cond_signal(&sco_cb.sco_recv_cond);
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
}
i = (sco_length % sco_packet_len);
}
return;
}
+
+ //use msbc codec
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_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);
+ RtbAddTail(skb_sco_data, sco_packet_len);
+ pthread_mutex_lock(&sco_cb.sco_recv_mutex);
RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
- pthread_cond_signal(&sco_cb.sco_cond);
- pthread_mutex_unlock(&sco_cb.sco_mutex);
+ pthread_cond_signal(&sco_cb.sco_recv_cond);
+ pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
sco_cb.current_pos = 0;
i += (sco_packet_len - 1);
}
#endif
-static int userial_handle_recv_data(unsigned char * recv_buffer, int total_length)
+static int userial_handle_recv_data(unsigned char * recv_buffer, unsigned int total_length)
{
serial_data_type_t type = 0;
unsigned char * p_data = recv_buffer;
- int length = total_length;
+ unsigned int length = total_length;
uint8_t event;
+ if(!length){
+ ALOGE("%s, length is 0, return immediately", __func__);
+ return total_length;
+ }
switch (received_packet_state) {
case RTKBT_PACKET_IDLE:
received_packet_bytes_need = 1;
case RTKBT_PACKET_CONTENT:
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;
+ if(received_resvered_length == 2) {
+ if(length >= 1) {
+ *p_data = 1;
+ }
}
}
else if(event == HCI_COMMAND_STATUS_EVT) {
- if(length >= 2) {
- *(p_data + 1) = 1;
+ if(received_resvered_length < 4) {
+ unsigned int act_len = 4 - received_resvered_length;
+ if(length >= act_len) {
+ *(p_data + act_len -1) = 1;
+ }
}
}
}
//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;
-
+#ifdef CONFIG_SCO_OVER_HCI
case DATA_TYPE_SCO :
- userial_enqueue_sco_data(received_resvered_header, received_resvered_length);
+ userial_enqueue_recv_sco_data(received_resvered_header, received_resvered_length);
break;
-
+#endif
default :
break;
}
-#endif
break;
default:
static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length)
{
unsigned char buffer[1028] = {0};
- unsigned int length = 0;
+ int length = 0;
length = h5_int_interface->h5_int_read_data(&buffer[1], total_length);
+ if(length == -1) {
+ ALOGE("%s, error read length", __func__);
+ assert(length != -1);
+ }
buffer[0] = type;
length++;
uint16_t transmitted_length = 0;
unsigned int read_length = 0;
do {
read_length += userial_handle_recv_data(buffer + read_length, real_length - read_length);
- }while(read_length < total_length);
+ }while(vnd_userial.thread_running && read_length < total_length);
#endif
while (length > 0) {
unsigned int read_length = 0;
do {
read_length += userial_handle_recv_data(buffer + read_length, total_length - read_length);
-
}while(read_length < total_length);
#endif
- while (length > 0) {
+ while (length > 0 && vnd_userial.thread_running) {
ssize_t ret;
RTK_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
switch (ret) {
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);
- }
+ uint16_t transmitted_length = 0;
+ unsigned int real_length = total_length;
+
+ while (vnd_userial.thread_running && (total_length > 0)) {
+ ssize_t ret;
+ RTK_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, total_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;
+ total_length -= ret;
+ break;
+ }
+ }
+ done:;
+ if(real_length && vnd_userial.thread_running)
+ userial_enqueue_coex_rawdata(buffer, real_length, true);
+ return;
+
}
-static void* userial_recv_socket_thread()//(void *arg)
+static void* userial_recv_socket_thread(void *arg)
{
+ RTK_UNUSED(arg);
struct epoll_event events[64];
int j;
while(vnd_userial.thread_running) {
do{
ret = epoll_wait(vnd_userial.epoll_fd, events, 32, 500);
}while(vnd_userial.thread_running && ret == -1 && errno == EINTR);
+
if (ret == -1) {
ALOGE("%s error in epoll_wait: %s", __func__, strerror(errno));
}
}
}
}
+ vnd_userial.thread_socket_id = -1;
ALOGD("%s exit", __func__);
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;
- pfd.fd = vnd_userial.fd;
+ RTK_UNUSED(arg);
+ struct pollfd pfd[2];
+ pfd[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
+ pfd[0].fd = vnd_userial.signal_fd[1];
+ pfd[1].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
+ pfd[1].fd = vnd_userial.fd;
int ret;
unsigned char read_buffer[2056] = {0};
ssize_t bytes_read;
while(vnd_userial.thread_running) {
do{
- ret = poll(&pfd, 1, 50);
+ ret = poll(pfd, 2, 500);
}while(ret == -1 && errno == EINTR && vnd_userial.thread_running);
- if (pfd.revents & POLLIN) {
+ //exit signal is always at first index
+ if(pfd[0].revents && !vnd_userial.thread_running) {
+ ALOGE("receive exit signal and stop thread ");
+ return NULL;
+ }
+
+ if (pfd[1].revents & POLLIN) {
RTK_NO_INTR(bytes_read = read(vnd_userial.fd, read_buffer, sizeof(read_buffer)));
if(!bytes_read)
continue;
+ if(bytes_read < 0) {
+ ALOGE("%s, read fail, error : %s", __func__, strerror(errno));
+ continue;
+ }
if(rtkbt_transtype & RTKBT_TRANS_H5) {
h5_int_interface->h5_recv_msg(read_buffer, bytes_read);
}
}
- if (pfd.revents & (POLLERR|POLLHUP)) {
+ if (pfd[1].revents & (POLLERR|POLLHUP)) {
ALOGE("%s poll error, fd : %d", __func__, vnd_userial.fd);
vnd_userial.btdriver_state = false;
close(vnd_userial.fd);
continue;
}
}
+ vnd_userial.thread_uart_id = -1;
ALOGD("%s exit", __func__);
return NULL;
}
-static void* userial_coex_thread()//(void *arg)
+static void* userial_coex_thread(void *arg)
{
+ RTK_UNUSED(arg);
struct epoll_event events[64];
int j;
while(vnd_userial.thread_running) {
}
}
}
+ vnd_userial.thread_coex_id = -1;
ALOGD("%s exit", __func__);
return NULL;
}
return ret;
}
+ if((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.signal_fd)) < 0) {
+ ALOGE("%s, errno : %s", __func__, strerror(errno));
+ return ret;
+ }
+
vnd_userial.epoll_fd = epoll_create(64);
if (vnd_userial.epoll_fd == -1) {
ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.uart_fd[1], &event) == -1) {
ALOGE("%s unable to register fd %d to epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
close(vnd_userial.epoll_fd);
+ vnd_userial.epoll_fd = -1;
return -1;
}
+ event.data.ptr = NULL;
+ if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
+ ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+ close(vnd_userial.epoll_fd);
+ vnd_userial.epoll_fd = -1;
+ return -1;
+ }
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
{
ALOGE("pthread_create : %s", strerror(errno));
close(vnd_userial.epoll_fd);
+ vnd_userial.epoll_fd = -1;
+ vnd_userial.thread_socket_id = -1;
return -1;
}
close(vnd_userial.epoll_fd);
vnd_userial.thread_running = false;
pthread_join(vnd_userial.thread_socket_id, NULL);
+ vnd_userial.thread_socket_id = -1;
return -1;
}
assert(false);
}
+ event.data.ptr = NULL;
+ if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
+ ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+ assert(false);
+ }
+
if (pthread_create(&vnd_userial.thread_coex_id, &thread_attr, userial_coex_thread, NULL) !=0 )
{
ALOGE("pthread create coex : %s", strerror(errno));
+ vnd_userial.thread_coex_id = -1;
assert(false);
}
}
+
ret = vnd_userial.uart_fd[0];
return ret;
}
{
int retval;
retval = ioctl(vnd_userial.fd, operation, param);
+ if(retval == -1)
+ ALOGE("%s: error: %d : %s", __func__,errno, strerror(errno));
return retval;
}
$(LOCAL_PATH)/Firmware/BT/rtl8822b_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822b_fw \
$(LOCAL_PATH)/Firmware/BT/rtl8822bs_config:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822bs_config \
$(LOCAL_PATH)/Firmware/BT/rtl8822bs_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822bs_fw \
+ $(LOCAL_PATH)/Firmware/BT/rtl8822c_config:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822c_config \
+ $(LOCAL_PATH)/Firmware/BT/rtl8822c_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822c_fw \
+ $(LOCAL_PATH)/Firmware/BT/rtl8822cs_config:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822cs_config \
+ $(LOCAL_PATH)/Firmware/BT/rtl8822cs_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8822cs_fw \
+ $(LOCAL_PATH)/Firmware/BT/rtl8761b_config:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8761b_config \
+ $(LOCAL_PATH)/Firmware/BT/rtl8761b_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8761b_fw \
+ $(LOCAL_PATH)/Firmware/BT/rtl8761bt_config:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8761bt_config \
+ $(LOCAL_PATH)/Firmware/BT/rtl8761bt_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8761bt_fw \
+ $(LOCAL_PATH)/Firmware/BT/rtl8725a_config:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8725a_config \
+ $(LOCAL_PATH)/Firmware/BT/rtl8725a_fw:$(TARGET_COPY_OUT_VENDOR)/firmware/rtl8725a_fw \
+
+
FW CUT SVN Coex
-rtl8761au8192ee_fw D 19653 0006
-rtl8761au_fw D 19653 0006
+rtl8761au8192ee_fw D 20411 0007
+rtl8761au_fw D 20411 0007
rtl8723c_fw B 16592 0700
rtl8703cs_fw C 17903 0a0a
-rtl8761aw8192eu_fw D 19653 0006
+rtl8761aw8192eu_fw D 20411 0007
rtl8761at8812ae_fw D 19653 0006
-rtl8723ds_fw C 19297 1616
-rtl8703bs_fw B 19297 1600
-rtl8822b_fw C 19664 4b4b
-rtl8821cs_fw B 19504 1616
-rtl8761at_fw D 19653 0006
+rtl8723ds_fw C 21291 2d2d
+rtl8761bt_fw B 21430 0909
+rtl8703bs_fw B 20010 1c00
+rtl8822b_fw C 21253 6c6c
+rtl8821cs_fw B 21209 3939
+rtl8761at_fw D 20411 0007
+rtl8822c_fw D 21479 0a0a
+rtl8761b_fw B 21475 0a0a
rtl8761au8812ae_fw D 19653 0006
rtl8821as_fw B 19132 635d
rtl8821a_fw B 19132 635d
-rtl8723bs_fw B 19587 6b4e
-rtl8723b_fw B 19587 6b4e
+rtl8723bs_fw B 19897 6d50
+rtl8725a_fw B 21430 0909
+rtl8723b_fw B 19897 6d50
rtl8723cs_vf_fw B 15854 5844
rtl8703as_fw B 12234 473d
-rtl8723cs_xx_fw B 19602 1600
-rtl8821c_fw B 19504 1616
-rtl8822bs_fw C 19664 4b4b
-rtl8723d_fw C 19297 1616
+rtl8822cs_fw D 21479 0a0a
+rtl8723cs_xx_fw B 19927 1c00
+rtl8821c_fw B 21209 3939
+rtl8822bs_fw C 21253 6c6c
+rtl8723d_fw C 21291 2d2d
rtl8723cs_cg_fw B 15854 5844
-rtl8761at8192ee_fw D 19653 0006
+rtl8761at8192ee_fw D 20411 0007
rtl8723bs_VQ0_fw B 16527 6549