lkml.org 
[lkml]   [2000]   [Mar]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[RFT/PATCH] Re: Sound problem after suspend. Kernel version 2.3.99-pre3
On Mon, 27 Mar 2000, HvR wrote:
> the gpm killing is really necessary without this the
> sound module will not unload!!!

Really? That seems odd.

> > With kernel version 2.3.99-pre3 sound words until I
> > suspend my Toshiba
> > Satellite Pro 445CDX, but after resuming it will
> > produce no sound.
> > This problem came in with the sound clean-ups after
> > version 2.3.49.

I have a Toshiba Satellite 220CS laptop which has a OPL3-SA1 sound
chip. However I've never gotten the opl3sa1 driver to recognise it as such
so I've used the bare ad1848 (MS Sound System) driver instead. Unlike in
the case above I've never had working sound after suspend.

This is an experimental patch which fixes the suspend problem for me and
I'd appreciate if people would test it.

--- linux/drivers/sound/ad1848.c.bak Mon Mar 20 23:56:41 2000
+++ linux/drivers/sound/ad1848.c Tue Mar 21 10:09:04 2000
@@ -27,6 +27,7 @@
* Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free
* of irqs. Use dev_id.
* Christoph Hellwig : adapted to module_init/module_exit
+ * Aki Laukkanen : added power management support
*
* Status:
* Tested. Believed fully functional.
@@ -36,6 +37,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/stddef.h>
+#include <linux/pm.h>

#include "soundmodule.h"

@@ -52,6 +54,7 @@
int irq;
int dma1, dma2;
int dual_dma; /* 1, when two DMA channels allocated */
+ int subtype;
unsigned char MCE_bit;
unsigned char saved_regs[32];
int debug_flag;
@@ -87,6 +90,9 @@
int irq_ok;
mixer_ents *mix_devices;
int mixer_output_port;
+
+ /* Power management */
+ struct pm_dev *pmdev;
} ad1848_info;

typedef struct ad1848_port_info
@@ -100,7 +106,9 @@
}
ad1848_port_info;

+static struct address_info cfg;
static int nr_ad1848_devs = 0;
+
int deskpro_xl = 0;
int deskpro_m = 0;
int soundpro = 0;
@@ -163,11 +171,11 @@
static void ad1848_halt_input(int dev);
static void ad1848_halt_output(int dev);
static void ad1848_trigger(int dev, int bits);
+static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);

#ifndef EXCLUDE_TIMERS
static int ad1848_tmr_install(int dev);
static void ad1848_tmr_reprogram(int dev);
-
#endif

static int ad_read(ad1848_info * devc, int reg)
@@ -1415,7 +1423,7 @@
if (devc->model == MD_IWAVE)
ad_write(devc, 12, 0x6c); /* Select codec mode 3 */

- if (devc-> model != MD_1845_SSCAPE)
+ if (devc->model != MD_1845_SSCAPE)
for (i = 16; i < 32; i++)
ad_write(devc, i, init_values[i]);

@@ -1849,7 +1857,6 @@
* The actually used IRQ is ABS(irq).
*/

-
int my_dev;
char dev_name[100];
int e;
@@ -1863,6 +1870,7 @@
devc->timer_ticks = 0;
devc->dma1 = dma_playback;
devc->dma2 = dma_capture;
+ devc->subtype = cfg.card_subtype;
devc->audio_flags = DMA_AUTOMODE;
devc->playback_dev = devc->record_dev = 0;
if (name != NULL)
@@ -1915,6 +1923,10 @@

nr_ad1848_devs++;

+ devc->pmdev = pm_register(PM_ISA_DEV, my_dev, ad1848_pm_callback);
+ if (devc->pmdev)
+ devc->pmdev->data = devc;
+
ad1848_init_hw(devc);

if (irq > 0)
@@ -1950,7 +1962,7 @@
devc->irq_ok = 1;
}
#else
- devc->irq_ok=1;
+ devc->irq_ok = 1;
#endif
}
else
@@ -2076,6 +2088,9 @@
if(mixer>=0)
sound_unload_mixerdev(mixer);

+ if (devc->pmdev)
+ pm_unregister(devc->pmdev);
+
nr_ad1848_devs--;
for ( ; i < nr_ad1848_devs ; i++)
adev_info[i] = adev_info[i+1];
@@ -2507,7 +2522,8 @@
hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
hw_config->irq,
hw_config->dma,
- hw_config->dma2, 0, hw_config->osp);
+ hw_config->dma2, 0,
+ hw_config->osp);
request_region(hw_config->io_base, 4, "WSS config");
return;
}
@@ -2562,10 +2578,9 @@

outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */

- hw_config->slots[0] = ad1848_init("MSS audio codec", hw_config->io_base + 4,
+ hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
hw_config->irq,
- dma,
- dma2, 0,
+ dma, dma2, 0,
hw_config->osp);
request_region(hw_config->io_base, 4, "WSS config");
}
@@ -2692,6 +2707,83 @@
}
#endif /* EXCLUDE_TIMERS */

+static int ad1848_suspend(ad1848_info *devc)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ ad_mute(devc);
+
+ restore_flags(flags);
+ return 0;
+}
+
+static int ad1848_resume(ad1848_info *devc)
+{
+ unsigned long flags;
+ int mixer_levels[32], i;
+
+ save_flags(flags);
+ cli();
+
+ /* store old mixer levels */
+ memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));
+ ad1848_init_hw(devc);
+
+ /* restore mixer levels */
+ for (i = 0; i < 32; i++)
+ ad1848_mixer_set(devc, devc->dev_no, mixer_levels[i]);
+
+ if (!devc->subtype) {
+ static signed char interrupt_bits[12] = { -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 };
+ static char dma_bits[4] = { 1, 2, 0, 3 };
+
+ signed char bits;
+ char dma2_bit = 0;
+
+ int config_port = devc->base + 0;
+
+ bits = interrupt_bits[devc->irq];
+ if (bits == -1) {
+ printk(KERN_ERR "MSS: Bad IRQ %d\n", devc->irq);
+ return -1;
+ }
+
+ outb((bits | 0x40), config_port);
+
+ if (devc->dma2 != -1 && devc->dma2 != devc->dma1)
+ if ( (devc->dma1 == 0 && devc->dma2 == 1) ||
+ (devc->dma1 == 1 && devc->dma2 == 0) ||
+ (devc->dma1 == 3 && devc->dma2 == 0))
+ dma2_bit = 0x04;
+
+ outb((bits | dma_bits[devc->dma1] | dma2_bit), config_port);
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ ad1848_info *devc = dev->data;
+ if (devc) {
+ DEB(printk("ad1848: pm event received: 0x%x\n", rqst));
+
+ switch (rqst) {
+ case PM_SUSPEND:
+ ad1848_suspend(devc);
+ break;
+ case PM_RESUME:
+ ad1848_resume(devc);
+ break;
+ }
+ }
+ return 0;
+}
+

EXPORT_SYMBOL(ad1848_detect);
EXPORT_SYMBOL(ad1848_init);
@@ -2707,8 +2799,6 @@
static int __initdata dma = -1;
static int __initdata dma2 = -1;
static int __initdata type = 0;
-
-static struct address_info cfg;

MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */
MODULE_PARM(irq, "i"); /* IRQ to use */
\
 
 \ /
  Last update: 2005-03-22 13:57    [W:0.033 / U:1.712 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site