[ltp] A20p questions...

Markus Alt linux-thinkpad@www.bm-soft.com
Tue, 02 Jan 2001 00:45:54 +0100


This is a multi-part message in MIME format.
--------------B3A81093F8057955277E4C2B
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Guy Davis wrote:
> 
> Hi all,
> I purchased an A20p this summer and now have RH 7 running on it with
> all the latest Redhat Network updates.  Overall, I'm quite pleased
> with this laptop, but I was wondering if a few nagging problems had
> been solved yet.  Thanks.
> 
> 1) Alsa sound dying on a suspend/resume.  I'm using
> alsa-driver-0.5.9d, alsa-lib-0.5.9, and alsa-utils-0.5.9b. Basically,
> Alsa gives me a bunch of 'Device or resource busy' when downing it via
> /etc/rc.d/init.d/alsasound. Is there a patch?

You may want to set APMD_STOP_SOUND_BEFORE_SUSPEND="alsa" with the APM
config file /etc/rc.config.d/apmd.rc.config. This will kill all
applications using the sound modules, then unload the modules before
suspend and reload them after resume.

With respect to that common recommendation of turning off PCI bus power
management in the BIOS: There is a way to get ALSA sound on the CS461x
chipsets going even with PCI bus power management turned *on*. (Which
should be desirable as it consumes less power when running on
batteries.) SuSE has patched the ALSA drivers in their distribution. I
don't know if this patch has already made it into the stock ALSA
drivers. I've attached a file that corresponds to the 0.5.9c driver
AFAIK. (Maybe you have to apply the diffs manually, depending on the
version you're using.) After applying this patch, you should specify

snd-card-cs461x snd_index=0 snd_id=card1 snd_check_clkrun=1
                                         ^^^^^^^^^^^^^^^^^^

in /etc/modules.conf. The last option makes sure that the sound chip
"wakes up" the PCI bus when it needs it.
 
> 2) X dying when suspending via a lid closing.  I think I read that
> recompiling the kernal with APM_IGNORE_SUSPEND_BOUNCE fixed this.  Has
> anyone done this for RH 7?  Were there problems?

Only thing I can say is that I always had set APM_IGNORE_SUSPEND_BOUNCE
to yes so far and never had such problems. But this for SuSE 6.2 up to
7.0.

> 3) The Lucent Winmodem.  I am using kernal 2.2.16-22 and have had no
> luck with the binary linmodem.  Last I heard, IBM still hadn't
> released this.  Is this still the case? (I don't mind waiting, I just
> don't want to miss it when it's finally available.)

Currently, there's only a binary only driver available for "external
use". Hopefully this will change soon (as for the MWave driver). If you
want to run the binary driver on a different kernel version than
2.2.12-20 for which it was compiled, you might want to have a look at
http://www.physcip.uni-stuttgart.de/heby/computer/ltmodem .

> 4) Hibernation.  I have a 500 MB Fat16 partition which I created a
> hibernation file on (apparently) from W2K.  However, I can't get
> hibernation to work from Linux.  Does anyone have this working?

If you create the hibernation file from the TP utility in Win2k, it gets
created on the *same* partition as Win2k, AFAIK. Linux is not able to
write to this file when hibernating. Therefore you will have to create a
separate partition (FAT16 or FAT32) housing a hibernation file that you
create from a so called "Hibernation Utility Diskette II for Standalone
Boot". To find the latter, go to IBM's ThinkPad website at
http://www.pc.ibm.com/us/thinkpad/ , switch to the Support section,
select your model (A20p) and search for "hibernation".

Of course, if you want to hibernate from within Win2k *and* Linux, you
will have to have *two* hibernation files. But I suspect you're working
with the Rigth OS most of the time ... ;-)

HTH,
Markus
--------------B3A81093F8057955277E4C2B
Content-Type: text/plain; charset=us-ascii;
 name="01-cs461x-clkrun.dif"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="01-cs461x-clkrun.dif"

diff -ruN --exclude=CVS alsa-driver-latest/cards/card-cs461x.c alsa-driver-suse/cards/card-cs461x.c
--- alsa-driver-latest/cards/card-cs461x.c	Thu Apr  6 11:51:20 2000
+++ alsa-driver-suse/cards/card-cs461x.c	Thu Jul 27 10:34:23 2000
@@ -40,6 +40,7 @@
 char *snd_id[SND_CARDS] = SND_DEFAULT_STR;	/* ID for this card */
 int snd_dac_frame_size[SND_CARDS] = {[0 ... (SND_CARDS - 1)] = 128};
 int snd_adc_frame_size[SND_CARDS] = {[0 ... (SND_CARDS - 1)] = 128};
+int snd_check_clkrun[SND_CARDS] = {[0 ... (SND_CARDS - 1)] = 1};
 MODULE_PARM(snd_index, "1-" __MODULE_STRING(SND_CARDS) "i");
 MODULE_PARM_DESC(snd_index, "Index value for the CS461x soundcard.");
 MODULE_PARM(snd_id, "1-" __MODULE_STRING(SND_CARDS) "s");
@@ -48,6 +49,8 @@
 MODULE_PARM_DESC(snd_dac_frame_size, "DAC frame size in kB for the CS461x soundcard.");
 MODULE_PARM(snd_adc_frame_size, "1-" __MODULE_STRING(SND_CARDS) "i");
 MODULE_PARM_DESC(snd_adc_frame_size, "ADC frame size in kB for the CS461x soundcard.");
+MODULE_PARM(snd_check_clkrun, "1-" __MODULE_STRING(SND_CARDS) "i");
+MODULE_PARM_DESC(snd_check_clkrun, "Activate PCI bus power management for the CS461x soundcard.");
 
 struct snd_cs461x {
 	struct pci_dev *pci;
@@ -165,6 +168,7 @@
 			      scard->dma1ptr,
 			      scard->dma2ptr,
 			      scard->irqptr,
+			      snd_check_clkrun[dev],
 			      &scard->codec) < 0)
 		goto __nodev;
 	if (snd_cs461x_pcm(scard->codec, 0, &pcm) < 0)
diff -ruN --exclude=CVS alsa-driver-latest/include/cs461x.h alsa-driver-suse/include/cs461x.h
--- alsa-driver-latest/include/cs461x.h	Tue Nov 30 16:29:12 1999
+++ alsa-driver-suse/include/cs461x.h	Thu Jul 27 10:34:24 2000
@@ -26,6 +26,7 @@
 #include "mixer.h"
 #include "rawmidi.h"
 #include "ac97_codec.h"
+#include "piix4.h"
 
 #ifndef PCI_VENDOR_ID_CIRRUS
 #define PCI_VENDOR_ID_CIRRUS            0x1013
@@ -1670,6 +1671,7 @@
 	snd_pcm_subchn_t *capture_subchn;
 	snd_kmixer_t *mixer;
 	snd_rawmidi_t *rmidi;
+	snd_piix4_clkrun_t *clkrun;
 
 	void *entry_proc_BA0;
 	void *entry_proc_BA1_data0;
@@ -1688,6 +1690,7 @@
 		      snd_dma_t * dma1ptr,
 		      snd_dma_t * dma2ptr,
 		      snd_irq_t * irqptr,
+		      int check_clkrun,
 		      cs461x_t ** rcodec);
 int snd_cs461x_free(cs461x_t * codec);
 void snd_cs461x_interrupt(cs461x_t * codec);
diff -ruN --exclude=CVS alsa-driver-latest/include/piix4.h alsa-driver-suse/include/piix4.h
--- alsa-driver-latest/include/piix4.h	Thu Jan  1 01:00:00 1970
+++ alsa-driver-suse/include/piix4.h	Wed Jul 26 15:34:41 2000
@@ -0,0 +1,117 @@
+#ifndef __PIIX4_H
+#define __PIIX4_H
+
+/*
+ *  Support for piix4 interface
+ *  Copyright (c) 2000  Takashi Iwai <tiwai@suse.de>
+ *  Copyright, (c) 2000, by Linuxcare, Inc.
+ *  Written by David Kaiser <dkaiser@linuxcare.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* definitions */
+
+#define PIIX4_LOCATION 0x40
+#define PIIX4_OFFSET 0x10
+#define PIIX4_CLKRUN_BIT 0x2000
+
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL 0x8086
+#endif PCI_VENDOR_ID_INTEL
+
+#ifndef PCI_DEVICE_ID_INTEL_82371AB_3
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#endif PCI_DEVICE_ID_INTEL_82371AB_3
+
+typedef struct snd_piix4_clkrun {
+	long base;
+	int used;
+	spinlock_t lock;
+} snd_piix4_clkrun_t;
+
+/* hold spinlock */
+static inline void __snd_piix4_clkrun_set(snd_piix4_clkrun_t *pp, int up)
+{
+	unsigned int status;
+	status = inw(pp->base + PIIX4_OFFSET);
+	if (up)
+		status |= PIIX4_CLKRUN_BIT;
+	else
+		status &= ~PIIX4_CLKRUN_BIT;
+	outw(status, pp->base + PIIX4_OFFSET);
+	//snd_printk("piix4: status = %x\n", status);
+}
+
+static inline void snd_piix4_clkrun_set(snd_piix4_clkrun_t *pp, int up)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&pp->lock, flags);
+	__snd_piix4_clkrun_set(pp, up);
+	spin_unlock_irqrestore(&pp->lock, flags);
+}
+
+static inline void snd_piix4_clkrun_down(snd_piix4_clkrun_t *pp)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&pp->lock, flags);
+	pp->used++;
+	__snd_piix4_clkrun_set(pp, 0);
+	spin_unlock_irqrestore(&pp->lock, flags);
+}
+
+static inline void snd_piix4_clkrun_up(snd_piix4_clkrun_t *pp)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&pp->lock, flags);
+	pp->used--;
+	if (pp->used <= 0)
+		__snd_piix4_clkrun_set(pp, 1);
+	spin_unlock_irqrestore(&pp->lock, flags);
+}
+
+static inline int snd_piix4_clkrun_new(snd_piix4_clkrun_t **rec)
+{
+	struct pci_dev *pcidev = NULL;
+	snd_piix4_clkrun_t *pp;
+	u8 tmp;
+
+	*rec = NULL;
+	while ((pcidev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					 PCI_DEVICE_ID_INTEL_82371AB_3,
+					 pcidev)) != NULL) {
+		pci_read_config_byte(pcidev, PIIX4_LOCATION+1, &tmp);
+		if (tmp == 0) {
+			snd_printk("piix4: PIIX4 ACPI base scan failed\n");
+			return -EINVAL;
+		}
+		if ((pp = snd_kcalloc(sizeof(*pp), GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		pp->base = tmp << 8;
+		spin_lock_init(&pp->lock);
+		*rec = pp;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static inline void snd_piix4_clkrun_free(snd_piix4_clkrun_t *pp)
+{
+	if (pp)
+		snd_kfree(pp);
+}
+
+#endif __PIIX4_H
diff -ruN --exclude=CVS alsa-driver-latest/lowlevel/pci/cs461x.c alsa-driver-suse/lowlevel/pci/cs461x.c
--- alsa-driver-latest/lowlevel/pci/cs461x.c	Mon Jun 19 19:34:54 2000
+++ alsa-driver-suse/lowlevel/pci/cs461x.c	Thu Jul 27 10:34:29 2000
@@ -1007,6 +1007,9 @@
 	codec->playback_subchn = subchn;
 	subchn->runtime->hw = &snd_cs461x_playback;
 	snd_pcm_set_mixer(subchn, codec->mixer->device, codec->ac97->me_playback);
+	if (codec->clkrun)
+		snd_piix4_clkrun_down(codec->clkrun);
+
 	return 0;
 }
 
@@ -1026,6 +1029,9 @@
 	codec->capture_subchn = subchn;
 	subchn->runtime->hw = &snd_cs461x_capture;
 	snd_pcm_set_mixer(subchn, codec->mixer->device, codec->ac97->me_capture);
+	if (codec->clkrun)
+		snd_piix4_clkrun_down(codec->clkrun);
+
 	return 0;
 }
 
@@ -1038,6 +1044,9 @@
 	if (codec->pbuf)
 		snd_free_pages(codec->pbuf, PAGE_SIZE);
 	snd_pcm_dma_free(subchn);
+	if (codec->clkrun)
+		snd_piix4_clkrun_up(codec->clkrun);
+
 	return 0;
 }
 
@@ -1050,6 +1059,9 @@
 	if (codec->cbuf)
 		snd_free_pages(codec->cbuf, PAGE_SIZE);
 	snd_pcm_dma_free(subchn);
+	if (codec->clkrun)
+		snd_piix4_clkrun_up(codec->clkrun);
+
 	return 0;
 }
 
@@ -1089,6 +1101,28 @@
  *  Mixer routines
  */
 
+static void snd_cs461x_mixer_write(void *private_data, unsigned short reg, unsigned short val)
+{
+	cs461x_t *codec = snd_magic_cast(cs461x_t, private_data, );
+	if (codec->clkrun)
+		snd_piix4_clkrun_down(codec->clkrun);
+	snd_cs461x_codec_write(private_data, reg, val);
+	if (codec->clkrun)
+		snd_piix4_clkrun_up(codec->clkrun);
+}
+
+static unsigned short snd_cs461x_mixer_read(void *private_data, unsigned short reg)
+{
+	cs461x_t *codec = snd_magic_cast(cs461x_t, private_data, -ENXIO);
+	unsigned short val;
+	if (codec->clkrun)
+		snd_piix4_clkrun_down(codec->clkrun);
+	val = snd_cs461x_codec_read(private_data, reg);
+	if (codec->clkrun)
+		snd_piix4_clkrun_up(codec->clkrun);
+	return val;
+}
+
 static void snd_cs461x_mixer_free_ac97(void *private_data)
 {
 	cs461x_t *codec = snd_magic_cast(cs461x_t, private_data, );
@@ -1103,8 +1137,8 @@
 
 	*rmixer = NULL;
 	memset(&ac97, 0, sizeof(ac97));
-	ac97.write = snd_cs461x_codec_write;
-	ac97.read = snd_cs461x_codec_read;
+	ac97.write = snd_cs461x_mixer_write;
+	ac97.read = snd_cs461x_mixer_read;
 	ac97.private_data = codec;
 	ac97.private_free = snd_cs461x_mixer_free_ac97;
 	if ((err = snd_ac97_mixer(codec->card, device, &ac97, 1, &pcm->device, &mixer)) < 0)
@@ -1130,6 +1164,9 @@
 	unsigned long flags;
 	cs461x_t *codec = snd_magic_cast(cs461x_t, rmidi->private_data, -ENXIO);
 
+	// do we need this??
+	if (codec->clkrun)
+		snd_piix4_clkrun_down(codec->clkrun);
 	spin_lock_irqsave(&codec->reg_lock, flags);
 	codec->uartm |= CS461X_MODE_INPUT;
 	codec->midcr |= MIDCR_RXE;
@@ -1156,6 +1193,9 @@
 	}
 	codec->uartm &= ~CS461X_MODE_INPUT;
 	spin_unlock_irqrestore(&codec->reg_lock, flags);
+	// do we need this??
+	if (codec->clkrun)
+		snd_piix4_clkrun_up(codec->clkrun);
 	return 0;
 }
 
@@ -1164,6 +1204,9 @@
 	unsigned long flags;
 	cs461x_t *codec = snd_magic_cast(cs461x_t, rmidi->private_data, -ENXIO);
 
+	// do we need this??
+	if (codec->clkrun)
+		snd_piix4_clkrun_down(codec->clkrun);
 	spin_lock_irqsave(&codec->reg_lock, flags);
 	codec->uartm |= CS461X_MODE_OUTPUT;
 	codec->midcr |= MIDCR_TXE;
@@ -1190,6 +1233,9 @@
 	}
 	codec->uartm &= ~CS461X_MODE_OUTPUT;
 	spin_unlock_irqrestore(&codec->reg_lock, flags);
+	// do we need this??
+	if (codec->clkrun)
+		snd_piix4_clkrun_up(codec->clkrun);
 	return 0;
 }
 
@@ -1427,6 +1473,7 @@
 		      snd_dma_t * dma1ptr,
 		      snd_dma_t * dma2ptr,
 		      snd_irq_t * irqptr,
+		      int check_clkrun,
 		      cs461x_t ** rcodec)
 {
 	cs461x_t *codec;
@@ -1481,6 +1528,16 @@
 		cmdb = 32;
 	pci_write_config_byte(pci, PCI_LATENCY_TIMER, cmdb);
 
+	if (check_clkrun) {
+		err = snd_piix4_clkrun_new(&codec->clkrun);
+		if (err == -ENOMEM) {
+			snd_cs461x_free(codec);
+			return -ENOMEM;
+		}
+		if (codec->clkrun)
+			snd_piix4_clkrun_set(codec->clkrun, 0);
+	}
+
 	/* 
 	 *  First, blast the clock control register to zero so that the PLL starts
          *  out in a known state, and blast the master serial port control register
@@ -1702,6 +1759,9 @@
 		return err;
 	}
 
+	if (codec->clkrun)
+		snd_piix4_clkrun_set(codec->clkrun, 1);
+
 	*rcodec = codec;
 	return 0;
 }
@@ -1712,6 +1772,9 @@
 
 	snd_debug_check(codec == NULL, -EINVAL);
 
+	if (codec->clkrun)
+		snd_piix4_clkrun_set(codec->clkrun, 0);
+
 	snd_cs461x_proc_done(codec);
 
 	tmp = snd_cs461x_peek(codec, BA1_PFIE);
@@ -1771,6 +1834,11 @@
 		iounmap(codec->ba1.name.pmem);
 	if (codec->ba1.name.reg)
 		iounmap(codec->ba1.name.reg);
+
+	if (codec->clkrun) {
+		snd_piix4_clkrun_set(codec->clkrun, 1);
+		snd_piix4_clkrun_free(codec->clkrun);
+	}
 
 	snd_magic_kfree(codec);
 	return 0;

--------------B3A81093F8057955277E4C2B--

----- The Linux ThinkPad mailing list -----
The linux-thinkpad mailing list home page is at:
http://www.bm-soft.com/~bm/tp_mailing.html