[PATCH] [UBUNTU:sound/bluetooth/] Fix suspend/hibernate in snd-bt-sco driver
crimsun at fungus.sh.nu
crimsun at fungus.sh.nu
Mon May 15 19:14:37 UTC 2006
Subject: [PATCH] [UBUNTU:sound/bluetooth/] Fix suspend/hibernate in snd-bt-sco driver
UpstreamStatus: Already in upstream [0]
This patch from <whoopie79 at gmx.net> fixes suspend and hibernate in the
snd-bt-sco driver. Our current version does not perform either
correctly.
This commit closes Malone #44826.
[0] http://bluetooth-alsa.cvs.sourceforge.net/bluetooth-alsa/btsco/kernel/btsco.c?revision=1.11&view=markup
Signed-off-by: Daniel T Chen <crimsun at ubuntu.com>
---
sound/bluetooth/btsco.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 177 insertions(+), 4 deletions(-)
1f942b69a193d0017eb8a95fe83c74db115ed6b1
diff --git a/sound/bluetooth/btsco.c b/sound/bluetooth/btsco.c
index 1b723e3..b5f42fc 100644
--- a/sound/bluetooth/btsco.c
+++ b/sound/bluetooth/btsco.c
@@ -21,6 +21,26 @@
*
*/
+
+/* note: defining these two independently is not tested,
+ * thus not recommended
+ */
+
+/* enable dynamic compression */
+#define DYNAMIC_COMPRESSION
+/* enable automatic endianness fixup */
+#define AUTO_FIXUP_BYTESHIFT
+
+
+#ifdef DYNAMIC_COMPRESSION
+/* Autoadjust mic at most this often in 1/8000s */
+#define GRABSAMPLES 400
+/* Maximum push for the mike 16= 1:1 - default 20:1 = 320 */
+#define COMPRESSION_MAX_16 320
+/* Minimum push for the mike 1= 1:16 */
+#define COMPRESSION_MIN_16 1
+#endif
+
#define chip_t snd_card_bt_sco_t
#include <sound/driver.h>
@@ -61,7 +81,12 @@ MODULE_DESCRIPTION("Bluetooth SCO Headse
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{ALSA,Bluetooth SCO Soundcard}}");
-static char *mod_revision = "$Revision: 1.6 $";
+static char *mod_revision = "$Revision: 1.11 $";
+
+static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Bluetooth SCO Headset Soundcard.");
#undef dprintk
#if 1
@@ -93,8 +118,15 @@ typedef struct snd_card_bt_sco {
snd_card_t *card;
spinlock_t mixer_lock;
int mixer_volume[MIXER_ADDR_LAST + 1];
- snd_kcontrol_t *mixer_controls[MIXER_ADDR_LAST + 2]; /* also loopback */
+#ifdef DYNAMIC_COMPRESSION
+ snd_kcontrol_t *mixer_controls[MIXER_ADDR_LAST + 2 + 1]; /* also loopback and agc */
+#else
+ snd_kcontrol_t *mixer_controls[MIXER_ADDR_LAST + 2 ]; /* also loopback */
+#endif
volatile int loopback;
+#ifdef DYNAMIC_COMPRESSION
+ volatile int agc;
+#endif
atomic_t playback_count, capture_count;
volatile int count_changed;
spinlock_t count_changed_lock;
@@ -569,6 +601,37 @@ static int snd_bt_sco_loopback_put(snd_k
return changed;
}
+#ifdef DYNAMIC_COMPRESSION
+static int snd_bt_sco_agc_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bt_sco->mixer_lock, flags);
+ ucontrol->value.integer.value[0] = bt_sco->agc;
+ spin_unlock_irqrestore(&bt_sco->mixer_lock, flags);
+ return 0;
+}
+
+static int snd_bt_sco_agc_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int changed;
+ int agc;
+
+ agc = !!ucontrol->value.integer.value[0];
+
+ spin_lock_irqsave(&bt_sco->mixer_lock, flags);
+ changed = bt_sco->agc != agc;
+ bt_sco->agc = agc;
+ spin_unlock_irqrestore(&bt_sco->mixer_lock, flags);
+ return changed;
+}
+#endif
+
#define BT_SCO_CONTROLS (sizeof(snd_bt_sco_controls)/sizeof(snd_kcontrol_new_t))
static snd_kcontrol_new_t snd_bt_sco_controls[] = {
@@ -581,6 +644,16 @@ static snd_kcontrol_new_t snd_bt_sco_con
.get = snd_bt_sco_loopback_get,
.put = snd_bt_sco_loopback_put,
}
+#ifdef DYNAMIC_COMPRESSION
+ ,
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "AGC Switch",
+ .index = 0,
+ .info = snd_bt_sco_boolean_info,
+ .get = snd_bt_sco_agc_get,
+ .put = snd_bt_sco_agc_put,
+ }
+#endif
};
int __init snd_card_bt_sco_new_mixer(snd_card_bt_sco_t * bt_sco)
@@ -790,6 +863,18 @@ static int snd_card_bt_sco_thread(void *
struct msghdr msg;
struct iovec iov;
sigset_t unblocked;
+#if defined(DYNAMIC_COMPRESSION) || defined(AUTO_FIXUP_BYTESHIFT)
+ int i;
+#endif
+#ifdef DYNAMIC_COMPRESSION
+ static int factor=16;
+ static int maxvalsmoothed=0;
+ static int maxvalgrablen=GRABSAMPLES; /* adjust volume at most 4 times/second */
+#endif
+#ifdef AUTO_FIXUP_BYTESHIFT
+ static int shift=0;
+ static unsigned char lastbyte;
+#endif
lock_kernel();
@@ -806,6 +891,14 @@ static int snd_card_bt_sco_thread(void *
up(&bt_sco->thread_sem);
do {
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
+ try_to_freeze();
+#else
+ if (current->flags & PF_FREEZE)
+ refrigerator(PF_FREEZE);
+#endif
+
if (signal_pending(current))
flush_signals(current);
@@ -839,6 +932,85 @@ static int snd_card_bt_sco_thread(void *
len = sock_recvmsg(sock, &msg, BUF_SIZE, 0);
if (len > 0) {
+#if defined (AUTO_FIXUP_BYTESHIFT) || defined (DYNAMIC_COMPRESSION)
+
+#ifdef AUTO_FIXUP_BYTESHIFT
+ int lostatcnt=0;
+#endif
+ if (len&1) dprintk("odd len %d\n",len);
+#ifdef AUTO_FIXUP_BYTESHIFT
+ if (shift) {
+ unsigned char newlastbyte;
+ newlastbyte=buf[len-1];
+ memmove(buf+1,buf,len-1);
+ buf[0]=lastbyte;
+ lastbyte=newlastbyte;
+ }
+#endif
+ for(i=0;i<len-1;i+=2) {
+ short int j;
+ int k;
+ j=(buf[i+1]<<8)|buf[i];
+
+#ifdef AUTO_FIXUP_BYTESHIFT
+ /* occasionally the Headset will loose a byte
+ * on startup. Thus kind of swapping lo/hi.
+ * counting, if _all_ lo bytes (which are
+ * actually high bytes) are 0 or -1
+ * will detect this with a very high probability
+ */
+ if ((j&0xff)==0||(j&0xff)==0xff) {
+ lostatcnt++;
+ }
+#endif
+#ifdef DYNAMIC_COMPRESSION
+ /* scale the mic input - we do some kind
+ * of dynamics compression
+ */
+ k=((int)j*factor)/16;
+
+ /* clip overshoot. Better than just letting
+ * it wrap around. Immediately adjust factor.
+ */
+ if (k>0x7fff) {
+ k=0x7fff;
+ if (bt_sco->agc&&factor>COMPRESSION_MIN_16) factor--;
+ } else if (k<-0x8000) {
+ k=0x8000;
+ if (bt_sco->agc&&factor>COMPRESSION_MIN_16) factor--;
+ }
+ buf[i+1]=(k>>8)&0xff;
+ buf[i ]=k&0xff;
+
+ /* find the highest absolute value in a
+ * GRABSAMPLES long interval.
+ */
+ if (k<0) k=-j;
+ if (k>maxvalsmoothed) maxvalsmoothed=k;
+ /* if the interval is over, recalculate
+ * the compression factor. Move it slowly.
+ */
+ if (maxvalgrablen--<=0) {
+ maxvalgrablen=GRABSAMPLES;
+ /* If the noise goes up over 1000, we stop
+ * pushing the software gain
+ */
+ if (maxvalsmoothed<1000&&factor<COMPRESSION_MAX_16) {
+ factor++;
+ // dprintk("Up to %d\n",factor);
+ }
+ if (!bt_sco->agc) factor=16;
+ maxvalsmoothed=0;
+ }
+#endif
+ }
+#ifdef AUTO_FIXUP_BYTESHIFT
+ if (lostatcnt==len/2&&len>32) {
+ shift=!shift;
+ dprintk("Shift problem detected! Fixing to %d.\n",shift);
+ }
+#endif
+#endif /* any of them */
down(&bt_sco->capture_sem);
if (bt_sco->capture) {
snd_card_bt_sco_pcm_receive
@@ -964,7 +1136,7 @@ static int __init snd_card_bt_sco_probe(
snd_hwdep_t *hw;
card =
- snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ snd_card_new(index[dev], SNDRV_DEFAULT_STR1,
THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
@@ -979,7 +1151,8 @@ static int __init snd_card_bt_sco_probe(
bt_sco->card = card;
init_completion(&bt_sco->thread_done);
- init_MUTEX_LOCKED(&bt_sco->thread_sem);
+ init_MUTEX(&bt_sco->thread_sem);
+ down(&bt_sco->thread_sem);
init_MUTEX(&bt_sco->sock_sem);
init_MUTEX(&bt_sco->capture_sem);
init_MUTEX(&bt_sco->playback_sem);
--
1.1.3
--
Daniel T. Chen crimsun at ubuntu.com
GPG key: www.sh.nu/~crimsun/pubkey.gpg.asc
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20060515/5115e686/attachment.sig>
More information about the kernel-team
mailing list