patch-2.3.99-pre6 linux/drivers/sound/ad1848.c
Next file: linux/drivers/sound/cmpci.c
Previous file: linux/drivers/sound/Makefile
Back to the patch index
Back to the overall index
- Lines: 228
- Date:
Wed Apr 12 09:47:26 2000
- Orig file:
v2.3.99-pre5/linux/drivers/sound/ad1848.c
- Orig date:
Fri Mar 10 16:40:44 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
@@ -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 */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)