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.

Reply via email to