summaryrefslogtreecommitdiffstats
path: root/drivers/sound
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
commit78c388aed2b7184182c08428db1de6c872d815f5 (patch)
tree4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /drivers/sound
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'drivers/sound')
-rw-r--r--drivers/sound/Config.in49
-rw-r--r--drivers/sound/Makefile62
-rw-r--r--drivers/sound/Readme2
-rw-r--r--drivers/sound/Readme.modules28
-rw-r--r--drivers/sound/ad1848.c31
-rw-r--r--drivers/sound/ad1848_mixer.h2
-rw-r--r--drivers/sound/audio.c33
-rw-r--r--drivers/sound/cs4232.c4
-rw-r--r--drivers/sound/dev_table.c5
-rw-r--r--drivers/sound/dev_table.h25
-rw-r--r--drivers/sound/dmabuf.c149
-rw-r--r--drivers/sound/dmasound.c116
-rw-r--r--drivers/sound/es1370.c32
-rw-r--r--drivers/sound/es1371.c15
-rw-r--r--drivers/sound/gus_wave.c43
-rw-r--r--drivers/sound/legacy.h1
-rw-r--r--drivers/sound/mad16.c3
-rw-r--r--drivers/sound/maui.c4
-rw-r--r--drivers/sound/midibuf.c15
-rw-r--r--drivers/sound/msnd.c63
-rw-r--r--drivers/sound/msnd.h49
-rw-r--r--drivers/sound/msnd_classic.h2
-rw-r--r--drivers/sound/msnd_pinnacle.c994
-rw-r--r--drivers/sound/msnd_pinnacle.h2
-rw-r--r--drivers/sound/opl3sa2.c241
-rw-r--r--drivers/sound/os.h1
-rw-r--r--drivers/sound/pss.c2
-rw-r--r--drivers/sound/sb.h18
-rw-r--r--drivers/sound/sb_audio.c272
-rw-r--r--drivers/sound/sb_card.c72
-rw-r--r--drivers/sound/sb_common.c41
-rw-r--r--drivers/sound/sb_midi.c2
-rw-r--r--drivers/sound/sb_mixer.c51
-rw-r--r--drivers/sound/sb_mixer.h6
-rw-r--r--drivers/sound/sequencer.c37
-rw-r--r--drivers/sound/sgalaxy.c10
-rw-r--r--drivers/sound/sonicvibes.c10
-rw-r--r--drivers/sound/sound_calls.h8
-rw-r--r--drivers/sound/soundcard.c15
-rw-r--r--drivers/sound/sscape.c4
-rw-r--r--drivers/sound/trix.c5
-rw-r--r--drivers/sound/wavfront.c157
-rw-r--r--drivers/sound/wf_midi.c18
43 files changed, 1807 insertions, 892 deletions
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index b23a61f74..b13122e4e 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -11,43 +11,62 @@
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
+ if [ "$CONFIG_SOUND_ES1370" = "y" ]; then
+ bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT
+ fi
dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
fi
dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
+ if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
+ comment 'Compiled-in MSND Classic support requires firmware during compilation.'
+ define_bool CONFIG_MSNDCLAS_HAVE_BOOT y
+ else
+ define_bool CONFIG_MSNDCLAS_HAVE_BOOT n
+ fi
string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin"
string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin"
fi
if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
int 'MSND Classic IRQ 5,7,9,10,11,12' CONFIG_MSNDCLAS_IRQ 5
- hex 'MSND Classic Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000
+ hex 'MSND Classic memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000
hex 'MSND Classic I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDCLAS_IO 290
fi
dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND
if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDPIN" = "m" ]; then
+ if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then
+ comment 'Compiled-in MSND Pinnacle support requires firmware during compilation.'
+ define_bool CONFIG_MSNDPIN_HAVE_BOOT y
+ else
+ define_bool CONFIG_MSNDPIN_HAVE_BOOT n
+ fi
string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin"
string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin"
fi
if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then
int 'MSND Pinnacle IRQ 5,7,9,10,11,12' CONFIG_MSNDPIN_IRQ 5
- hex 'MSND Pinnacle Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000
+ hex 'MSND Pinnacle memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000
hex 'MSND Pinnacle I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290
- bool 'MSND Pinnacle Non-PnP Mode' CONFIG_MSNDPIN_NONPNP
+ bool 'MSND Pinnacle has S/PDIF I/O' CONFIG_MSNDPIN_DIGITAL
+ bool 'MSND Pinnacle non-PnP Mode' CONFIG_MSNDPIN_NONPNP
if [ "$CONFIG_MSNDPIN_NONPNP" = "y" ]; then
comment 'MSND Pinnacle DSP section will be configured to above parameters.'
- hex 'MSDN Pinnacle Config Port 250,260,270' CONFIG_MSNDPIN_CFG 250
+ hex 'MSND Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250
comment 'Pinnacle-specific Device Configuration (0 disables)'
- hex 'MSDN Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0
- int 'MSDN Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0
- hex 'MSDN Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0
- hex 'MSDN Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0
- int 'MSDN Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0
- hex 'MSDN Pinnacle Joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0
+ hex 'MSND Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0
+ int 'MSND Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0
+ hex 'MSND Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0
+ hex 'MSND Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0
+ int 'MSND Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0
+ hex 'MSND Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0
fi
fi
+if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
+ int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128
+fi
dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
@@ -176,6 +195,16 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9
fi
+ dep_tristate 'Support for Yamaha OPL3-SA[2,3,x] based (PnP) cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
+ if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then
+ hex 'OPL3SA2 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA2_BASE 530
+ int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 11
+ int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0
+ int 'OPL3SA2 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA2 1
+ hex 'OPL3SA2 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA2_MPU_BASE 330
+ int 'OPL3SA2 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_MPU_IRQ 9
+ fi
+
dep_tristate 'Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index f072b7fad..c4fb47dce 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -41,19 +41,7 @@ obj- :=
# Each configuration option enables a list of files.
obj-$(CONFIG_SOUND) += soundcore.o
-
-ifeq ($(ARCH),m68k)
-
-obj-$(CONFIG_DMASOUND) += dmasound.o
-
-else
-
-ifeq ($(CONFIG_PMAC),y)
-
obj-$(CONFIG_DMASOUND) += dmasound.o
-
-else
-
obj-$(CONFIG_SOUND_OSS) += sound.o
obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
@@ -72,6 +60,7 @@ obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
+obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o uart401.o mpu401.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_SB) += sb.o uart401.o
@@ -89,9 +78,6 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o
obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
-endif
-endif
-
# Declare multi-part drivers.
list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
@@ -219,7 +205,7 @@ maui.o: maui_boot.h
ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) bin2hex
- bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@
+ ./bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@
else
maui_boot.h:
( \
@@ -235,6 +221,50 @@ endif
+# Turtle Beach MultiSound
+
+ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y)
+ msnd_classic.o: msndperm.c msndinit.c
+
+ msndperm.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_PERM_FILE)) bin2hex
+ ./bin2hex msndperm < $(CONFIG_MSNDCLAS_PERM_FILE) > $@
+ @ ( \
+ echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_PERM_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_PERM_FILE)))'; \
+ echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+ echo 'endif' \
+ ) > .$@.boot
+
+ msndinit.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_INIT_FILE)) bin2hex
+ ./bin2hex msndinit < $(CONFIG_MSNDCLAS_INIT_FILE) > $@
+ @ ( \
+ echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_INIT_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_INIT_FILE)))'; \
+ echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+ echo 'endif' \
+ ) > .$@.boot
+endif
+
+ifeq ($(CONFIG_MSNDPIN_HAVE_BOOT),y)
+ msnd_pinnacle.o: pndsperm.c pndspini.c
+
+ pndsperm.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_PERM_FILE)) bin2hex
+ ./bin2hex pndsperm < $(CONFIG_MSNDPIN_PERM_FILE) > $@
+ @ ( \
+ echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_PERM_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_PERM_FILE)))'; \
+ echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+ echo 'endif' \
+ ) > .$@.boot
+
+ pndspini.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_INIT_FILE)) bin2hex
+ ./bin2hex pndspini < $(CONFIG_MSNDPIN_INIT_FILE) > $@
+ @ ( \
+ echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_INIT_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_INIT_FILE)))'; \
+ echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+ echo 'endif' \
+ ) > .$@.boot
+endif
+
+
+
# PSS (ECHO-ADI2111)
pss.o: pss_boot.h
diff --git a/drivers/sound/Readme b/drivers/sound/Readme
index 2bb76549f..cd506f29a 100644
--- a/drivers/sound/Readme
+++ b/drivers/sound/Readme
@@ -168,7 +168,7 @@ The following errors are likely with /dev/dsp and /dev/audio.
with impossible parameters. Check that the application is
for sound driver version 2.X or later.
-In general the printout of of /dev/sndstat should tell what is the problem.
+In general the printout of /dev/sndstat should tell what is the problem.
It's possible that there are bugs in the sound driver but 99% of the problems
reported to me are caused by somehow incorrect setup during "make config".
diff --git a/drivers/sound/Readme.modules b/drivers/sound/Readme.modules
index 9740035b4..670fbe87b 100644
--- a/drivers/sound/Readme.modules
+++ b/drivers/sound/Readme.modules
@@ -66,6 +66,34 @@ modprobe -k adlib_card io=0x388
recommend using /etc/modules.conf.
+Persistent DMA Buffers:
+
+The sound modules normally allocate DMA buffers during open() and
+deallocate them during close(). Linux can often have problems allocating
+DMA buffers for ISA cards on machines with more than 16MB RAM. This is
+because ISA DMA buffers must exist below the 16MB boundry and it is quite
+possible that we can't find a large enough free block in this region after
+the machine has been running for any amount of time. The way to avoid this
+problem is to allocate the DMA buffers during module load and deallocate
+them when the module is unloaded. For this to be effective we need to load
+the sound modules right after the kernel boots, either manually or by an
+init script, and keep them around until we shut down. This is a little
+wasteful of RAM, but it guarantees that sound always works.
+
+To make the sound driver use persistent DMA buffers we need to pass the
+sound.o module a "dmabuf=1" command-line argument. This is normally done
+in /etc/conf.modules (or the more proper /etc/modules.conf) like so:
+
+options sound dmabuf=1
+
+If you have 16MB or less RAM or a PCI sound card, this is wasteful and
+unnecessary. It is possible that machine with 16MB or less RAM will find
+this option useful, but if your machine is so memory-starved that it
+cannot find a 64K block free, you will be wasting even more RAM by keeping
+the sound modules loaded and the DMA buffers allocated when they are not
+needed. The proper solution is to upgrade your RAM. But you do also have
+this improper solution as well. Use it wisely.
+
I'm afraid I know nothing about anything but my setup, being more of a
text-mode guy anyway. If you have options for other cards or other helpful
hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb.
diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c
index 34148d990..d3a743550 100644
--- a/drivers/sound/ad1848.c
+++ b/drivers/sound/ad1848.c
@@ -206,7 +206,7 @@ static void wait_for_calibration(ad1848_info * devc)
return;
timeout = 80000;
- while (timeout > 0 && ad_read(devc, 11) & 0x20)
+ while (timeout > 0 && (ad_read(devc, 11) & 0x20))
timeout--;
if (ad_read(devc, 11) & 0x20)
if (devc->model != MD_1845)
@@ -916,7 +916,7 @@ static void ad1848_output_block(int dev, unsigned long buf, int count, int intrf
cnt >>= 1;
cnt--;
- if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+ if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) &&
intrflag &&
cnt == devc->xfer_count)
{
@@ -958,7 +958,7 @@ static void ad1848_start_input(int dev, unsigned long buf, int count, int intrfl
cnt >>= 1;
cnt--;
- if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+ if ((devc->audio_mode & PCM_ENABLE_INPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) &&
intrflag &&
cnt == devc->xfer_count)
{
@@ -1182,10 +1182,10 @@ static void ad1848_halt(int dev)
unsigned char bits = ad_read(devc, 9);
- if (bits & 0x01 && portc->open_mode & OPEN_WRITE)
+ if (bits & 0x01 && (portc->open_mode & OPEN_WRITE))
ad1848_halt_output(dev);
- if (bits & 0x02 && portc->open_mode & OPEN_READ)
+ if (bits & 0x02 && (portc->open_mode & OPEN_READ))
ad1848_halt_input(dev);
devc->audio_mode = 0;
}
@@ -1308,7 +1308,7 @@ static void ad1848_init_hw(ad1848_info * devc)
0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
/* Positions 16 to 31 just for CS4231/2 and ad1845 */
- 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -1814,7 +1814,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
ad_write(devc, 16, tmp & ~0x40); /* Disable timer */
if (devc->timer_ticks == 0)
- printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", devc->irq);
+ printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", irq);
else
{
DDB(printk("Interrupt test OK\n"));
@@ -1934,8 +1934,8 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
if (!share_dma)
{
- if (irq > 0)
- free_irq(devc->irq, NULL);
+ if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */
+ free_irq(devc->irq, (void *)devc->dev_no);
sound_free_dma(audio_devs[dev]->dmap_out->dma);
@@ -1945,6 +1945,10 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
mixer = audio_devs[devc->dev_no]->mixer_dev;
if(mixer>=0)
sound_unload_mixerdev(mixer);
+
+ nr_ad1848_devs--;
+ for ( ; i < nr_ad1848_devs ; i++)
+ adev_info[i] = adev_info[i+1];
}
else
printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
@@ -1997,16 +2001,16 @@ interrupt_again: /* Jump back here if int status doesn't reset */
ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */
}
- if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
+ if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20))
{
DMAbuf_inputintr(devc->record_dev);
}
- if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT &&
- alt_stat & 0x10)
+ if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) &&
+ (alt_stat & 0x10))
{
DMAbuf_outputintr(devc->playback_dev, 1);
}
- if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */
+ if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */
{
devc->timer_ticks++;
#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
@@ -2401,7 +2405,6 @@ void attach_ms_sound(struct address_info *hw_config)
void unload_ms_sound(struct address_info *hw_config)
{
- int mixer = audio_devs[hw_config->slots[0]]->mixer_dev;
ad1848_unload(hw_config->io_base + 4,
hw_config->irq,
hw_config->dma,
diff --git a/drivers/sound/ad1848_mixer.h b/drivers/sound/ad1848_mixer.h
index ab8eb2035..5768420a9 100644
--- a/drivers/sound/ad1848_mixer.h
+++ b/drivers/sound/ad1848_mixer.h
@@ -17,7 +17,7 @@
* The AD1848 codec has generic input lines called Line, Aux1 and Aux2.
* Sound card manufacturers have connected actual inputs (CD, synth, line,
* etc) to these inputs in different order. Therefore it's difficult
- * to assign mixer channels to to these inputs correctly. The following
+ * to assign mixer channels to these inputs correctly. The following
* contains two alternative mappings. The first one is for GUS MAX and
* the second is just a generic one (line1, line2 and line3).
* (Actually this is not a mapping but rather some kind of interleaving
diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c
index 54d8e5f5b..286eca011 100644
--- a/drivers/sound/audio.c
+++ b/drivers/sound/audio.c
@@ -18,6 +18,8 @@
* lifetime as the rest in there and dynamic allocation saves
* 12k or so
* Thomas Sailer : use more logical O_NONBLOCK semantics
+ * Daniel Rodriksson: reworked the use of the device specific copy_user
+ * still generic
*/
#include <linux/config.h>
@@ -155,10 +157,21 @@ void audio_release(int dev, struct file *file)
dev = dev >> 4;
+ /*
+ * We do this in DMAbuf_release(). Why are we doing it
+ * here? Why don't we test the file mode before setting
+ * both flags? DMAbuf_release() does.
+ * ...pester...pester...pester...
+ */
audio_devs[dev]->dmap_out->closing = 1;
audio_devs[dev]->dmap_in->closing = 1;
- sync_output(dev);
+ /*
+ * We need to make sure we allocated the dmap_out buffer
+ * before we go mucking around with it in sync_output().
+ */
+ if (mode & OPEN_WRITE)
+ sync_output(dev);
if (audio_devs[dev]->coproc)
audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM);
@@ -178,7 +191,7 @@ static void translate_bytes(const unsigned char *table, unsigned char *buff, int
int audio_write(int dev, struct file *file, const char *buf, int count)
{
- int c, p, l, buf_size;
+ int c, p, l, buf_size, used, returned;
int err;
char *dma_buf;
@@ -215,6 +228,8 @@ int audio_write(int dev, struct file *file, const char *buf, int count)
if (l > buf_size)
l = buf_size;
+ returned = l;
+ used = l;
if (!audio_devs[dev]->d->copy_user)
{
if ((dma_buf + l) >
@@ -231,7 +246,13 @@ int audio_write(int dev, struct file *file, const char *buf, int count)
if(copy_from_user(dma_buf, &(buf)[p], l))
return -EFAULT;
}
- else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l);
+ else audio_devs[dev]->d->copy_user (dev,
+ dma_buf, 0,
+ buf, p,
+ c, buf_size,
+ &used, &returned,
+ l);
+ l = returned;
if (audio_devs[dev]->local_conversion & CNV_MU_LAW)
{
@@ -241,8 +262,8 @@ int audio_write(int dev, struct file *file, const char *buf, int count)
sti();
translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
}
- c -= l;
- p += l;
+ c -= used;
+ p += used;
DMAbuf_move_wrpointer(dev, l);
}
@@ -279,7 +300,7 @@ int audio_read(int dev, struct file *file, char *buf, int count)
* Nonblocking mode handling. Return current # of bytes
*/
- if (file->f_flags & O_NONBLOCK && buf_no == -EAGAIN)
+ if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN)
return p;
if (p > 0) /* Avoid throwing away data */
diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c
index 43bc92911..122b0198f 100644
--- a/drivers/sound/cs4232.c
+++ b/drivers/sound/cs4232.c
@@ -96,9 +96,7 @@ static unsigned char crystal_key[] = /* A 32 byte magic key sequence */
static void sleep(unsigned howlong)
{
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + howlong;
- schedule();
- current->timeout = 0;
+ schedule_timeout(howlong);
}
int probe_cs4232(struct address_info *hw_config)
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
index 99e15cb22..7e5c4b76c 100644
--- a/drivers/sound/dev_table.c
+++ b/drivers/sound/dev_table.c
@@ -516,6 +516,7 @@ void sound_unload_audiodev(int dev)
{
if (dev != -1)
{
+ DMAbuf_deinit(dev);
audio_devs[dev] = NULL;
unregister_sound_dsp((dev<<4)+3);
}
@@ -534,6 +535,7 @@ int sound_alloc_audiodev(void)
int sound_alloc_mididev(void)
{
+#ifdef CONFIG_MIDI
int i = register_sound_midi(&oss_sound_fops);
if(i==-1)
return i;
@@ -541,6 +543,9 @@ int sound_alloc_mididev(void)
if(i>=num_midis)
num_midis = i + 1;
return i;
+#else
+ return (-1);
+#endif
}
int sound_alloc_synthdev(void)
diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h
index 215df408a..b440f3c09 100644
--- a/drivers/sound/dev_table.h
+++ b/drivers/sound/dev_table.h
@@ -31,6 +31,8 @@
#define SNDCARD_SOFTOSS 36
#define SNDCARD_VMIDI 37
#define SNDCARD_WAVEFRONT 41
+#define SNDCARD_OPL3SA2 42
+#define SNDCARD_OPL3SA2_MPU 43
void attach_opl3sa_wss (struct address_info *hw_config);
int probe_opl3sa_wss (struct address_info *hw_config);
@@ -186,8 +188,12 @@ struct audio_driver
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
void (*halt_io) (int dev);
int (*local_qlen)(int dev);
- void (*copy_user)(int dev, char *localbuf, int localoffs,
- const char *userbuf, int useroffs, int len);
+ void (*copy_user) (int dev,
+ char *localbuf, int localoffs,
+ const char *userbuf, int useroffs,
+ int max_in, int max_out,
+ int *used, int *returned,
+ int len);
void (*halt_input) (int dev);
void (*halt_output) (int dev);
void (*trigger) (int dev, int bits);
@@ -412,6 +418,11 @@ struct driver_info sound_drivers[] =
{"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu},
#endif
+#ifdef CONFIG_SOUND_OPL3SA2
+ {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2},
+ {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu},
+#endif
+
#ifdef CONFIG_SGALAXY
{"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy},
#endif
@@ -560,6 +571,16 @@ struct card_info snd_installed_cards[] =
{SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE},
#endif
+#ifdef CONFIG_SOUND_OPL3SA2
+#ifndef CONFIG_OPL3SA2_DMA2
+#define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA
+#endif
+#ifdef CONFIG_OPL3SA2_MPU_BASE
+ {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+ {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
+#endif
+
#ifdef CONFIG_SGALAXY
#ifndef CONFIG_SGALAXY_DMA2
#define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA
diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c
index 51b9d87de..014d6a73c 100644
--- a/drivers/sound/dmabuf.c
+++ b/drivers/sound/dmabuf.c
@@ -16,9 +16,12 @@
* 12k or so
* Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to
* determine if it was woken up by the expiring timeout or by
- * an explicit wake_up. current->timeout can be used instead;
- * if 0, the wakeup was due to the timeout.
+ * an explicit wake_up. The return value from schedule_timeout
+ * can be used instead; if 0, the wakeup was due to the timeout.
+ *
+ * Rob Riggs Added persistent DMA buffers (1998/10/17)
*/
+
#include <linux/config.h>
#define BE_CONSERVATIVE
@@ -28,6 +31,9 @@
#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
+#define DMAP_FREE_ON_CLOSE 0
+#define DMAP_KEEP_ON_CLOSE 1
+extern int sound_dmap_flag;
static void dma_reset_output(int dev);
static void dma_reset_input(int dev);
@@ -38,9 +44,9 @@ static int local_start_dma(struct audio_operations *adev, unsigned long physaddr
static int debugmem = 0; /* switched off by default */
static int dma_buffsize = DSP_BUFFSIZE;
-static void dmabuf_set_timeout(struct dma_buffparms *dmap)
+static long dmabuf_timeout(struct dma_buffparms *dmap)
{
- unsigned long tmout;
+ long tmout;
tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
tmout += HZ / 5; /* Some safety distance */
@@ -48,7 +54,7 @@ static void dmabuf_set_timeout(struct dma_buffparms *dmap)
tmout = HZ / 2;
if (tmout > 20 * HZ)
tmout = 20 * HZ;
- current->timeout = jiffies + tmout;
+ return tmout;
}
static int sound_alloc_dmap(struct dma_buffparms *dmap)
@@ -138,15 +144,15 @@ static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, i
int chan = dmap->dma;
/* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */
- save_flags(flags);
- cli();
+
+ 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);
- restore_flags(flags);
+ release_dma_lock(flags);
return 0;
}
@@ -201,12 +207,19 @@ static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffpar
static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap)
{
+ unsigned long flags;
+
sound_close_dma(dmap->dma);
if (dmap->flags & DMA_BUSY)
dmap->dma_mode = DMODE_NONE;
dmap->flags &= ~DMA_BUSY;
+
+ flags=claim_dma_lock();
disable_dma(dmap->dma);
- sound_free_dmap(dmap);
+ release_dma_lock(flags);
+
+ if (sound_dmap_flag == DMAP_FREE_ON_CLOSE)
+ sound_free_dmap(dmap);
}
@@ -279,7 +292,7 @@ int DMAbuf_open(int dev, int mode)
}
adev->enable_bits = mode;
- if (mode == OPEN_READ || (mode != OPEN_WRITE && adev->flags & DMA_DUPLEX)) {
+ if (mode == OPEN_READ || (mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) {
if ((retval = open_dmap(adev, mode, dmap_in)) < 0) {
adev->d->close(dev);
if (mode & OPEN_WRITE)
@@ -311,7 +324,7 @@ void DMAbuf_reset(int dev)
static void dma_reset_output(int dev)
{
struct audio_operations *adev = audio_devs[dev];
- unsigned long flags;
+ unsigned long flags,f ;
struct dma_buffparms *dmap = adev->dmap_out;
if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */
@@ -326,11 +339,9 @@ static void dma_reset_output(int dev)
adev->dmap_out->underrun_count = 0;
if (!signal_pending(current) && adev->dmap_out->qlen &&
- adev->dmap_out->underrun_count == 0) {
- dmabuf_set_timeout(dmap);
- interruptible_sleep_on(&adev->out_sleeper);
- current->timeout = 0;
- }
+ adev->dmap_out->underrun_count == 0)
+ interruptible_sleep_on_timeout(&adev->out_sleeper,
+ dmabuf_timeout(dmap));
adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
/*
@@ -341,8 +352,12 @@ static void dma_reset_output(int dev)
else
adev->d->halt_output(dev);
adev->dmap_out->flags &= ~DMA_STARTED;
+
+ f=claim_dma_lock();
clear_dma_ff(dmap->dma);
disable_dma(dmap->dma);
+ release_dma_lock(f);
+
restore_flags(flags);
dmap->byte_counter = 0;
reorganize_buffers(dev, adev->dmap_out, 0);
@@ -377,7 +392,7 @@ void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap)
return; /* Don't start DMA yet */
dmap->dma_mode = DMODE_OUTPUT;
- if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) {
+ if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) {
if (!(dmap->flags & DMA_STARTED)) {
reorganize_buffers(dev, dmap, 0);
if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs))
@@ -404,7 +419,7 @@ int DMAbuf_sync(int dev)
int n = 0;
struct dma_buffparms *dmap;
- if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT))
+ if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT))
return 0;
if (adev->dmap_out->dma_mode == DMODE_OUTPUT) {
@@ -417,14 +432,14 @@ int DMAbuf_sync(int dev)
adev->dmap_out->underrun_count = 0;
while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs &&
adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
- dmabuf_set_timeout(dmap);
- interruptible_sleep_on(&adev->out_sleeper);
- if (!current->timeout) {
+ long t = dmabuf_timeout(dmap);
+ t = interruptible_sleep_on_timeout(&adev->out_sleeper,
+ t);
+ if (!t) {
adev->dmap_out->flags &= ~DMA_SYNCING;
restore_flags(flags);
return adev->dmap_out->qlen;
}
- current->timeout = 0;
}
adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
restore_flags(flags);
@@ -437,11 +452,10 @@ int DMAbuf_sync(int dev)
save_flags(flags);
cli();
if (adev->d->local_qlen) { /* Device has hidden buffers */
- while (!signal_pending(current) && adev->d->local_qlen(dev)) {
- dmabuf_set_timeout(dmap);
- interruptible_sleep_on(&adev->out_sleeper);
- current->timeout = 0;
- }
+ while (!signal_pending(current) &&
+ adev->d->local_qlen(dev))
+ interruptible_sleep_on_timeout(&adev->out_sleeper,
+ dmabuf_timeout(dmap));
}
restore_flags(flags);
}
@@ -476,7 +490,7 @@ int DMAbuf_release(int dev, int mode)
if (adev->open_mode == OPEN_READ ||
(adev->open_mode != OPEN_WRITE &&
- adev->flags & DMA_DUPLEX))
+ (adev->flags & DMA_DUPLEX)))
close_dmap(adev, adev->dmap_in);
adev->open_mode = 0;
restore_flags(flags);
@@ -536,6 +550,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
restore_flags(flags);
return -EINVAL;
} else while (dmap->qlen <= 0 && n++ < 10) {
+ long timeout = MAX_SCHEDULE_TIMEOUT;
if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) {
restore_flags(flags);
return -EAGAIN;
@@ -550,19 +565,17 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
restore_flags(flags);
return -EAGAIN;
}
- if (!(go = adev->go))
- current->timeout = 0;
- else
- dmabuf_set_timeout(dmap);
- interruptible_sleep_on(&adev->in_sleeper);
- if (go && !current->timeout) {
+ if ((go = adev->go))
+ timeout = dmabuf_timeout(dmap);
+ timeout = interruptible_sleep_on_timeout(&adev->in_sleeper,
+ timeout);
+ if (!timeout) {
/* FIXME: include device name */
err = -EIO;
printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
dma_reset_input(dev);
} else
err = -EINTR;
- current->timeout = 0;
}
restore_flags(flags);
@@ -606,6 +619,7 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction
int pos;
unsigned long flags;
+ unsigned long f;
save_flags(flags);
cli();
@@ -613,9 +627,12 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction
pos = 0;
else {
int chan = dmap->dma;
+
+ f=claim_dma_lock();
clear_dma_ff(chan);
disable_dma(dmap->dma);
pos = get_dma_residue(chan);
+
pos = dmap->bytes_in_use - pos;
if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) {
@@ -634,6 +651,7 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction
if (pos >= dmap->bytes_in_use)
pos = 0;
enable_dma(dmap->dma);
+ release_dma_lock(f);
}
restore_flags(flags);
/* printk( "%04x ", pos); */
@@ -710,6 +728,7 @@ static int output_sleep(int dev, int dontblock)
int err = 0;
struct dma_buffparms *dmap = adev->dmap_out;
int timeout;
+ long timeout_value;
if (dontblock)
return -EAGAIN;
@@ -720,18 +739,18 @@ static int output_sleep(int dev, int dontblock)
* Wait for free space
*/
if (signal_pending(current))
- return -EIO;
+ return -EINTR;
timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT));
if (timeout)
- dmabuf_set_timeout(dmap);
+ timeout_value = dmabuf_timeout(dmap);
else
- current->timeout = 0;
- interruptible_sleep_on(&adev->out_sleeper);
- if (timeout && !current->timeout) {
+ timeout_value = MAX_SCHEDULE_TIMEOUT;
+ timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper,
+ timeout_value);
+ if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) {
printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
dma_reset_output(dev);
} else {
- current->timeout = 0;
if (signal_pending(current))
err = -EINTR;
}
@@ -961,10 +980,16 @@ static void do_outputintr(int dev, int dummy)
}
if (!(adev->flags & DMA_AUTOMODE))
dmap->flags &= ~DMA_ACTIVE;
- while (dmap->qlen <= 0) {
+
+ /*
+ * This is dmap->qlen <= 0 except when closing when
+ * dmap->qlen < 0
+ */
+
+ while (dmap->qlen <= -dmap->closing) {
dmap->underrun_count++;
dmap->qlen++;
- if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) {
+ if ((dmap->flags & DMA_DIRTY) && dmap->applic_profile != APF_CPUINTENS) {
dmap->flags &= ~DMA_DIRTY;
memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte,
adev->dmap_out->buffsize);
@@ -988,10 +1013,15 @@ void DMAbuf_outputintr(int dev, int notify_only)
cli();
if (!(dmap->flags & DMA_NODMA)) {
int chan = dmap->dma, pos, n;
- clear_dma_ff(chan);
+ unsigned long f;
+
+ f=claim_dma_lock();
disable_dma(dmap->dma);
+ clear_dma_ff(chan);
pos = dmap->bytes_in_use - get_dma_residue(chan);
enable_dma(dmap->dma);
+ release_dma_lock(f);
+
pos = pos / dmap->fragment_size; /* Actual qhead */
if (pos < 0 || pos >= dmap->nbufs)
pos = 0;
@@ -1056,7 +1086,7 @@ static void do_inputintr(int dev)
}
}
}
- if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) {
+ if (!(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) {
local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ);
adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1);
if (adev->d->trigger)
@@ -1078,10 +1108,14 @@ void DMAbuf_inputintr(int dev)
if (!(dmap->flags & DMA_NODMA)) {
int chan = dmap->dma, pos, n;
- clear_dma_ff(chan);
+ unsigned long f;
+
+ f=claim_dma_lock();
disable_dma(dmap->dma);
+ clear_dma_ff(chan);
pos = dmap->bytes_in_use - get_dma_residue(chan);
enable_dma(dmap->dma);
+ release_dma_lock(f);
pos = pos / dmap->fragment_size; /* Actual qhead */
if (pos < 0 || pos >= dmap->nbufs)
@@ -1112,11 +1146,10 @@ int DMAbuf_open_dma(int dev)
if (adev->dmap_out->dma >= 0) {
unsigned long flags;
- save_flags(flags);
- cli();
+ flags=claim_dma_lock();
clear_dma_ff(adev->dmap_out->dma);
disable_dma(adev->dmap_out->dma);
- restore_flags(flags);
+ release_dma_lock(flags);
}
return 0;
}
@@ -1155,6 +1188,13 @@ void DMAbuf_init(int dev, int dma1, int dma2)
adev->dmap_in->dma = dma2;
}
}
+ /* Persistent DMA buffers allocated here */
+ if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) {
+ if (adev->dmap_in->raw_buf == NULL)
+ sound_alloc_dmap(adev->dmap_in);
+ if (adev->dmap_out->raw_buf == NULL)
+ sound_alloc_dmap(adev->dmap_out);
+ }
}
}
@@ -1225,12 +1265,13 @@ void DMAbuf_deinit(int dev)
/* This routine is called when driver is being unloaded */
if (!adev)
return;
-#ifdef RUNTIME_DMA_ALLOC
- sound_free_dmap(adev->dmap_out);
- if (adev->flags & DMA_DUPLEX)
- sound_free_dmap(adev->dmap_in);
-#endif
+ /* Persistent DMA buffers deallocated here */
+ if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) {
+ sound_free_dmap(adev->dmap_out);
+ if (adev->flags & DMA_DUPLEX)
+ sound_free_dmap(adev->dmap_in);
+ }
}
#endif
diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c
index b351c73db..aaf21e2ba 100644
--- a/drivers/sound/dmasound.c
+++ b/drivers/sound/dmasound.c
@@ -107,18 +107,17 @@ History:
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/dbdma.h>
-#ifdef CONFIG_PMAC_PBOOK
#include <asm/adb.h>
+#include <asm/cuda.h>
#include <asm/pmu.h>
-#endif /* CONFIG_PMAC_PBOOK */
#include "awacs_defs.h"
#include <linux/nvram.h>
#include <linux/vt_kern.h>
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
#include "dmasound.h"
#include <linux/soundcard.h>
@@ -165,7 +164,7 @@ extern u_short amiga_audio_period;
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
/*
* Interrupt numbers and addresses, obtained from the device tree.
*/
@@ -174,6 +173,8 @@ static volatile struct awacs_regs *awacs;
static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
static int awacs_rate_index;
static int awacs_subframe;
+static int awacs_revision;
+static int awacs_spkr_vol;
/*
* Space for the DBDMA command blocks.
@@ -249,7 +250,7 @@ struct notifier_block awacs_sleep_notifier = {
};
#endif /* CONFIG_PMAC_PBOOK */
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
/*** Some declarations *******************************************************/
@@ -587,7 +588,7 @@ static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
ssize_t frameLeft);
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft);
@@ -618,7 +619,7 @@ static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft);
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
/*** Machine definitions *****************************************************/
@@ -675,7 +676,7 @@ struct sound_settings {
int treble;
int gain;
int minDev; /* minor device number currently open */
-#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC)
+#if defined(CONFIG_ATARI) || defined(CONFIG_PPC)
int bal; /* balance factor for expanding (not volume!) */
u_long data; /* data for expanding */
#endif /* CONFIG_ATARI */
@@ -724,7 +725,7 @@ static void AmiPlay(void);
static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
static void *PMacAlloc(unsigned int size, int flags) __init;
static void PMacFree(void *ptr, unsigned int size) __init;
static int PMacIrqInit(void) __init;
@@ -743,7 +744,7 @@ static int awacs_get_volume(int reg, int lshift);
static int awacs_volume_setter(int volume, int n, int mute, int lshift);
static void awacs_mksound(unsigned int hz, unsigned int ticks);
static void awacs_nosound(unsigned long xx);
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
/*** Mid level stuff *********************************************************/
@@ -816,8 +817,7 @@ static struct sound_queue sq;
#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
#define NO_TIME_LIMIT 0xffffffff
#define SLEEP(queue, time_limit) \
- current->timeout = jiffies+(time_limit); \
- interruptible_sleep_on(&queue);
+ interruptible_sleep_on_timeout(&queue, (time_limit));
#define WAKE_UP(queue) (wake_up_interruptible(&queue))
/*
@@ -1778,7 +1778,7 @@ static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
}
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft)
@@ -2162,7 +2162,7 @@ static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
return stereo? utotal * 4: utotal * 2;
}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
#ifdef CONFIG_ATARI
@@ -2192,7 +2192,7 @@ static TRANS transAmiga = {
};
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
static TRANS transAwacsNormal = {
pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
@@ -2202,7 +2202,7 @@ static TRANS transAwacsExpand = {
pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
};
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
/*** Low level stuff *********************************************************/
@@ -2972,7 +2972,7 @@ static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
}
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
/*
* PCI PowerMac, with AWACS and DBDMA.
@@ -3227,7 +3227,7 @@ awacs_write(int val)
{
while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
; /* XXX should have timeout */
- out_le32(&awacs->codec_ctrl, val);
+ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
}
static void awacs_nosound(unsigned long xx)
@@ -3344,7 +3344,38 @@ static int awacs_sleep_notify(struct notifier_block *this,
}
#endif /* CONFIG_PMAC_PBOOK */
-#endif /* CONFIG_PMAC */
+/* Turn on sound output, needed on G3 desktop powermacs */
+static void
+awacs_enable_amp(int spkr_vol)
+{
+ struct adb_request req;
+
+ awacs_spkr_vol = spkr_vol;
+ if (adb_hardware != ADB_VIACUDA)
+ return;
+
+ /* turn on headphones */
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 4, 0);
+ while (!req.complete) cuda_poll();
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 6, 0);
+ while (!req.complete) cuda_poll();
+
+ /* turn on speaker */
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
+ while (!req.complete) cuda_poll();
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
+ while (!req.complete) cuda_poll();
+
+ cuda_request(&req, NULL, 5, CUDA_PACKET,
+ CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
+ while (!req.complete) cuda_poll();
+}
+
+#endif /* CONFIG_PPC */
/*** Machine definitions *****************************************************/
@@ -3383,7 +3414,7 @@ static MACHINE machAmiga = {
};
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
static MACHINE machPMac = {
DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
#ifdef MODULE
@@ -3684,7 +3715,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
break;
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
case DMASND_AWACS:
switch (cmd) {
case SOUND_MIXER_READ_DEVMASK:
@@ -3734,12 +3765,18 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_volume(data));
case SOUND_MIXER_READ_SPEAKER:
- data = (awacs_reg[1] & MASK_CMUTE)? 0:
- awacs_get_volume(awacs_reg[4], 6);
+ if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA)
+ data = awacs_spkr_vol;
+ else
+ data = (awacs_reg[1] & MASK_CMUTE)? 0:
+ awacs_get_volume(awacs_reg[4], 6);
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_SPEAKER:
IOCTL_IN(arg, data);
- data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+ if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA)
+ awacs_enable_amp(data);
+ else
+ data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
IOCTL_IN(arg, data);
@@ -3863,10 +3900,10 @@ __initfunc(static void mixer_init(void))
static void sq_setup(int numBufs, int bufSize, char **buffers)
{
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
int i;
volatile struct dbdma_cmd *cp;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
sq.max_count = numBufs;
sq.max_active = numBufs;
@@ -3888,7 +3925,7 @@ static void sq_setup(int numBufs, int bufSize, char **buffers)
sq.block_size_half = sq.block_size>>1;
sq.block_size_quarter = sq.block_size_half>>1;
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
cp = awacs_tx_cmds;
memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
for (i = 0; i < numBufs; ++i, ++cp) {
@@ -3898,7 +3935,7 @@ static void sq_setup(int numBufs, int bufSize, char **buffers)
st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
}
static void sq_play(void)
@@ -4207,11 +4244,11 @@ __initfunc(static void sq_init(void))
sound.dsp.speed = 8000;
break;
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
case DMASND_AWACS:
sound.dsp.speed = 8000;
break;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
}
/* before the first open to /dev/dsp this wouldn't be set */
@@ -4252,11 +4289,11 @@ static int state_open(struct inode *inode, struct file *file)
mach = "Amiga ";
break;
#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
case DMASND_AWACS:
mach = "PowerMac ";
break;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
}
len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
@@ -4397,7 +4434,7 @@ __initfunc(void dmasound_init(void))
{
int has_sound = 0;
int i;
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
struct device_node *np;
#endif
@@ -4431,7 +4468,7 @@ __initfunc(void dmasound_init(void))
}
#endif /* __mc68000__ */
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
awacs_subframe = 0;
np = find_devices("awacs");
if (np == 0) {
@@ -4480,6 +4517,13 @@ __initfunc(void dmasound_init(void))
awacs_write(awacs_reg[2] + MASK_ADDR2);
awacs_write(awacs_reg[4] + MASK_ADDR4);
+ /* Initialize recent versions of the awacs */
+ awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf;
+ if (awacs_revision >= 3) {
+ awacs_write(0x6000);
+ awacs_enable_amp(100 * 0x101);
+ }
+
/* Initialize beep stuff */
beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
orig_mksound = kd_mksound;
@@ -4493,7 +4537,7 @@ __initfunc(void dmasound_init(void))
&awacs_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
if (!has_sound)
return;
diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c
index 00794bf39..f7dd0c8a3 100644
--- a/drivers/sound/es1370.c
+++ b/drivers/sound/es1370.c
@@ -24,9 +24,10 @@
*
* Module command line parameters:
* joystick if 1 enables the joystick interface on the card; but it still
- * needs a separate joystick driver (presumably PC standard, although
- * the chip doc doesn't say anything and it looks slightly fishy from
- * the PCI standpoint...)
+ * needs a driver for joysticks connected to a standard IBM-PC
+ * joyport. It is tested with the joy-analog driver. This
+ * module must be loaded before the joystick driver. Kmod will
+ * not ensure that.
* lineout if 1 the LINE jack is used as an output instead of an input.
* LINE then contains the unmixed dsp output. This can be used
* to make the card a four channel one: use dsp to output two
@@ -76,6 +77,8 @@
* 22.08.98 0.12 Mixer registers actually have 5 instead of 4 bits
* pointed out by Itai Nahshon
* 31.08.98 0.13 Fix realplayer problems - dac.count issues
+ * 08.10.98 0.14 Joystick support fixed
+ * -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
*
* some important things missing in Ensoniq documentation:
*
@@ -98,6 +101,7 @@
/*****************************************************************************/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
@@ -1013,11 +1017,8 @@ static int drain_dac1(struct es1370_state *s, int nonblock)
}
tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- current->timeout = jiffies + (tmo ? tmo : 1);
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "es1370: dma timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
current->state = TASK_RUNNING;
@@ -1051,11 +1052,8 @@ static int drain_dac2(struct es1370_state *s, int nonblock)
}
tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- current->timeout = jiffies + (tmo ? tmo : 1);
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "es1370: dma timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
current->state = TASK_RUNNING;
@@ -2197,11 +2195,8 @@ static int es1370_midi_release(struct inode *inode, struct file *file)
return -EBUSY;
}
tmo = (count * HZ) / 3100;
- current->timeout = tmo ? jiffies + tmo : 0;
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "es1370: midi timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->midi.owait, &wait);
current->state = TASK_RUNNING;
@@ -2242,8 +2237,11 @@ static /*const*/ struct file_operations es1370_midi_fops = {
/* maximum number of devices */
#define NR_DEVICE 5
-
+#ifdef CONFIG_SOUND_ES1370_JOYPORT_BOOT
+static int joystick[NR_DEVICE] = { 1, 0, };
+#else
static int joystick[NR_DEVICE] = { 0, };
+#endif
static int lineout[NR_DEVICE] = { 0, };
static int micz[NR_DEVICE] = { 0, };
@@ -2337,8 +2335,6 @@ __initfunc(int init_es1370(void))
goto err_dev3;
if ((s->dev_midi = register_sound_midi(&es1370_midi_fops)) < 0)
goto err_dev4;
- if (s->ctrl & CTRL_JYSTK_EN)
- request_region(0x200, JOY_EXTENT, "es1370");
/* initialize the chips */
outl(s->ctrl, s->io+ES1370_REG_CONTROL);
outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c
index 1c025fa2e..754aa443b 100644
--- a/drivers/sound/es1371.c
+++ b/drivers/sound/es1371.c
@@ -1462,11 +1462,8 @@ static int drain_dac1(struct es1371_state *s, int nonblock)
}
tmo = (count * HZ) / s->dac1rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- current->timeout = jiffies + (tmo ? tmo : 1);
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "es1371: dma timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
current->state = TASK_RUNNING;
@@ -1500,11 +1497,8 @@ static int drain_dac2(struct es1371_state *s, int nonblock)
}
tmo = (count * HZ) / s->dac2rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- current->timeout = jiffies + (tmo ? tmo : 1);
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "es1371: dma timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
current->state = TASK_RUNNING;
@@ -2635,11 +2629,8 @@ static int es1371_midi_release(struct inode *inode, struct file *file)
return -EBUSY;
}
tmo = (count * HZ) / 3100;
- current->timeout = tmo ? jiffies + tmo : 0;
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "es1371: midi timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->midi.owait, &wait);
current->state = TASK_RUNNING;
diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c
index c73e6f06b..4bf4cd38d 100644
--- a/drivers/sound/gus_wave.c
+++ b/drivers/sound/gus_wave.c
@@ -863,7 +863,7 @@ static void pnp_mem_init(void)
int bank, chunk, addr, total = 0;
int bank_sizes[4];
- int i, j, bits = -1, nbanks = 0;
+ int i, j, bits = -1, testbits = -1, nbanks = 0;
/*
* This routine determines what kind of RAM is installed in each of the four
@@ -974,28 +974,26 @@ static void pnp_mem_init(void)
}
}
/*
- * The last resort is to search for a combination where the last bank is
- * smaller than the actual SIMM. This leaves some memory in the last bank
- * unused but doesn't leave holes in the DRAM address space.
- */
- if (bits == -1) /* No luck yet */
- {
- for (i = 0; bits == -1 && i < 13; i++)
- {
- bits = i;
-
- for (j = 0; bits != -1 && j < nbanks - 1; j++)
- if (mem_decode[i][j] != bank_sizes[j])
- bits = -1; /* No hit */
- }
- if (bits != -1)
- {
+ * The last resort is to search for a combination where the banks are
+ * smaller than the actual SIMMs. This leaves some memory in the banks
+ * unused but doesn't leave holes in the DRAM address space.
+ */
+ if (bits == -1) /* No luck yet */
+ {
+ for (i = 0; i < 13; i++)
+ {
+ testbits = i;
+ for (j = 0; testbits != -1 && j < nbanks - 1; j++)
+ if (mem_decode[i][j] > bank_sizes[j]) {
+ testbits = -1;
+ }
+ if(testbits > bits) bits = testbits;
+ }
+ if (bits != -1)
+ {
printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");
printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");
}
- }
- if (bits == -1)
- {
printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");
printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
bits = 0;
@@ -1929,11 +1927,8 @@ static int guswave_load_patch(int dev, int format, const char *addr,
*/
active_device = GUS_DEV_WAVE;
- current->timeout = jiffies + HZ;
- interruptible_sleep_on(&dram_sleeper);
- if (!current->timeout)
+ if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
printk("GUS: DMA Transfer timed out\n");
- current->timeout = 0;
restore_flags(flags);
}
diff --git a/drivers/sound/legacy.h b/drivers/sound/legacy.h
index c9b39b1c9..cde5bc2fc 100644
--- a/drivers/sound/legacy.h
+++ b/drivers/sound/legacy.h
@@ -27,6 +27,7 @@
#define CONFIG_MPU401
#define CONFIG_MSS
#define CONFIG_OPL3SA1
+#define CONFIG_OPL3SA2
#define CONFIG_PAS
#define CONFIG_PSS
#define CONFIG_SB
diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c
index 607955d23..489c2c7c0 100644
--- a/drivers/sound/mad16.c
+++ b/drivers/sound/mad16.c
@@ -834,7 +834,6 @@ int probe_mad16_mpu(struct address_info *hw_config)
void unload_mad16(struct address_info *hw_config)
{
- int mixer = audio_devs[hw_config->slots[0]]->mixer_dev;
ad1848_unload(hw_config->io_base + 4,
hw_config->irq,
hw_config->dma,
@@ -849,7 +848,7 @@ unload_mad16_mpu(struct address_info *hw_config)
#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
{
- sb_dsp_unload(hw_config);
+ sb_dsp_unload(hw_config, 0);
return;
}
#endif
diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c
index baf770a96..d6b12e07b 100644
--- a/drivers/sound/maui.c
+++ b/drivers/sound/maui.c
@@ -81,10 +81,8 @@ static int maui_wait(int mask)
{
if (inb(HOST_STAT_PORT) & mask)
return 1;
- current->timeout = jiffies + HZ / 10;
current->state = TASK_INTERRUPTIBLE;
- schedule();
- current->timeout = 0;
+ schedule_timeout(HZ / 10);
if (signal_pending(current))
return 0;
}
diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c
index 23780b5a2..7adfeb89c 100644
--- a/drivers/sound/midibuf.c
+++ b/drivers/sound/midibuf.c
@@ -90,11 +90,8 @@ static void drain_midi_queue(int dev)
if (midi_devs[dev]->buffer_status != NULL)
while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev))
- {
- current->timeout = jiffies + HZ / 10;
- interruptible_sleep_on(&midi_sleeper[dev]);
- current->timeout = 0;
- }
+ interruptible_sleep_on_timeout(&midi_sleeper[dev],
+ HZ/10);
}
static void midi_input_intr(int dev, unsigned char data)
@@ -181,7 +178,7 @@ int MIDIbuf_open(int dev, struct file *file)
midi_input_intr, midi_output_intr)) < 0)
return err;
- parms[dev].prech_timeout = 0;
+ parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
if (midi_in_buf[dev] == NULL)
@@ -325,9 +322,9 @@ int MIDIbuf_read(int dev, struct file *file, char *buf, int count)
if (!DATA_AVAIL(midi_in_buf[dev])) { /*
* No data yet, wait
*/
- current->timeout = parms[dev].prech_timeout ? jiffies + parms[dev].prech_timeout : 0;
- interruptible_sleep_on(&input_sleeper[dev]);
- current->timeout = 0;
+ interruptible_sleep_on_timeout(&input_sleeper[dev],
+ parms[dev].prech_timeout);
+
if (signal_pending(current))
c = -EINTR; /* The user is getting restless */
}
diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c
index ad7ceaa48..a3f73eded 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.9 1998/09/04 18:41:27 andrewtv Exp $
+ * $Id: msnd.c,v 1.16 1998/09/08 04:05:56 andrewtv Exp $
*
********************************************************************/
@@ -46,6 +46,7 @@
# include <asm/uaccess.h>
# include <asm/spinlock.h>
#endif
+#include <asm/irq.h>
#include "msnd.h"
#define LOGNAME "msnd"
@@ -224,7 +225,7 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
int msnd_wait_TXDE(multisound_dev_t *dev)
{
register unsigned int io = dev->io;
- register int timeout = 100;
+ register int timeout = 1000;
while(timeout-- > 0)
if (inb(io + HP_ISR) & HPISR_TXDE)
@@ -236,7 +237,7 @@ int msnd_wait_TXDE(multisound_dev_t *dev)
int msnd_wait_HC0(multisound_dev_t *dev)
{
register unsigned int io = dev->io;
- register int timeout = 100;
+ register int timeout = 1000;
while(timeout-- > 0)
if (!(inb(io + HP_CVR) & HPCVR_HC))
@@ -248,17 +249,16 @@ int msnd_wait_HC0(multisound_dev_t *dev)
int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
{
unsigned long flags;
-
+
spin_lock_irqsave(&dev->lock, flags);
if (msnd_wait_HC0(dev) == 0) {
-
outb(cmd, dev->io + HP_CVR);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n");
+ printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n");
return -EIO;
}
@@ -269,14 +269,13 @@ int msnd_send_word(multisound_dev_t *dev, unsigned char high,
register unsigned int io = dev->io;
if (msnd_wait_TXDE(dev) == 0) {
-
outb(high, io + HP_TXH);
outb(mid, io + HP_TXM);
outb(low, io + HP_TXL);
return 0;
}
- printk(KERN_WARNING LOGNAME ": Send host word timeout\n");
+ printk(KERN_DEBUG LOGNAME ": Send host word timeout\n");
return -EIO;
}
@@ -286,7 +285,6 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
int i;
if (len % 3 != 0) {
-
printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");
return -EINVAL;
}
@@ -303,31 +301,27 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
int msnd_enable_irq(multisound_dev_t *dev)
{
- printk(KERN_DEBUG LOGNAME ": enable_irq: count %d\n", dev->irq_ref);
+ unsigned long flags;
- if (dev->irq_ref++ != 0)
+ if (dev->irq_ref++)
return 0;
printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
-
+
+ spin_lock_irqsave(&dev->lock, flags);
if (msnd_wait_TXDE(dev) == 0) {
-
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
-
outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
-
if (dev->type == msndClassic)
outb(dev->irqid, dev->io + HP_IRQM);
-
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);
spin_unlock_irqrestore(&dev->lock, flags);
-
return 0;
}
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n");
return -EIO;
}
@@ -336,29 +330,28 @@ int msnd_disable_irq(multisound_dev_t *dev)
{
unsigned long flags;
- printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref);
-
if (--dev->irq_ref > 0)
return 0;
- if (dev->irq_ref < 0) {
- printk(KERN_WARNING LOGNAME ": IRQ ref count is %d\n", dev->irq_ref);
-/* dev->irq_ref = 0; */
- }
+ if (dev->irq_ref < 0)
+ printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref);
printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
-
- udelay(50);
spin_lock_irqsave(&dev->lock, flags);
- outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
-
- if (dev->type == msndClassic)
- outb(HPIRQ_NONE, dev->io + HP_IRQM);
-
+ if (msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(HPIRQ_NONE, dev->io + HP_IRQM);
+ disable_irq(dev->irq);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
+ printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n");
+
+ return -EIO;
}
#ifndef LINUX20
diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h
index 804cff425..1dbdedf37 100644
--- a/drivers/sound/msnd.h
+++ b/drivers/sound/msnd.h
@@ -24,19 +24,19 @@
* 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.18 1998/09/04 18:43:40 andrewtv Exp $
+ * $Id: msnd.h,v 1.32 1998/10/09 19:54:39 andrewtv Exp $
*
********************************************************************/
#ifndef __MSND_H
#define __MSND_H
-#define VERSION "0.7.13"
+#define VERSION "0.8.2.1"
#define DEFSAMPLERATE DSP_DEFAULT_SPEED
#define DEFSAMPLESIZE AFMT_U8
#define DEFCHANNELS 1
-#define DEFFIFOSIZE 64
+#define DEFFIFOSIZE 128
#define SNDCARD_MSND 38
@@ -151,6 +151,7 @@
#define PCTODSP_OFFSET(w) (USHORT)((w)/2)
#define PCTODSP_BASED(w) (USHORT)(((w)/2) + DSP_BASE_ADDR)
+#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2)
#ifdef SLOWIO
# undef outb
@@ -207,14 +208,10 @@ typedef struct multisound_dev {
int memid, irqid;
int irq, irq_ref;
unsigned char info;
- char *base;
-#ifndef LINUX20
- spinlock_t lock;
-#endif
+ volatile BYTE *base;
/* Motorola 56k DSP SMA */
volatile BYTE *SMA;
- volatile BYTE *CurDAQD, *CurDARQD;
volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ;
volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData;
@@ -222,27 +219,33 @@ typedef struct multisound_dev {
enum { msndClassic, msndPinnacle } type;
mode_t mode;
unsigned long flags;
-#define F_BANKONE 0
-#define F_INTERRUPT 1
-#define F_WRITING 2
-#define F_WRITEBLOCK 3
-#define F_READING 4
-#define F_READBLOCK 5
-#define F_AUDIO_INUSE 6
-#define F_EXT_MIDI_INUSE 7
-#define F_INT_MIDI_INUSE 8
-#define F_WRITEFLUSH 9
-#define F_HAVEDIGITAL 10
+#define F_RESETTING 0
+#define F_HAVEDIGITAL 1
+#define F_AUDIO_WRITE_INUSE 2
+#define F_WRITING 3
+#define F_WRITEBLOCK 4
+#define F_WRITEFLUSH 5
+#define F_AUDIO_READ_INUSE 6
+#define F_READING 7
+#define F_READBLOCK 8
+#define F_EXT_MIDI_INUSE 9
+#define F_INT_MIDI_INUSE 10
+#define F_DISABLE_WRITE_NDELAY 11
struct wait_queue *writeblock, *readblock;
struct wait_queue *writeflush;
+#ifndef LINUX20
+ spinlock_t lock;
+#endif
+ int nresets;
unsigned long recsrc;
int left_levels[16];
int right_levels[16];
int mixer_mod_count;
int calibrate_signal;
- int sample_size;
- int sample_rate;
- int channels;
+ int play_sample_size, play_sample_rate, play_channels;
+ int play_ndelay;
+ int rec_sample_size, rec_sample_rate, rec_channels;
+ int rec_ndelay;
BYTE bCurrentMidiPatch;
void (*inc_ref)(void);
void (*dec_ref)(void);
@@ -250,7 +253,7 @@ typedef struct multisound_dev {
/* Digital audio FIFOs */
msnd_fifo DAPF, DARF;
int fifosize;
- int lastbank;
+ int last_playbank, last_recbank;
/* MIDI in callback */
void (*midi_in_interrupt)(struct multisound_dev *);
diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h
index bdc28ffd0..25898f8e0 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.7 1998/09/03 06:39:47 andrewtv Exp $
+ * $Id: msnd_classic.h,v 1.9 1998/09/10 04:11:18 andrewtv Exp $
*
********************************************************************/
#ifndef __MSND_CLASSIC_H
diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c
index bebb5d49c..8f0b6de86 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.17 1998/09/04 18:41:27 andrewtv Exp $
+ * $Id: msnd_pinnacle.c,v 1.66 1998/10/09 19:54:39 andrewtv Exp $
*
********************************************************************/
@@ -45,6 +45,7 @@
#ifndef LINUX20
# include <linux/init.h>
#endif
+#include <asm/irq.h>
#include "sound_config.h"
#include "sound_firmware.h"
#ifdef MSND_CLASSIC
@@ -52,13 +53,33 @@
#endif
#include "msnd.h"
#ifdef MSND_CLASSIC
+# ifdef CONFIG_MSNDCLAS_HAVE_BOOT
+# define HAVE_DSPCODEH
+# endif
# include "msnd_classic.h"
# define LOGNAME "msnd_classic"
#else
+# ifdef CONFIG_MSNDPIN_HAVE_BOOT
+# define HAVE_DSPCODEH
+# endif
# include "msnd_pinnacle.h"
# define LOGNAME "msnd_pinnacle"
#endif
+#ifndef CONFIG_MSND_WRITE_NDELAY
+# define CONFIG_MSND_WRITE_NDELAY 0
+#endif
+
+#define get_play_delay_jiffies(size) ((size) * HZ * \
+ dev.play_sample_size / 8 / \
+ dev.play_sample_rate / \
+ dev.play_channels)
+
+#define get_rec_delay_jiffies(size) ((size) * HZ * \
+ dev.rec_sample_size / 8 / \
+ dev.rec_sample_rate / \
+ dev.rec_channels)
+
static multisound_dev_t dev;
#ifndef HAVE_DSPCODEH
@@ -66,71 +87,86 @@ static char *dspini, *permini;
static int sizeof_dspini, sizeof_permini;
#endif
+static int dsp_full_reset(void);
+static void dsp_write_flush(void);
+
+static __inline__ int chk_send_dsp_cmd(multisound_dev_t *dev, register BYTE cmd)
+{
+ if (msnd_send_dsp_cmd(dev, cmd) == 0)
+ return 0;
+ dsp_full_reset();
+ return msnd_send_dsp_cmd(dev, cmd);
+}
+
static void reset_play_queue(void)
{
int n;
LPDAQD lpDAQ;
- msnd_fifo_make_empty(&dev.DAPF);
- writew(0, dev.DAPQ + JQS_wHead);
- writew(PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE), dev.DAPQ + JQS_wTail);
- dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
- memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+ dev.last_playbank = -1;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
- for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) {
+ for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
- writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize);
+ writew(0, lpDAQ + DAQDS_wSize);
writew(1, lpDAQ + DAQDS_wFormat);
- writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
- writew(dev.channels, lpDAQ + DAQDS_wChannels);
- writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
+ writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
+ writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
+ writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
- writew(n + 1, lpDAQ + DAQDS_wFlags);
+ writew(n, lpDAQ + DAQDS_wFlags);
}
- dev.lastbank = -1;
}
static void reset_record_queue(void)
{
int n;
LPDAQD lpDAQ;
+ unsigned long flags;
+
+ dev.last_recbank = 2;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
- msnd_fifo_make_empty(&dev.DARF);
- writew(0, dev.DARQ + JQS_wHead);
- writew(PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE), dev.DARQ + JQS_wTail);
- dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+ /* Critical section: bank 1 access */
+ spin_lock_irqsave(&dev.lock, flags);
outb(HPBLKSEL_1, dev.io + HP_BLKS);
memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ spin_unlock_irqrestore(&dev.lock, flags);
- for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) {
+ for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
writew(1, lpDAQ + DAQDS_wFormat);
- writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
- writew(dev.channels, lpDAQ + DAQDS_wChannels);
- writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
+ writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
+ writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
+ writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
- writew(n + 1, lpDAQ + DAQDS_wFlags);
+ writew(n, lpDAQ + DAQDS_wFlags);
}
}
static void reset_queues(void)
{
- writew(0, dev.DSPQ + JQS_wHead);
- writew(0, dev.DSPQ + JQS_wTail);
- reset_play_queue();
- reset_record_queue();
+ if (dev.mode & FMODE_WRITE) {
+ msnd_fifo_make_empty(&dev.DAPF);
+ reset_play_queue();
+ }
+ if (dev.mode & FMODE_READ) {
+ msnd_fifo_make_empty(&dev.DARF);
+ reset_record_queue();
+ }
}
-static int dsp_set_format(int val)
+static int dsp_set_format(struct file *file, int val)
{
int data, i;
LPDAQD lpDAQ, lpDARQ;
- lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
- lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+ lpDAQ = dev.base + DAPQ_DATA_BUFF;
+ lpDARQ = dev.base + DARQ_DATA_BUFF;
switch (val) {
case AFMT_U8:
@@ -143,28 +179,43 @@ static int dsp_set_format(int val)
}
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
- writew(data, lpDAQ + DAQDS_wSampleSize);
- writew(data, lpDARQ + DAQDS_wSampleSize);
+ if (file->f_mode & FMODE_WRITE)
+ writew(data, lpDAQ + DAQDS_wSampleSize);
+ if (file->f_mode & FMODE_READ)
+ writew(data, lpDARQ + DAQDS_wSampleSize);
}
-
- dev.sample_size = data;
+ if (file->f_mode & FMODE_WRITE)
+ dev.play_sample_size = data;
+ if (file->f_mode & FMODE_READ)
+ dev.rec_sample_size = data;
return data;
}
-static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+static int dsp_get_frag_size(void)
+{
+ int size;
+ size = dev.fifosize / 4;
+ if (size > 32 * 1024)
+ size = 32 * 1024;
+ return size;
+}
+
+static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int val, i, data, tmp;
LPDAQD lpDAQ, lpDARQ;
+ audio_buf_info abinfo;
+ unsigned long flags;
- lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
- lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+ lpDAQ = dev.base + DAPQ_DATA_BUFF;
+ lpDARQ = dev.base + DARQ_DATA_BUFF;
switch (cmd) {
case SNDCTL_DSP_SUBDIVIDE:
case SNDCTL_DSP_SETFRAGMENT:
case SNDCTL_DSP_SETDUPLEX:
+ case SNDCTL_DSP_POST:
return 0;
case SNDCTL_DSP_GETIPTR:
@@ -173,14 +224,39 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg)
case SNDCTL_DSP_MAPOUTBUF:
return -EINVAL;
- case SNDCTL_DSP_SYNC:
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&dev.lock, flags);
+ abinfo.fragsize = dsp_get_frag_size();
+ abinfo.bytes = dev.DAPF.n - dev.DAPF.len;
+ abinfo.fragstotal = dev.DAPF.n / abinfo.fragsize;
+ abinfo.fragments = abinfo.bytes / abinfo.fragsize;
+ spin_unlock_irqrestore(&dev.lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&dev.lock, flags);
+ abinfo.fragsize = dsp_get_frag_size();
+ abinfo.bytes = dev.DARF.n - dev.DARF.len;
+ abinfo.fragstotal = dev.DARF.n / abinfo.fragsize;
+ abinfo.fragments = abinfo.bytes / abinfo.fragsize;
+ spin_unlock_irqrestore(&dev.lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
case SNDCTL_DSP_RESET:
- reset_play_queue();
- reset_record_queue();
+ dev.nresets = 0;
+ reset_queues();
+ return 0;
+
+ case SNDCTL_DSP_SYNC:
+ dsp_write_flush();
return 0;
case SNDCTL_DSP_GETBLKSIZE:
- tmp = dev.fifosize / 4;
+ tmp = dsp_get_frag_size();
if (put_user(tmp, (int *)arg))
return -EFAULT;
return 0;
@@ -195,14 +271,25 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg)
if (get_user(val, (int *)arg))
return -EFAULT;
- data = (val == AFMT_QUERY) ? dev.sample_size : dsp_set_format(val);
+ if (file->f_mode & FMODE_WRITE)
+ data = val == AFMT_QUERY
+ ? dev.play_sample_size
+ : dsp_set_format(file, val);
+ else
+ data = val == AFMT_QUERY
+ ? dev.rec_sample_size
+ : dsp_set_format(file, val);
if (put_user(data, (int *)arg))
return -EFAULT;
return 0;
case SNDCTL_DSP_NONBLOCK:
- dev.mode |= O_NONBLOCK;
+ if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags) &&
+ file->f_mode & FMODE_WRITE)
+ dev.play_ndelay = 1;
+ if (file->f_mode & FMODE_READ)
+ dev.rec_ndelay = 1;
return 0;
case SNDCTL_DSP_GETCAPS:
@@ -224,65 +311,58 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg)
data = val;
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
- writew(data, lpDAQ + DAQDS_wSampleRate);
- writew(data, lpDARQ + DAQDS_wSampleRate);
+ if (file->f_mode & FMODE_WRITE)
+ writew(data, lpDAQ + DAQDS_wSampleRate);
+ if (file->f_mode & FMODE_READ)
+ writew(data, lpDARQ + DAQDS_wSampleRate);
}
-
- dev.sample_rate = data;
+ if (file->f_mode & FMODE_WRITE)
+ dev.play_sample_rate = data;
+ if (file->f_mode & FMODE_READ)
+ dev.rec_sample_rate = data;
if (put_user(data, (int *)arg))
return -EFAULT;
return 0;
case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *)arg))
- return -EFAULT;
-
- switch (val) {
- case 1:
- case 2:
- data = val;
- break;
- default:
- val = data = 2;
- break;
- }
-
- for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
- writew(data, lpDAQ + DAQDS_wChannels);
- writew(data, lpDARQ + DAQDS_wChannels);
- }
-
- dev.channels = data;
-
- if (put_user(val, (int *)arg))
- return -EFAULT;
- return 0;
-
case SNDCTL_DSP_STEREO:
if (get_user(val, (int *)arg))
return -EFAULT;
-
- switch (val) {
- case 0:
- data = 1;
- break;
- default:
- val = 1;
- case 1:
- data = 2;
- break;
+
+ if (cmd == SNDCTL_DSP_CHANNELS) {
+ switch (val) {
+ case 1:
+ case 2:
+ data = val;
+ break;
+ default:
+ val = data = 2;
+ break;
+ }
+ } else {
+ switch (val) {
+ case 0:
+ data = 1;
+ break;
+ default:
+ val = 1;
+ case 1:
+ data = 2;
+ break;
+ }
}
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
- writew(data, lpDAQ + DAQDS_wChannels);
- writew(data, lpDARQ + DAQDS_wChannels);
+ if (file->f_mode & FMODE_WRITE)
+ writew(data, lpDAQ + DAQDS_wChannels);
+ if (file->f_mode & FMODE_READ)
+ writew(data, lpDARQ + DAQDS_wChannels);
}
-
- dev.channels = data;
+ if (file->f_mode & FMODE_WRITE)
+ dev.play_channels = data;
+ if (file->f_mode & FMODE_READ)
+ dev.rec_channels = data;
if (put_user(val, (int *)arg))
return -EFAULT;
@@ -320,6 +400,12 @@ static int mixer_get(int d)
writew(dev.right_levels[a] * readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff / s, \
dev.SMA + SMA_##b##Right);
+#define update_pot(d,s,ar) \
+ writeb(dev.left_levels[d] >> 8, dev.SMA + SMA_##s##Left); \
+ writeb(dev.right_levels[d] >> 8, dev.SMA + SMA_##s##Right); \
+ if (msnd_send_word(&dev, 0, 0, ar) == 0) \
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
static int mixer_set(int d, int value)
{
int left = value & 0x000000ff;
@@ -350,7 +436,7 @@ static int mixer_set(int d, int value)
writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
writeb(bRight, dev.SMA + SMA_bInPotPosRight);
if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
break;
#ifndef MSND_CLASSIC
@@ -358,7 +444,7 @@ static int mixer_set(int d, int value)
writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
break;
#endif
@@ -366,7 +452,7 @@ static int mixer_set(int d, int value)
writeb(bLeft, dev.SMA + SMA_bAuxPotPosLeft);
writeb(bRight, dev.SMA + SMA_bAuxPotPosRight);
if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
break;
/* digital controls */
@@ -389,6 +475,20 @@ static int mixer_set(int d, int value)
return mixer_get(d);
}
+static void mixer_setup(void)
+{
+ update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
+#ifndef MSND_CLASSIC
+ update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
+#endif
+ update_pot(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+ update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+#ifndef MSND_CLASSIC
+ update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1);
+#endif
+}
+
static unsigned long set_recsrc(unsigned long recsrc)
{
if (dev.recsrc == recsrc)
@@ -403,17 +503,15 @@ static unsigned long set_recsrc(unsigned long recsrc)
#ifndef MSND_CLASSIC
if (dev.recsrc & SOUND_MASK_LINE) {
if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
}
else if (dev.recsrc & SOUND_MASK_SYNTH) {
if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0)
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
}
else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) {
- if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) {
- udelay(50);
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
- }
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0)
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
}
else {
#ifdef HAVE_NORECSRC
@@ -422,7 +520,7 @@ static unsigned long set_recsrc(unsigned long recsrc)
#else
dev.recsrc = SOUND_MASK_LINE;
if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
#endif
}
#endif /* MSND_CLASSIC */
@@ -430,6 +528,12 @@ static unsigned long set_recsrc(unsigned long recsrc)
return dev.recsrc;
}
+static unsigned long force_recsrc(unsigned long recsrc)
+{
+ dev.recsrc = 0;
+ return set_recsrc(recsrc);
+}
+
#define set_mixer_info() \
strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \
strncpy(info.name, "MultiSound Mixer", sizeof(info.name));
@@ -447,10 +551,6 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
set_mixer_info();
return copy_to_user((void *)arg, &info, sizeof(info));
}
- else if (cmd == OSS_GETVERSION) {
- int sound_version = SOUND_VERSION;
- return put_user(sound_version, (int *)arg);
- }
else if (((cmd >> 8) & 0xff) == 'M') {
int val = 0;
@@ -521,77 +621,138 @@ static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
{
int minor = MINOR(inode->i_rdev);
+ if (cmd == OSS_GETVERSION) {
+ int sound_version = SOUND_VERSION;
+ return put_user(sound_version, (int *)arg);
+ }
+
if (minor == dev.dsp_minor)
- return dsp_ioctl(cmd, arg);
+ return dsp_ioctl(file, cmd, arg);
else if (minor == dev.mixer_minor)
return mixer_ioctl(cmd, arg);
return -EINVAL;
}
-static void dsp_halt(void)
+static void dsp_write_flush(void)
{
- mdelay(1);
-#ifdef LINUX20
- if (test_bit(F_READING, &dev.flags)) {
+ if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags))
+ return;
+ set_bit(F_WRITEFLUSH, &dev.flags);
+ interruptible_sleep_on_timeout(&dev.writeflush, get_play_delay_jiffies(dev.DAPF.len) + HZ / 8);
+ clear_bit(F_WRITEFLUSH, &dev.flags);
+ if (!signal_pending(current)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE));
+ }
+ clear_bit(F_WRITING, &dev.flags);
+}
+
+static void dsp_halt(struct file *file)
+{
+ if ((file ? file->f_mode : dev.mode) & FMODE_READ) {
clear_bit(F_READING, &dev.flags);
-#else
- if (test_and_clear_bit(F_READING, &dev.flags)) {
-#endif
- msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+ chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
msnd_disable_irq(&dev);
-
+ if (file) {
+ printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file);
+ dev.mode &= ~FMODE_READ;
+ }
+ clear_bit(F_AUDIO_READ_INUSE, &dev.flags);
}
- mdelay(1);
-#ifdef LINUX20
- if (test_bit(F_WRITING, &dev.flags)) {
- clear_bit(F_WRITING, &dev.flags);
-#else
- if (test_and_clear_bit(F_WRITING, &dev.flags)) {
-#endif
- set_bit(F_WRITEFLUSH, &dev.flags);
- interruptible_sleep_on(&dev.writeflush);
- current->state = TASK_INTERRUPTIBLE;
- current->timeout =
- jiffies + DAP_BUFF_SIZE / 2 * HZ /
- dev.sample_rate / dev.channels;
- schedule();
- current->timeout = 0;
- msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+ if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) {
+ if (test_bit(F_WRITING, &dev.flags)) {
+ dsp_write_flush();
+ chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+ }
msnd_disable_irq(&dev);
- memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
-
+ if (file) {
+ printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file);
+ dev.mode &= ~FMODE_WRITE;
+ }
+ clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags);
}
- mdelay(1);
- reset_queues();
}
-static int dsp_open(struct file *file)
+static int dsp_release(struct file *file)
{
- dev.mode = file->f_mode;
- set_bit(F_AUDIO_INUSE, &dev.flags);
- reset_queues();
+ dsp_halt(file);
return 0;
}
-static int dsp_close(void)
+static int dsp_open(struct file *file)
{
- dsp_halt();
- clear_bit(F_AUDIO_INUSE, &dev.flags);
+ if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) {
+ set_bit(F_AUDIO_WRITE_INUSE, &dev.flags);
+ clear_bit(F_WRITING, &dev.flags);
+ msnd_fifo_make_empty(&dev.DAPF);
+ reset_play_queue();
+ if (file) {
+ printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file);
+ dev.mode |= FMODE_WRITE;
+ }
+ msnd_enable_irq(&dev);
+ }
+ if ((file ? file->f_mode : dev.mode) & FMODE_READ) {
+ set_bit(F_AUDIO_READ_INUSE, &dev.flags);
+ clear_bit(F_READING, &dev.flags);
+ msnd_fifo_make_empty(&dev.DARF);
+ reset_record_queue();
+ if (file) {
+ printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file);
+ dev.mode |= FMODE_READ;
+ }
+ msnd_enable_irq(&dev);
+ }
return 0;
}
+static void set_default_play_audio_parameters(void)
+{
+ dev.play_sample_size = DEFSAMPLESIZE;
+ dev.play_sample_rate = DEFSAMPLERATE;
+ dev.play_channels = DEFCHANNELS;
+}
+
+static void set_default_rec_audio_parameters(void)
+{
+ dev.rec_sample_size = DEFSAMPLESIZE;
+ dev.rec_sample_rate = DEFSAMPLERATE;
+ dev.rec_channels = DEFCHANNELS;
+}
+
+static void set_default_audio_parameters(void)
+{
+ set_default_play_audio_parameters();
+ set_default_rec_audio_parameters();
+}
+
static int dev_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
int err = 0;
if (minor == dev.dsp_minor) {
-
- if (test_bit(F_AUDIO_INUSE, &dev.flags))
+ if ((file->f_mode & FMODE_WRITE &&
+ test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
+ (file->f_mode & FMODE_READ &&
+ test_bit(F_AUDIO_READ_INUSE, &dev.flags)))
return -EBUSY;
- err = dsp_open(file);
+ if ((err = dsp_open(file)) >= 0) {
+ dev.nresets = 0;
+ if (file->f_mode & FMODE_WRITE) {
+ set_default_play_audio_parameters();
+ if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags))
+ dev.play_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0;
+ else
+ dev.play_ndelay = 0;
+ }
+ if (file->f_mode & FMODE_READ) {
+ set_default_rec_audio_parameters();
+ dev.rec_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0;
+ }
+ }
}
else if (minor == dev.mixer_minor) {
/* nothing */
@@ -605,9 +766,9 @@ static int dev_open(struct inode *inode, struct file *file)
}
#ifdef LINUX20
-static void dev_close(struct inode *inode, struct file *file)
+static void dev_release(struct inode *inode, struct file *file)
#else
-static int dev_close(struct inode *inode, struct file *file)
+static int dev_release(struct inode *inode, struct file *file)
#endif
{
int minor = MINOR(inode->i_rdev);
@@ -619,7 +780,7 @@ static int dev_close(struct inode *inode, struct file *file)
#ifndef LINUX20
err =
#endif
- dsp_close();
+ dsp_release(file);
}
else if (minor == dev.mixer_minor) {
/* nothing */
@@ -637,62 +798,133 @@ static int dev_close(struct inode *inode, struct file *file)
#endif
}
-static int DAPF_to_bank(int bank)
+static __inline__ int pack_DARQ_to_DARF(register int bank)
{
- return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+ register int size, n, timeout = 3;
+ register WORD wTmp;
+ LPDAQD DAQD;
+
+ /* Increment the tail and check for queue wrap */
+ wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+ if (wTmp > readw(dev.DARQ + JQS_wSize))
+ wTmp = 0;
+ while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--)
+ udelay(1);
+ writew(wTmp, dev.DARQ + JQS_wTail);
+
+ /* Get our digital audio queue struct */
+ DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF;
+
+ /* Get length of data */
+ size = readw(DAQD + DAQDS_wSize);
+
+ /* Read data from the head (unprotected bank 1 access okay
+ since this is only called inside an interrupt) */
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ if ((n = msnd_fifo_write(
+ &dev.DARF,
+ (char *)(dev.base + bank * DAR_BUFF_SIZE),
+ size, 0)) <= 0) {
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ return n;
+ }
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ return 1;
}
-static int bank_to_DARF(int bank)
+static __inline__ int pack_DAPF_to_DAPQ(register int start)
{
- return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+ register WORD DAPQ_tail;
+ register int protect = start, nbanks = 0;
+ LPDAQD DAQD;
+
+ DAPQ_tail = readw(dev.DAPQ + JQS_wTail);
+ while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || 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 */
+ spin_lock_irqsave(&dev.lock, flags);
+ if ((n = msnd_fifo_read(
+ &dev.DAPF,
+ (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
+ DAP_BUFF_SIZE, 0)) < 0) {
+ spin_unlock_irqrestore(&dev.lock, flags);
+ return n;
+ }
+ spin_unlock_irqrestore(&dev.lock, flags);
+ } else {
+ if ((n = msnd_fifo_read(
+ &dev.DAPF,
+ (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
+ DAP_BUFF_SIZE, 0)) < 0) {
+ return n;
+ }
+ }
+ if (!n)
+ break;
+
+ if (start)
+ start = 0;
+
+ /* Get our digital audio queue struct */
+ DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF;
+
+ /* Write size of this bank */
+ writew(n, DAQD + DAQDS_wSize);
+ ++nbanks;
+
+ /* Then advance the tail */
+ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+ writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
+
+ /* Tell the DSP to play the bank */
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+ }
+
+ return nbanks;
}
static int dsp_read(char *buf, size_t len)
{
- int err = 0;
int count = len;
while (count > 0) {
-
int n;
+ unsigned long flags;
+ /* Critical section: protect fifo in non-interrupt */
+ spin_lock_irqsave(&dev.lock, flags);
if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
-
printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+ spin_unlock_irqrestore(&dev.lock, flags);
return n;
}
-
+ spin_unlock_irqrestore(&dev.lock, flags);
buf += n;
count -= n;
-#ifdef LINUX20
- if (!test_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
- set_bit(F_READING, &dev.flags);
-#else
- if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
-#endif
- reset_record_queue();
- msnd_enable_irq(&dev);
- msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
-
+ if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) {
+ dev.last_recbank = -1;
+ if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0)
+ set_bit(F_READING, &dev.flags);
}
- if (dev.mode & O_NONBLOCK)
+ if (dev.rec_ndelay)
return count == len ? -EAGAIN : len - count;
if (count > 0) {
-
set_bit(F_READBLOCK, &dev.flags);
- interruptible_sleep_on(&dev.readblock);
+ if (!interruptible_sleep_on_timeout(&dev.readblock, get_rec_delay_jiffies(DAR_BUFF_SIZE)))
+ clear_bit(F_READING, &dev.flags);
clear_bit(F_READBLOCK, &dev.flags);
-
if (signal_pending(current))
- err = -EINTR;
-
+ return -EINTR;
}
-
- if (err != 0)
- return err;
}
return len - count;
@@ -700,50 +932,39 @@ static int dsp_read(char *buf, size_t len)
static int dsp_write(const char *buf, size_t len)
{
- int err = 0;
int count = len;
while (count > 0) {
-
int n;
+ unsigned long flags;
+ /* Critical section: protect fifo in non-interrupt */
+ spin_lock_irqsave(&dev.lock, flags);
if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
-
printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+ spin_unlock_irqrestore(&dev.lock, flags);
return n;
}
-
+ spin_unlock_irqrestore(&dev.lock, flags);
buf += n;
count -= n;
-#ifdef LINUX20
if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
- set_bit(F_WRITING, &dev.flags);
-#else
- if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
-#endif
- reset_play_queue();
- msnd_enable_irq(&dev);
- msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
-
+ dev.last_playbank = -1;
+ if (pack_DAPF_to_DAPQ(1) > 0)
+ set_bit(F_WRITING, &dev.flags);
}
- if (dev.mode & O_NONBLOCK)
+ if (dev.play_ndelay)
return count == len ? -EAGAIN : len - count;
if (count > 0) {
-
set_bit(F_WRITEBLOCK, &dev.flags);
- interruptible_sleep_on(&dev.writeblock);
+ interruptible_sleep_on_timeout(&dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE));
clear_bit(F_WRITEBLOCK, &dev.flags);
-
if (signal_pending(current))
- err = -EINTR;
-
+ return -EINTR;
}
-
- if (err != 0)
- return err;
}
return len - count;
@@ -758,12 +979,9 @@ static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
{
int minor = MINOR(file->f_dentry->d_inode->i_rdev);
#endif
-
- if (minor == dev.dsp_minor) {
-
+ if (minor == dev.dsp_minor)
return dsp_read(buf, count);
-
- } else
+ else
return -EINVAL;
}
@@ -776,44 +994,22 @@ static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_
{
int minor = MINOR(file->f_dentry->d_inode->i_rdev);
#endif
-
- if (minor == dev.dsp_minor) {
-
+ if (minor == dev.dsp_minor)
return dsp_write(buf, count);
-
- } else
+ else
return -EINVAL;
}
-static void eval_dsp_msg(WORD wMessage)
+static __inline__ void eval_dsp_msg(register WORD wMessage)
{
- WORD wTmp;
-
switch (HIBYTE(wMessage)) {
case HIMT_PLAY_DONE:
- if (dev.lastbank == LOBYTE(wMessage))
+ if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags))
break;
-
- dev.lastbank = LOBYTE(wMessage);
-
- writew(DAP_BUFF_SIZE, dev.CurDAQD + DAQDS_wSize);
+ dev.last_playbank = LOBYTE(wMessage);
- wTmp = readw(dev.DAPQ + JQS_wTail) + PCTODSP_OFFSET(DAPQ_STRUCT_SIZE);
- if (wTmp > readw(dev.DAPQ + JQS_wSize))
- writew(0, dev.DAPQ + JQS_wTail);
- else
- writew(wTmp, dev.DAPQ + JQS_wTail);
-
- if ((dev.CurDAQD += DAQDS__size) > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
- dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
-
- if (dev.lastbank < 3) {
- if (DAPF_to_bank(dev.lastbank) > 0) {
- mdelay(1);
- msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
- }
- else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
- clear_bit(F_WRITING, &dev.flags);
+ if (pack_DAPF_to_DAPQ(0) <= 0) {
+ if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
#ifdef LINUX20
if (test_bit(F_WRITEFLUSH, &dev.flags)) {
clear_bit(F_WRITEFLUSH, &dev.flags);
@@ -824,6 +1020,7 @@ static void eval_dsp_msg(WORD wMessage)
wake_up_interruptible(&dev.writeflush);
#endif
}
+ clear_bit(F_WRITING, &dev.flags);
}
if (test_bit(F_WRITEBLOCK, &dev.flags))
@@ -831,21 +1028,11 @@ static void eval_dsp_msg(WORD wMessage)
break;
case HIMT_RECORD_DONE:
- wTmp = readw(dev.DARQ + JQS_wTail) + DARQ_STRUCT_SIZE / 2;
-
- if (wTmp > readw(dev.DARQ + JQS_wSize))
- wTmp = 0;
-
- while (wTmp == readw(dev.DARQ + JQS_wHead));
-
- writew(wTmp, dev.DARQ + JQS_wTail);
+ if (dev.last_recbank == LOBYTE(wMessage))
+ break;
+ dev.last_recbank = LOBYTE(wMessage);
- outb(HPBLKSEL_1, dev.io + HP_BLKS);
- if (bank_to_DARF(LOBYTE(wMessage)) == 0 && !test_bit(F_READBLOCK, &dev.flags)) {
- memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
- clear_bit(F_READING, &dev.flags);
- }
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ pack_DARQ_to_DARF(dev.last_recbank);
if (test_bit(F_READBLOCK, &dev.flags))
wake_up_interruptible(&dev.readblock);
@@ -857,17 +1044,17 @@ static void eval_dsp_msg(WORD wMessage)
case HIDSP_PLAY_UNDER:
#endif
case HIDSP_INT_PLAY_UNDER:
-/* printk(KERN_INFO LOGNAME ": Write underflow\n"); */
- reset_play_queue();
+/* printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */
+ clear_bit(F_WRITING, &dev.flags);
break;
case HIDSP_INT_RECORD_OVER:
-/* printk(KERN_INFO LOGNAME ": Read overflow\n"); */
- reset_record_queue();
+/* printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */
+ clear_bit(F_READING, &dev.flags);
break;
default:
- printk(KERN_DEBUG LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", LOBYTE(wMessage), LOBYTE(wMessage)); */
break;
}
break;
@@ -877,85 +1064,68 @@ static void eval_dsp_msg(WORD wMessage)
(*dev.midi_in_interrupt)(&dev);
break;
- case HIMT_MIDI_OUT:
- printk(KERN_DEBUG LOGNAME ": MIDI out event\n");
- break;
-
default:
- printk(KERN_DEBUG LOGNAME ": HIMT message %u\n", HIBYTE(wMessage));
+/* printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */
break;
}
}
static void intr(int irq, void *dev_id, struct pt_regs *regs)
{
- if (test_bit(F_INTERRUPT, &dev.flags))
- return;
-
- set_bit(F_INTERRUPT, &dev.flags);
-
- if (test_bit(F_BANKONE, &dev.flags))
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
-
+ /* Send ack to DSP */
inb(dev.io + HP_RXL);
-
+
+ /* Evaluate queued DSP messages */
while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) {
- WORD wTmp;
+ register WORD wTmp;
- eval_dsp_msg(*(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead)));
-
- wTmp = readw(dev.DSPQ + JQS_wHead) + 1;
- if (wTmp > readw(dev.DSPQ + JQS_wSize))
+ eval_dsp_msg(readw(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead)));
+
+ if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize))
writew(0, dev.DSPQ + JQS_wHead);
else
writew(wTmp, dev.DSPQ + JQS_wHead);
}
-
- if (test_bit(F_BANKONE, &dev.flags))
- outb(HPBLKSEL_1, dev.io + HP_BLKS);
-
- clear_bit(F_INTERRUPT, &dev.flags);
}
static struct file_operations dev_fileops = {
- NULL,
- dev_read,
- dev_write,
- NULL,
- NULL,
- dev_ioctl,
- NULL,
- dev_open,
+ NULL, /* llseek */
+ dev_read, /* read */
+ dev_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ dev_ioctl, /* ioctl */
+ NULL, /* mmap */
+ dev_open, /* open */
+#ifndef LINUX20
+ NULL, /* flush */
+#endif
+ dev_release, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
#ifndef LINUX20
-# if LINUX_VERSION_CODE >= 0x020100 + 118
- NULL,
-# endif /* >= 2.1.118 */
+ NULL, /* lock */
#endif
- dev_close,
};
-__initfunc(static int reset_dsp(void))
+static int reset_dsp(void)
{
int timeout = 100;
outb(HPDSPRESET_ON, dev.io + HP_DSPR);
-
mdelay(1);
-
+#ifndef MSND_CLASSIC
dev.info = inb(dev.io + HP_INFO);
-
+#endif
outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
-
mdelay(1);
-
while (timeout-- > 0) {
-
if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
return 0;
-
mdelay(1);
}
-
printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
return -EIO;
@@ -973,7 +1143,6 @@ __initfunc(static int probe_multisound(void))
printk(KERN_ERR LOGNAME ": I/O port conflict\n");
return -ENODEV;
}
-
request_region(dev.io, dev.numio, "probing");
if (reset_dsp() < 0) {
@@ -1024,127 +1193,82 @@ __initfunc(static int probe_multisound(void))
return 0;
}
-__initfunc(static int init_sma(void))
+static void msnd_init_queue(volatile BYTE *base, int start, int size)
{
- int n;
- LPDAQD lpDAQ;
+ writew(PCTODSP_BASED(start), base + JQS_wStart);
+ writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ writew(0, base + JQS_wHead);
+ writew(0, base + JQS_wTail);
+}
+
+static int init_sma(void)
+{
+ static int initted;
+ WORD mastVolLeft, mastVolRight;
+ unsigned long flags;
#ifdef MSND_CLASSIC
outb(dev.memid, dev.io + HP_MEMM);
#endif
outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ if (initted) {
+ mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft);
+ mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight);
+ } else
+ mastVolLeft = mastVolRight = 0;
memset_io(dev.base, 0, 0x8000);
-
+
+ /* Critical section: bank 1 access */
+ spin_lock_irqsave(&dev.lock, flags);
outb(HPBLKSEL_1, dev.io + HP_BLKS);
memset_io(dev.base, 0, 0x8000);
-
outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ spin_unlock_irqrestore(&dev.lock, flags);
- dev.DAPQ = (BYTE *)(dev.base + DAPQ_OFFSET);
- dev.DARQ = (BYTE *)(dev.base + DARQ_OFFSET);
- dev.MODQ = (BYTE *)(dev.base + MODQ_OFFSET);
- dev.MIDQ = (BYTE *)(dev.base + MIDQ_OFFSET);
- dev.DSPQ = (BYTE *)(dev.base + DSPQ_OFFSET);
- dev.SMA = (BYTE *)(dev.base + SMA_STRUCT_START);
-
- dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
- dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
-
- dev.sample_size = DEFSAMPLESIZE;
- dev.sample_rate = DEFSAMPLERATE;
- dev.channels = DEFCHANNELS;
-
- for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) {
-
- writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
- writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize);
- writew(1, lpDAQ + DAQDS_wFormat);
- writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
- writew(dev.channels, lpDAQ + DAQDS_wChannels);
- writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
- writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
- writew(n + 1, lpDAQ + DAQDS_wFlags);
- }
-
- for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) {
-
- writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
- writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
- writew(1, lpDAQ + DAQDS_wFormat);
- writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
- writew(dev.channels, lpDAQ + DAQDS_wChannels);
- writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
- writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
- writew(n + 1, lpDAQ + DAQDS_wFlags);
-
- }
-
- dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
- dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
- dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
-
- writew(PCTODSP_BASED(MIDQ_DATA_BUFF), dev.MIDQ + JQS_wStart);
- writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, dev.MIDQ + JQS_wSize);
- writew(0, dev.MIDQ + JQS_wHead);
- writew(0, dev.MIDQ + JQS_wTail);
+ dev.pwDSPQData = (volatile WORD *)(dev.base + DSPQ_DATA_BUFF);
+ dev.pwMODQData = (volatile WORD *)(dev.base + MODQ_DATA_BUFF);
+ dev.pwMIDQData = (volatile WORD *)(dev.base + MIDQ_DATA_BUFF);
- writew(PCTODSP_BASED(MODQ_DATA_BUFF), dev.MODQ + JQS_wStart);
- writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, dev.MODQ + JQS_wSize);
- writew(0, dev.MODQ + JQS_wHead);
- writew(0, dev.MODQ + JQS_wTail);
+ /* Motorola 56k shared memory base */
+ dev.SMA = dev.base + SMA_STRUCT_START;
- writew(PCTODSP_BASED(DAPQ_DATA_BUFF), dev.DAPQ + JQS_wStart);
- writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, dev.DAPQ + JQS_wSize);
- writew(0, dev.DAPQ + JQS_wHead);
- writew(0, dev.DAPQ + JQS_wTail);
+ /* Digital audio play queue */
+ dev.DAPQ = dev.base + DAPQ_OFFSET;
+ msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
- writew(PCTODSP_BASED(DARQ_DATA_BUFF), dev.DARQ + JQS_wStart);
- writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, dev.DARQ + JQS_wSize);
- writew(0, dev.DARQ + JQS_wHead);
- writew(0, dev.DARQ + JQS_wTail);
+ /* Digital audio record queue */
+ dev.DARQ = dev.base + DARQ_OFFSET;
+ msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
- writew(PCTODSP_BASED(DSPQ_DATA_BUFF), dev.DSPQ + JQS_wStart);
- writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, dev.DSPQ + JQS_wSize);
- writew(0, dev.DSPQ + JQS_wHead);
- writew(0, dev.DSPQ + JQS_wTail);
+ /* MIDI out queue */
+ dev.MODQ = dev.base + MODQ_OFFSET;
+ msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
- writew(0, dev.SMA + SMA_wCurrPlayBytes);
- writew(0, dev.SMA + SMA_wCurrRecordBytes);
+ /* MIDI in queue */
+ dev.MIDQ = dev.base + MIDQ_OFFSET;
+ msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
- writew(0, dev.SMA + SMA_wCurrPlayVolLeft);
- writew(0, dev.SMA + SMA_wCurrPlayVolRight);
-
- writew(0, dev.SMA + SMA_wCurrInVolLeft);
- writew(0, dev.SMA + SMA_wCurrInVolRight);
-
- writew(0, dev.SMA + SMA_wCurrMastVolLeft);
- writew(0, dev.SMA + SMA_wCurrMastVolRight);
+ /* DSP -> host message queue */
+ dev.DSPQ = dev.base + DSPQ_OFFSET;
+ msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
+ /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+ writew(1, dev.SMA + SMA_wCurrPlayFormat);
+ writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
+ writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
+ writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
+#endif
+ writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+ writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
+ writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
#ifndef MSND_CLASSIC
writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
#endif
-
- writew(0x0000, dev.SMA + SMA_wCurrDSPStatusFlags);
- writew(0x0000, dev.SMA + SMA_wCurrHostStatusFlags);
-
writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
- writew(0, dev.SMA + SMA_wCurrLeftPeak);
- writew(0, dev.SMA + SMA_wCurrRightPeak);
-
- writeb(0, dev.SMA + SMA_bInPotPosRight);
- writeb(0, dev.SMA + SMA_bInPotPosLeft);
-
- writeb(0, dev.SMA + SMA_bAuxPotPosRight);
- writeb(0, dev.SMA + SMA_bAuxPotPosLeft);
-#ifndef MSND_CLASSIC
- writew(1, dev.SMA + SMA_wCurrPlayFormat);
- writew(dev.sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
- writew(dev.channels, dev.SMA + SMA_wCurrPlayChannels);
- writew(dev.sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
-#endif
- writew(dev.sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+ initted = 1;
return 0;
}
@@ -1164,21 +1288,18 @@ __initfunc(static int calibrate_adc(WORD srate))
writew(srate, dev.SMA + SMA_wCalFreqAtoD);
if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
- msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + HZ / 3;
- schedule();
- current->timeout = 0;
+ schedule_timeout(HZ / 3);
printk("successful\n");
return 0;
}
-
printk("failed\n");
return -EIO;
}
-__initfunc(static int upload_dsp_code(void))
+static int upload_dsp_code(void)
{
outb(HPBLKSEL_0, dev.io + HP_BLKS);
@@ -1214,7 +1335,7 @@ __initfunc(static int upload_dsp_code(void))
}
#ifdef MSND_CLASSIC
-__initfunc(static void reset_proteus(void))
+static void reset_proteus(void)
{
outb(HPPRORESET_ON, dev.io + HP_PROR);
mdelay(TIME_PRO_RESET);
@@ -1223,7 +1344,7 @@ __initfunc(static void reset_proteus(void))
}
#endif
-__initfunc(static int initialize(void))
+static int initialize(void)
{
int err, timeout;
@@ -1233,7 +1354,6 @@ __initfunc(static int initialize(void))
reset_proteus();
#endif
-
if ((err = init_sma()) < 0) {
printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
return err;
@@ -1250,36 +1370,52 @@ __initfunc(static int initialize(void))
printk(KERN_INFO LOGNAME ": DSP upload successful\n");
timeout = 200;
-
while (readw(dev.base)) {
mdelay(1);
- if (--timeout < 0)
+ if (!timeout--) {
+ printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n");
return -EIO;
+ }
}
+ mixer_setup();
+
return 0;
}
+static int dsp_full_reset(void)
+{
+ int rv;
+
+ if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10)
+ return 0;
+
+ printk(KERN_INFO LOGNAME ": Resetting DSP\n");
+ set_bit(F_RESETTING, &dev.flags);
+ dsp_halt(NULL); /* Unconditionally halt */
+ if ((rv = initialize()))
+ printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+ force_recsrc(dev.recsrc);
+ dsp_open(NULL);
+ clear_bit(F_RESETTING, &dev.flags);
+
+ return rv;
+}
+
__initfunc(static int attach_multisound(void))
{
int err;
- printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
-
- if ((err = request_irq(dev.irq, intr, SA_SHIRQ, dev.name, &dev)) < 0) {
+ if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) {
printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
return err;
-
}
-
request_region(dev.io, dev.numio, dev.name);
- if ((err = initialize()) < 0) {
- printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+ if ((err = dsp_full_reset()) < 0) {
release_region(dev.io, dev.numio);
free_irq(dev.irq, &dev);
return err;
-
}
if ((err = msnd_register(&dev)) < 0) {
@@ -1307,15 +1443,17 @@ __initfunc(static int attach_multisound(void))
}
printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", dev.dsp_minor, dev.mixer_minor);
- calibrate_adc(dev.sample_rate);
+ disable_irq(dev.irq);
+ calibrate_adc(dev.play_sample_rate);
#ifndef MSND_CLASSIC
printk(KERN_INFO LOGNAME ": Setting initial recording source to Line In\n");
- set_recsrc(SOUND_MASK_LINE);
+ force_recsrc(SOUND_MASK_LINE);
#endif
return 0;
}
+#ifdef MODULE
static void unload_multisound(void)
{
release_region(dev.io, dev.numio);
@@ -1324,6 +1462,7 @@ static void unload_multisound(void)
unregister_sound_dsp(dev.dsp_minor);
msnd_unregister(&dev);
}
+#endif
static void mod_inc_ref(void)
{
@@ -1490,6 +1629,7 @@ MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver");
MODULE_PARM (io, "i");
MODULE_PARM (irq, "i");
MODULE_PARM (mem, "i");
+MODULE_PARM (write_ndelay, "i");
MODULE_PARM (major, "i");
MODULE_PARM (fifosize, "i");
MODULE_PARM (calibrate_signal, "i");
@@ -1508,6 +1648,7 @@ MODULE_PARM (joystick_io, "i");
static int io __initdata = -1;
static int irq __initdata = -1;
static int mem __initdata = -1;
+static int write_ndelay __initdata = -1;
#ifndef MSND_CLASSIC
/* Pinnacle/Fiji non-PnP Config Port */
@@ -1535,6 +1676,8 @@ int init_module(void)
#else /* not a module */
+static int write_ndelay __initdata = -1;
+
#ifdef MSND_CLASSIC
static int io __initdata = CONFIG_MSNDCLAS_IO;
static int irq __initdata = CONFIG_MSNDCLAS_IRQ;
@@ -1558,7 +1701,7 @@ static int mem __initdata = CONFIG_MSNDPIN_MEM;
#endif
static int cfg __initdata = CONFIG_MSNDPIN_CFG;
/* If not a module, we don't need to bother with reset=1 */
-static int reset __initdata;
+static int reset;
/* Extra Peripheral Configuration (Default: Disable) */
#ifndef CONFIG_MSNDPIN_MPU_IO
@@ -1626,10 +1769,8 @@ __initfunc(int 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) {
-
+ if (io == -1 || irq == -1 || mem == -1)
printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
- }
if (io == -1 ||
!(io == 0x290 ||
@@ -1640,7 +1781,6 @@ __initfunc(int msnd_pinnacle_init(void))
io == 0x220 ||
io == 0x210 ||
io == 0x3e0)) {
-
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;
}
@@ -1652,7 +1792,6 @@ __initfunc(int msnd_pinnacle_init(void))
irq == 10 ||
irq == 11 ||
irq == 12)) {
-
printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
return -EINVAL;
}
@@ -1664,7 +1803,6 @@ __initfunc(int msnd_pinnacle_init(void))
mem == 0xd8000 ||
mem == 0xe0000 ||
mem == 0xe8000)) {
-
printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
"0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
return -EINVAL;
@@ -1734,9 +1872,10 @@ __initfunc(int msnd_pinnacle_init(void))
if (fifosize < 16)
fifosize = 16;
- if (fifosize > 768)
- fifosize = 768;
+ if (fifosize > 1024)
+ fifosize = 1024;
+ set_default_audio_parameters();
#ifdef MSND_CLASSIC
dev.type = msndClassic;
#else
@@ -1751,6 +1890,12 @@ __initfunc(int msnd_pinnacle_init(void))
dev.recsrc = 0;
dev.inc_ref = mod_inc_ref;
dev.dec_ref = mod_dec_ref;
+ if (write_ndelay == -1)
+ write_ndelay = CONFIG_MSND_WRITE_NDELAY;
+ if (write_ndelay)
+ clear_bit(F_DISABLE_WRITE_NDELAY, &dev.flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &dev.flags);
#ifndef MSND_CLASSIC
if (digital) {
@@ -1771,34 +1916,28 @@ __initfunc(int msnd_pinnacle_init(void))
printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
-
printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
return err;
}
if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
-
printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
msnd_fifo_free(&dev.DAPF);
return err;
}
if ((err = probe_multisound()) < 0) {
-
printk(KERN_ERR LOGNAME ": Probe failed\n");
msnd_fifo_free(&dev.DAPF);
msnd_fifo_free(&dev.DARF);
return err;
-
}
if ((err = attach_multisound()) < 0) {
-
printk(KERN_ERR LOGNAME ": Attach failed\n");
msnd_fifo_free(&dev.DAPF);
msnd_fifo_free(&dev.DARF);
return err;
-
}
return 0;
@@ -1813,6 +1952,5 @@ void cleanup_module(void)
msnd_fifo_free(&dev.DAPF);
msnd_fifo_free(&dev.DARF);
-
}
#endif
diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h
index 0ae9a1026..2f572af2c 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.8 1998/09/03 06:39:47 andrewtv Exp $
+ * $Id: msnd_pinnacle.h,v 1.10 1998/09/10 04:11:18 andrewtv Exp $
*
********************************************************************/
#ifndef __MSND_PINNACLE_H
diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c
new file mode 100644
index 000000000..d9d95c278
--- /dev/null
+++ b/drivers/sound/opl3sa2.c
@@ -0,0 +1,241 @@
+/*
+ * sound/opl3sa2.c
+ *
+ * A low level driver for Yamaha OPL3-SA[2,3,x] based cards.
+ *
+ * Scott Murray, Jun 14, 1998
+ *
+ */
+
+/* Based on the CS4232 driver:
+ *
+ * Copyright (C) by Hannu Savolainen 1993-1997
+ *
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+
+#ifdef CONFIG_OPL3SA2
+
+int probe_opl3sa2_mpu(struct address_info *hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ return probe_mpu401(hw_config);
+#else
+ return 0;
+#endif
+}
+
+
+void attach_opl3sa2_mpu(struct address_info *hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ attach_mpu401(hw_config);
+#endif
+}
+
+
+void unload_opl3sa2_mpu(struct address_info *hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ unload_mpu401(hw_config);
+#endif
+}
+
+
+int probe_opl3sa2_mss(struct address_info *hw_config)
+{
+ return probe_ms_sound(hw_config);
+}
+
+
+void attach_opl3sa2_mss(struct address_info *hw_config)
+{
+ printk(KERN_INFO "opl3sa2.c: trying to init WSS\n");
+
+ attach_ms_sound(hw_config);
+
+ /* request_region(hw_config->io_base, 4, "Yamaha 7xx WSS Config"); */
+
+ if (hw_config->slots[0] != -1 &&
+ audio_devs[hw_config->slots[0]]->mixer_dev != -1)
+ {
+ AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
+ AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
+ /* GSM! test the following: */
+ AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+ }
+}
+
+
+void unload_opl3sa2_mss(struct address_info *hw_config)
+{
+ int mixer;
+
+ /* Find mixer */
+ mixer = audio_devs[hw_config->slots[0]]->mixer_dev;
+
+ /* Unload MSS audio codec */
+ unload_ms_sound(hw_config);
+
+ sound_unload_audiodev(hw_config->slots[0]);
+
+ /* Unload mixer if there */
+ if(mixer >= 0)
+ {
+ sound_unload_mixerdev(mixer);
+ }
+
+ /* Release MSS config ports */
+ release_region(hw_config->io_base, 4);
+}
+
+
+int probe_opl3sa2(struct address_info *hw_config)
+{
+ /*
+ * Verify that the I/O port range is free.
+ */
+
+ printk(KERN_INFO "opl3sa2.c: Control using I/O port 0x%03x\n", hw_config->io_base);
+
+ if (check_region(hw_config->io_base, 2))
+ {
+ printk(KERN_ERR "opl3sa2.c: Control I/O port 0x%03x not free\n", hw_config->io_base);
+ return 0;
+ }
+
+ /* GSM!: Add some kind of other test here... */
+
+ return 1;
+}
+
+
+void attach_opl3sa2(struct address_info *hw_config)
+{
+ printk(KERN_INFO "opl3sa2.c: trying to init!\n");
+
+ request_region(hw_config->io_base, 2, "Yamaha 7xx Control");
+
+ /* GSM! Mixer stuff should go here... */
+}
+
+
+void unload_opl3sa2(struct address_info *hw_config)
+{
+ /* Release control ports */
+ release_region(hw_config->io_base, 2);
+
+ /* GSM! Mixer stuff should go here... */
+}
+
+
+#ifdef MODULE
+
+int io = -1;
+int mss_io = -1;
+int mpu_io = -1;
+int irq = -1;
+int dma = -1;
+int dma2 = -1;
+
+MODULE_PARM(io,"i");
+MODULE_PARM(mss_io,"i");
+MODULE_PARM(mpu_io,"i");
+MODULE_PARM(irq,"i");
+MODULE_PARM(dma,"i");
+MODULE_PARM(dma2,"i");
+
+EXPORT_NO_SYMBOLS;
+
+struct address_info cfg;
+struct address_info mss_cfg;
+struct address_info mpu_cfg;
+
+/*
+ * Install a OPL3SA2 based card. Need to have ad1848 and mpu401
+ * loaded ready.
+ */
+int init_module(void)
+{
+ int i;
+
+ if (io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1)
+ {
+ printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set.\n");
+ return -EINVAL;
+ }
+
+ /* Our own config: */
+ cfg.io_base = io;
+ cfg.irq = irq;
+ cfg.dma = dma;
+ cfg.dma2 = dma2;
+
+ /* The MSS config: */
+ mss_cfg.io_base = mss_io;
+ mss_cfg.irq = irq;
+ mss_cfg.dma = dma;
+ mss_cfg.dma2 = dma2;
+ mss_cfg.card_subtype = 1; /* No IRQ or DMA setup */
+
+ /* Call me paranoid: */
+ for(i = 0; i < 6; i++)
+ {
+ cfg.slots[i] = mss_cfg.slots[i] = mpu_cfg.slots[i] = -1;
+ }
+
+ if (probe_opl3sa2(&cfg) == 0)
+ {
+ return -ENODEV;
+ }
+ attach_opl3sa2(&cfg);
+
+ if (probe_opl3sa2_mss(&mss_cfg) == 0)
+ {
+ return -ENODEV;
+ }
+ attach_opl3sa2_mss(&mss_cfg);
+
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if(mpu_io != -1)
+ {
+ /* MPU config: */
+ mpu_cfg.io_base = mpu_io;
+ mpu_cfg.irq = irq;
+ mpu_cfg.dma = dma;
+ mpu_cfg.always_detect = 1; /* It's there, so use shared IRQs */
+
+ if (probe_opl3sa2_mpu(&mpu_cfg))
+ {
+ attach_opl3sa2_mpu(&mpu_cfg);
+ }
+ }
+#endif
+ SOUND_LOCK;
+ return 0;
+}
+
+
+void cleanup_module(void)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if(mpu_cfg.slots[1] != -1)
+ {
+ unload_opl3sa2_mpu(&mpu_cfg);
+ }
+#endif
+ unload_opl3sa2_mss(&mss_cfg);
+ unload_opl3sa2(&cfg);
+ SOUND_LOCK_END;
+}
+
+#endif
+#endif
diff --git a/drivers/sound/os.h b/drivers/sound/os.h
index 794036b81..2b2be83d5 100644
--- a/drivers/sound/os.h
+++ b/drivers/sound/os.h
@@ -48,7 +48,6 @@ extern void sound_close_dma(int chn);
extern void reprogram_timer(void);
-#define RUNTIME_DMA_ALLOC
#define USE_AUTOINIT_DMA
extern caddr_t sound_mem_blocks[1024];
diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c
index fd6e0b6f5..701be5289 100644
--- a/drivers/sound/pss.c
+++ b/drivers/sound/pss.c
@@ -796,7 +796,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l
data = (unsigned short *)mbuf->data;
save_flags(flags);
cli();
- for (i = 0; i < mbuf->len; i++) {
+ for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) {
mbuf->len = i; /* feed back number of WORDs read */
if (!pss_get_dspword(devc, data++)) {
if (i == 0)
diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h
index 19f8ee825..dc864646e 100644
--- a/drivers/sound/sb.h
+++ b/drivers/sound/sb.h
@@ -87,15 +87,20 @@ typedef struct sb_devc {
/* State variables */
int opened;
+ /* new audio fields for full duplex support */
+ int fullduplex;
+ int duplex;
int speed, bits, channels;
volatile int irq_ok;
volatile int intr_active, irq_mode;
+ /* duplicate audio fields for full duplex support */
+ volatile int intr_active_16, irq_mode_16;
/* Mixer fields */
int *levels;
mixer_tab *iomap;
- int mixer_caps, recmask, supported_devices;
- int supported_rec_devices;
+ int mixer_caps, recmask, outmask, supported_devices;
+ int supported_rec_devices, supported_out_devices;
int my_mixerdev;
int sbmixnum;
@@ -105,6 +110,13 @@ typedef struct sb_devc {
int trg_bytes;
int trg_intrflag;
int trg_restart;
+ /* duplicate audio fields for full duplex support */
+ unsigned long trg_buf_16;
+ int trigger_bits_16;
+ int trg_bytes_16;
+ int trg_intrflag_16;
+ int trg_restart_16;
+
unsigned char tconst;
int my_dev;
@@ -122,7 +134,7 @@ void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value);
unsigned int sb_getmixer (sb_devc *devc, unsigned int port);
int sb_dsp_detect (struct address_info *hw_config);
int sb_dsp_init (struct address_info *hw_config);
-void sb_dsp_unload(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_set_stereo (sb_devc *devc, int mode);
void smw_mixer_init(sb_devc *devc);
diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c
index 971a7414f..b14924e4e 100644
--- a/drivers/sound/sb_audio.c
+++ b/drivers/sound/sb_audio.c
@@ -15,6 +15,10 @@
*
* Status
* Mostly working. Weird uart bug causing irq storms
+ *
+ * Daniel J. Rodriksson: Changes to make sb16 work full duplex.
+ * Maybe other 16 bit cards in this code could behave
+ * the same.
*/
#include <linux/config.h>
@@ -47,7 +51,7 @@ static int sb_audio_open(int dev, int mode)
restore_flags(flags);
return -EBUSY;
}
- if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
+ if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
{
if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
{
@@ -59,6 +63,9 @@ static int sb_audio_open(int dev, int mode)
restore_flags(flags);
devc->irq_mode = IMODE_NONE;
+ devc->irq_mode_16 = IMODE_NONE;
+ devc->fullduplex = devc->duplex &&
+ ((mode & OPEN_READ) && (mode & OPEN_WRITE));
sb_dsp_reset(devc);
/* The ALS007 seems to require that the DSP be removed from the output */
@@ -84,9 +91,11 @@ static void sb_audio_close(int dev)
{
sb_devc *devc = audio_devs[dev]->devc;
- audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma = devc->dma8;
+ audio_devs[dev]->dmap_out->dma = devc->dma8;
+ audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ?
+ devc->dma16 : devc->dma8;
- if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
+ if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
sound_close_dma(devc->dma16);
/* For ALS007, turn DSP output back on if closing the device for read */
@@ -104,20 +113,40 @@ static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes,
{
sb_devc *devc = audio_devs[dev]->devc;
- devc->trg_buf = buf;
- devc->trg_bytes = nr_bytes;
- devc->trg_intrflag = intrflag;
- devc->irq_mode = IMODE_OUTPUT;
+ if (!devc->fullduplex || devc->bits == AFMT_S16_LE)
+ {
+ devc->trg_buf = buf;
+ devc->trg_bytes = nr_bytes;
+ devc->trg_intrflag = intrflag;
+ devc->irq_mode = IMODE_OUTPUT;
+ }
+ else
+ {
+ devc->trg_buf_16 = buf;
+ devc->trg_bytes_16 = nr_bytes;
+ devc->trg_intrflag_16 = intrflag;
+ devc->irq_mode_16 = IMODE_OUTPUT;
+ }
}
static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag)
{
sb_devc *devc = audio_devs[dev]->devc;
- devc->trg_buf = buf;
- devc->trg_bytes = count;
- devc->trg_intrflag = intrflag;
- devc->irq_mode = IMODE_INPUT;
+ if (!devc->fullduplex || devc->bits != AFMT_S16_LE)
+ {
+ devc->trg_buf = buf;
+ devc->trg_bytes = count;
+ devc->trg_intrflag = intrflag;
+ devc->irq_mode = IMODE_INPUT;
+ }
+ else
+ {
+ devc->trg_buf_16 = buf;
+ devc->trg_bytes_16 = count;
+ devc->trg_intrflag_16 = intrflag;
+ devc->irq_mode_16 = IMODE_INPUT;
+ }
}
/*
@@ -830,9 +859,23 @@ static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount)
{
sb_devc *devc = audio_devs[dev]->devc;
- audio_devs[dev]->dmap_out->dma =
- audio_devs[dev]->dmap_in->dma =
- devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+ if (!devc->fullduplex)
+ {
+ audio_devs[dev]->dmap_out->dma =
+ audio_devs[dev]->dmap_in->dma =
+ devc->bits == AFMT_S16_LE ?
+ devc->dma16 : devc->dma8;
+ }
+ else if (devc->bits == AFMT_S16_LE)
+ {
+ audio_devs[dev]->dmap_out->dma = devc->dma8;
+ audio_devs[dev]->dmap_in->dma = devc->dma16;
+ }
+ else
+ {
+ audio_devs[dev]->dmap_out->dma = devc->dma16;
+ audio_devs[dev]->dmap_in->dma = devc->dma8;
+ }
devc->trigger_bits = 0;
return 0;
@@ -842,8 +885,23 @@ static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount)
{
sb_devc *devc = audio_devs[dev]->devc;
- audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma =
- devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+ if (!devc->fullduplex)
+ {
+ audio_devs[dev]->dmap_out->dma =
+ audio_devs[dev]->dmap_in->dma =
+ devc->bits == AFMT_S16_LE ?
+ devc->dma16 : devc->dma8;
+ }
+ else if (devc->bits == AFMT_S16_LE)
+ {
+ audio_devs[dev]->dmap_out->dma = devc->dma8;
+ audio_devs[dev]->dmap_in->dma = devc->dma16;
+ }
+ else
+ {
+ audio_devs[dev]->dmap_out->dma = devc->dma16;
+ audio_devs[dev]->dmap_in->dma = devc->dma8;
+ }
devc->trigger_bits = 0;
return 0;
@@ -854,9 +912,27 @@ static void sb16_audio_output_block(int dev, unsigned long buf, int count,
{
unsigned long flags, cnt;
sb_devc *devc = audio_devs[dev]->devc;
+ unsigned long bits;
- devc->irq_mode = IMODE_OUTPUT;
- devc->intr_active = 1;
+ if (!devc->fullduplex || devc->bits == AFMT_S16_LE)
+ {
+ devc->irq_mode = IMODE_OUTPUT;
+ devc->intr_active = 1;
+ }
+ else
+ {
+ devc->irq_mode_16 = IMODE_OUTPUT;
+ devc->intr_active_16 = 1;
+ }
+
+ /* save value */
+ save_flags (flags);
+ cli ();
+ bits = devc->bits;
+ if (devc->fullduplex)
+ devc->bits = (devc->bits == AFMT_S16_LE) ?
+ AFMT_U8 : AFMT_S16_LE;
+ restore_flags (flags);
cnt = count;
if (devc->bits == AFMT_S16_LE)
@@ -878,6 +954,8 @@ static void sb16_audio_output_block(int dev, unsigned long buf, int count,
sb_dsp_command(devc, (unsigned char) (cnt & 0xff));
sb_dsp_command(devc, (unsigned char) (cnt >> 8));
+ /* restore real value after all programming */
+ devc->bits = bits;
restore_flags(flags);
}
@@ -886,8 +964,16 @@ static void sb16_audio_start_input(int dev, unsigned long buf, int count, int in
unsigned long flags, cnt;
sb_devc *devc = audio_devs[dev]->devc;
- devc->irq_mode = IMODE_INPUT;
- devc->intr_active = 1;
+ if (!devc->fullduplex || devc->bits != AFMT_S16_LE)
+ {
+ devc->irq_mode = IMODE_INPUT;
+ devc->intr_active = 1;
+ }
+ else
+ {
+ devc->irq_mode_16 = IMODE_INPUT;
+ devc->intr_active_16 = 1;
+ }
cnt = count;
if (devc->bits == AFMT_S16_LE)
@@ -916,29 +1002,141 @@ static void sb16_audio_trigger(int dev, int bits)
{
sb_devc *devc = audio_devs[dev]->devc;
+ int bits_16 = bits & devc->irq_mode_16;
bits &= devc->irq_mode;
- if (!bits)
+ if (!bits && !bits_16)
sb_dsp_command(devc, 0xd0); /* Halt DMA */
else
{
- switch (devc->irq_mode)
+ if (bits)
{
- case IMODE_INPUT:
- sb16_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
- devc->trg_intrflag);
- break;
-
- case IMODE_OUTPUT:
- sb16_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
- devc->trg_intrflag);
- break;
+ switch (devc->irq_mode)
+ {
+ case IMODE_INPUT:
+ sb16_audio_start_input(dev,
+ devc->trg_buf,
+ devc->trg_bytes,
+ devc->trg_intrflag);
+ break;
+
+ case IMODE_OUTPUT:
+ sb16_audio_output_block(dev,
+ devc->trg_buf,
+ devc->trg_bytes,
+ devc->trg_intrflag);
+ break;
+ }
+ }
+ if (bits_16)
+ {
+ switch (devc->irq_mode_16)
+ {
+ case IMODE_INPUT:
+ sb16_audio_start_input(dev,
+ devc->trg_buf_16,
+ devc->trg_bytes_16,
+ devc->trg_intrflag_16);
+ break;
+
+ case IMODE_OUTPUT:
+ sb16_audio_output_block(dev,
+ devc->trg_buf_16,
+ devc->trg_bytes_16,
+ devc->trg_intrflag_16);
+ break;
+ }
}
}
- devc->trigger_bits = bits;
+ devc->trigger_bits = bits | bits_16;
}
+static unsigned char lbuf8[2048];
+static signed short *lbuf16 = (signed short *)lbuf8;
+#define LBUFCOPYSIZE 1024
+static void
+sb16_copy_from_user(int dev,
+ char *localbuf, int localoffs,
+ const char *userbuf, int useroffs,
+ int max_in, int max_out,
+ int *used, int *returned,
+ int len)
+{
+ sb_devc *devc = audio_devs[dev]->devc;
+ int i, c, p, locallen;
+ unsigned char *buf8;
+ signed short *buf16;
+
+ /* if not duplex no conversion */
+ if (!devc->fullduplex)
+ {
+ copy_from_user (localbuf + localoffs, userbuf + useroffs, len);
+ *used = len;
+ *returned = len;
+ }
+ else if (devc->bits == AFMT_S16_LE)
+ {
+ /* 16 -> 8 */
+ /* max_in >> 1, max number of samples in ( 16 bits ) */
+ /* max_out, max number of samples out ( 8 bits ) */
+ /* len, number of samples that will be taken ( 16 bits )*/
+ /* c, count of samples remaining in buffer ( 16 bits )*/
+ /* p, count of samples already processed ( 16 bits )*/
+ len = ( (max_in >> 1) > max_out) ? max_out : (max_in >> 1);
+ c = len;
+ p = 0;
+ buf8 = (unsigned char *)(localbuf + localoffs);
+ while (c)
+ {
+ locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c);
+ /* << 1 in order to get 16 bit samples */
+ copy_from_user (lbuf16,
+ userbuf+useroffs + (p << 1),
+ locallen << 1);
+ for (i = 0; i < locallen; i++)
+ {
+ buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80;
+ }
+ c -= locallen; p += locallen;
+ }
+ /* used = ( samples * 16 bits size ) */
+ *used = len << 1;
+ /* returned = ( samples * 8 bits size ) */
+ *returned = len;
+ }
+ else
+ {
+ /* 8 -> 16 */
+ /* max_in, max number of samples in ( 8 bits ) */
+ /* max_out >> 1, max number of samples out ( 16 bits ) */
+ /* len, number of samples that will be taken ( 8 bits )*/
+ /* c, count of samples remaining in buffer ( 8 bits )*/
+ /* p, count of samples already processed ( 8 bits )*/
+ len = max_in > (max_out >> 1) ? (max_out >> 1) : max_in;
+ c = len;
+ p = 0;
+ buf16 = (signed short *)(localbuf + localoffs);
+ while (c)
+ {
+ locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c);
+ copy_from_user (lbuf8,
+ userbuf+useroffs + p,
+ locallen);
+ for (i = 0; i < locallen; i++)
+ {
+ buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8;
+ }
+ c -= locallen; p += locallen;
+ }
+ /* used = ( samples * 8 bits size ) */
+ *used = len;
+ /* returned = ( samples * 16 bits size ) */
+ *returned = len << 1;
+ }
+}
+
+
static struct audio_driver sb1_audio_driver = /* SB1.x */
{
sb_audio_open,
@@ -1050,7 +1248,7 @@ static struct audio_driver sb16_audio_driver = /* SB16 */
sb16_audio_prepare_for_output,
sb1_audio_halt_xfer,
NULL, /* local_qlen */
- NULL, /* copy_from_user */
+ sb16_copy_from_user, /* copy_from_user */
NULL,
NULL,
sb16_audio_trigger,
@@ -1124,6 +1322,11 @@ void sb_audio_init(sb_devc * devc, char *name)
DDB(printk("Will use SB16 driver\n"));
audio_flags = DMA_AUTOMODE;
format_mask |= AFMT_S16_LE;
+ if (devc->dma8 != devc->dma16 && devc->dma16 != -1)
+ {
+ audio_flags |= DMA_DUPLEX;
+ devc->duplex = 1;
+ }
driver = &sb16_audio_driver;
break;
@@ -1136,7 +1339,8 @@ void sb_audio_init(sb_devc * devc, char *name)
if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
name,driver, sizeof(struct audio_driver),
audio_flags, format_mask, devc,
- devc->dma8, devc->dma8)) < 0)
+ devc->dma8,
+ devc->duplex ? devc->dma16 : devc->dma8) < 0))
{
printk(KERN_ERR "Sound Blaster: unable to install audio.\n");
return;
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index 2fc88cb24..24a3aa829 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -12,6 +12,9 @@
*/
#include <linux/config.h>
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
#include <linux/module.h>
#include "sound_config.h"
@@ -22,6 +25,8 @@
#include "sb_mixer.h"
#include "sb.h"
+static int sbmpu = 0;
+
void attach_sb_card(struct address_info *hw_config)
{
#if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI)
@@ -32,6 +37,67 @@ void attach_sb_card(struct address_info *hw_config)
int probe_sb(struct address_info *hw_config)
{
+#ifdef CONFIG_MCA
+ /* MCA code added by ZP Gu (zpg@castle.net) */
+ if (MCA_bus) { /* no multiple REPLY card probing */
+ int slot;
+ u8 pos2, pos3, pos4;
+
+ slot = mca_find_adapter( 0x5138, 0 );
+ if( slot == MCA_NOTFOUND )
+ {
+ slot = mca_find_adapter( 0x5137, 0 );
+
+ if (slot != MCA_NOTFOUND)
+ mca_set_adapter_name( slot, "REPLY SB16 & SCSI Adapter" );
+ }
+ else
+ {
+ mca_set_adapter_name( slot, "REPLY SB16 Adapter" );
+ }
+
+ if (slot != MCA_NOTFOUND)
+ {
+ mca_mark_as_used(slot);
+ pos2 = mca_read_stored_pos( slot, 2 );
+ pos3 = mca_read_stored_pos( slot, 3 );
+ pos4 = mca_read_stored_pos( slot, 4 );
+
+ if (pos2 & 0x4)
+ {
+ /* enabled? */
+ static unsigned short irq[] = { 0, 5, 7, 10 };
+ /*
+ static unsigned short midiaddr[] = {0, 0x330, 0, 0x300 };
+ */
+
+ hw_config->io_base = 0x220 + 0x20 * (pos2 >> 6);
+ hw_config->irq = irq[(pos4 >> 5) & 0x3];
+ hw_config->dma = pos3 & 0xf;
+ /* Reply ADF wrong on High DMA, pos[1] should start w/ 00 */
+ hw_config->dma2 = (pos3 >> 4) & 0x3;
+ if (hw_config->dma2 == 0)
+ hw_config->dma2 = hw_config->dma;
+ else
+ hw_config->dma2 += 4;
+ /*
+ hw_config->driver_use_2 = midiaddr[(pos2 >> 3) & 0x3];
+ */
+
+ printk("SB: Reply MCA SB at slot=%d \
+iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n",
+ slot+1,
+ hw_config->io_base, hw_config->irq,
+ hw_config->dma, hw_config->dma2);
+ }
+ else
+ {
+ printk ("Reply SB Base I/O address disabled\n");
+ }
+ }
+ }
+#endif
+
if (check_region(hw_config->io_base, 16))
{
printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base);
@@ -43,7 +109,7 @@ int probe_sb(struct address_info *hw_config)
void unload_sb(struct address_info *hw_config)
{
if(hw_config->slots[0]!=-1)
- sb_dsp_unload(hw_config);
+ sb_dsp_unload(hw_config, sbmpu);
}
int sb_be_quiet=0;
@@ -82,8 +148,6 @@ MODULE_PARM(trix, "i");
MODULE_PARM(pas2, "i");
MODULE_PARM(sm_games, "i");
-static int sbmpu = 0;
-
void *smw_free = NULL;
int init_module(void)
@@ -113,8 +177,6 @@ int init_module(void)
config_mpu.io_base = mpu_io;
if (mpu_io && probe_sbmpu(&config_mpu))
sbmpu = 1;
-#endif
-#ifdef CONFIG_MIDI
if (sbmpu)
attach_sbmpu(&config_mpu);
#endif
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 04b3d7854..34f82ff70 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -10,7 +10,10 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
-
+/*
+ * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
+ * for full duplex support ( only sb16 by now )
+ */
#include <linux/config.h>
#include <linux/delay.h>
#include <asm/init.h>
@@ -140,7 +143,7 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy)
if (!(src & 3))
return; /* Not a DSP interrupt */
}
- if (devc->intr_active)
+ if (devc->intr_active && (!devc->fullduplex || (src & 0x01)))
{
switch (devc->irq_mode)
{
@@ -166,6 +169,26 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy)
;
}
}
+ else if (devc->intr_active_16 && (src & 0x02))
+ {
+ switch (devc->irq_mode_16)
+ {
+ case IMODE_OUTPUT:
+ DMAbuf_outputintr(devc->dev, 1);
+ break;
+
+ case IMODE_INPUT:
+ DMAbuf_inputintr(devc->dev);
+ break;
+
+ case IMODE_INIT:
+ break;
+
+ default:
+ /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */
+ ;
+ }
+ }
/*
* Acknowledge interrupts
*/
@@ -592,6 +615,7 @@ int sb_dsp_detect(struct address_info *hw_config)
sb_devc sb_info;
sb_devc *devc = &sb_info;
+ memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */
sb_info.my_mididev = -1;
sb_info.my_mixerdev = -1;
sb_info.my_dev = -1;
@@ -608,7 +632,6 @@ int sb_dsp_detect(struct address_info *hw_config)
#endif
return 0;
}
- memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */
devc->type = hw_config->card_subtype;
@@ -855,6 +878,7 @@ int sb_dsp_init(struct address_info *hw_config)
if(!sb16_set_dma_hw(devc)) {
free_irq(devc->irq, devc);
+ release_region(hw_config->io_base, 16);
return 0;
}
@@ -932,7 +956,10 @@ void sb_dsp_disable_recording(int io_base)
{
}
-void sb_dsp_unload(struct address_info *hw_config)
+/* if (sbmpu) below we allow mpu401 to manage the midi devs
+ otherwise we have to unload them. (Andrzej Krzysztofowicz) */
+
+void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
{
sb_devc *devc;
@@ -954,7 +981,9 @@ void sb_dsp_unload(struct address_info *hw_config)
sound_unload_mixerdev(devc->my_mixerdev);
/* We don't have to do this bit any more the UART401 is its own
master -- Krzysztof Halasa */
- /* sound_unload_mididev(devc->my_mididev); */
+ /* But we have to do it, if UART401 is not detected */
+ if (!sbmpu)
+ sound_unload_mididev(devc->my_mididev);
sound_unload_audiodev(devc->my_dev);
}
kfree(devc);
@@ -1301,10 +1330,8 @@ int probe_sbmpu(struct address_info *hw_config)
}
hw_config->name = "Sound Blaster 16";
hw_config->irq = -devc->irq;
-#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
if (devc->minor > 12) /* What is Vibra's version??? */
sb16_set_mpu_port(devc, hw_config);
-#endif
break;
case MDL_ESS:
diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c
index 970ec4a0b..31a299a96 100644
--- a/drivers/sound/sb_midi.c
+++ b/drivers/sound/sb_midi.c
@@ -182,8 +182,6 @@ void sb_dsp_midi_init(sb_devc * devc)
printk(KERN_ERR "sb_midi: too many MIDI devices detected\n");
return;
}
- std_midi_synth.midi_dev = dev;
- devc->my_mididev = dev;
std_midi_synth.midi_dev = devc->my_mididev = dev;
midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
if (midi_devs[dev] == NULL)
diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c
index 7c4af3d03..aaab4907d 100644
--- a/drivers/sound/sb_mixer.c
+++ b/drivers/sound/sb_mixer.c
@@ -294,6 +294,39 @@ static int set_recmask(sb_devc * devc, int mask)
return devc->recmask;
}
+static int set_outmask(sb_devc * devc, int mask)
+{
+ int devmask, i;
+ unsigned char regimage;
+
+ devmask = mask & devc->supported_out_devices;
+
+ switch (devc->model)
+ {
+ case MDL_SB16:
+ if (devc->submodel == SUBMDL_ALS007)
+ break;
+ else
+ {
+ regimage = 0;
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ {
+ if ((1 << i) & devmask)
+ {
+ regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]);
+ }
+ sb_setmixer (devc, SB16_OMASK, regimage);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ devc->outmask = devmask;
+ return devc->outmask;
+}
+
static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
{
sb_devc *devc = mixer_devs[dev]->devc;
@@ -321,6 +354,10 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
ret = set_recmask(devc, val);
break;
+ case SOUND_MIXER_OUTSRC:
+ ret = set_outmask(devc, val);
+ break;
+
default:
ret = sb_mixer_set(devc, cmd & 0xff, val);
}
@@ -331,13 +368,20 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
ret = devc->recmask;
break;
+ case SOUND_MIXER_OUTSRC:
+ ret = devc->outmask;
+ break;
+
case SOUND_MIXER_DEVMASK:
ret = devc->supported_devices;
break;
case SOUND_MIXER_STEREODEVS:
ret = devc->supported_devices;
- if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
+ /* The ESS seems to have stereo mic controls */
+ if (devc->model == MDL_ESS)
+ ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX);
+ else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
break;
@@ -345,6 +389,10 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
ret = devc->supported_rec_devices;
break;
+ case SOUND_MIXER_OUTMASK:
+ ret = devc->supported_out_devices;
+ break;
+
case SOUND_MIXER_CAPS:
ret = devc->mixer_caps;
break;
@@ -432,6 +480,7 @@ int sb_mixer_init(sb_devc * devc)
case MDL_SB16:
devc->mixer_caps = 0;
devc->supported_rec_devices = SB16_RECORDING_DEVICES;
+ devc->supported_out_devices = SB16_OUTFILTER_DEVICES;
if (devc->submodel != SUBMDL_ALS007)
{
devc->supported_devices = SB16_MIXER_DEVICES;
diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h
index 714b8a4d8..7f61e6e0c 100644
--- a/drivers/sound/sb_mixer.h
+++ b/drivers/sound/sb_mixer.h
@@ -41,6 +41,9 @@
#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD)
+#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD)
+
#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER)
@@ -99,6 +102,7 @@
/*
* Mixer registers of SB16
*/
+#define SB16_OMASK 0x3c
#define SB16_IMASK_L 0x3d
#define SB16_IMASK_R 0x3e
@@ -197,7 +201,7 @@ MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4),
MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4),
MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC, 0x6a, 6, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4),
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c
index 514333512..b5cb59cdf 100644
--- a/drivers/sound/sequencer.c
+++ b/drivers/sound/sequencer.c
@@ -113,9 +113,9 @@ int sequencer_read(int dev, struct file *file, char *buf, int count)
restore_flags(flags);
return -EAGAIN;
}
- current->timeout = pre_event_timeout ? jiffies + pre_event_timeout : 0;
- interruptible_sleep_on(&midi_sleeper);
- current->timeout = 0;
+
+ interruptible_sleep_on_timeout(&midi_sleeper,
+ pre_event_timeout);
if (!iqlen)
{
restore_flags(flags);
@@ -355,7 +355,6 @@ static int seq_queue(unsigned char *note, char nonblock)
/*
* Sleep until there is enough space on the queue
*/
- current->timeout = 0;
interruptible_sleep_on(&seq_sleeper);
}
if (qlen >= SEQ_MAX_QUEUE)
@@ -1026,7 +1025,7 @@ int sequencer_open(int dev, struct file *file)
max_mididev = num_midis;
max_synthdev = num_synths;
- pre_event_timeout = 0;
+ pre_event_timeout = MAX_SCHEDULE_TIMEOUT;
seq_mode = SEQ_1;
if (pending_timer != -1)
@@ -1153,11 +1152,9 @@ void seq_drain_midi_queues(void)
* Let's have a delay
*/
- if (n) {
- current->timeout = jiffies + HZ / 10;
- interruptible_sleep_on(&seq_sleeper);
- current->timeout = 0;
- }
+ if (n)
+ interruptible_sleep_on_timeout(&seq_sleeper,
+ HZ/10);
}
}
@@ -1179,9 +1176,8 @@ void sequencer_release(int dev, struct file *file)
while (!signal_pending(current) && qlen > 0)
{
seq_sync();
- current->timeout = jiffies + 3 * HZ;
- interruptible_sleep_on(&seq_sleeper);
- current->timeout = 0;
+ interruptible_sleep_on_timeout(&seq_sleeper,
+ 3*HZ);
/* Extra delay */
}
}
@@ -1233,11 +1229,8 @@ static int seq_sync(void)
save_flags(flags);
cli();
- if (qlen > 0) {
- current->timeout = jiffies + HZ;
- interruptible_sleep_on(&seq_sleeper);
- current->timeout = 0;
- }
+ if (qlen > 0)
+ interruptible_sleep_on_timeout(&seq_sleeper, HZ);
restore_flags(flags);
return qlen;
}
@@ -1262,9 +1255,7 @@ static void midi_outc(int dev, unsigned char data)
save_flags(flags);
cli();
while (n && !midi_devs[dev]->outputc(dev, data)) {
- current->timeout = jiffies + 4;
- interruptible_sleep_on(&seq_sleeper);
- current->timeout = 0;
+ interruptible_sleep_on_timeout(&seq_sleeper, HZ/25);
n--;
}
restore_flags(flags);
@@ -1540,12 +1531,12 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg)
return 0;
case SNDCTL_MIDI_INFO:
- if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device))))
+ if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device))))
return -EFAULT;
if (dev < 0 || dev >= max_mididev)
return -ENXIO;
midi_devs[dev]->info.device = dev;
- return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct synth_info))?-EFAULT:0;
+ return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0;
case SNDCTL_SEQ_THRESHOLD:
if (get_user(val, (int *)arg))
diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c
index 4e5cb870e..baff3e5cc 100644
--- a/drivers/sound/sgalaxy.c
+++ b/drivers/sound/sgalaxy.c
@@ -29,9 +29,7 @@
static void sleep( unsigned howlong )
{
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + howlong;
- schedule();
- current->timeout = 0;
+ schedule_timeout(howlong);
}
#define DPORT 0x80
@@ -93,7 +91,7 @@ int probe_sgalaxy( struct address_info *ai )
}
if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) )
- return 1; /* The card is already active */
+ return probe_ms_sound(ai); /* The card is already active, check irq etc... */
if ( check_region( ai->ai_sgbase, 0x10 ) )
{
@@ -110,9 +108,7 @@ int probe_sgalaxy( struct address_info *ai )
sleep( HZ/10 );
- if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) )
- return 1;
- return 0;
+ return probe_ms_sound(ai);
}
void attach_sgalaxy( struct address_info *ai )
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c
index 82d0461a4..b57cd186a 100644
--- a/drivers/sound/sonicvibes.c
+++ b/drivers/sound/sonicvibes.c
@@ -1245,11 +1245,8 @@ static int drain_dac(struct sv_state *s, int nonblock)
}
tmo = (count * HZ) / s->ratedac;
tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
- current->timeout = jiffies + (tmo ? tmo : 1);
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "sv: dma timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
@@ -2025,11 +2022,8 @@ static int sv_midi_release(struct inode *inode, struct file *file)
return -EBUSY;
}
tmo = (count * HZ) / 3100;
- current->timeout = tmo ? jiffies + tmo : 0;
- schedule();
- if (tmo && !current->timeout)
+ if (!schedule_timeout(tmo ? : 1) && tmo)
printk(KERN_DEBUG "sv: midi timed out??\n");
- current->timeout = 0;
}
remove_wait_queue(&s->midi.owait, &wait);
current->state = TASK_RUNNING;
diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h
index a5d2272b4..8c91cb72d 100644
--- a/drivers/sound/sound_calls.h
+++ b/drivers/sound/sound_calls.h
@@ -251,6 +251,8 @@ void unload_trix_sb(struct address_info *hw_info);
void unload_trix_mpu(struct address_info *hw_info);
void unload_cs4232(struct address_info *hw_info);
void unload_cs4232_mpu(struct address_info *hw_info);
+void unload_opl3sa2(struct address_info *hw_info);
+void unload_opl3sa2_mpu(struct address_info *hw_info);
/* From cs4232.c */
@@ -259,6 +261,12 @@ void attach_cs4232 (struct address_info *hw_config);
int probe_cs4232_mpu (struct address_info *hw_config);
void attach_cs4232_mpu (struct address_info *hw_config);
+/* From opl3sa2.c */
+int probe_opl3sa2 (struct address_info *hw_config);
+void attach_opl3sa2 (struct address_info *hw_config);
+int probe_opl3sa2_mpu (struct address_info *hw_config);
+void attach_opl3sa2_mpu (struct address_info *hw_config);
+
/* From maui.c */
void attach_maui(struct address_info * hw_config);
int probe_maui(struct address_info *hw_config);
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index 1fbb368d8..b830afdd2 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -15,6 +15,8 @@
* integrated sound_switch.c
* Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat,
* which should disappear in the near future)
+ *
+ * Rob Riggs Added persistent DMA buffers support (1998/10/17)
*/
#include <linux/config.h>
@@ -64,6 +66,9 @@ static int is_unloading = 0;
caddr_t sound_mem_blocks[1024];
int sound_nblocks = 0;
+/* Persistent DMA buffers */
+int sound_dmap_flag = 0; /* Off by default */
+
static int soundcard_configured = 0;
static char dma_alloc_map[MAX_DMA_CHANNELS] =
@@ -287,11 +292,13 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
return len;
}
+#ifdef CONFIG_PROC_FS
static struct proc_dir_entry proc_root_sound = {
PROC_SOUND, 5, "sound",
S_IFREG | S_IRUGO, 1, 0, 0,
0, NULL, sound_proc_get_info
};
+#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -837,8 +844,10 @@ soundcard_init(void)
audio_init_devices();
}
#endif
+#ifdef CONFIG_PROC_FS
if (proc_register(&proc_root, &proc_root_sound))
printk(KERN_ERR "sound: registering /proc/sound failed\n");
+#endif
}
static int sound[20] = {
@@ -848,7 +857,9 @@ static int sound[20] = {
#ifdef MODULE
int traceinit = 0;
+static int dmabuf = 0;
MODULE_PARM(traceinit, "i");
+MODULE_PARM(dmabuf, "i");
int init_module(void)
{
@@ -874,6 +885,10 @@ int init_module(void)
printk(KERN_ERR "sound: driver already loaded/included in kernel\n");
return err;
}
+
+ /* Protecting the innocent */
+ sound_dmap_flag = (dmabuf > 0 ? 1 : 0);
+
chrdev_registered = 1;
soundcard_init();
diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c
index 1b823692c..48017eeed 100644
--- a/drivers/sound/sscape.c
+++ b/drivers/sound/sscape.c
@@ -124,10 +124,8 @@ static char old_hardware = 0;
static void sleep(unsigned howlong)
{
- current->timeout = jiffies + 1;
current->state = TASK_INTERRUPTIBLE;
- schedule();
- current->timeout = 0;
+ schedule_timeout(1);
}
static unsigned char sscape_read(struct sscape_info *devc, int reg)
diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c
index 1ed1b8d78..97113a838 100644
--- a/drivers/sound/trix.c
+++ b/drivers/sound/trix.c
@@ -39,6 +39,8 @@ static int mpu_initialized = 0;
static int *trix_osp = NULL;
+static int mpu = 0;
+
static unsigned char trix_read(int addr)
{
outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */
@@ -445,7 +447,7 @@ void unload_trix_mpu(struct address_info *hw_config)
void unload_trix_sb(struct address_info *hw_config)
{
#ifdef CONFIG_SBDSP
- sb_dsp_unload(hw_config);
+ sb_dsp_unload(hw_config, mpu);
#endif
}
@@ -479,7 +481,6 @@ struct address_info config;
struct address_info sb_config;
struct address_info mpu_config;
-static int mpu = 0;
static int sb = 0;
static int fw_load;
diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c
index 3740dd263..b2e33ab1a 100644
--- a/drivers/sound/wavfront.c
+++ b/drivers/sound/wavfront.c
@@ -49,7 +49,7 @@
* aspects of configuring a WaveFront soundcard, particularly the
* effects processor.
*
- * $Id: wavfront.c,v 0.4 1998/07/22 02:12:11 pbd Exp $
+ * $Id: wavfront.c,v 0.5 1998/07/22 16:16:41 pbd Exp $
*
* This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
@@ -343,11 +343,8 @@ static int
wavefront_sleep (wf_config *hw, int limit)
{
- current->timeout = jiffies + limit;
current->state = TASK_INTERRUPTIBLE;
- schedule();
- current->timeout = 0;
-
+ schedule_timeout(limit);
return signal_pending(current);
}
@@ -667,16 +664,16 @@ wavefront_cmd (wf_config *hw, int cmd,
/***********************************************************************
WaveFront: data munging
-Things here are weird. All data written to the board cannot
-have its most significant bit set. Any data item with values
+Things here are wierd. All data written to the board cannot
+have its most significant bit set. Any data item with values
potentially > 0x7F (127) must be split across multiple bytes.
Sometimes, we need to munge numeric values that are represented on
-the x86 side as 8- to 32-bit values. Sometimes, we need to munge data
-that is represented on the x86 side as an array of bytes. The most
+the x86 side as 8-32 bit values. Sometimes, we need to munge data
+that is represented on the x86 side as an array of bytes. The most
efficient approach to handling both cases seems to be to use 2
-different functions for munging and 2 for de-munging. This avoids
-weird casting and worrying about bit-level offsets.
+different functions for munging and 2 for de-munging. This avoids
+wierd casting and worrying about bit-level offsets.
**********************************************************************/
@@ -1198,14 +1195,14 @@ wavefront_send_sample (wf_config *hw,
shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
shptr, 4);
- /* This one is truly weird. What kind of weirdo decided that in
- a system dominated by 16- and 32-bit integers, they would use
- just 12 bits ?
+ /* This one is truly wierd. What kind of wierdo decided that in
+ a system dominated by 16 and 32 bit integers, they would use
+ a just 12 bits ?
*/
shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3);
- /* Why is this nybblified, when the MSB is *always* zero?
+ /* Why is this nybblified, when the MSB is *always* zero ?
Anyway, we can't take address of bitfield, so make a
good-faith guess at where it starts.
*/
@@ -2058,14 +2055,12 @@ wavefront_open (int dev, int mode)
return (0);
}
-static void
-wavefront_close (int dev)
-
+static void wavefront_close (int dev)
{
struct wf_config *hw = &wavefront_configuration;
- int i;
#ifdef WF_STATS
+ int i;
printk ("Status during loop: %ld\n", hw->status_found_during_loop);
for (i = 0; i < 4; i++) {
printk ("Status during sleep[%d]: %ld\n",
@@ -2078,42 +2073,36 @@ wavefront_close (int dev)
return;
}
-static void
-wavefront_aftertouch (int dev, int channel, int pressure)
+static void wavefront_aftertouch (int dev, int channel, int pressure)
{
midi_synth_aftertouch (wavefront_configuration.mididev,channel,pressure);
};
-static void
-wavefront_bender (int dev, int chn, int value)
+static void wavefront_bender (int dev, int chn, int value)
{
midi_synth_bender (wavefront_configuration.mididev, chn, value);
};
-static void
-wavefront_controller (int dev, int channel, int ctrl_num, int value)
+static void wavefront_controller (int dev, int channel, int ctrl_num, int value)
{
if(ctrl_num==CTRL_PITCH_BENDER) wavefront_bender(0,channel,value);
midi_synth_controller (wavefront_configuration.mididev,
channel,ctrl_num,value);
};
-static void
-wavefront_panning(int dev, int channel, int pressure)
+static void wavefront_panning(int dev, int channel, int pressure)
{
midi_synth_controller (wavefront_configuration.mididev,
channel,CTL_PAN,pressure);
};
-static int
-wavefront_set_instr (int dev, int channel, int instr_no)
+static int wavefront_set_instr (int dev, int channel, int instr_no)
{
return(midi_synth_set_instr (wavefront_configuration.mididev,
channel,instr_no));
};
-static int
-wavefront_kill_note (int dev, int channel, int note, int volume)
+static int wavefront_kill_note (int dev, int channel, int note, int volume)
{
if (note==255)
return (midi_synth_start_note (wavefront_configuration.mididev,
@@ -2122,8 +2111,7 @@ wavefront_kill_note (int dev, int channel, int note, int volume)
channel, note, volume));
};
-static int
-wavefront_start_note (int dev, int channel, int note, int volume)
+static int wavefront_start_note (int dev, int channel, int note, int volume)
{
if (note==255) {
midi_synth_aftertouch (wavefront_configuration.mididev,
@@ -2143,13 +2131,11 @@ wavefront_start_note (int dev, int channel, int note, int volume)
return(0);
};
-static void
-wavefront_setup_voice (int dev, int voice, int chn)
+static void wavefront_setup_voice (int dev, int voice, int chn)
{
};
static void wavefront_reset (int dev)
-
{
int i;
@@ -2266,8 +2252,7 @@ wavefront_should_cause_interrupt (wf_config *hw, int val, int port, int timeout)
cli();
hw->irq_ok = 0;
outb (val,port);
- current->timeout = jiffies + timeout;
- interruptible_sleep_on (&hw->interrupt_sleeper);
+ interruptible_sleep_on_timeout(&hw->interrupt_sleeper, timeout);
restore_flags (flags);
}
@@ -2278,6 +2263,12 @@ wavefront_hw_reset (wf_config *hw)
int bits;
int hwv[2];
+ /* Check IRQ is legal */
+
+ if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) {
+ return 1;
+ }
+
if (request_irq (hw->irq, wavefrontintr,
0, "WaveFront", (void *) hw) < 0) {
printk (KERN_WARNING "WaveFront: IRQ %d not available!\n",
@@ -2325,10 +2316,6 @@ wavefront_hw_reset (wf_config *hw)
plus external 9-pin MIDI interface selected
*/
- if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) {
- return 1;
- }
-
outb (0x80 | 0x40 | bits, hw->data_port);
/* CONTROL REGISTER
@@ -2350,7 +2337,6 @@ wavefront_hw_reset (wf_config *hw)
wait till it gets back to use. After a cold boot, this can
take some time.
-
I think this is because its only after a cold boot that the
onboard ROM does its memory check, which can take "up to 4
seconds" according to the WaveFront SDK. So, since sleeping
@@ -2797,51 +2783,50 @@ wavefront_do_reset (wf_config *hw, int atboot)
if (hw->israw || wf_raw) {
if (wavefront_download_firmware (hw, ospath)) {
goto gone_bad;
- return 1;
}
- }
-
- if (fx_raw) {
- wffx_init (hw);
- }
-
- /* If we loaded the OS, we now have to wait for it to be ready
- to roll. We can't guarantee that interrupts are enabled,
- because we might be reloading the module without forcing a
- reset/reload of the firmware.
-
- Rather than busy-wait, lets just turn interrupts on.
- */
- outb (0x80|0x40|0x10|0x1, hw->control_port);
+ /* Wait for the OS to get running. The protocol for
+ this is non-obvious, and was determined by
+ using port-IO tracing in DOSemu and some
+ experimentation here.
+
+ Rather than busy-wait, use interrupts creatively.
+ */
- wavefront_should_cause_interrupt (hw, WFC_NOOP,
+ wavefront_should_cause_interrupt (hw, WFC_NOOP,
hw->data_port, (10*HZ));
-
- if (!hw->irq_ok) {
- printk (KERN_WARNING "WaveFront: no post-OS interrupt.\n");
- goto gone_bad;
- }
-
- /* Now, do it again ! */
+
+ if (!hw->irq_ok) {
+ printk (KERN_WARNING
+ "WaveFront: no post-OS interrupt.\n");
+ goto gone_bad;
+ }
+
+ /* Now, do it again ! */
+
+ wavefront_should_cause_interrupt (hw, WFC_NOOP,
+ hw->data_port, (10*HZ));
+
+ if (!hw->irq_ok) {
+ printk (KERN_WARNING
+ "WaveFront: no post-OS interrupt(2).\n");
+ goto gone_bad;
+ }
- wavefront_should_cause_interrupt (hw, WFC_NOOP,
- hw->data_port, (10*HZ));
-
- if (!hw->irq_ok) {
- printk (KERN_WARNING "WaveFront: no post-OS interrupt(2).\n");
- goto gone_bad;
+ /* OK, no (RX/TX) interrupts any more, but leave mute
+ on. Master interrupts get enabled when we're done here.
+ */
+
+ outb (0x80, hw->control_port);
+
+ /* No need for the IRQ anymore */
+
+ free_irq (hw->irq, hw);
}
-
- /* OK, no (RX/TX) interrupts any more, but leave mute
- on. Master interrupts get enabled when we're done here.
- */
-
- outb (0x80, hw->control_port);
- /* No need for the IRQ anymore */
-
- free_irq (hw->irq, hw);
+ if (/*XXX has_fx_device() && */ fx_raw) {
+ wffx_init (hw);
+ }
/* SETUPSND.EXE asks for sample memory config here, but since i
have no idea how to interpret the result, we'll forget
@@ -3109,14 +3094,14 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r)
/* YSS225 initialization.
- This code was developed using DOSEmu. The Turtle Beach SETUPSND
- utility was run with I/O tracing in DOSEmu enabled, and a reconstruction
+ This code was developed using DOSEMU. The Turtle Beach SETUPSND
+ utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
of the port I/O done, using the Yamaha faxback document as a guide
- to add more logic to the code. It's really pretty weird.
+ to add more logic to the code. Its really pretty wierd.
There was an alternative approach of just dumping the whole I/O
sequence as a series of port/value pairs and a simple loop
- that output it. However, I hope that eventually I'll get more
+ that output it. However, I hope that eventually I'll get more
control over what this code does, and so I tried to stick with
a somewhat "algorithmic" approach.
*/
@@ -3592,7 +3577,7 @@ int init_module (void)
{
printk ("Turtle Beach WaveFront Driver\n"
- "Copyright (C) by Hannu Savolainen, "
+ "Copyright (C) by Hannu Solvainen, "
"Paul Barton-Davis 1993-1998.\n");
if (io == -1 || irq == -1) {
diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c
index 2333fd118..ee26fb1ec 100644
--- a/drivers/sound/wf_midi.c
+++ b/drivers/sound/wf_midi.c
@@ -375,24 +375,25 @@ wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic)
return 1;
}
-void
-wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
+void wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
{
struct wf_mpu_config *devc;
- int dev;
+ int dev;
static struct wf_mpu_config *isrc = 0;
- int n;
+ int n;
struct midi_input_info *mi;
- static int cnt = 0;
- if (irq < 0 || irq > 15) {
+ if (irq < 0 || irq > 15)
+ {
printk (KERN_ERR "WF-MPU: bogus interrupt #%d", irq);
return;
}
dev = irq2dev[irq];
mi = &midi_devs[dev]->in_info;
- if (mi->m_busy) return;
+ if (mi->m_busy)
+ return;
mi->m_busy = 1;
+
sti ();
n = 50;
@@ -445,8 +446,7 @@ wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
mi->m_busy = 0;
}
-static int
-wf_mpu_open (int dev, int mode,
+static int wf_mpu_open (int dev, int mode,
void (*input) (int dev, unsigned char data),
void (*output) (int dev)
)