* [PATCH v5 04/16] sbc: add odd member variable to sbc_encoder_state
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
sbc/sbc_primitives.c | 2 ++
sbc/sbc_primitives.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index dce0ed2..0b48ddb 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -521,6 +521,8 @@ static int sbc_calc_scalefactors_j(
*/
void sbc_init_primitives(struct sbc_encoder_state *state)
{
+ state->odd = 1;
+
/* Default implementation for analyze functions */
state->sbc_analyze_4s = sbc_analyze_4b_4s_simd;
state->sbc_analyze_8s = sbc_analyze_4b_8s_simd;
diff --git a/sbc/sbc_primitives.h b/sbc/sbc_primitives.h
index 267c277..ffee339 100644
--- a/sbc/sbc_primitives.h
+++ b/sbc/sbc_primitives.h
@@ -40,6 +40,7 @@ struct sbc_encoder_state {
int position;
/* Number of consecutive blocks handled by the encoder */
int increment;
+ int odd;
int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE];
/* Polyphase analysis filter for 4 subbands configuration,
* it handles "increment" blocks at once */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 05/16] sbc: Add mmx primitive for 1b 8s analysis
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
sbc/sbc_primitives_mmx.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/sbc/sbc_primitives_mmx.c b/sbc/sbc_primitives_mmx.c
index 03070f5..21d7b74 100644
--- a/sbc/sbc_primitives_mmx.c
+++ b/sbc/sbc_primitives_mmx.c
@@ -276,6 +276,19 @@ static inline void sbc_analyze_4b_8s_mmx(struct sbc_encoder_state *state,
__asm__ volatile ("emms\n");
}
+static inline void sbc_analyze_1b_8s_mmx(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ if (state->odd)
+ sbc_analyze_eight_mmx(x, out, analysis_consts_fixed8_simd_odd);
+ else
+ sbc_analyze_eight_mmx(x, out, analysis_consts_fixed8_simd_even);
+
+ state->odd = !state->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],
@@ -366,7 +379,10 @@ void sbc_init_primitives_mmx(struct sbc_encoder_state *state)
{
if (check_mmx_support()) {
state->sbc_analyze_4s = sbc_analyze_4b_4s_mmx;
- state->sbc_analyze_8s = sbc_analyze_4b_8s_mmx;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_mmx;
state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
state->implementation_info = "MMX";
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 06/16] sbc: Add armv6 primitive for 1b 8s analysis
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
sbc/sbc_primitives_armv6.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/sbc/sbc_primitives_armv6.c b/sbc/sbc_primitives_armv6.c
index 068648a..a2cb2a8 100644
--- a/sbc/sbc_primitives_armv6.c
+++ b/sbc/sbc_primitives_armv6.c
@@ -291,10 +291,26 @@ static void sbc_analyze_4b_8s_armv6(struct sbc_encoder_state *state,
sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
}
+static void sbc_analyze_1b_8s_armv6(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ if (state->odd)
+ sbc_analyze_eight_armv6(x, out,
+ analysis_consts_fixed8_simd_odd);
+ else
+ sbc_analyze_eight_armv6(x, out,
+ analysis_consts_fixed8_simd_even);
+
+ state->odd = !state->odd;
+}
+
void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
{
state->sbc_analyze_4s = sbc_analyze_4b_4s_armv6;
- state->sbc_analyze_8s = sbc_analyze_4b_8s_armv6;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_armv6;
state->implementation_info = "ARMv6 SIMD";
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 07/16] sbc: Add iwmmxt primitive for 1b 8s encoding
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
sbc/sbc_primitives_iwmmxt.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/sbc/sbc_primitives_iwmmxt.c b/sbc/sbc_primitives_iwmmxt.c
index 0c8f329..44bfd47 100644
--- a/sbc/sbc_primitives_iwmmxt.c
+++ b/sbc/sbc_primitives_iwmmxt.c
@@ -294,10 +294,26 @@ static inline void sbc_analyze_4b_8s_iwmmxt(struct sbc_encoder_state *state,
sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even);
}
+static inline void sbc_analyze_1b_8s_iwmmxt(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ if (state->odd)
+ sbc_analyze_eight_iwmmxt(x, out,
+ analysis_consts_fixed8_simd_odd);
+ else
+ sbc_analyze_eight_iwmmxt(x, out,
+ analysis_consts_fixed8_simd_even);
+
+ state->odd = !state->odd;
+}
+
void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state)
{
state->sbc_analyze_4s = sbc_analyze_4b_4s_iwmmxt;
- state->sbc_analyze_8s = sbc_analyze_4b_8s_iwmmxt;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt;
+ else
+ state->sbc_analyze_8s = sbc_analyze_4b_8s_iwmmxt;
state->implementation_info = "IWMMXT";
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 08/16] sbc: Add plain C primitive for 1b 8s analysis
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
sbc/sbc_primitives.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index 0b48ddb..a4767ef 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -209,6 +209,19 @@ static inline void sbc_analyze_4b_8s_simd(struct sbc_encoder_state *state,
sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even);
}
+static inline void sbc_analyze_1b_8s_simd(struct sbc_encoder_state *state,
+ int16_t *x, int32_t *out, int out_stride)
+{
+ if (state->odd)
+ sbc_analyze_eight_simd(x, out,
+ analysis_consts_fixed8_simd_odd);
+ else
+ sbc_analyze_eight_simd(x, out,
+ analysis_consts_fixed8_simd_even);
+
+ state->odd = !state->odd;
+}
+
static inline int16_t unaligned16_be(const uint8_t *ptr)
{
return (int16_t) ((ptr[0] << 8) | ptr[1]);
@@ -525,7 +538,10 @@ void sbc_init_primitives(struct sbc_encoder_state *state)
/* Default implementation for analyze functions */
state->sbc_analyze_4s = sbc_analyze_4b_4s_simd;
- state->sbc_analyze_8s = sbc_analyze_4b_8s_simd;
+ if (state->increment == 1)
+ state->sbc_analyze_8s = sbc_analyze_1b_8s_simd;
+ 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;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 09/16] sbc: Use plain C primitive if doing msbc on neon
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
neon has it's own optimized input reordering. Until this code gets optimized,
the neon assembly code will not work with the mSBC input reordering.
However, the plain C version of mSBC can be used in this case.
This patch makes use of plain C code if the block increment is 1 which is
typical for mSBC.
---
sbc/sbc_primitives.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index a4767ef..319e625 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -568,5 +568,13 @@ void sbc_init_primitives(struct sbc_encoder_state *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;
+ 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
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 10/16] sbc: Fix input reordering for 15 blocks case
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
SBC analysis handles 8 samples at a time. The optimisation requires 8 samples
forming an "odd" block, followed by 8 samples, forming an "even" block. Until
now SBC was used for encoding 4, 8, 12, or 16 blocks in a frame. Reordering
took a frame and for each 16 samples (ie 2 blocks) it produced one "odd" block
and one "even" block.
A mSBC frame encodes 15 blocks of 8 samples. 14 blocks are processed as before,
two at a time. If 8 samples are remaining, it will form the first half of two
blocks (a bit of an "odd" block, and a bit of an "even" block). When processing
the next frame, we detect eight samples were missing at previous iteration and
the two block can be finished.
This reordering is possible because only one sample is moved (x[-7]) AND the
first coefficient in the coef table is 0. Thus x[0] doesn't need to be set and
0 can be used in calculation instead. Note that x[-7] is not used in
analysis for this block.
see: analysis_consts_fixed8_simd_odd.
To detect that two blocks are not completed, the number of processed samples
can be used. This value is stored in position. position starts at
SBC_X_BUFFER_SIZE-72 and is decremented by 16 as long as two blocks can be
formed. If only 8 samples are remaining in input, then position is decremented
by 8 *arbitrarly*, thus indicating that some samples are pending. During next
frame reordering, position will be decremented by 8 again, back to a 16
multiple.
This logic works for SBC_X_BUFFER_SIZE-72 multiple of 16 and bigger than
8*2*15+72=312 and less than 8*3*15+72=432. The current value of 328 matches this
constraint and X buffer is shifted every two frames (30 blocks) in mSBC. This
way, we don't need to care about x[-7] when shifting, we also know that it
won't be before X.
---
sbc/sbc_primitives.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index 319e625..8933132 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -309,8 +309,37 @@ static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal(
#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) >= 0) {
+ while (nsamples >= 16) {
position -= 16;
if (nchannels > 0) {
int16_t *x = &X[0][position];
@@ -351,6 +380,33 @@ static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal(
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
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 11/16] sbc: Add SBC_MSBC flag to enable 15 block encoding
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
The sbc API provides a flag parameter which is currently unused. This patch
defines the SBC_MSBC flag. The meaning of this flag is to encode 15 blocks.
---
sbc/sbc.c | 35 +++++++++++++++++++++++++++--------
sbc/sbc.h | 3 +++
2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/sbc/sbc.c b/sbc/sbc.c
index ffdf05d..ead25da 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -52,6 +52,9 @@
#define SBC_SYNCWORD 0x9C
+#define MSBC_SYNCWORD 0xAD
+#define MSBC_BLOCKS 15
+
/* This structure contains an unpacked SBC frame.
Yes, there is probably quite some unused space herein */
struct sbc_frame {
@@ -903,12 +906,15 @@ static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len
}
}
-static void sbc_encoder_init(struct sbc_encoder_state *state,
- const struct sbc_frame *frame)
+static void sbc_encoder_init(unsigned long flags,
+ 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;
- state->increment = 4;
+ if (flags & SBC_MSBC)
+ state->increment = 1;
+ else
+ state->increment = 4;
sbc_init_primitives(state);
}
@@ -922,6 +928,7 @@ struct sbc_priv {
static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
{
+ sbc->flags = flags;
sbc->frequency = SBC_FREQ_44100;
sbc->mode = SBC_MODE_STEREO;
sbc->subbands = SBC_SB_8;
@@ -1057,12 +1064,15 @@ SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
priv->frame.subband_mode = sbc->subbands;
priv->frame.subbands = sbc->subbands ? 8 : 4;
priv->frame.block_mode = sbc->blocks;
- priv->frame.blocks = 4 + (sbc->blocks * 4);
+ if (sbc->flags & SBC_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->enc_state, &priv->frame);
+ sbc_encoder_init(sbc->flags, &priv->enc_state, &priv->frame);
priv->init = 1;
} else if (priv->frame.bitpool != sbc->bitpool) {
priv->frame.length = sbc_get_frame_length(sbc);
@@ -1141,7 +1151,10 @@ SBC_EXPORT size_t sbc_get_frame_length(sbc_t *sbc)
return priv->frame.length;
subbands = sbc->subbands ? 8 : 4;
- blocks = 4 + (sbc->blocks * 4);
+ if (sbc->flags & SBC_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;
@@ -1165,7 +1178,10 @@ SBC_EXPORT unsigned sbc_get_frame_duration(sbc_t *sbc)
priv = sbc->priv;
if (!priv->init) {
subbands = sbc->subbands ? 8 : 4;
- blocks = 4 + (sbc->blocks * 4);
+ if (sbc->flags & SBC_MSBC)
+ blocks = MSBC_BLOCKS;
+ else
+ blocks = 4 + (sbc->blocks * 4);
} else {
subbands = priv->frame.subbands;
blocks = priv->frame.blocks;
@@ -1202,7 +1218,10 @@ SBC_EXPORT size_t sbc_get_codesize(sbc_t *sbc)
priv = sbc->priv;
if (!priv->init) {
subbands = sbc->subbands ? 8 : 4;
- blocks = 4 + (sbc->blocks * 4);
+ if (sbc->flags & SBC_MSBC)
+ blocks = MSBC_BLOCKS;
+ else
+ blocks = 4 + (sbc->blocks * 4);
channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
} else {
subbands = priv->frame.subbands;
diff --git a/sbc/sbc.h b/sbc/sbc.h
index bbd45da..3511119 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -64,6 +64,9 @@ extern "C" {
#define SBC_LE 0x00
#define SBC_BE 0x01
+/* Additional features */
+#define SBC_MSBC 0x01
+
struct sbc_struct {
unsigned long flags;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 12/16] sbc: Add support for mSBC frame header
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
Traditionnal SBC frame header describe encoding parameters for each frame: nr
of blocks, subbands, allocation method, and bitpool. In mSBC, only one
combination of parameter is defined. That combination cannot be expressed using
a traditionnal SBC header. Because of this, a specific header is defined with
0xAD followed by two reserved zero bytes.
---
sbc/sbc.c | 228 +++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 138 insertions(+), 90 deletions(-)
diff --git a/sbc/sbc.c b/sbc/sbc.c
index ead25da..af45e65 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -377,8 +377,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
* -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)
+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
@@ -393,59 +393,6 @@ static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
int bits[2][8]; /* bits distribution */
uint32_t levels[2][8]; /* levels derived from that */
- 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;
-
- /* data[3] is crc, we're checking it later */
-
consumed = 32;
crc_header[0] = data[1];
@@ -546,6 +493,90 @@ static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
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)
{
@@ -790,38 +821,6 @@ static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
uint32_t levels[2][8]; /* levels are derived from that */
uint32_t sb_sample_delta[2][8];
- 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;
-
- 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->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;
-
/* Can't fill in crc yet */
crc_header[0] = data[1];
@@ -889,6 +888,28 @@ static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *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(
@@ -897,6 +918,7 @@ static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len
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);
@@ -906,6 +928,16 @@ static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len
}
}
+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(unsigned long flags,
struct sbc_encoder_state *state, const struct sbc_frame *frame)
{
@@ -924,10 +956,24 @@ struct sbc_priv {
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 (flags & SBC_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;
@@ -981,7 +1027,7 @@ SBC_EXPORT ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
priv = sbc->priv;
- framelen = sbc_unpack_frame(input, &priv->frame, input_len);
+ framelen = priv->unpack_frame(input, &priv->frame, input_len);
if (!priv->init) {
sbc_decoder_init(&priv->dec_state, &priv->frame);
@@ -1115,13 +1161,15 @@ SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
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 = sbc_pack_frame(output, &priv->frame, output_len, j);
+ 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 = sbc_pack_frame(output, &priv->frame, output_len, 0);
+ framelen = priv->pack_frame(output,
+ &priv->frame, output_len, 0);
}
if (written)
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 13/16] sbc: Update sbcdec for msbc
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
src/sbcdec.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/sbcdec.c b/src/sbcdec.c
index 0077a82..37d2e98 100644
--- a/src/sbcdec.c
+++ b/src/sbcdec.c
@@ -44,7 +44,7 @@
static int verbose = 0;
-static void decode(char *filename, char *output, int tofile)
+static void decode(char *filename, char *output, int tofile, int msbc)
{
unsigned char buf[BUF_SIZE], *stream;
struct stat st;
@@ -98,7 +98,7 @@ static void decode(char *filename, char *output, int tofile)
goto free;
}
- sbc_init(&sbc, 0L);
+ sbc_init(&sbc, msbc ? SBC_MSBC : 0L);
sbc.endian = SBC_BE;
framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len);
@@ -228,14 +228,16 @@ static void usage(void)
printf("Options:\n"
"\t-h, --help Display help\n"
- "\t-v, --verbose Verbose mode\n"
"\t-d, --device <dsp> Sound device\n"
+ "\t-v, --verbose Verbose mode\n"
+ "\t-m, --msbc mSBC codec\n"
"\t-f, --file <file> Decode to a file\n"
"\n");
}
static struct option main_options[] = {
{ "help", 0, 0, 'h' },
+ { "msbc", 0, 0, 'm' },
{ "device", 1, 0, 'd' },
{ "verbose", 0, 0, 'v' },
{ "file", 1, 0, 'f' },
@@ -246,8 +248,9 @@ int main(int argc, char *argv[])
{
char *output = NULL;
int i, opt, tofile = 0;
+ int msbc = 0;
- while ((opt = getopt_long(argc, argv, "+hvd:f:",
+ while ((opt = getopt_long(argc, argv, "+hmvd:f:",
main_options, NULL)) != -1) {
switch(opt) {
case 'h':
@@ -258,6 +261,10 @@ int main(int argc, char *argv[])
verbose = 1;
break;
+ case 'm':
+ msbc = 1;
+ break;
+
case 'd':
free(output);
output = strdup(optarg);
@@ -285,7 +292,7 @@ int main(int argc, char *argv[])
}
for (i = 0; i < argc; i++)
- decode(argv[i], output ? output : "/dev/dsp", tofile);
+ decode(argv[i], output ? output : "/dev/dsp", tofile, msbc);
free(output);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 14/16] sbc: Update sbcenc for msbc
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
src/sbcenc.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/src/sbcenc.c b/src/sbcenc.c
index a723b03..71ad6bb 100644
--- a/src/sbcenc.c
+++ b/src/sbcenc.c
@@ -45,7 +45,7 @@ static int verbose = 0;
static unsigned char input[BUF_SIZE], output[BUF_SIZE + BUF_SIZE / 4];
static void encode(char *filename, int subbands, int bitpool, int joint,
- int dualchannel, int snr, int blocks)
+ int dualchannel, int snr, int blocks, int msbc)
{
struct au_header au_hdr;
sbc_t sbc;
@@ -87,7 +87,7 @@ static void encode(char *filename, int subbands, int bitpool, int joint,
goto done;
}
- sbc_init(&sbc, 0L);
+ sbc_init(&sbc, msbc ? SBC_MSBC : 0L);
switch (BE_INT(au_hdr.sample_rate)) {
case 16000:
@@ -215,6 +215,7 @@ static void usage(void)
printf("Options:\n"
"\t-h, --help Display help\n"
"\t-v, --verbose Verbose mode\n"
+ "\t-m, --msbc mSBC codec\n"
"\t-s, --subbands Number of subbands to use (4 or 8)\n"
"\t-b, --bitpool Bitpool value (default is 32)\n"
"\t-j, --joint Joint stereo\n"
@@ -227,6 +228,7 @@ static void usage(void)
static struct option main_options[] = {
{ "help", 0, 0, 'h' },
{ "verbose", 0, 0, 'v' },
+ { "msbc", 0, 0, 'm' },
{ "subbands", 1, 0, 's' },
{ "bitpool", 1, 0, 'b' },
{ "joint", 0, 0, 'j' },
@@ -239,9 +241,9 @@ static struct option main_options[] = {
int main(int argc, char *argv[])
{
int i, opt, subbands = 8, bitpool = 32, joint = 0, dualchannel = 0;
- int snr = 0, blocks = 16;
+ int snr = 0, blocks = 16, msbc = 0;
- while ((opt = getopt_long(argc, argv, "+hvs:b:jdSB:",
+ while ((opt = getopt_long(argc, argv, "+hmvs:b:jdSB:",
main_options, NULL)) != -1) {
switch(opt) {
case 'h':
@@ -252,6 +254,10 @@ int main(int argc, char *argv[])
verbose = 1;
break;
+ case 'm':
+ msbc = 1;
+ break;
+
case 's':
subbands = atoi(optarg);
if (subbands != 8 && subbands != 4) {
@@ -300,9 +306,18 @@ int main(int argc, char *argv[])
exit(1);
}
+ if (msbc) {
+ subbands = 8;
+ bitpool = 26;
+ joint = 0;
+ dualchannel = 0;
+ snr = 0;
+ blocks = 15;
+ }
+
for (i = 0; i < argc; i++)
encode(argv[i], subbands, bitpool, joint, dualchannel,
- snr, blocks);
+ snr, blocks, msbc);
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 15/16] sbc: Update sbcinfo for msbc
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
src/sbcinfo.c | 51 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 15 deletions(-)
diff --git a/src/sbcinfo.c b/src/sbcinfo.c
index 8cfb54a..01426b8 100644
--- a/src/sbcinfo.c
+++ b/src/sbcinfo.c
@@ -61,12 +61,11 @@ struct sbc_frame_hdr {
#error "Unknown byte order"
#endif
-static int calc_frame_len(struct sbc_frame_hdr *hdr)
+static int calc_frame_len(struct sbc_frame_hdr *hdr, int nrof_blocks)
{
- int tmp, nrof_subbands, nrof_blocks;
+ int tmp, nrof_subbands;
nrof_subbands = (hdr->subbands + 1) * 4;
- nrof_blocks = (hdr->blocks + 1) * 4;
switch (hdr->channel_mode) {
case 0x00:
@@ -89,13 +88,12 @@ static int calc_frame_len(struct sbc_frame_hdr *hdr)
return (nrof_subbands + ((tmp + 7) / 8));
}
-static double calc_bit_rate(struct sbc_frame_hdr *hdr)
+static double calc_bit_rate(struct sbc_frame_hdr *hdr, int nrof_blocks)
{
- int nrof_subbands, nrof_blocks;
+ int nrof_subbands;
double f;
nrof_subbands = (hdr->subbands + 1) * 4;
- nrof_blocks = (hdr->blocks + 1) * 4;
switch (hdr->sampling_frequency) {
case 0:
@@ -114,7 +112,7 @@ static double calc_bit_rate(struct sbc_frame_hdr *hdr)
return 0;
}
- return ((8 * (calc_frame_len(hdr) + 4) * f) /
+ return ((8 * (calc_frame_len(hdr, nrof_blocks) + 4) * f) /
(nrof_subbands * nrof_blocks));
}
@@ -175,7 +173,7 @@ static int analyze_file(char *filename)
double rate;
int bitpool[SIZE], frame_len[SIZE];
int subbands, blocks, freq, method;
- int n, p1, p2, fd, size, num;
+ int n, p1, p2, fd, size, num, msbc;
ssize_t len;
unsigned int count;
@@ -191,17 +189,30 @@ static int analyze_file(char *filename)
fd = fileno(stdin);
len = __read(fd, &hdr, sizeof(hdr));
- if (len != sizeof(hdr) || hdr.syncword != 0x9c) {
+ if (len != sizeof(hdr) || !(hdr.syncword == 0x9c ||
+ hdr.syncword == 0xad)) {
fprintf(stderr, "Not a SBC audio file\n");
return -1;
}
+ msbc = (hdr.syncword == 0xad) ? 1 : 0;
+
+ if (msbc) {
+ hdr.subbands = 1; /* 8 */
+ hdr.sampling_frequency = 0x00; /* 16000 */
+ hdr.allocation_method = 0; /* Loudness */
+ hdr.bitpool = 26;
+ hdr.channel_mode = 0x00; /* Mono */
+
+ blocks = 15;
+ } else {
+ blocks = (hdr.blocks + 1) * 4;
+ }
subbands = (hdr.subbands + 1) * 4;
- blocks = (hdr.blocks + 1) * 4;
freq = hdr.sampling_frequency;
method = hdr.allocation_method;
- count = calc_frame_len(&hdr);
+ count = calc_frame_len(&hdr, blocks);
bitpool[0] = hdr.bitpool;
frame_len[0] = count + 4;
@@ -213,7 +224,7 @@ static int analyze_file(char *filename)
if (lseek(fd, 0, SEEK_SET) < 0) {
num = 1;
- rate = calc_bit_rate(&hdr);
+ rate = calc_bit_rate(&hdr, blocks);
while (count) {
size = count > sizeof(buf) ? sizeof(buf) : count;
len = __read(fd, buf, size);
@@ -237,14 +248,23 @@ static int analyze_file(char *filename)
if (len == 0)
break;
- if ((size_t) len < sizeof(hdr) || hdr.syncword != 0x9c) {
+ if ((size_t) len < sizeof(hdr) || !(hdr.syncword == 0x9c ||
+ hdr.syncword == 0xad)) {
fprintf(stderr, "Corrupted SBC stream "
"(len %zd syncword 0x%02x)\n",
len, hdr.syncword);
break;
}
- count = calc_frame_len(&hdr);
+ if (msbc) {
+ hdr.subbands = 1; /* 8 */
+ hdr.sampling_frequency = 0x00; /* 16000 */
+ hdr.allocation_method = 0; /* Loudness */
+ hdr.bitpool = 26;
+ hdr.channel_mode = 0x00; /* Mono */
+ }
+
+ count = calc_frame_len(&hdr, blocks);
len = count + 4;
p1 = -1;
@@ -273,10 +293,11 @@ static int analyze_file(char *filename)
count -= len;
}
- rate += calc_bit_rate(&hdr);
+ rate += calc_bit_rate(&hdr, blocks);
num++;
}
+ printf("mSBC\t\t\t%d\n", msbc);
printf("Subbands\t\t%d\n", subbands);
printf("Block length\t\t%d\n", blocks);
printf("Sampling frequency\t%s\n", freq2str(freq));
--
1.7.9.5
^ permalink raw reply related
* [PATCH v5 16/16] sbc: Update copyrights
From: Frédéric Dalleau @ 2012-12-14 15:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In-Reply-To: <1355497417-10357-1-git-send-email-frederic.dalleau@linux.intel.com>
---
sbc/sbc.c | 1 +
sbc/sbc_primitives.c | 1 +
sbc/sbc_primitives.h | 1 +
sbc/sbc_primitives_mmx.c | 1 +
src/sbcdec.c | 1 +
src/sbcenc.c | 1 +
src/sbcinfo.c | 1 +
7 files changed, 7 insertions(+)
diff --git a/sbc/sbc.c b/sbc/sbc.c
index af45e65..792edb4 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -6,6 +6,7 @@
* 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 Intel Corporation
*
*
* This library is free software; you can redistribute it and/or
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index 8933132..9c6e56a 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -6,6 +6,7 @@
* 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 Intel Corporation
*
*
* This library is free software; you can redistribute it and/or
diff --git a/sbc/sbc_primitives.h b/sbc/sbc_primitives.h
index ffee339..5c4c0af 100644
--- a/sbc/sbc_primitives.h
+++ b/sbc/sbc_primitives.h
@@ -6,6 +6,7 @@
* 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 Intel Corporation
*
*
* This library is free software; you can redistribute it and/or
diff --git a/sbc/sbc_primitives_mmx.c b/sbc/sbc_primitives_mmx.c
index 21d7b74..02f23d9 100644
--- a/sbc/sbc_primitives_mmx.c
+++ b/sbc/sbc_primitives_mmx.c
@@ -6,6 +6,7 @@
* 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 Intel Corporation
*
*
* This library is free software; you can redistribute it and/or
diff --git a/src/sbcdec.c b/src/sbcdec.c
index 37d2e98..908292c 100644
--- a/src/sbcdec.c
+++ b/src/sbcdec.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2008-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2012 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sbcenc.c b/src/sbcenc.c
index 71ad6bb..0156b74 100644
--- a/src/sbcenc.c
+++ b/src/sbcenc.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2008-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2012 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sbcinfo.c b/src/sbcinfo.c
index 01426b8..676b949 100644
--- a/src/sbcinfo.c
+++ b/src/sbcinfo.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2008-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2012 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/5] device : Add EndGroupHandle key in attributes storage
From: Frédéric Danis @ 2012-12-14 16:45 UTC (permalink / raw)
To: linux-bluetooth
End group handle should also be converted/saved for each
group in device's attributes file.
---
doc/settings-storage.txt | 8 +++++---
src/adapter.c | 8 +++++---
src/device.c | 10 ++++++++++
3 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/doc/settings-storage.txt b/doc/settings-storage.txt
index 351b17e..11b127f 100644
--- a/doc/settings-storage.txt
+++ b/doc/settings-storage.txt
@@ -94,10 +94,12 @@ Attributes are stored using their handle as group name (decimal format).
Each group contains:
- UUID String 128-bit UUID of the attribute
+ UUID String 128-bit UUID of the attribute
- Value String Value of the attribute as hexadecimal encoded
- string
+ Value String Value of the attribute as hexadecimal encoded
+ string
+
+ EndGroupHandle Integer End group handle in decimal format
Sample:
[1]
diff --git a/src/adapter.c b/src/adapter.c
index b962bc1..37e85ed 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2419,7 +2419,8 @@ static gboolean record_has_uuid(const sdp_record_t *rec,
}
static void store_attribute_uuid(GKeyFile *key_file, uint16_t start,
- char *att_uuid, uuid_t uuid)
+ uint16_t end, char *att_uuid,
+ uuid_t uuid)
{
char handle[6], uuid_str[33];
int i;
@@ -2443,6 +2444,7 @@ static void store_attribute_uuid(GKeyFile *key_file, uint16_t start,
sprintf(handle, "%hu", start);
g_key_file_set_string(key_file, handle, "UUID", att_uuid);
g_key_file_set_string(key_file, handle, "Value", uuid_str);
+ g_key_file_set_integer(key_file, handle, "EndGroupHandle", end);
}
static void store_sdp_record(char *local, char *peer, int handle, char *value)
@@ -2535,7 +2537,7 @@ static void convert_sdp_entry(char *key, char *value, void *user_data)
key_file = g_key_file_new();
g_key_file_load_from_file(key_file, filename, 0, NULL);
- store_attribute_uuid(key_file, start, prim_uuid, uuid);
+ store_attribute_uuid(key_file, start, end, prim_uuid, uuid);
data = g_key_file_to_data(key_file, &length, NULL);
if (length > 0) {
@@ -2597,7 +2599,7 @@ static void convert_primaries_entry(char *key, char *value, void *user_data)
bt_string2uuid(&uuid, uuid_str);
sdp_uuid128_to_uuid(&uuid);
- store_attribute_uuid(key_file, start, prim_uuid, uuid);
+ store_attribute_uuid(key_file, start, end, prim_uuid, uuid);
}
g_strfreev(services);
diff --git a/src/device.c b/src/device.c
index 77466ff..780a496 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1907,6 +1907,7 @@ static void load_att_info(struct btd_device *device, const gchar *local,
for (handle = groups; *handle; handle++) {
gboolean uuid_ok;
+ gint end;
str = g_key_file_get_string(key_file, *handle, "UUID", NULL);
if (!str)
@@ -1922,8 +1923,16 @@ static void load_att_info(struct btd_device *device, const gchar *local,
if (!str)
continue;
+ end = g_key_file_get_integer(key_file, *handle,
+ "EndGroupHandle", NULL);
+ if (end == 0) {
+ g_free(str);
+ continue;
+ }
+
prim = g_new0(struct gatt_primary, 1);
prim->range.start = atoi(*handle);
+ prim->range.end = end;
switch (strlen(str)) {
case 4:
@@ -2524,6 +2533,7 @@ static void store_primaries_from_sdp_record(GKeyFile *key_file,
g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
g_key_file_set_string(key_file, handle, "Value", uuid_str);
+ g_key_file_set_integer(key_file, handle, "EndGroupHandle", end);
done:
g_free(prim_uuid);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/5] device: Store services in device's attributes file
From: Frédéric Danis @ 2012-12-14 16:45 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1355503519-26573-1-git-send-email-frederic.danis@linux.intel.com>
Remove no more used write_device_primaries() from storage.[ch].
---
src/device.c | 73 +++++++++++++++++++++++++++++++++++++++++----------------
src/storage.c | 15 ------------
src/storage.h | 2 --
3 files changed, 53 insertions(+), 37 deletions(-)
diff --git a/src/device.c b/src/device.c
index 780a496..d6a6f04 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2872,37 +2872,70 @@ static void init_browse(struct browse_req *req, gboolean reverse)
l->data);
}
-static char *primary_list_to_string(GSList *primary_list)
+static void store_services(struct btd_device *device)
{
- GString *services;
+ struct btd_adapter *adapter = device->adapter;
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ uuid_t uuid;
+ char *prim_uuid;
+ GKeyFile *key_file;
GSList *l;
+ char *data;
+ gsize length = 0;
- services = g_string_new(NULL);
+ sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+ prim_uuid = bt_uuid2string(&uuid);
- for (l = primary_list; l; l = l->next) {
- struct gatt_primary *primary = l->data;
- char service[64];
+ ba2str(adapter_get_address(adapter), src_addr);
+ ba2str(&device->bdaddr, dst_addr);
- memset(service, 0, sizeof(service));
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
+ dst_addr);
+ filename[PATH_MAX] = '\0';
- snprintf(service, sizeof(service), "%04X#%04X#%s ",
- primary->range.start, primary->range.end, primary->uuid);
+ key_file = g_key_file_new();
- services = g_string_append(services, service);
- }
+ for (l = device->primaries; l; l = l->next) {
+ struct gatt_primary *primary = l->data;
+ char handle[6], uuid_str[33];
+ int i;
- return g_string_free(services, FALSE);
-}
+ sprintf(handle, "%hu", primary->range.start);
-static void store_services(struct btd_device *device)
-{
- struct btd_adapter *adapter = device->adapter;
- char *str = primary_list_to_string(device->primaries);
+ bt_string2uuid(&uuid, primary->uuid);
+ sdp_uuid128_to_uuid(&uuid);
- write_device_primaries(adapter_get_address(adapter), &device->bdaddr,
- device->bdaddr_type, str);
+ switch (uuid.type) {
+ case SDP_UUID16:
+ sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+ break;
+ case SDP_UUID32:
+ sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+ break;
+ case SDP_UUID128:
+ for (i = 0; i < 16; i++)
+ sprintf(uuid_str + (i * 2), "%2.2X",
+ uuid.value.uuid128.data[i]);
+ break;
+ default:
+ uuid_str[0] = '\0';
+ }
- g_free(str);
+ g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
+ g_key_file_set_string(key_file, handle, "Value", uuid_str);
+ g_key_file_set_integer(key_file, handle, "EndGroupHandle",
+ primary->range.end);
+ }
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ if (length > 0) {
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ g_file_set_contents(filename, data, length, NULL);
+ }
+
+ g_free(data);
+ g_key_file_free(key_file);
}
static void attio_connected(gpointer data, gpointer user_data)
diff --git a/src/storage.c b/src/storage.c
index 713a421..02ac1f3 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -273,21 +273,6 @@ int read_device_pairable(const bdaddr_t *bdaddr, gboolean *mode)
return 0;
}
-int write_device_primaries(const bdaddr_t *sba, const bdaddr_t *dba,
- uint8_t bdaddr_type, const char *services)
-{
- char filename[PATH_MAX + 1], key[20];
-
- create_filename(filename, PATH_MAX, sba, "primaries");
-
- create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
- ba2str(dba, key);
- sprintf(&key[17], "#%hhu", bdaddr_type);
-
- return textfile_put(filename, key, services);
-}
-
static void filter_keys(char *key, char *value, void *data)
{
struct match *match = data;
diff --git a/src/storage.h b/src/storage.h
index d150f15..682523a 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -35,8 +35,6 @@ ssize_t read_pin_code(const bdaddr_t *local, const bdaddr_t *peer, char *pin);
sdp_record_t *record_from_string(const gchar *str);
sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid);
int read_device_pairable(const bdaddr_t *local, gboolean *mode);
-int write_device_primaries(const bdaddr_t *sba, const bdaddr_t *dba,
- uint8_t bdaddr_type, const char *services);
int read_device_ccc(const bdaddr_t *local, const bdaddr_t *peer,
uint8_t bdaddr_type, uint16_t handle, uint16_t *value);
int write_device_ccc(const bdaddr_t *local, const bdaddr_t *peer,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/5] adapter: Convert ccc file
From: Frédéric Danis @ 2012-12-14 16:45 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1355503519-26573-1-git-send-email-frederic.danis@linux.intel.com>
---
doc/settings-storage.txt | 14 +++++++++++
src/adapter.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+)
diff --git a/doc/settings-storage.txt b/doc/settings-storage.txt
index 11b127f..ced51d9 100644
--- a/doc/settings-storage.txt
+++ b/doc/settings-storage.txt
@@ -31,6 +31,7 @@ contains:
contains:
- an info file
- an attributes file containing attributes of remote LE services
+ - a ccc file containing CCC info of remote LE services
So the directory structure is:
/var/lib/bluetooth/<adapter address>/
@@ -43,6 +44,7 @@ So the directory structure is:
./<remote device address>/
./info
./attributes
+ ./ccc
./<remote device address>/
./info
./attributes
@@ -114,6 +116,18 @@ Sample:
UUID=00002a00-0000-1000-8000-00805f9b34fb
Value=4578616D706C6520446576696365
+CCC file format
+======================
+
+The ccc file stores CCC informations related to remote device.
+
+Informations are stored using their handle as group name (decimal format).
+
+Each group contains:
+
+ Value String Value of the CCC as hexadecimal encoded
+ string
+
Cache directory file format
============================
diff --git a/src/adapter.c b/src/adapter.c
index 37e85ed..0dda57d 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2636,6 +2636,56 @@ end:
g_key_file_free(key_file);
}
+static void convert_ccc_entry(char *key, char *value, void *user_data)
+{
+ char *src_addr = user_data;
+ char dst_addr[18];
+ char type = BDADDR_BREDR;
+ int handle, ret;
+ char filename[PATH_MAX + 1];
+ GKeyFile *key_file;
+ struct stat st;
+ int err;
+ char group[6];
+ char *data;
+ gsize length = 0;
+
+ ret = sscanf(key, "%17s#%hhu#%04X", dst_addr, &type, &handle);
+ if (ret < 3)
+ return;
+
+ if (bachk(dst_addr) != 0)
+ return;
+
+ /* Check if the device directory has been created as records should
+ * only be converted for known devices */
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+ filename[PATH_MAX] = '\0';
+
+ err = stat(filename, &st);
+ if (err || !S_ISDIR(st.st_mode))
+ return;
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/ccc", src_addr,
+ dst_addr);
+ filename[PATH_MAX] = '\0';
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ sprintf(group, "%hu", handle);
+ g_key_file_set_string(key_file, group, "Value", value);
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ if (length > 0) {
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ g_file_set_contents(filename, data, length, NULL);
+ }
+
+ g_free(data);
+ g_key_file_free(key_file);
+}
+
static void convert_device_storage(struct btd_adapter *adapter)
{
char filename[PATH_MAX + 1];
@@ -2706,6 +2756,19 @@ static void convert_device_storage(struct btd_adapter *adapter)
textfile_put(filename, "converted", "yes");
}
free(str);
+
+ /* Convert ccc */
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/ccc", address);
+ filename[PATH_MAX] = '\0';
+
+ str = textfile_get(filename, "converted");
+ if (str && strcmp(str, "yes") == 0) {
+ DBG("Legacy %s file already converted", filename);
+ } else {
+ textfile_foreach(filename, convert_ccc_entry, address);
+ textfile_put(filename, "converted", "yes");
+ }
+ free(str);
}
static void convert_config(struct btd_adapter *adapter, const char *filename,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/5] device: Add btd_device_get_storage_path()
From: Frédéric Danis @ 2012-12-14 16:45 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1355503519-26573-1-git-send-email-frederic.danis@linux.intel.com>
---
src/device.c | 15 +++++++++++++++
src/device.h | 2 ++
2 files changed, 17 insertions(+)
diff --git a/src/device.c b/src/device.c
index d6a6f04..0bc8a09 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2049,6 +2049,21 @@ struct btd_device *device_create(struct btd_adapter *adapter,
return btd_device_ref(device);
}
+char *btd_device_get_storage_path(struct btd_device *device,
+ const char *filename)
+{
+ char srcaddr[18], dstaddr[18];
+
+ ba2str(adapter_get_address(device->adapter), srcaddr);
+ ba2str(&device->bdaddr, dstaddr);
+
+ if (!filename)
+ return g_strdup_printf(STORAGEDIR "/%s/%s", srcaddr, dstaddr);
+
+ return g_strdup_printf(STORAGEDIR "/%s/%s/%s", srcaddr, dstaddr,
+ filename);
+}
+
void device_set_name(struct btd_device *device, const char *name)
{
if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0)
diff --git a/src/device.h b/src/device.h
index 8534117..7707bce 100644
--- a/src/device.h
+++ b/src/device.h
@@ -30,6 +30,8 @@ struct btd_device *device_create(struct btd_adapter *adapter,
const char *address, uint8_t bdaddr_type);
struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
const char *address, GKeyFile *key_file);
+char *btd_device_get_storage_path(struct btd_device *device,
+ const char *filename);
void device_set_name(struct btd_device *device, const char *name);
void device_get_name(struct btd_device *device, char *name, size_t len);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 5/5] attrib-server: Read/write CCC info from new storage
From: Frédéric Danis @ 2012-12-14 16:45 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1355503519-26573-1-git-send-email-frederic.danis@linux.intel.com>
Remove no more used storage functions.
---
src/attrib-server.c | 79 +++++++++++++++++++++++++++++++++++++---------
src/storage.c | 87 ---------------------------------------------------
src/storage.h | 6 ----
3 files changed, 64 insertions(+), 108 deletions(-)
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 8dc0d6a..e3715e8 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <unistd.h>
#include <glib.h>
+#include <sys/file.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/uuid.h>
@@ -746,6 +747,36 @@ static uint16_t find_by_type(struct gatt_channel *channel, uint16_t start,
return len;
}
+static int read_device_ccc(struct btd_device *device, uint16_t handle,
+ uint16_t *value)
+{
+ char *filename;
+ GKeyFile *key_file;
+ char group[6];
+ char *str;
+ unsigned int config;
+ int err = 0;
+
+ filename = btd_device_get_storage_path(device, "ccc");
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ sprintf(group, "%hu", handle);
+
+ str = g_key_file_get_string(key_file, group, "Value", NULL);
+ if (!str || sscanf(str, "%04X", &config) != 1)
+ err = -ENOENT;
+ else
+ *value = config;
+
+ g_free(str);
+ g_free(filename);
+ g_key_file_free(key_file);
+
+ return err;
+}
+
static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
uint8_t *pdu, size_t len)
{
@@ -753,7 +784,6 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
uint8_t status;
GList *l;
uint16_t cccval;
- uint8_t bdaddr_type;
guint h = handle;
l = g_list_find_custom(channel->server->database,
@@ -764,11 +794,8 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
a = l->data;
- bdaddr_type = device_get_addr_type(channel->device);
-
if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
- read_device_ccc(&channel->src, &channel->dst, bdaddr_type,
- handle, &cccval) == 0) {
+ read_device_ccc(channel->device, handle, &cccval) == 0) {
uint8_t config[2];
att_put_u16(cccval, config);
@@ -794,7 +821,6 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
uint8_t status;
GList *l;
uint16_t cccval;
- uint8_t bdaddr_type;
guint h = handle;
l = g_list_find_custom(channel->server->database,
@@ -809,11 +835,8 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
ATT_ECODE_INVALID_OFFSET, pdu, len);
- bdaddr_type = device_get_addr_type(channel->device);
-
if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
- read_device_ccc(&channel->src, &channel->dst, bdaddr_type,
- handle, &cccval) == 0) {
+ read_device_ccc(channel->device, handle, &cccval) == 0) {
uint8_t config[2];
att_put_u16(cccval, config);
@@ -869,10 +892,31 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
}
} else {
uint16_t cccval = att_get_u16(value);
- uint8_t bdaddr_type = device_get_addr_type(channel->device);
+ char *filename;
+ GKeyFile *key_file;
+ char group[6], value[5];
+ char *data;
+ gsize length = 0;
+
+ filename = btd_device_get_storage_path(channel->device, "ccc");
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ sprintf(group, "%hu", handle);
+ sprintf(value, "%hhX", cccval);
+ g_key_file_set_string(key_file, group, "Value", value);
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ if (length > 0) {
+ create_file(filename,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ g_file_set_contents(filename, data, length, NULL);
+ }
- write_device_ccc(&channel->src, &channel->dst, bdaddr_type,
- handle, cccval);
+ g_free(data);
+ g_free(filename);
+ g_key_file_free(key_file);
}
return enc_write_resp(pdu, len);
@@ -1089,8 +1133,13 @@ guint attrib_channel_attach(GAttrib *attrib)
ba2str(&channel->dst, addr);
device = adapter_find_device(server->adapter, addr);
- if (device == NULL || device_is_bonded(device) == FALSE)
- delete_device_ccc(&channel->src, &channel->dst);
+ if (device == NULL || device_is_bonded(device) == FALSE) {
+ char *filename;
+
+ filename = btd_device_get_storage_path(channel->device, "ccc");
+ unlink(filename);
+ g_free(filename);
+ }
if (cid != ATT_CID) {
channel->le = FALSE;
diff --git a/src/storage.c b/src/storage.c
index 02ac1f3..38e5897 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -272,90 +272,3 @@ int read_device_pairable(const bdaddr_t *bdaddr, gboolean *mode)
return 0;
}
-
-static void filter_keys(char *key, char *value, void *data)
-{
- struct match *match = data;
-
- if (strncasecmp(key, match->pattern, strlen(match->pattern)) == 0)
- match->keys = g_slist_append(match->keys, g_strdup(key));
-}
-
-static void delete_by_pattern(const char *filename, char *pattern)
-{
- struct match match;
- GSList *l;
- int err;
-
- memset(&match, 0, sizeof(match));
- match.pattern = pattern;
-
- err = textfile_foreach(filename, filter_keys, &match);
- if (err < 0)
- goto done;
-
- for (l = match.keys; l; l = l->next) {
- const char *key = l->data;
- textfile_del(filename, key);
- }
-
-done:
- g_slist_free_full(match.keys, g_free);
-}
-
-int read_device_ccc(const bdaddr_t *local, const bdaddr_t *peer,
- uint8_t bdaddr_type, uint16_t handle,
- uint16_t *value)
-{
- char filename[PATH_MAX + 1], addr[18], key[25];
- char *str;
- unsigned int config;
- int err = 0;
-
- create_filename(filename, PATH_MAX, local, "ccc");
-
- ba2str(peer, addr);
- snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
-
- str = textfile_caseget(filename, key);
- if (str == NULL)
- return -ENOENT;
-
- if (sscanf(str, "%04X", &config) != 1)
- err = -ENOENT;
- else
- *value = config;
-
- free(str);
-
- return err;
-}
-
-int write_device_ccc(const bdaddr_t *local, const bdaddr_t *peer,
- uint8_t bdaddr_type, uint16_t handle,
- uint16_t value)
-{
- char filename[PATH_MAX + 1], addr[18], key[25], config[5];
-
- create_filename(filename, PATH_MAX, local, "ccc");
-
- create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
- ba2str(peer, addr);
- snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
-
- snprintf(config, sizeof(config), "%04X", value);
-
- return textfile_put(filename, key, config);
-}
-
-void delete_device_ccc(const bdaddr_t *local, const bdaddr_t *peer)
-{
- char filename[PATH_MAX + 1], addr[18];
-
- ba2str(peer, addr);
-
- /* Deleting all CCC values of a given address */
- create_filename(filename, PATH_MAX, local, "ccc");
- delete_by_pattern(filename, addr);
-}
diff --git a/src/storage.h b/src/storage.h
index 682523a..cc7f930 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -35,9 +35,3 @@ ssize_t read_pin_code(const bdaddr_t *local, const bdaddr_t *peer, char *pin);
sdp_record_t *record_from_string(const gchar *str);
sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid);
int read_device_pairable(const bdaddr_t *local, gboolean *mode);
-int read_device_ccc(const bdaddr_t *local, const bdaddr_t *peer,
- uint8_t bdaddr_type, uint16_t handle, uint16_t *value);
-int write_device_ccc(const bdaddr_t *local, const bdaddr_t *peer,
- uint8_t bdaddr_type, uint16_t handle,
- uint16_t value);
-void delete_device_ccc(const bdaddr_t *local, const bdaddr_t *peer);
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 3/5] adapter: Convert ccc file
From: Anderson Lizardo @ 2012-12-14 17:31 UTC (permalink / raw)
To: Frédéric Danis; +Cc: linux-bluetooth
In-Reply-To: <1355503519-26573-3-git-send-email-frederic.danis@linux.intel.com>
Hi Frédéric,
On Fri, Dec 14, 2012 at 12:45 PM, Frédéric Danis
<frederic.danis@linux.intel.com> wrote:
> ---
> doc/settings-storage.txt | 14 +++++++++++
> src/adapter.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 77 insertions(+)
>
> diff --git a/doc/settings-storage.txt b/doc/settings-storage.txt
> index 11b127f..ced51d9 100644
> --- a/doc/settings-storage.txt
> +++ b/doc/settings-storage.txt
> @@ -31,6 +31,7 @@ contains:
> contains:
> - an info file
> - an attributes file containing attributes of remote LE services
> + - a ccc file containing CCC info of remote LE services
Just a few textual improvements:
"- a ccc file containing persistent Client Characteristic
Configuration (CCC) descriptor information for GATT characteristics"
> +CCC file format
> +======================
> +
> +The ccc file stores CCC informations related to remote device.
> +
> +Informations are stored using their handle as group name (decimal format).
"""
The ccc file stores the current CCC descriptor values for GATT
characteristics which have notification/indication enabled by the
remote device.
Information is stored using CCC attribute handle as group name (in
decimal format).
"""
> +
> +Each group contains:
> +
> + Value String Value of the CCC as hexadecimal encoded
"CCC descriptor value encoded in hexadecimal"
> + string
> +
Everything else looks good as per my review.
Best Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* [PATCH 00/12] Add LE broadcaster and observer functionality
From: Jefferson Delfes @ 2012-12-14 18:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
This patch series adds broadcaster and observer functionality.
For the userspace, we are updating our branch and we will send it in s few
days.
Aloisio Almeida Jr (10):
Bluetooth: Set advertising parameters on LE setup
Bluetooth: Add set controller data MGMT command
Bluetooth: Add set broadcaster MGMT command
Bluetooth: Advertise controller data in broadcaster mode
Bluetooth: Stop to acquire hdev lock inside hci_update_ad
Bluetooth: Enable on-the-fly update of broadcast data
Bluetooth: Enable support for broadcaster mode when powered off.
Bluetooth: Refactor le scan helpers to enable observer support
Bluetooth: Add set observer MGMT command
Bluetooth: Enable support for observer mode when powered off.
Jefferson Delfes (2):
Bluetooth: Add HCI command to set advertising parameters
Bluetooth: Add unset controller data MGMT command
include/net/bluetooth/hci.h | 19 +++
include/net/bluetooth/hci_core.h | 42 ++++-
include/net/bluetooth/mgmt.h | 21 +++
net/bluetooth/hci_core.c | 183 ++++++++++++++++-----
net/bluetooth/hci_event.c | 121 +++++++++-----
net/bluetooth/mgmt.c | 335 +++++++++++++++++++++++++++++++++++++--
6 files changed, 628 insertions(+), 93 deletions(-)
--
1.8.0.2
^ permalink raw reply
* [PATCH 01/12] Bluetooth: Add HCI command to set advertising parameters
From: Jefferson Delfes @ 2012-12-14 18:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes, Aloisio Almeida Jr
In-Reply-To: <1355511098-10190-1-git-send-email-jefferson.delfes@openbossa.org>
Add command to set advertising parameters before enable it.
Signed-off-by: Jefferson Delfes <jefferson.delfes@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
---
include/net/bluetooth/hci.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 45eee08..e89311d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -959,6 +959,20 @@ struct hci_cp_le_set_adv_data {
#define HCI_OP_LE_SET_ADV_ENABLE 0x200a
+#define ADV_USE_ALL_CHANNELS 0x07
+
+#define HCI_OP_LE_SET_ADV_PARAMS 0x2006
+struct hci_cp_le_set_adv_params {
+ __le16 interval_min;
+ __le16 interval_max;
+ __u8 type;
+ __u8 own_address_type;
+ __u8 direct_address_type;
+ __u8 direct_address[6];
+ __u8 channel_map;
+ __u8 filter_policy;
+} __packed;
+
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
struct hci_cp_le_set_scan_param {
__u8 type;
--
1.8.0.2
^ permalink raw reply related
* [PATCH 02/12] Bluetooth: Set advertising parameters on LE setup
From: Jefferson Delfes @ 2012-12-14 18:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Aloisio Almeida Jr
In-Reply-To: <1355511098-10190-1-git-send-email-jefferson.delfes@openbossa.org>
From: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
To enable broadcasting we need to set up the advertising parameters. As these
parameters are constant (only broadcaster is using until now), they are set on LE
setup.
This patch makes the advertising non-connectable as default. To make connectable
advertising using 'hciconfig leadv' command, you must change these parameters
first.
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
---
net/bluetooth/hci_event.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 705078a..8f84f71 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -606,11 +606,22 @@ static void bredr_setup(struct hci_dev *hdev)
static void le_setup(struct hci_dev *hdev)
{
+ struct hci_cp_le_set_adv_params params;
+
/* Read LE Buffer Size */
hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
/* Read LE Advertising Channel TX Power */
hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
+
+ /* Set ADV params */
+ memset(¶ms, 0, sizeof(params));
+ params.interval_min = __constant_cpu_to_le16(0x0800);
+ params.interval_max = __constant_cpu_to_le16(0x0800);
+ params.type = ADV_NONCONN_IND;
+ params.own_address_type = ADDR_LE_DEV_PUBLIC;
+ params.channel_map = ADV_USE_ALL_CHANNELS;
+ hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_PARAMS, sizeof(params), ¶ms);
}
static void hci_setup(struct hci_dev *hdev)
@@ -1359,6 +1370,15 @@ static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
amp_write_rem_assoc_continue(hdev, rp->phy_handle);
}
+static void hci_cc_le_set_adv_params(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ __u8 status = *((__u8 *) skb->data);
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ hci_req_complete(hdev, HCI_OP_LE_SET_ADV_PARAMS, status);
+}
+
static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -2680,6 +2700,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_write_remote_amp_assoc(hdev, skb);
break;
+ case HCI_OP_LE_SET_ADV_PARAMS:
+ hci_cc_le_set_adv_params(hdev, skb);
+ break;
+
default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break;
--
1.8.0.2
^ permalink raw reply related
* [PATCH 03/12] Bluetooth: Add set controller data MGMT command
From: Jefferson Delfes @ 2012-12-14 18:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Aloisio Almeida Jr, Jefferson Delfes
In-Reply-To: <1355511098-10190-1-git-send-email-jefferson.delfes@openbossa.org>
From: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Set controller data allows user to set broadcast advertising data. The available
data types are 'service data' and 'manufacturer specific data'.
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Signed-off-by: Jefferson Delfes <jefferson.delfes@openbossa.org>
---
include/net/bluetooth/hci.h | 3 +++
include/net/bluetooth/hci_core.h | 15 +++++++++++++++
include/net/bluetooth/mgmt.h | 9 +++++++++
net/bluetooth/hci_core.c | 36 ++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 39 +++++++++++++++++++++++++++++++++++++++
5 files changed, 102 insertions(+)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index e89311d..a89ff01 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -337,6 +337,9 @@ enum {
#define EIR_SSP_HASH_C 0x0E /* Simple Pairing Hash C */
#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
#define EIR_DEVICE_ID 0x10 /* device ID */
+/* Advertising field types */
+#define ADV_SERVICE_DATA 0x16 /* Service Data */
+#define ADV_MANUFACTURER_DATA 0xFF /* Manufacturer Specific Data */
/* Low Energy Advertising Flags */
#define LE_AD_LIMITED 0x01 /* Limited Discoverable */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 014a2ea..49a9ead 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -123,6 +123,14 @@ struct le_scan_params {
int timeout;
};
+struct broadcast_data {
+ struct list_head list;
+ u8 flags;
+ u8 type;
+ u8 length;
+ u8 data[0];
+};
+
#define HCI_MAX_SHORT_NAME_LENGTH 10
struct amp_assoc {
@@ -282,6 +290,9 @@ struct hci_dev {
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u8 adv_data_len;
+ struct list_head broadcast_data;
+ __u16 broadcast_data_len;
+
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
@@ -752,6 +763,10 @@ void hci_conn_init_sysfs(struct hci_conn *conn);
void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);
+int hci_broadcast_data_add(struct hci_dev *hdev, u8 flags, u8 type, u8 length,
+ u8 *data);
+int hci_broadcast_data_clear(struct hci_dev *hdev);
+
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
/* ----- LMP capabilities ----- */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 22980a7..f99e0a8 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -350,6 +350,15 @@ struct mgmt_cp_set_device_id {
} __packed;
#define MGMT_SET_DEVICE_ID_SIZE 8
+#define MGMT_OP_SET_CONTROLLER_DATA 0x0029
+struct mgmt_cp_set_controller_data {
+ __u8 flags;
+ __u8 type;
+ __u8 length;
+ __u8 data[0];
+} __packed;
+#define MGMT_SET_CONTROLLER_DATA_SIZE 3
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ec7d3a7..6d6ee0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1504,6 +1504,40 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
return 0;
}
+int hci_broadcast_data_add(struct hci_dev *hdev, u8 flags, u8 type, u8 length,
+ u8 *data)
+{
+ struct broadcast_data *b_data;
+
+ b_data = kmalloc(sizeof(*b_data) + length, GFP_KERNEL);
+ if (!b_data)
+ return -ENOMEM;
+
+ b_data->flags = flags;
+ b_data->type = type;
+ b_data->length = length;
+ memcpy(b_data->data, data, length);
+
+ list_add(&b_data->list, &hdev->broadcast_data);
+ hdev->broadcast_data_len += sizeof(length) + sizeof(type) + length;
+
+ return 0;
+}
+
+int hci_broadcast_data_clear(struct hci_dev *hdev)
+{
+ struct broadcast_data *b_data, *n;
+
+ list_for_each_entry_safe(b_data, n, &hdev->broadcast_data, list) {
+ list_del(&b_data->list);
+ kfree(b_data);
+ }
+
+ hdev->broadcast_data_len = 0;
+
+ return 0;
+}
+
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *b;
@@ -1721,6 +1755,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->long_term_keys);
INIT_LIST_HEAD(&hdev->remote_oob_data);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->broadcast_data);
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -1887,6 +1922,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_link_keys_clear(hdev);
hci_smp_ltks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_broadcast_data_clear(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5d0ef75..4623cf0 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2701,6 +2701,44 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
return 0;
}
+static int set_controller_data(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_set_controller_data *cp = data;
+ u8 room;
+
+ BT_DBG("%s", hdev->name);
+
+ if (cp->type != ADV_SERVICE_DATA && cp->type != ADV_MANUFACTURER_DATA)
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_CONTROLLER_DATA,
+ MGMT_STATUS_INVALID_PARAMS);
+
+ hci_dev_lock(hdev);
+
+ if (!hdev_is_powered(hdev)) {
+ hci_dev_unlock(hdev);
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_CONTROLLER_DATA,
+ MGMT_STATUS_NOT_POWERED);
+ }
+
+ room = HCI_MAX_AD_LENGTH - hdev->broadcast_data_len;
+ if (sizeof(cp->length) + sizeof(cp->type) + cp->length > room) {
+ hci_dev_unlock(hdev);
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_CONTROLLER_DATA,
+ MGMT_STATUS_NO_RESOURCES);
+ }
+
+ BT_DBG("flags:0x%02x length:%i type:0x%02x", cp->flags, cp->length,
+ cp->type);
+
+ hci_broadcast_data_add(hdev, cp->flags, cp->type, cp->length, cp->data);
+
+ hci_dev_unlock(hdev);
+
+ return cmd_complete(sk, hdev->id, MGMT_OP_SET_CONTROLLER_DATA, 0, NULL,
+ 0);
+}
+
static const struct mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len);
@@ -2748,6 +2786,7 @@ static const struct mgmt_handler {
{ block_device, false, MGMT_BLOCK_DEVICE_SIZE },
{ unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
{ set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
+ { set_controller_data, true, MGMT_SET_CONTROLLER_DATA_SIZE },
};
--
1.8.0.2
^ permalink raw reply related
* [PATCH 04/12] Bluetooth: Add unset controller data MGMT command
From: Jefferson Delfes @ 2012-12-14 18:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes, Aloisio Almeida Jr
In-Reply-To: <1355511098-10190-1-git-send-email-jefferson.delfes@openbossa.org>
Unset controller data allows user to remove some data previously set to be
broadcasted via set controller data MGMT command.
Signed-off-by: Jefferson Delfes <jefferson.delfes@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
---
include/net/bluetooth/hci_core.h | 1 +
include/net/bluetooth/mgmt.h | 6 ++++++
net/bluetooth/hci_core.c | 19 +++++++++++++++++++
net/bluetooth/mgmt.c | 24 ++++++++++++++++++++++++
4 files changed, 50 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 49a9ead..cf8d125 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -765,6 +765,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
int hci_broadcast_data_add(struct hci_dev *hdev, u8 flags, u8 type, u8 length,
u8 *data);
+int hci_broadcast_data_remove(struct hci_dev *hdev, u8 type);
int hci_broadcast_data_clear(struct hci_dev *hdev);
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f99e0a8..bbb4b4a 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -359,6 +359,12 @@ struct mgmt_cp_set_controller_data {
} __packed;
#define MGMT_SET_CONTROLLER_DATA_SIZE 3
+#define MGMT_OP_UNSET_CONTROLLER_DATA 0x002A
+struct mgmt_cp_unset_controller_data {
+ __u8 type;
+} __packed;
+#define MGMT_UNSET_CONTROLLER_DATA_SIZE 1
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6d6ee0c..d015e1f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1524,6 +1524,25 @@ int hci_broadcast_data_add(struct hci_dev *hdev, u8 flags, u8 type, u8 length,
return 0;
}
+int hci_broadcast_data_remove(struct hci_dev *hdev, u8 type)
+{
+ struct broadcast_data *match, *n;
+ int matches = 0;
+
+ list_for_each_entry_safe(match, n, &hdev->broadcast_data, list) {
+ if (type != match->type)
+ continue;
+
+ list_del(&match->list);
+ hdev->broadcast_data_len -= sizeof(match->length) +
+ sizeof(match->type) + match->length;
+ kfree(match);
+ matches++;
+ }
+
+ return matches;
+}
+
int hci_broadcast_data_clear(struct hci_dev *hdev)
{
struct broadcast_data *b_data, *n;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4623cf0..0aa96bb 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2739,6 +2739,29 @@ static int set_controller_data(struct sock *sk, struct hci_dev *hdev,
0);
}
+static int unset_controller_data(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_unset_controller_data *cp = data;
+
+ BT_DBG("%s type:0x%02x", hdev->name, cp->type);
+
+ hci_dev_lock(hdev);
+
+ if (!hdev_is_powered(hdev)) {
+ hci_dev_unlock(hdev);
+ return cmd_status(sk, hdev->id, MGMT_OP_UNSET_CONTROLLER_DATA,
+ MGMT_STATUS_NOT_POWERED);
+ }
+
+ hci_broadcast_data_remove(hdev, cp->type);
+
+ hci_dev_unlock(hdev);
+
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNSET_CONTROLLER_DATA, 0,
+ NULL, 0);
+}
+
static const struct mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len);
@@ -2787,6 +2810,7 @@ static const struct mgmt_handler {
{ unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
{ set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
{ set_controller_data, true, MGMT_SET_CONTROLLER_DATA_SIZE },
+ { unset_controller_data, false, MGMT_UNSET_CONTROLLER_DATA_SIZE },
};
--
1.8.0.2
^ permalink raw reply related
* [PATCH 05/12] Bluetooth: Add set broadcaster MGMT command
From: Jefferson Delfes @ 2012-12-14 18:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Aloisio Almeida Jr
In-Reply-To: <1355511098-10190-1-git-send-email-jefferson.delfes@openbossa.org>
From: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
This command will enable or disable broadcaster mode. Data can be added
with set_controller_data command.
If LE_ENABLED is set, the HCI_OP_LE_SET_ADV_ENABLE command will be sent.
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
---
include/net/bluetooth/hci.h | 1 +
include/net/bluetooth/hci_core.h | 8 ++++
include/net/bluetooth/mgmt.h | 3 ++
net/bluetooth/hci_event.c | 28 +++++++++---
net/bluetooth/mgmt.c | 93 +++++++++++++++++++++++++++++++++++++++-
5 files changed, 127 insertions(+), 6 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index a89ff01..efbdd3d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -121,6 +121,7 @@ enum {
HCI_LINK_SECURITY,
HCI_PENDING_CLASS,
HCI_PERIODIC_INQ,
+ HCI_BROADCASTER,
};
/* HCI ioctl defines */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index cf8d125..56af0fd 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -131,6 +131,10 @@ struct broadcast_data {
u8 data[0];
};
+enum {
+ LE_ADV_REQ_REASON_BROADCASTER,
+};
+
#define HCI_MAX_SHORT_NAME_LENGTH 10
struct amp_assoc {
@@ -293,6 +297,8 @@ struct hci_dev {
struct list_head broadcast_data;
__u16 broadcast_data_len;
+ __u8 le_adv_req_reason;
+
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
@@ -1122,6 +1128,8 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
u8 *randomizer, u8 status);
int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
+int mgmt_set_broadcaster_complete(struct hci_dev *hdev, bool changed,
+ u8 status);
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
u8 ssp, u8 *eir, u16 eir_len);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index bbb4b4a..bd64816 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -92,6 +92,7 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_BREDR 0x00000080
#define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200
+#define MGMT_SETTING_BROADCASTER 0x00000400
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0
@@ -365,6 +366,8 @@ struct mgmt_cp_unset_controller_data {
} __packed;
#define MGMT_UNSET_CONTROLLER_DATA_SIZE 1
+#define MGMT_OP_SET_BROADCASTER 0x002B
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8f84f71..46f76d6 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1204,6 +1204,7 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 *sent, status = *((__u8 *) skb->data);
+ __u8 enable;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -1211,13 +1212,30 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (!sent)
return;
+ enable = *sent;
+
hci_dev_lock(hdev);
- if (!status) {
- if (*sent)
- set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
- else
- clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
+ if (hdev->le_adv_req_reason == LE_ADV_REQ_REASON_BROADCASTER) {
+ bool changed = false;
+ if (enable) {
+ if (!test_and_set_bit(HCI_BROADCASTER,
+ &hdev->dev_flags))
+ changed = true;
+ } else {
+ if (test_and_clear_bit(HCI_BROADCASTER,
+ &hdev->dev_flags))
+ changed = true;
+ }
+ if (!test_bit(HCI_INIT, &hdev->flags))
+ mgmt_set_broadcaster_complete(hdev, changed, status);
+ } else {
+ if (!status) {
+ if (enable)
+ set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
+ else
+ clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
+ }
}
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0aa96bb..608e81af 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -392,8 +392,10 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (enable_hs)
settings |= MGMT_SETTING_HS;
- if (lmp_le_capable(hdev))
+ if (lmp_le_capable(hdev)) {
settings |= MGMT_SETTING_LE;
+ settings |= MGMT_SETTING_BROADCASTER;
+ }
return settings;
}
@@ -420,6 +422,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
settings |= MGMT_SETTING_LE;
+ if (test_bit(HCI_BROADCASTER, &hdev->dev_flags))
+ settings |= MGMT_SETTING_BROADCASTER;
+
if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
settings |= MGMT_SETTING_LINK_SECURITY;
@@ -2762,6 +2767,64 @@ static int unset_controller_data(struct sock *sk, struct hci_dev *hdev,
NULL, 0);
}
+static int set_broadcaster_le(struct sock *sk, struct hci_dev *hdev, u8 enable)
+{
+ struct pending_cmd *cmd;
+ int err;
+
+ BT_DBG("%s enable:%i", hdev->name, enable);
+
+ hci_dev_lock(hdev);
+
+ if (!hdev_is_powered(hdev)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_BROADCASTER,
+ MGMT_STATUS_NOT_POWERED);
+ goto unlock;
+ }
+
+ if (enable == test_bit(HCI_BROADCASTER, &hdev->dev_flags)) {
+ err = send_settings_rsp(sk, MGMT_OP_SET_BROADCASTER, hdev);
+ goto unlock;
+ }
+
+ if (mgmt_pending_find(MGMT_OP_SET_BROADCASTER, hdev)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_BROADCASTER,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_BROADCASTER, hdev, NULL, 0);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlock;
+ }
+
+ hdev->le_adv_req_reason = LE_ADV_REQ_REASON_BROADCASTER;
+
+ err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
+ &enable);
+ if (err < 0)
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+ return err;
+}
+
+static int set_broadcaster(struct sock *sk, struct hci_dev *hdev, void *data,
+ u16 len)
+{
+ struct mgmt_mode *cp = data;
+
+ BT_DBG("%s val:%i", hdev->name, cp->val);
+
+ if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_BROADCASTER,
+ MGMT_STATUS_NOT_SUPPORTED);
+
+ return set_broadcaster_le(sk, hdev, cp->val);
+}
+
static const struct mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len);
@@ -2811,6 +2874,7 @@ static const struct mgmt_handler {
{ set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
{ set_controller_data, true, MGMT_SET_CONTROLLER_DATA_SIZE },
{ unset_controller_data, false, MGMT_UNSET_CONTROLLER_DATA_SIZE },
+ { set_broadcaster, false, MGMT_SETTING_SIZE },
};
@@ -3667,6 +3731,33 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
return err;
}
+int mgmt_set_broadcaster_complete(struct hci_dev *hdev, bool changed, u8 status)
+{
+ struct pending_cmd *cmd;
+ struct cmd_lookup match = { NULL, hdev };
+ int err = 0;
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_BROADCASTER, hdev);
+ if (!cmd)
+ return -ENOENT;
+
+ if (status) {
+ u8 mgmt_err = mgmt_status(status);
+ cmd_status_rsp(cmd, &mgmt_err);
+ return err;
+ }
+
+ settings_rsp(cmd, &match);
+
+ if (changed)
+ err = new_settings(hdev, match.sk);
+
+ if (match.sk)
+ sock_put(match.sk);
+
+ return err;
+}
+
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
ssp, u8 *eir, u16 eir_len)
--
1.8.0.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox