diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
commit | 95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch) | |
tree | 27a92a942821cde1edda9a1b088718d436b3efe4 /drivers/sound | |
parent | 45b27b0a0652331d104c953a5b192d843fff88f8 (diff) |
Merge with Linux 2.3.40.
Diffstat (limited to 'drivers/sound')
-rw-r--r-- | drivers/sound/cmpci.c | 3 | ||||
-rw-r--r-- | drivers/sound/es1370.c | 48 | ||||
-rw-r--r-- | drivers/sound/es1371.c | 48 | ||||
-rw-r--r-- | drivers/sound/esssolo1.c | 221 | ||||
-rw-r--r-- | drivers/sound/msnd.c | 41 | ||||
-rw-r--r-- | drivers/sound/msnd.h | 10 | ||||
-rw-r--r-- | drivers/sound/msnd_classic.h | 6 | ||||
-rw-r--r-- | drivers/sound/msnd_pinnacle.c | 53 | ||||
-rw-r--r-- | drivers/sound/msnd_pinnacle.h | 22 | ||||
-rw-r--r-- | drivers/sound/sonicvibes.c | 44 | ||||
-rw-r--r-- | drivers/sound/sscape.c | 679 | ||||
-rw-r--r-- | drivers/sound/trident.c | 19 |
12 files changed, 935 insertions, 259 deletions
diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index 9c6851832..c7bbffca6 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -62,7 +62,7 @@ * 18.08.99 1.5 Only deallocate DMA buffer when unloading. * 02.09.99 1.6 Enable SPDIF LOOP * Change the mixer read back - * 21.09.99 2.33 Use RCS version aas driver version. + * 21.09.99 2.33 Use RCS version as driver version. * Add support for modem, S/PDIF loop and 4 channels. * (8738 only) * Fix bug cause x11amp cannot play. @@ -2372,6 +2372,7 @@ int __init init_cmpci(void) init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); s->magic = CM_MAGIC; s->iobase = pcidev->resource[0].start; s->iosynth = 0x388; diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 89fcbf2b6..acea8e22f 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -114,6 +114,8 @@ * 03.09.1999 0.30 change read semantics for MIDI to match * OSS more closely; remove possible wakeup race * 28.10.1999 0.31 More waitqueue races fixed + * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this * * some important things missing in Ensoniq documentation: * @@ -1331,6 +1333,7 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, mapped, ret; VALIDATE_STATE(s); @@ -1508,7 +1511,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; - abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac2.dmasize - count; abinfo.fragstotal = s->dma_dac2.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1522,7 +1528,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; + count = s->dma_adc.count; + if (count < 0) + count = 0; + abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1537,9 +1546,11 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd return -EINVAL; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); - val = s->dma_dac2.count; + count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) @@ -1547,7 +1558,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + count = s->dma_adc.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1560,7 +1574,10 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1853,6 +1870,7 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; unsigned ctrl; int val, ret; @@ -1961,7 +1979,10 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_dac1.fragsize; - abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac1.dmasize - count; abinfo.fragstotal = s->dma_dac1.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1974,9 +1995,11 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int case SNDCTL_DSP_GETODELAY: spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); - val = s->dma_dac1.count; + count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) @@ -1984,7 +2007,10 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2444,7 +2470,7 @@ static int __init init_es1370(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.32 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (!RSRCISIOREGION(pcidev, 0)) diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 2ef9d0bf5..1a4844d47 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -96,6 +96,8 @@ * detect ES137x chip and derivatives. * 05.01.2000 0.22 Should now work with rev7 boards; patch by * Eric Lemar, elemar@cs.washington.edu + * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this */ /*****************************************************************************/ @@ -1911,6 +1913,7 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, mapped, ret; VALIDATE_STATE(s); @@ -2085,7 +2088,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; - abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac2.dmasize - count; abinfo.fragstotal = s->dma_dac2.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -2099,7 +2105,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; + count = s->dma_adc.count; + if (count < 0) + count = 0; + abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -2114,9 +2123,11 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd return -EINVAL; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); - val = s->dma_dac2.count; + count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) @@ -2124,7 +2135,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + count = s->dma_adc.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -2137,7 +2151,10 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -2430,6 +2447,7 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, ret; VALIDATE_STATE(s); @@ -2529,7 +2547,10 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_dac1.fragsize; - abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac1.dmasize - count; abinfo.fragstotal = s->dma_dac1.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -2542,9 +2563,11 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int case SNDCTL_DSP_GETODELAY: spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); - val = s->dma_dac1.count; + count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) @@ -2552,7 +2575,10 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -3229,7 +3255,7 @@ static int __init init_es1371(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.23 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))) { if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) { if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 && diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index 2d33c895a..255efbc2b 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -3,7 +3,7 @@ /* * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver. * - * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) * * 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 @@ -28,41 +28,44 @@ * /dev/midi simple MIDI UART interface, no ioctl * * Revision history - * 10.11.98 0.1 Initial release (without any hardware) - * 22.03.99 0.2 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes <joma@telindus.be> - * return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 07.04.99 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE, - * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; - * Alpha fixes reported by Peter Jones <pjones@redhat.com> - * 15.06.99 0.4 Fix bad allocation bug. - * Thanks to Deti Fliegl <fliegl@in.tum.de> - * 28.06.99 0.5 Add pci_set_master - * 12.08.99 0.6 Fix MIDI UART crashing the driver - * Changed mixer semantics from OSS documented - * behaviour to OSS "code behaviour". - * Recording might actually work now. - * The real DDMA controller address register is at PCI config - * 0x60, while the register at 0x18 is used as a placeholder - * register for BIOS address allocation. This register - * is supposed to be copied into 0x60, according - * to the Solo1 datasheet. When I do that, I can access - * the DDMA registers except the mask bit, which - * is stuck at 1. When I copy the contents of 0x18 +0x10 - * to the DDMA base register, everything seems to work. - * The fun part is that the Windows Solo1 driver doesn't - * seem to do these tricks. - * Bugs remaining: plops and clicks when starting/stopping playback - * 31.08.99 0.7 add spin_lock_init - * replaced current->state = x with set_current_state(x) - * 03.09.99 0.8 change read semantics for MIDI to match - * OSS more closely; remove possible wakeup race - * 07.10.99 0.9 Fix initialization; complain if sequencer writes time out - * Revised resource grabbing for the FM synthesizer - * 28.10.99 0.10 More waitqueue races fixed - * 09.12.99 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M) - * Disabling recording on Alpha + * 10.11.1998 0.1 Initial release (without any hardware) + * 22.03.1999 0.2 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes <joma@telindus.be> + * return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 07.04.1999 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones <pjones@redhat.com> + * 15.06.1999 0.4 Fix bad allocation bug. + * Thanks to Deti Fliegl <fliegl@in.tum.de> + * 28.06.1999 0.5 Add pci_set_master + * 12.08.1999 0.6 Fix MIDI UART crashing the driver + * Changed mixer semantics from OSS documented + * behaviour to OSS "code behaviour". + * Recording might actually work now. + * The real DDMA controller address register is at PCI config + * 0x60, while the register at 0x18 is used as a placeholder + * register for BIOS address allocation. This register + * is supposed to be copied into 0x60, according + * to the Solo1 datasheet. When I do that, I can access + * the DDMA registers except the mask bit, which + * is stuck at 1. When I copy the contents of 0x18 +0x10 + * to the DDMA base register, everything seems to work. + * The fun part is that the Windows Solo1 driver doesn't + * seem to do these tricks. + * Bugs remaining: plops and clicks when starting/stopping playback + * 31.08.1999 0.7 add spin_lock_init + * replaced current->state = x with set_current_state(x) + * 03.09.1999 0.8 change read semantics for MIDI to match + * OSS more closely; remove possible wakeup race + * 07.10.1999 0.9 Fix initialization; complain if sequencer writes time out + * Revised resource grabbing for the FM synthesizer + * 28.10.1999 0.10 More waitqueue races fixed + * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M) + * Disabling recording on Alpha + * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this + * Integrated (aka redid 8-)) APM support patch by Zach Brown * */ @@ -79,6 +82,7 @@ #include <linux/soundcard.h> #include <linux/pci.h> #include <linux/bitops.h> +#include <linux/apm_bios.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/init.h> @@ -1224,7 +1228,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long flags; audio_buf_info abinfo; count_info cinfo; - int val, mapped, ret; + int val, mapped, ret, count; int div1, div2; unsigned rate1, rate2; @@ -1304,7 +1308,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, stop_dac(s); s->dma_adc.ready = s->dma_dac.ready = 0; /* program channels */ - s->channels = val ? 2 : 1; + s->channels = (val >= 2) ? 2 : 1; prog_codec(s); } return put_user(s->channels, (int *)arg); @@ -1368,7 +1372,10 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + count = s->dma_dac.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac.dmasize - count; abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1397,9 +1404,11 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EINVAL; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); - val = s->dma_dac.count; + count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) @@ -1420,7 +1429,10 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + count = s->dma_dac.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -2132,6 +2144,79 @@ static struct initvol { { SOUND_MIXER_WRITE_MIC, 0x4040 } }; +static int setup_solo1(struct solo1_state *s) +{ + struct pci_dev *pcidev = s->pcidev; + mm_segment_t fs; + int i, val; + + /* initialize the chips */ + if (!reset_ctrl(s)) { + printk(KERN_ERR "esssolo1: cannot reset controller\n"); + return -1; + } + outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */ + + /* initialize mixer regs */ + write_mixer(s, 0x7f, 0); /* disable music digital recording */ + write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */ + write_mixer(s, 0x64, 0x45); /* volume control */ + write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */ + write_mixer(s, 0x50, 0); /* disable spatializer */ + write_mixer(s, 0x52, 0); + write_mixer(s, 0x14, 0); /* DAC1 minimum volume */ + write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */ + outb(0, s->ddmabase+0xd); /* DMA master clear */ + outb(1, s->ddmabase+0xf); /* mask channel */ + /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */ + + pci_set_master(pcidev); /* enable bus mastering */ + + fs = get_fs(); + set_fs(KERNEL_DS); + val = SOUND_MASK_LINE; + mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { + val = initvol[i].vol; + mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + } + val = 1; /* enable mic preamp */ + mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val); + set_fs(fs); + return 0; +} + +#ifdef CONFIG_APM + +static int solo1_apm_callback(apm_event_t event) +{ + struct solo1_state *s; + + switch(event) { + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + case APM_STANDBY_RESUME: + for(s = devs ; s ; s = s->next) + setup_solo1(s); + break; + + default: + for(s = devs ; s ; s = s->next) { + outb(0, s->iobase+6); + /* DMA master clear */ + outb(0, s->ddmabase+0xd); + /* reset sequencer and FIFO */ + outb(3, s->sbbase+6); + /* turn off DDMA controller address space */ + pci_write_config_word(s->pcidev, 0x60, 0); + } + } + return 0; +} + +#endif + + #define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) @@ -2141,12 +2226,11 @@ static int __init init_solo1(void) { struct solo1_state *s; struct pci_dev *pcidev = NULL; - mm_segment_t fs; - int i, val, index = 0; + int index = 0; if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.12 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) { if (!RSRCISIOREGION(pcidev, 0) || @@ -2192,13 +2276,7 @@ static int __init init_solo1(void) printk(KERN_ERR "solo1: irq %u in use\n", s->irq); goto err_irq; } - /* initialize DDMA base address */ printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase); - pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1); - /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */ - pci_write_config_dword(pcidev, 0x50, 0); - /* disable legacy audio address decode */ - pci_write_config_word(pcidev, 0x40, 0x907f); printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1); @@ -2211,39 +2289,8 @@ static int __init init_solo1(void) goto err_dev3; if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) goto err_dev4; - /* initialize the chips */ - if (!reset_ctrl(s)) { - printk(KERN_ERR "esssolo1: cannot reset controller\n"); + if (setup_solo1(s)) goto err; - } - outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */ - - /* initialize mixer regs */ - write_mixer(s, 0x7f, 0); /* disable music digital recording */ - write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */ - write_mixer(s, 0x64, 0x45); /* volume control */ - write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */ - write_mixer(s, 0x50, 0); /* disable spatializer */ - write_mixer(s, 0x52, 0); - write_mixer(s, 0x14, 0); /* DAC1 minimum volume */ - write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */ - outb(0, s->ddmabase+0xd); /* DMA master clear */ - outb(1, s->ddmabase+0xf); /* mask channel */ - /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */ - - pci_set_master(pcidev); /* enable bus mastering */ - - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - val = 1; /* enable mic preamp */ - mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val); - set_fs(fs); /* queue it for later freeing */ s->next = devs; devs = s; @@ -2259,7 +2306,7 @@ static int __init init_solo1(void) err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: - printk(KERN_ERR "solo1: cannot register misc device\n"); + printk(KERN_ERR "solo1: initialisation error\n"); free_irq(s->irq, s); err_irq: release_region(s->iobase, IOBASE_EXTENT); @@ -2271,6 +2318,9 @@ static int __init init_solo1(void) } if (!devs) return -ENODEV; +#ifdef CONFIG_APM + apm_register_callback(solo1_apm_callback); +#endif return 0; } @@ -2302,6 +2352,9 @@ static void __exit cleanup_solo1(void) unregister_sound_special(s->dev_dmfm); kfree_s(s, sizeof(struct solo1_state)); } +#ifdef CONFIG_APM + apm_unregister_callback(solo1_apm_callback); +#endif printk(KERN_INFO "solo1: unloading\n"); } diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c index 4bfca0875..e47c30f90 100644 --- a/drivers/sound/msnd.c +++ b/drivers/sound/msnd.c @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.c,v 1.16 1998/09/08 04:05:56 andrewtv Exp $ + * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $ * ********************************************************************/ @@ -66,7 +66,7 @@ int msnd_register(multisound_dev_t *dev) if (i == MSND_MAX_DEVS) return -ENOMEM; - + devs[i] = dev; ++num_devs; @@ -106,13 +106,21 @@ multisound_dev_t *msnd_get_dev(int j) for (i = 0; i < MSND_MAX_DEVS && j; ++i) if (devs[i] != NULL) --j; - + if (i == MSND_MAX_DEVS || j != 0) return NULL; return devs[i]; } +void msnd_init_queue(unsigned long base, int start, int size) +{ + isa_writew(PCTODSP_BASED(start), base + JQS_wStart); + isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); + isa_writew(0, base + JQS_wHead); + isa_writew(0, base + JQS_wTail); +} + void msnd_fifo_init(msnd_fifo *f) { f->data = NULL; @@ -152,11 +160,11 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) if (f->len == f->n) return 0; - + while ((count < len) && (f->len != f->n)) { - + int nwritten; - + if (f->head <= f->tail) { nwritten = len - count; if (nwritten > f->n - f->tail) @@ -180,7 +188,7 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) f->tail += nwritten; f->tail %= f->n; } - + return count; } @@ -190,11 +198,11 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) if (f->len == 0) return f->len; - + while ((count < len) && (f->len > 0)) { - + int nread; - + if (f->tail <= f->head) { nread = len - count; if (nread > f->n - f->head) @@ -205,20 +213,20 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) if (nread > len - count) nread = len - count; } - + if (user) { if (copy_to_user(buf, f->data + f->head, nread)) return -EFAULT; } else memcpy(buf, f->data + f->head, nread); - + count += nread; buf += nread; f->len -= nread; f->head += nread; f->head %= f->n; } - + return count; } @@ -259,7 +267,7 @@ int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd) spin_unlock_irqrestore(&dev->lock, flags); printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n"); - + return -EIO; } @@ -307,7 +315,7 @@ int msnd_enable_irq(multisound_dev_t *dev) return 0; printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n"); - + spin_lock_irqsave(&dev->lock, flags); if (msnd_wait_TXDE(dev) == 0) { outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); @@ -316,6 +324,7 @@ int msnd_enable_irq(multisound_dev_t *dev) outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR); outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR); enable_irq(dev->irq); + msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size); spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -360,6 +369,8 @@ EXPORT_SYMBOL(msnd_unregister); EXPORT_SYMBOL(msnd_get_num_devs); EXPORT_SYMBOL(msnd_get_dev); +EXPORT_SYMBOL(msnd_init_queue); + EXPORT_SYMBOL(msnd_fifo_init); EXPORT_SYMBOL(msnd_fifo_free); EXPORT_SYMBOL(msnd_fifo_alloc); diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index 54bf5fd01..219a6bfe0 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -24,13 +24,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.h,v 1.33 1998/11/05 20:26:18 andrewtv Exp $ + * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_H #define __MSND_H -#define VERSION "0.8.2.2" +#define VERSION "0.8.3.1" #define DEFSAMPLERATE DSP_DEFAULT_SPEED #define DEFSAMPLESIZE AFMT_U8 @@ -202,6 +202,7 @@ typedef struct multisound_dev { /* Linux device info */ char *name; int dsp_minor, mixer_minor; + int ext_midi_dev, hdr_midi_dev; /* Hardware resources */ int io, numio; @@ -214,6 +215,7 @@ typedef struct multisound_dev { unsigned long SMA; unsigned long DAPQ, DARQ, MODQ, MIDQ, DSPQ; unsigned long pwDSPQData, pwMIDQData, pwMODQData; + int dspq_data_buff, dspq_buff_size; /* State variables */ enum { msndClassic, msndPinnacle } type; @@ -229,7 +231,7 @@ typedef struct multisound_dev { #define F_READING 7 #define F_READBLOCK 8 #define F_EXT_MIDI_INUSE 9 -#define F_INT_MIDI_INUSE 10 +#define F_HDR_MIDI_INUSE 10 #define F_DISABLE_WRITE_NDELAY 11 wait_queue_head_t writeblock; wait_queue_head_t readblock; @@ -269,6 +271,8 @@ void msnd_unregister(multisound_dev_t *dev); int msnd_get_num_devs(void); multisound_dev_t * msnd_get_dev(int i); +void msnd_init_queue(unsigned long, int start, int size); + void msnd_fifo_init(msnd_fifo *f); void msnd_fifo_free(msnd_fifo *f); int msnd_fifo_alloc(msnd_fifo *f, size_t n); diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h index 25898f8e0..83c3c46ff 100644 --- a/drivers/sound/msnd_classic.h +++ b/drivers/sound/msnd_classic.h @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_classic.h,v 1.9 1998/09/10 04:11:18 andrewtv Exp $ + * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_CLASSIC_H @@ -108,13 +108,13 @@ #define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) #define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) -#define MOP_PROTEUS 0x10 +#define MOP_SYNTH 0x10 #define MOP_EXTOUT 0x32 #define MOP_EXTTHRU 0x02 #define MOP_OUTMASK 0x01 #define MIP_EXTIN 0x01 -#define MIP_PROTEUS 0x00 +#define MIP_SYNTH 0x00 #define MIP_INMASK 0x32 /* Classic SMA Common Data */ diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index d90bb071a..dd1b596f4 100644 --- a/drivers/sound/msnd_pinnacle.c +++ b/drivers/sound/msnd_pinnacle.c @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.c,v 1.73 1998/12/04 14:41:02 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv Exp $ * ********************************************************************/ @@ -254,7 +254,7 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case SNDCTL_DSP_SYNC: dsp_write_flush(); return 0; - + case SNDCTL_DSP_GETBLKSIZE: tmp = dsp_get_frag_size(); if (put_user(tmp, (int *)arg)) @@ -352,7 +352,7 @@ static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } } - + for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { if (file->f_mode & FMODE_WRITE) isa_writew(data, lpDAQ + DAQDS_wChannels); @@ -570,7 +570,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) return 0; } else if (((cmd >> 8) & 0xff) == 'M') { int val = 0; - + if (_SIOC_DIR(cmd) & _SIOC_WRITE) { switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: @@ -578,7 +578,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) return -EFAULT; val = set_recsrc(val); break; - + default: if (get_user(val, (int *)arg)) return -EFAULT; @@ -592,7 +592,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) case SOUND_MIXER_RECSRC: val = dev.recsrc; break; - + case SOUND_MIXER_DEVMASK: case SOUND_MIXER_STEREODEVS: val = SOUND_MASK_PCM | @@ -620,7 +620,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) case SOUND_MIXER_CAPS: val = SOUND_CAP_EXCL_INPUT; break; - + default: if ((val = mixer_get(cmd & 0xff)) < 0) return -EINVAL; @@ -787,7 +787,7 @@ static int dev_open(struct inode *inode, struct file *file) /* nothing */ } else err = -EINVAL; - + if (err >= 0) mod_inc_ref(); @@ -873,7 +873,7 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); register int n; unsigned long flags; - + /* Write the data to the new tail */ if (protect) { /* Critical section: protect fifo in non-interrupt */ @@ -910,11 +910,9 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) /* Then advance the tail */ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); isa_writew(DAPQ_tail, dev.DAPQ + JQS_wTail); - /* Tell the DSP to play the bank */ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); } - return nbanks; } @@ -999,7 +997,7 @@ static int dsp_write(const char *buf, size_t len) return -EINTR; } } - + return len - count; } @@ -1142,7 +1140,7 @@ static struct file_operations dev_fileops = { static int reset_dsp(void) { int timeout = 100; - + outb(HPDSPRESET_ON, dev.io + HP_DSPR); mdelay(1); #ifndef MSND_CLASSIC @@ -1190,7 +1188,7 @@ static int __init probe_multisound(void) case 0x3: xv = "1.4"; break; default: xv = "unknown"; break; } - + switch (dev.info & 0x7) { case 0x0: rev = "I"; dev.name = pin; break; case 0x1: rev = "F"; dev.name = pin; break; @@ -1216,18 +1214,9 @@ static int __init probe_multisound(void) dev.base, dev.base + 0x7fff); release_region(dev.io, dev.numio); - return 0; } -static void msnd_init_queue(unsigned long base, int start, int size) -{ - isa_writew(PCTODSP_BASED(start), base + JQS_wStart); - isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); - isa_writew(0, base + JQS_wHead); - isa_writew(0, base + JQS_wTail); -} - static int init_sma(void) { static int initted; @@ -1383,7 +1372,7 @@ static int initialize(void) if ((err = reset_dsp()) < 0) return err; - + if ((err = upload_dsp_code()) < 0) { printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n"); return err; @@ -1462,12 +1451,14 @@ static int __init attach_multisound(void) return dev.mixer_minor; } + dev.ext_midi_dev = dev.hdr_midi_dev = -1; + disable_irq(dev.irq); calibrate_adc(dev.play_sample_rate); #ifndef MSND_CLASSIC force_recsrc(SOUND_MASK_IMIX); #endif - + return 0; } @@ -1593,7 +1584,7 @@ static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cf /* Configure specified devices */ for (i = 0; i < 4; ++i) { - + switch (i) { case 0: /* DSP */ if (!(device[i].io0 && device[i].irq && device[i].mem)) @@ -1776,7 +1767,7 @@ int __init msnd_pinnacle_init(void) printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version " VERSION ", Copyright (C) 1998 Andrew Veliath\n"); - + if (io == -1 || irq == -1 || mem == -1) printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n"); @@ -1792,7 +1783,7 @@ int __init msnd_pinnacle_init(void) printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n"); return -EINVAL; } - + if (irq == -1 || !(irq == 5 || irq == 7 || @@ -1849,7 +1840,7 @@ int __init msnd_pinnacle_init(void) pinnacle_devs[0].mem = mem; /* The following are Pinnacle specific */ - + /* MPU */ pinnacle_devs[1].io0 = mpu_io; pinnacle_devs[1].irq = mpu_irq; @@ -1896,6 +1887,8 @@ int __init msnd_pinnacle_init(void) dev.fifosize = fifosize * 1024; dev.calibrate_signal = calibrate_signal ? 1 : 0; dev.recsrc = 0; + dev.dspq_data_buff = DSPQ_DATA_BUFF; + dev.dspq_buff_size = DSPQ_BUFF_SIZE; dev.inc_ref = mod_inc_ref; dev.dec_ref = mod_dec_ref; if (write_ndelay == -1) @@ -1934,7 +1927,7 @@ int __init msnd_pinnacle_init(void) msnd_fifo_free(&dev.DARF); return err; } - + if ((err = attach_multisound()) < 0) { printk(KERN_ERR LOGNAME ": Attach failed\n"); msnd_fifo_free(&dev.DAPF); diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h index 2f572af2c..e85aef4a5 100644 --- a/drivers/sound/msnd_pinnacle.h +++ b/drivers/sound/msnd_pinnacle.h @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.h,v 1.10 1998/09/10 04:11:18 andrewtv Exp $ + * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_PINNACLE_H @@ -141,18 +141,16 @@ #define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) #define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) -#define WAVEHDR_MOP 0 -#define EXTOUT_MOP 1 -#define HWINIT_MOP 0xFE -#define NO_MOP 0xFF +#define MOP_WAVEHDR 0 +#define MOP_EXTOUT 1 +#define MOP_HWINIT 0xfe +#define MOP_NONE 0xff +#define MOP_MAX 1 -#define MAX_MOP 1 - -#define EXTIN_MIP 0 -#define WAVEHDR_MIP 1 -#define HWINIT_MIP 0xFE - -#define MAX_MIP 1 +#define MIP_EXTIN 0 +#define MIP_WAVEHDR 1 +#define MIP_HWINIT 0xfe +#define MIP_MAX 1 /* Pinnacle/Fiji SMA Common Data */ #define SMA_wCurrPlayBytes 0x0000 diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index f52ec2247..245d16a19 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -84,6 +84,9 @@ * 28.10.1999 0.22 More waitqueue races fixed * 01.12.1999 0.23 New argument to allocate_resource * 07.12.1999 0.24 More allocate_resource semantics change + * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this + * use Martin Mares' pci_assign_resource * */ @@ -131,6 +134,10 @@ #define SV_EXTENT_GAME 0x8 #define SV_EXTENT_DMA 0x10 +/* + * we are not a bridge and thus use a resource for DDMA that is used for bridges but + * left empty for normal devices + */ #define RESOURCE_SB 0 #define RESOURCE_ENH 1 #define RESOURCE_SYNTH 2 @@ -1533,6 +1540,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, mapped, ret; unsigned char fmtm, fmtd; @@ -1700,7 +1708,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + count = s->dma_dac.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac.dmasize - count; abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1714,7 +1725,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; + count = s->dma_adc.count; + if (count < 0) + count = 0; + abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1729,9 +1743,11 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un return -EINVAL; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); - val = s->dma_dac.count; + count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) @@ -1739,7 +1755,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + count = s->dma_adc.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1752,7 +1771,10 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + count = s->dma_dac.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -2427,7 +2449,7 @@ static int __init init_sonicvibes(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.24 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.25 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); @@ -2444,20 +2466,20 @@ static int __init init_sonicvibes(void) continue; /* try to allocate a DDMA resource if not already available */ if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { - /* take care of ISA aliases */ + pcidev->resource[RESOURCE_DDMA].start = 0; + pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1; + pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO; ddmanamelen = strlen(sv_ddma_name)+1; if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL))) continue; memcpy(ddmaname, sv_ddma_name, ddmanamelen); pcidev->resource[RESOURCE_DDMA].name = ddmaname; - if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA, - 2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024, NULL, NULL)) { + if (pci_assign_resource(pcidev, RESOURCE_DDMA)) { pcidev->resource[RESOURCE_DDMA].name = NULL; kfree(ddmaname); printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n"); continue; } - pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO; } if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) { printk(KERN_WARNING "sv: out of memory\n"); diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 4acffcf6d..4dce39e81 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -3,7 +3,6 @@ * * Low level driver for Ensoniq SoundScape */ - /* * Copyright (C) by Hannu Savolainen 1993-1997 * @@ -11,9 +10,10 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ - + /* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Sergey Smitienko : ensoniq p'n'p support */ #include <linux/config.h> @@ -21,6 +21,26 @@ #include "sound_config.h" #include "soundmodule.h" +#include "sound_firmware.h" + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/fcntl.h> +#include <linux/ctype.h> +#include <linux/stddef.h> +#include <linux/kmod.h> +#ifdef __KERNEL__ +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/segment.h> +#include <linux/wait.h> +#include <linux/malloc.h> +#include <linux/ioport.h> +#endif /* __KERNEL__ */ +#include <linux/delay.h> +#include <linux/proc_fs.h> + #ifdef CONFIG_SSCAPE @@ -71,10 +91,10 @@ #define CMD_GET_BOARD_TYPE 0x82 #define CMD_SET_CONTROL 0x88 /* Old firmware only */ #define CMD_GET_CONTROL 0x89 /* Old firmware only */ -#define CTL_MASTER_VOL 0 -#define CTL_MIC_MODE 2 -#define CTL_SYNTH_VOL 4 -#define CTL_WAVE_VOL 7 +#define CTL_MASTER_VOL 0 +#define CTL_MIC_MODE 2 +#define CTL_SYNTH_VOL 4 +#define CTL_WAVE_VOL 7 #define CMD_SET_EXTMIDI 0x8a #define CMD_GET_EXTMIDI 0x8b #define CMD_SET_MT32 0x8c @@ -82,9 +102,20 @@ #define CMD_ACK 0x80 +#define IC_ODIE 1 +#define IC_OPUS 2 + typedef struct sscape_info { int base, irq, dma; + + int codec, codec_irq; /* required to setup pnp cards*/ + int codec_type; + int ic_type; + char* raw_buf; + unsigned long raw_buf_phys; + int buffsize; /* -------------------------- */ + int ok; /* Properly detected */ int failed; int dma_allocated; @@ -152,6 +183,31 @@ static void sscape_write(struct sscape_info *devc, int reg, int data) restore_flags(flags); } +static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg) +{ + unsigned char res; + unsigned long flags; + + save_flags(flags); + cli(); + outb( reg, devc -> codec); + res = inb (devc -> codec + 1); + restore_flags(flags); + return res; + +} + +static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data) +{ + unsigned long flags; + + save_flags(flags); + cli(); + outb( reg, devc -> codec); + outb( data, devc -> codec + 1); + restore_flags(flags); +} + static void host_open(struct sscape_info *devc) { outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */ @@ -218,6 +274,13 @@ static int host_read(struct sscape_info *devc) return data; } +static int host_command1(struct sscape_info *devc, int cmd) +{ + unsigned char buf[10]; + buf[0] = (unsigned char) (cmd & 0xff); + return host_write(devc, buf, 1); +} + static int host_command2(struct sscape_info *devc, int cmd, int parm1) { @@ -544,6 +607,7 @@ static coproc_operations sscape_coproc_operations = }; static int sscape_detected = 0; +static int sscape_is_pnp = 0; void attach_sscape(struct address_info *hw_config) { @@ -563,14 +627,14 @@ void attach_sscape(struct address_info *hw_config) */ #define SSCAPE_REGS { \ /* I0 */ 0x00, \ - 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ - 0x20, /* Note! Ignored. Set always to 0x20 */ \ - 0x20, /* Note! Ignored. Set always to 0x20 */ \ - 0xf5, /* Ignored */ \ - 0x10, \ - 0x00, \ - 0x2e, /* I7 MEM config A. Likely to vary between models */ \ - 0x00, /* I8 MEM config B. Likely to vary between models */ \ +/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ +/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ +/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ +/* I4 */ 0xf5, /* Ignored */ \ +/* I5 */ 0x10, \ +/* I6 */ 0x00, \ +/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ +/* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \ /* I9 */ 0x40 /* Ignored */ \ } #endif @@ -605,11 +669,13 @@ void attach_sscape(struct address_info *hw_config) printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq); return; } - save_flags(flags); - cli(); - - for (i = 1; i < 10; i++) - { + + if (sscape_is_pnp == 0) { + + save_flags(flags); + cli(); + for (i = 1; i < 10; i++) + { switch (i) { case 1: /* Host interrupt enable */ @@ -640,9 +706,9 @@ void attach_sscape(struct address_info *hw_config) default: sscape_write(devc, i, regs[i]); } + } + restore_flags(flags); } - restore_flags(flags); - #ifdef SSCAPE_DEBUG2 /* * Temporary debugging aid. Print contents of the registers after @@ -733,6 +799,452 @@ static int detect_ga(sscape_info * devc) return 1; } +static int sscape_read_host_ctrl(sscape_info* devc) +{ + return host_read(devc); +} + +static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b) +{ + host_command2(devc, a, b); +} + +static int sscape_alloc_dma(sscape_info *devc) +{ + char *start_addr, *end_addr; + int i, dma_pagesize; + int sz, size; + + if (devc->raw_buf != NULL) return 0; /* Already done */ + dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024); + devc->raw_buf = NULL; + devc->buffsize = 8192*4; + if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize; + start_addr = NULL; + /* + * Now loop until we get a free buffer. Try to get smaller buffer if + * it fails. Don't accept smaller than 8k buffer for performance + * reasons. + */ + while (start_addr == NULL && devc->buffsize > PAGE_SIZE) { + for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); + devc->buffsize = PAGE_SIZE * (1 << sz); + start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); + if (start_addr == NULL) devc->buffsize /= 2; + } + + if (start_addr == NULL) { + printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n"); + return 0; + } else { + /* make some checks */ + end_addr = start_addr + devc->buffsize - 1; + /* now check if it fits into the same dma-pagesize */ + + if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) + || end_addr >= (char *) (MAX_DMA_ADDRESS)) { + printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize); + return 0; + } + } + devc->raw_buf = start_addr; + devc->raw_buf_phys = virt_to_bus(start_addr); + + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + set_bit(PG_reserved, &mem_map[i].flags);; + return 1; +} + +static void sscape_free_dma(sscape_info *devc) +{ + int sz, size, i; + unsigned long start_addr, end_addr; + + if (devc->raw_buf == NULL) return; + for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); + start_addr = (unsigned long) devc->raw_buf; + end_addr = start_addr + devc->buffsize; + + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + clear_bit(PG_reserved, &mem_map[i].flags);; + + free_pages((unsigned long) devc->raw_buf, sz); + devc->raw_buf = NULL; +} + +/* Intel version !!!!!!!!! */ + +static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode) +{ + unsigned long flags; + + flags = claim_dma_lock(); + disable_dma(chan); + clear_dma_ff(chan); + set_dma_mode(chan, dma_mode); + set_dma_addr(chan, physaddr); + set_dma_count(chan, count); + enable_dma(chan); + release_dma_lock(flags); + return 0; +} + +static void sscape_pnp_start_dma(sscape_info* devc, int arg ) +{ + int reg; + if (arg == 0) reg = 2; + else reg = 3; + + sscape_write(devc, reg, sscape_read( devc, reg) | 0x01); + sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE); +} + +static int sscape_pnp_wait_dma (sscape_info* devc, int arg ) +{ + int reg; + unsigned long i; + unsigned char d; + + if (arg == 0) reg = 2; + else reg = 3; + + sleep ( 1 ); + i = 0; + do { + d = sscape_read(devc, reg) & 1; + if ( d == 1) break; + i++; + } while (i < 500000); + d = sscape_read(devc, reg) & 1; + return d; +} + +static int sscape_pnp_alloc_dma(sscape_info* devc) +{ + /* printk(KERN_INFO "sscape: requesting dma\n"); */ + if (request_dma(devc -> dma, "sscape")) return 0; + /* printk(KERN_INFO "sscape: dma channel allocated\n"); */ + if (!sscape_alloc_dma(devc)) { + free_dma(devc -> dma); + return 0; + }; + return 1; +} + +static void sscape_pnp_free_dma(sscape_info* devc) +{ + sscape_free_dma( devc); + free_dma(devc -> dma ); + /* printk(KERN_INFO "sscape: dma released\n"); */ +} + +static int sscape_pnp_upload_file(sscape_info* devc, char* fn) +{ + int done = 0; + int timeout_val; + char* data,*dt; + int len,l; + unsigned long flags; + + sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F ); + sscape_write( devc, 2, (devc -> dma << 4) | 0x80 ); + sscape_write( devc, 3, 0x20 ); + sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 ); + + len = mod_firmware_load(fn, &data); + if (len == 0) { + printk(KERN_ERR "sscape: file not found: %s\n", fn); + return 0; + } + dt = data; + save_flags(flags); + cli(); + while ( len > 0 ) { + if (len > devc -> buffsize) l = devc->buffsize; + else l = len; + len -= l; + memcpy(devc->raw_buf, dt, l); dt += l; + sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48); + sscape_pnp_start_dma ( devc, 0 ); + if (sscape_pnp_wait_dma ( devc, 0 ) == 0) return 0; + } + + restore_flags(flags); + vfree(data); + + outb(0, devc -> base + 2); + outb(0, devc -> base); + + sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40); + + timeout_val = 5 * HZ; + while (!done && timeout_val-- > 0) + { + unsigned char x; + sleep(1); + x = inb( devc -> base + 3); + if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ + { + //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); + done = 1; + } + } + timeout_val = 5 * HZ; + done = 0; + while (!done && timeout_val-- > 0) + { + unsigned char x; + sleep(1); + x = inb( devc -> base + 3); + if (x == 0xfe) /* OBP startup acknowledge */ + { + //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); + done = 1; + } + } + + if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); + + sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); + sscape_write( devc, 3, (devc -> dma << 4) + 0x80); + return 1; +} + +static void sscape_pnp_init_hw(sscape_info* devc) +{ + unsigned char midi_irq = 0, sb_irq = 0; + unsigned i; + static char code_file_name[23] = "/sndscape/sndscape.cox"; + + int sscape_sb_enable = 0; + int sscape_joystic_enable = 0x7f; + int sscape_mic_enable = 0; + int sscape_ext_midi = 0; + + if ( !sscape_pnp_alloc_dma(devc) ) { + printk(KERN_ERR "sscape: faild to allocate dma\n"); + return; + } + + for (i = 0; i < 4; i++) { + if ( devc -> irq == valid_interrupts[i] ) + midi_irq = i; + if ( devc -> codec_irq == valid_interrupts[i] ) + sb_irq = i; + } + + sscape_write( devc, 5, 0x50); + sscape_write( devc, 7, 0x2e); + sscape_write( devc, 8, 0x00); + + sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); + sscape_write( devc, 3, ( devc -> dma << 4) | 0x80); + + if ( sscape_sb_enable ) + sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq); + else + sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); + + i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0); + if ( sscape_sb_enable ) + i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07; + if (sscape_joystic_enable) i |= 8; + + sscape_write (devc, 9, i); + sscape_write (devc, 6, 0x80); + sscape_write (devc, 1, 0x80); + + if (devc -> codec_type == 2) { + sscape_pnp_write_codec( devc, 0x0C, 0x50); + sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F); + sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0); + sscape_pnp_write_codec( devc, 29, 0x20); + } + + if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) { + printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n"); + sscape_pnp_free_dma(devc); + return; + } + + i = sscape_read_host_ctrl( devc ); + + if ( (i & 0x0F) > 7 ) { + printk(KERN_ERR "sscape: scope.cod faild\n"); + sscape_pnp_free_dma(devc); + return; + } + if ( i & 0x10 ) sscape_write( devc, 7, 0x2F); + code_file_name[21] = (char) ( i & 0x0F) + 0x30; + if (sscape_pnp_upload_file( devc, code_file_name) == 0) { + printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name); + sscape_pnp_free_dma(devc); + return; + } + + if (devc->ic_type != IC_ODIE) { + sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) | + ( sscape_mic_enable == 0 ? 0x00 : 0x80) ); + } + sscape_write_host_ctrl2( devc, 0x84, 0x32 ); + sscape_write_host_ctrl2( devc, 0x86, 0x32 ); + sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi); + + sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL + sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL + sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL + sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR + + if (devc -> codec_type == 1) { + sscape_pnp_write_codec ( devc, 4, 0x1F ); + sscape_pnp_write_codec ( devc, 5, 0x1F ); + sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable); + } else { + int t; + sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1); + sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1)); + + t = sscape_pnp_read_codec( devc, 0x00) & 0xDF; + if ( (sscape_mic_enable == 0)) t |= 0; + else t |= 0x20; + sscape_pnp_write_codec ( devc, 0x00, t); + t = sscape_pnp_read_codec( devc, 0x01) & 0xDF; + if ( (sscape_mic_enable == 0) ) t |= 0; + else t |= 0x20; + sscape_pnp_write_codec ( devc, 0x01, t); + sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20); + outb(0, devc -> codec); + } + if (devc -> ic_type == IC_OPUS ) { + int i = sscape_read( devc, 9 ); + sscape_write( devc, 9, i | 3 ); + sscape_write( devc, 3, 0x40); + + if (check_region(0x228, 1)) { + outb(0, 0x228); + release_region(0x228,1); + } + sscape_write( devc, 3, (devc -> dma << 4) | 0x80); + sscape_write( devc, 9, i ); + } + + host_close ( devc ); + sscape_pnp_free_dma(devc); +} + +static int detect_sscape_pnp(sscape_info* devc) +{ + long i, irq_bits = 0xff; + unsigned int d; + + DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base)); + + if (check_region(devc->base, 8)) { + printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->base); + return 0; + } + + if (check_region(devc->codec, 2)) { + printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec); + return 0; + } + + if ( (inb( devc -> base + 2) & 0x78) != 0) return 0; + + d = inb ( devc -> base + 4) & 0xF0; + if ( (d & 0x80) != 0) return 0; + + if (d == 0) { + devc->codec_type = 1; + devc->ic_type = IC_ODIE; + } + else if ( (d & 0x60) != 0) { + devc->codec_type = 2; + devc->ic_type = IC_OPUS; + } + else if ( (d & 0x40) != 0) { + devc->codec_type = 2; + devc->ic_type = IC_ODIE; + } + else return 0; + + sscape_is_pnp = 1; + + outb(0xFA, devc -> base+4); + if ((inb( devc -> base+4) & 0x9F) != 0x0A) + return 0; + outb(0xFE, devc -> base+4); + if ( (inb(devc -> base+4) & 0x9F) != 0x0E) + return 0; + if ( (inb(devc -> base+5) & 0x9F) != 0x0E) + return 0; + + if (devc->codec_type == 2) { + if (devc -> codec != devc -> base + 8) + printk("soundscape warning: incorrect codec port specified\n"); + devc -> codec = devc -> base + 8; + d = 0x10 | (sscape_read(devc, 9) & 0xCF); + sscape_write(devc, 9, d); + sscape_write(devc, 6, 0x80); + } else { + //todo: check codec is not base + 8 + } + + d = (sscape_read(devc, 9) & 0x3F) | 0xC0; + sscape_write(devc, 9, d); + + for (i = 0; i < 550000; i++) + if ( !(inb(devc -> codec) & 0x80) ) break; + + d = inb(devc -> codec); + if (d & 0x80) + return 0; + if ( inb(devc -> codec + 2) == 0xFF) + return 0; + + sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F ); + + d = inb(devc -> codec) & 0x80; + if ( d == 0) { + printk(KERN_INFO "soundscape: hardware detected\n"); + valid_interrupts = valid_interrupts_new; + } else { + printk(KERN_INFO "soundscape: board looks like media fx\n"); + valid_interrupts = valid_interrupts_old; + old_hardware = 1; + } + + sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9) & 0x3F) ); + + for (i = 0; i < 550000; i++) + if ( !(inb(devc -> codec) & 0x80)) + break; + + sscape_pnp_init_hw(devc); + + for (i = 0; i < sizeof(valid_interrupts); i++) + { + if (devc->codec_irq == valid_interrupts[i]) { + irq_bits = i; + break; + } + } + sscape_write(devc, GA_INTENA_REG, 0x00); + sscape_write(devc, GA_DMACFG_REG, 0x50); + sscape_write(devc, GA_DMAA_REG, 0x70); + sscape_write(devc, GA_DMAB_REG, 0x20); + sscape_write(devc, GA_INTCFG_REG, 0xf0); + sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1)); + + sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20); + sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20); + + release_region(devc->codec, 2); + release_region(devc->base, 8); + + return 1; +} + int probe_sscape(struct address_info *hw_config) { @@ -758,8 +1270,13 @@ int probe_sscape(struct address_info *hw_config) #endif devc->failed = 1; - if (!detect_ga(devc)) - return 0; + if (!detect_ga(devc)) { + if (detect_sscape_pnp(devc)) { + sscape_detected = hw_config->io_base; + return 1; + } + else return 0; + } if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ { @@ -781,11 +1298,11 @@ int probe_ss_ms_sound(struct address_info *hw_config) { int i, irq_bits = 0xff; int ad_flags = 0; - + if (devc->failed) { - printk(KERN_ERR "soundscape: Card not detected\n"); - return 0; + printk(KERN_ERR "soundscape: Card not detected\n"); + return 0; } if (devc->ok == 0) { @@ -805,9 +1322,19 @@ int probe_ss_ms_sound(struct address_info *hw_config) printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq); return 0; } - if (old_hardware) - ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ - return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp); + + if (!sscape_is_pnp) { + if (old_hardware) + ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ + return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp); + } + else { + if (old_hardware) + ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ + else + ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */ + return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp); + } } void attach_ss_ms_sound(struct address_info *hw_config) @@ -820,44 +1347,52 @@ void attach_ss_ms_sound(struct address_info *hw_config) int i, irq_bits = 0xff; - hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ - - /* - * Setup the DMA polarity. - */ - - sscape_write(devc, GA_DMACFG_REG, 0x50); - - /* - * Take the gate-array off of the DMA channel. - */ - - sscape_write(devc, GA_DMAB_REG, 0x20); - - /* - * Init the AD1848 (CD-ROM) config reg. - */ - - for (i = 0; i < sizeof(valid_interrupts); i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1)); - - if (hw_config->irq == devc->irq) - printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); - - hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); - + + if (!sscape_is_pnp) /*pnp is already setup*/ + { + /* + * Setup the DMA polarity. + */ + sscape_write(devc, GA_DMACFG_REG, 0x50); + + /* + * Take the gate-array off of the DMA channel. + */ + sscape_write(devc, GA_DMAB_REG, 0x20); + + /* + * Init the AD1848 (CD-ROM) config reg. + */ + for (i = 0; i < sizeof(valid_interrupts); i++) + { + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + } + sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1)); + } + + if (hw_config->irq == devc->irq) + printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); + + if (! sscape_is_pnp ) + hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, + 0, + devc->osp); + + else + hw_config->slots[0] = ad1848_init("SoundScape PNP", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, + 0, + devc->osp); + if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ { audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations; @@ -867,6 +1402,7 @@ void attach_ss_ms_sound(struct address_info *hw_config) /* Set proper routings here (what are they) */ AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); } + #ifdef SSCAPE_DEBUG5 /* * Temporary debugging aid. Print contents of the registers @@ -937,6 +1473,13 @@ int init_module(void) printk(KERN_ERR "CONFIG_MPU_IRQ must be specified if CONFIG_MPU_IO is set.\n"); return -EINVAL; } + + devc->codec = io; + devc->codec_irq = irq; + devc->codec_type = 0; + devc->ic_type = 0; + devc->raw_buf = NULL; + config.irq = irq; config.dma = dma; config.io_base = io; diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index bfb92dd5e..c8c0cd0c3 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -29,6 +29,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com> + * adapt to 2.3.x new __setup/__initcall * v0.04 Dec 31 1999 Ollie Lho * Multiple Open, useing Middle Loop Interrupt to smooth playback * v0.03 Dec 24 1999 Ollie Lho @@ -68,7 +70,7 @@ #undef DEBUG -#define DRIVER_VERSION "0.03" +#define DRIVER_VERSION "0.05" #define TRIDENT_FMT_STEREO 0x01 #define TRIDENT_FMT_16BIT 0x02 @@ -2921,11 +2923,7 @@ static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_in return 1; } -#ifdef MODULE -int init_module(void) -#else -int __init init_trident(void) -#endif +static int __init init_trident(void) { struct pci_dev *pcidev = NULL; int foundone = 0; @@ -2951,15 +2949,14 @@ int __init init_trident(void) return 0; } -#ifdef MODULE -MODULE_AUTHOR("Alan Cox <alan@redhat.com>"); +MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho"); MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver"); #ifdef DEBUG MODULE_PARM(debug,"i"); #endif -void cleanup_module(void) +static void __exit cleanup_trident(void) { while (devs != NULL) { /* Kill interrupts, and SP/DIF */ @@ -2978,6 +2975,8 @@ void cleanup_module(void) devs = devs->next; } } -#endif /* MODULE */ + +module_init(init_trident); +module_exit(cleanup_trident); |