[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