Hello, this is an experimental patch to add pm support to the soundblaster
driver. Contrary to what I earlier said I couldn't test it myself because
sound worked with the sb driver just fine after suspend (On a Toshiba 220CS).
I happened to test it only after making this patch so now I need testers who
have troubles with suspend and the sb driver.
diff -urN --exclude=*.flc linux-2.4.0-test1-ac22/drivers/sound/sb.h
linux-2.4.0-test1-ac22.sb/drivers/sound/sb.h
--- linux-2.4.0-test1-ac22/drivers/sound/sb.h Sun Apr 16 19:33:22 2000
+++ linux-2.4.0-test1-ac22.sb/drivers/sound/sb.h Wed Jun 21 01:57:06 2000
@@ -1,3 +1,5 @@
+#include <linux/pm.h>
+
#define DSP_RESET (devc->base + 0x6)
#define DSP_READ (devc->base + 0xA)
#define DSP_WRITE (devc->base + 0xC)
@@ -138,7 +140,9 @@
void *midi_irq_cookie; /* IRQ cookie for the midi */
struct sb_module_options sbmo; /* Module options */
-
+
+ /* Power management */
+ struct pm_dev *pmdev;
} sb_devc;
/*
@@ -160,18 +164,16 @@
int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct
sb_module_options *sbmo);
int sb_dsp_init (struct address_info *hw_config);
void sb_dsp_unload(struct address_info *hw_config, int sbmpu);
-int sb_mixer_init(sb_devc *devc);
-void sb_mixer_unload(sb_devc *devc);
-void sb_mixer_set_stereo (sb_devc *devc, int mode);
-void smw_mixer_init(sb_devc *devc);
void sb_dsp_midi_init (sb_devc *devc);
void sb_audio_init (sb_devc *devc, char *name);
void sb_midi_interrupt (sb_devc *devc);
void sb_chgmixer (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int
val);
int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right);
+
int sb_audio_open(int dev, int mode);
void sb_audio_close(int dev);
+int sb_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);
extern sb_devc *last_sb;
@@ -184,3 +186,11 @@
void unload_sb16(struct address_info *hw_info);
void unload_sb16midi(struct address_info *hw_info);
+
+/* From sb_mixer.c */
+int sb_mixer_set(sb_devc *devc, int dev, int value);
+int sb_set_recmask(sb_devc *devc, int mask);
+int sb_mixer_init(sb_devc *devc);
+void sb_mixer_unload(sb_devc *devc);
+void sb_mixer_set_stereo (sb_devc *devc, int mode);
+void smw_mixer_init(sb_devc *devc);
diff -urN --exclude=*.flc linux-2.4.0-test1-ac22/drivers/sound/sb_audio.c
linux-2.4.0-test1-ac22.sb/drivers/sound/sb_audio.c
--- linux-2.4.0-test1-ac22/drivers/sound/sb_audio.c Mon Feb 28 17:18:20 2000
+++ linux-2.4.0-test1-ac22.sb/drivers/sound/sb_audio.c Wed Jun 21 01:57:38 2000
@@ -1122,4 +1122,10 @@
}
audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev;
audio_devs[devc->dev]->min_fragment = 5;
+
+ /* FIXME: PM_PCI_ID() needed but no access to pcidev */
+ devc->pmdev = pm_register(devc->caps&SB_PCI_IRQ?PM_PCI_DEV:PM_ISA_DEV,
+ devc->dev, sb_pm_callback);
+ if (devc->pmdev)
+ devc->pmdev->data = devc;
}
diff -urN --exclude=*.flc linux-2.4.0-test1-ac22/drivers/sound/sb_card.c
linux-2.4.0-test1-ac22.sb/drivers/sound/sb_card.c
--- linux-2.4.0-test1-ac22/drivers/sound/sb_card.c Wed Jun 21 00:03:52 2000
+++ linux-2.4.0-test1-ac22.sb/drivers/sound/sb_card.c Wed Jun 21 20:11:48 2000
@@ -45,6 +45,8 @@
* 25-05-2000 Added Creative SB AWE64 Gold (CTL00B2).
* P�l-Kristian Engstad <[EMAIL PROTECTED]>
*
+ * 21-06-2000 Power Management support.
+ * Aki Laukkanen <[EMAIL PROTECTED]>
*/
#include <linux/config.h>
@@ -489,6 +491,7 @@
}
return(dev);
}
+
static struct pci_dev *sb_init(struct pci_bus *bus, struct address_info *hw_config,
struct address_info *mpu_config, int slot, int card)
{
diff -urN --exclude=*.flc linux-2.4.0-test1-ac22/drivers/sound/sb_common.c
linux-2.4.0-test1-ac22.sb/drivers/sound/sb_common.c
--- linux-2.4.0-test1-ac22/drivers/sound/sb_common.c Sat Apr 29 14:27:55 2000
+++ linux-2.4.0-test1-ac22.sb/drivers/sound/sb_common.c Wed Jun 21 20:14:23 2000
@@ -891,6 +891,9 @@
if (devc && devc->base == hw_config->io_base)
{
+ if (devc->pmdev)
+ pm_unregister(devc->pmdev);
+
if ((devc->model & MDL_ESS) && devc->pcibase)
release_region(devc->pcibase, 8);
@@ -915,6 +918,7 @@
sound_unload_mididev(devc->my_mididev);
sound_unload_audiodev(devc->dev);
}
+
kfree(devc);
}
else
@@ -1291,6 +1295,65 @@
#endif
unload_uart401(hw_config);
}
+
+static int sb_suspend(sb_devc *devc)
+{
+ return 0;
+}
+
+static int sb_resume(sb_devc *devc)
+{
+ int mixer_levels[SOUND_MIXER_NRDEVICES], i;
+
+ /* store old mixer levels */
+ memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));
+
+ /* FIXME: can not test this */
+#if 0
+ if (!((devc->caps & SB_NO_AUDIO) && (devc->caps & SB_NO_MIDI)) &&
+hw_config->irq > 0) {
+ /* rewrite incase was forgotten */
+ if (devc->major == 4) {
+ sb16_set_irq_hw(devc, devc->irq);
+ sb16_set_dma_hw(devc, devc);
+ }
+ }
+#endif
+
+ if (!sb_dsp_reset(devc)) {
+ DDB(printk("SB reset failed\n"));
+#ifdef MODULE
+ printk(KERN_INFO "sb: dsp reset failed.\n");
+#endif
+ return 0;
+ }
+
+ /* restore mixer settings */
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ sb_mixer_set(devc, i, mixer_levels[i]);
+
+ if (devc->model != MDL_ESS || !ess_mixer_reset (devc))
+ sb_set_recmask(devc, SOUND_MASK_MIC);
+ return 0;
+}
+
+
+int sb_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ sb_devc *devc = dev->data;
+ if (devc) {
+ DEB(printk(KERN_DEBUG "sb: dev %p pm_event: %d\n", devc, rqst));
+ switch (rqst) {
+ case PM_SUSPEND:
+ sb_suspend(devc);
+ break;
+ case PM_RESUME:
+ sb_resume(devc);
+ break;
+ }
+ }
+ return 0;
+}
+
EXPORT_SYMBOL(sb_dsp_init);
EXPORT_SYMBOL(sb_dsp_detect);
diff -urN --exclude=*.flc linux-2.4.0-test1-ac22/drivers/sound/sb_mixer.c
linux-2.4.0-test1-ac22.sb/drivers/sound/sb_mixer.c
--- linux-2.4.0-test1-ac22/drivers/sound/sb_mixer.c Sun Apr 16 19:33:22 2000
+++ linux-2.4.0-test1-ac22.sb/drivers/sound/sb_mixer.c Wed Jun 21 01:36:30 2000
@@ -344,7 +344,7 @@
return left | (right << 8);
}
-static int sb_mixer_set(sb_devc * devc, int dev, int value)
+int sb_mixer_set(sb_devc * devc, int dev, int value)
{
int left = value & 0x000000ff;
int right = (value & 0x0000ff00) >> 8;
@@ -387,7 +387,7 @@
sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src &
0x7));
}
-static int set_recmask(sb_devc * devc, int mask)
+int sb_set_recmask(sb_devc * devc, int mask)
{
int devmask, i;
unsigned char regimageL, regimageR;
@@ -569,7 +569,7 @@
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
- ret = set_recmask(devc, val);
+ ret = sb_set_recmask(devc, val);
break;
case SOUND_MIXER_OUTSRC:
@@ -654,7 +654,7 @@
sb_mixer_set(devc, i, devc->levels[i]);
if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) {
- set_recmask(devc, SOUND_MASK_MIC);
+ sb_set_recmask(devc, SOUND_MASK_MIC);
};
}
--
D.