diff options
Diffstat (limited to 'drivers/sound')
76 files changed, 32023 insertions, 28401 deletions
diff --git a/drivers/sound/.objects b/drivers/sound/.objects index f2f789a28..e7880fcc2 100644 --- a/drivers/sound/.objects +++ b/drivers/sound/.objects @@ -89,3 +89,11 @@ ifdef CONFIG_UART401 OBJS := $(OBJS) uart401.o endif +ifdef CONFIG_OPL3SA1 + OBJS := $(OBJS) opl3sa.o +endif + +ifdef CONFIG_SOFTOSS + OBJS := $(OBJS) softoss.o softoss_rs.o +endif + diff --git a/drivers/sound/.version b/drivers/sound/.version index 56cbb7db2..39159f8e2 100644 --- a/drivers/sound/.version +++ b/drivers/sound/.version @@ -1,2 +1,2 @@ -3.8a +3.8s 0x030804 diff --git a/drivers/sound/CHANGELOG b/drivers/sound/CHANGELOG index 17c2dad5f..daa9652e5 100644 --- a/drivers/sound/CHANGELOG +++ b/drivers/sound/CHANGELOG @@ -1,6 +1,16 @@ -Changelog for version 3.8 +Note these changes relate to Hannu's code and don't include the changes +made outside of this for modularising the sound + +Changelog for version 3.8o -------------------------- +Since 3.8h +- Included support for OPL3-SA1 and SoftOSS + +Since 3.8 +- Fixed SNDCTL_DSP_GETOSPACE +- Compatibility fixes for Linux 2.1.47 + Since 3.8-beta21 - Fixed all known bugs (I think). diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index d14653d45..310bf01bf 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -1,277 +1,15 @@ -bool 'ProAudioSpectrum 16 support' CONFIG_PAS -bool '100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB -bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB -bool 'Gravis Ultrasound support' CONFIG_GUS -bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 -bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS -bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 -bool 'GUS MAX support' CONFIG_GUSMAX -bool 'Microsoft Sound System support' CONFIG_MSS -bool 'Ensoniq SoundScape support' CONFIG_SSCAPE -bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX -bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16 -bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 -bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI -bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 - -if [ "$CONFIG_AEDSP16" = "y" ]; then -hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 -fi - -if [ "$CONFIG_SB" = "y" ]; then -hex 'I/O base for SB Check from manual of the card' SBC_BASE 220 -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7 -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1 -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5 -fi - -if [ "$CONFIG_SB" = "y" ]; then -hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330 -fi - - -if [ "$CONFIG_SB" = "y" ]; then -comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.' -fi - - -if [ "$CONFIG_SB" = "y" ]; then -comment 'Enter -1 to the following question if you have something else such as SB16/32.' -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1 -fi - -if [ "$CONFIG_PAS" = "y" ]; then -int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10 -fi - -if [ "$CONFIG_PAS" = "y" ]; then -int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1 -fi - -if [ "$CONFIG_GUS16" = "y" ]; then -hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530 -fi - -if [ "$CONFIG_GUS16" = "y" ]; then -int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7 -fi - -if [ "$CONFIG_GUS16" = "y" ]; then -int 'GUS DMA 0, 1 or 3' GUS16_DMA 3 -fi - -if [ "$CONFIG_MPU401" = "y" ]; then -hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330 -fi - -if [ "$CONFIG_MPU401" = "y" ]; then -int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9 -fi - - -if [ "$CONFIG_MAUI" = "y" ]; then -comment 'ERROR! You have to use old sound configuration method with Maui.' -fi - -if [ "$CONFIG_MAUI" = "y" ]; then -hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330 -fi - -if [ "$CONFIG_MAUI" = "y" ]; then -int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9 -fi - -if [ "$CONFIG_UART6850" = "y" ]; then -hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0 -fi - -if [ "$CONFIG_UART6850" = "y" ]; then -int 'UART6850 IRQ (Unknown)' U6850_IRQ -1 -fi - - -if [ "$CONFIG_PSS" = "y" ]; then -comment 'ERROR! You have to use old sound configuration method with PSS cards.' -fi - -if [ "$CONFIG_PSS" = "y" ]; then -hex 'PSS I/O base 220 or 240' PSS_BASE 220 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11 -fi - - -if [ "$CONFIG_TRIX" = "y" ]; then -comment 'ERROR! You have to use old sound configuration method with AudioTrix.' -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9 -fi # -$MAKE -C drivers/sound kernelconfig || exit 1 +# Sound driver configuration +# +#-------- +# There is another confic script which is compatible with rest of +# the kernel. It can be activated by running 'make mkscript' in this +# directory. Please note that this is an _experimental_ feature which +# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). +#-------- +# +$MAKE -C drivers/sound config || exit 1 + bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index b0a3483d5..e90ba9a03 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -1,3 +1,4 @@ +BUILDCODE=s # Makefile for the Linux sound card driver # # Note 2! The CFLAGS definitions are now inherited from the @@ -31,108 +32,201 @@ mkscript: kernelconfig: else -.PHONY: dummy -SUB_DIRS = lowlevel -VERSION = `head -1 .version` -TARGET_OS = linux -USRINCDIR = /usr/include -MODULEDIR = /lib/modules/misc - -FIXEDOBJS = soundcard.o dev_table.o sound_switch.o - -ifndef NO_LOWLEVEL - FIXEDOBJS := $(FIXEDOBJS) lowlevel/lowlevel.o -endif ifeq (.defines,$(wildcard .defines)) -include .defines +#include .defines include .objects endif +TARGET_OS=linux + ifndef TOPDIR TOPDIR=/usr/src/linux endif +SUB_DIRS := lowlevel +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) -ifndef HOSTCC -build: - @echo Compiling modularized sound driver - @make sound.o - @echo Sound module compiled. +L_TARGET := sound.a +M_OBJS := +L_OBJS := -install: sound.o - cp sound.o $(MODULEDIR) +ifeq ($(CONFIG_SOUND),y) + L_OBJS += soundcard.o dev_table.o sound_switch.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o audio.o dmabuf.o else + ifeq ($(CONFIG_SOUND),m) + M_OBJS += sound.o + MX_OBJS += sound_syms.o + endif endif -.c.o: - $(CC) $(CFLAGS) -c $< +ifeq ($(CONFIG_MIDI),y) + L_OBJS += midibuf.o + LX_OBJS += midi_synth.o +endif -ifeq ($(CONFIG_SOUND),y) +ifeq ($(CONFIG_MIDI),y) + L_OBJS += midibuf.o + LX_OBJS += midi_synth.o +endif -all: local.h sound.a +#ifeq ($(CONFIG_AUDIO),y) +#L_OBJS += dmabuf.o +#endif -OBJS += $(FIXEDOBJS) +ifeq ($(CONFIG_YM3812),y) +LX_OBJS += opl3.o +else + ifeq ($(CONFIG_YM3812),m) + MX_OBJS += opl3.o + endif +endif +ifeq ($(CONFIG_PAS),y) +L_OBJS += pas2_card.c pas2_midi.c pas2_mixer.c pas2_pcm.c else -all: + ifeq ($(CONFIG_PAS),m) + M_OBJS += pas2.o + endif endif -ifndef HOSTCC -# -# Running outside the kernel build. -# -CC = gcc -HOSTCC = gcc -CFLAGS = -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -pipe -m486 -USE_DEPEND=y +ifeq ($(CONFIG_GUS),y) +L_OBJS += gus_card.c gus_midi.c gus_vol.c gus_wave.c ics2101.c else -include $(TOPDIR)/Rules.make + ifeq ($(CONFIG_GUS),m) + M_OBJS += gus.o + endif endif -sound.a: $(OBJS) - -rm -f sound.a - $(AR) rcs sound.a $(OBJS) - sync +ifeq ($(CONFIG_SB),y) +L_OBJS += sb_audio.o sb_common.o sb_midi.o sb_mixer.o +LX_OBJS += sb_card.o uart401.o +else + ifeq ($(CONFIG_SB),m) + M_OBJS += sb.o + MX_OBJS += sb_card.o uart401.o + endif +endif -clean: - rm -f core core.* *.o *.a tmp_make *~ x y z *% - rm -f configure - cd lowlevel;make clean - -indent: - for n in *.c;do echo indent $$n;indent $$n;done - -local.h: - $(MAKE) clean - $(MAKE) setup - $(MAKE) oldconfig - $(MAKE) dep - @echo - @echo - @echo - @echo NOTE! Object file dependencies may not be up to date. Run - @echo make again if kernel/driver doesn''t link properly. Restarting - @echo it now may save some time. - @echo - @echo - -config: configure - @$(MAKE) setup - @./configure > local.h - @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h - @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h -# @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h 2>/dev/null -# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null - @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h +ifeq ($(CONFIG_ADLIB),y) +LX_OBJS += ad1848.o +else + ifeq ($(CONFIG_ADLIB),m) + MX_OBJS += ad1848.o + endif +endif -oldconfig: setup configure - @./configure -o > local.h - @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h - @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h -# @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h 2>/dev/null -# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null - @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h +ifeq ($(CONFIG_ADLIB),y) +LX_OBJS += adlib_card.o +else + ifeq ($(CONFIG_ADLIB),m) + MX_OBJS += adlib_card.o + endif +endif + +ifeq ($(CONFIG_MPU401),y) +LX_OBJS += mpu401.o +else + ifeq ($(CONFIG_MPU401),m) + MX_OBJS += mpu401.o + endif +endif + +ifeq ($(CONFIG_UART401),y) +LX_OBJS += uart401.o +else + ifeq ($(CONFIG_UART401),m) + MX_OBJS += uart401.o + endif +endif + +ifeq ($(CONFIG_UART6850),y) +LX_OBJS += uart6850.o +else + ifeq ($(CONFIG_UART6850),m) + MX_OBJS += uart6850.o + endif +endif + +ifeq ($(CONFIG_PSS),y) +L_OBJS += pss.o +else + ifeq ($(CONFIG_PSS),m) + M_OBJS += pss.o + endif +endif + +ifeq ($(CONFIG_SSCAPE),y) +L_OBJS += sscape.o +else + ifeq ($(CONFIG_SSCAPE),m) + M_OBJS += sscape.o + endif +endif + +ifeq ($(CONFIG_TRIX),y) +L_OBJS += trix.o +else + ifeq ($(CONFIG_TRIX),m) + M_OBJS += trix.o + endif +endif + +ifeq ($(CONFIG_MAD16),y) +L_OBJS += mad16.o +else + ifeq ($(CONFIG_MAD16),m) + M_OBJS += mad16.o + endif +endif + +ifeq ($(CONFIG_CS4232),y) +LX_OBJS += cs4232.o +else + ifeq ($(CONFIG_CS4232),m) + MX_OBJS += cs4232.o + endif +endif + +ifeq ($(CONFIG_MAUI),y) +L_OBJS += maui.o +else + ifeq ($(CONFIG_MAUI),m) + M_OBJS += maui.o + endif +endif + +ifeq ($(CONFIG_SOFTOSS),y) +L_OBJS += softoss.o softoss_rs.o +else + ifeq ($(CONFIG_SOFTOSS),m) + M_OBJS += softoss2.o + endif +endif + +include $(TOPDIR)/Rules.make + +softoss2.o: softoss.o softoss_rs.o + ld -r -o softoss2.o softoss.o softoss_rs.o + +pas2.o: pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + ld -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + +sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o + ld -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o + +lowlevel/lowlevel.o: + cd lowlevel; make + +sound.o: soundcard.o dev_table.o sound_switch.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o + ld -r -o sound.o soundcard.o dev_table.o sound_switch.o audio.o dmabuf.o \ + sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \ + midi_synth.o midibuf.o sound_firmware.o + rm sound_syms.o + +gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o + ld -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o kernelconfig: setup rm -f configure @@ -145,47 +239,13 @@ kernelconfig: setup # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h -mkscript: setup - rm -f configure - $(HOSTCC) -o configure configure.c - ./configure script > Config.in - cat lowlevel/Config.tmpl >> Config.in - ./configure fixedlocal > local.h - ./configure fixeddefines > .defines - -clrconf: - rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h maui_boot.h .defines - configure: configure.c $(HOSTCC) -o configure configure.c @cat .blurb -dep: - $(CPP) -M $(CFLAGS) -I. *.c > .depend - setup: @echo Compiling Sound Driver v $(VERSION) for Linux -sound.o: local.h $(FIXEDOBJS) sound.a - -rm -f sound.o - $(LD) -r -o sound.o $(FIXEDOBJS) sound.a - -modules: local.h sound.o - ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o - - -lowlevel/lowlevel.o: dummy - cd lowlevel;make CC="$(CC)" CFLAGS="$(CFLAGS)" - -contrib: - cd lowlevel;make clean;make module "CC=$(CC)" CFLAGS="$(CFLAGS)" +mkscript: -ifdef USE_DEPEND -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif -endif endif diff --git a/drivers/sound/README.FIRST b/drivers/sound/README.FIRST new file mode 100644 index 000000000..3a6b60483 --- /dev/null +++ b/drivers/sound/README.FIRST @@ -0,0 +1,7 @@ +The modular sound driver patches where funded by Red Hat Software +(www.redhat.com). The sound driver here is thus a modified version of +Hannu's code. Please bear that in mind when considering the appropriate +forums for bug reporting. + +Alan Cox + diff --git a/drivers/sound/Readme b/drivers/sound/Readme index c5002a1f7..113ad9130 100644 --- a/drivers/sound/Readme +++ b/drivers/sound/Readme @@ -1,22 +1,21 @@ -OSS Lite version 3.8 release notes +OSS/Free version 3.8 release notes ---------------------------------- Most up to date information about this driver is available from -http://www.4front-tech.com/ossfree or http://personal.eunet.fi/pp/voxware -(European mirror). +http://www.4front-tech.com/ossfree. Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux FTP sites). It gives instructions about using sound with Linux. It's bit out of date but still very useful. Information about bug fixes and such things -is available from the web page (see below). +is available from the web page (see above). Please check http://www.4front-tech.com/pguide for more info about programming -with OSS. +with OSS API. ==================================================== -- THIS VERSION ____REQUIRES____ Linux 2.1.36 OR LATER. +- THIS VERSION ____REQUIRES____ Linux 2.1.57 OR LATER. ==================================================== Packages "snd-util-3.8.tar.gz" and "snd-data-0.1.tar.Z" @@ -78,6 +77,18 @@ contributors. (I could have forgotten some names.) There are probably many other names missing. If you have sent me some patches and your name is not in the above list, please inform me. +Sending your contributions or patches +------------------------------------- + +First of all it's highly recommended to contact me before sending anything +or before even starting to do any work. Tell me what you suggest to be +changed or what you have planned to do. Also ensure you are using the +very latest (development) version of OSS/Free since the change may already be +implemented there. In general it's major waste of time to try to improve +several months old version. Information about the latest version can be found +from http://www.4front-tech.com/ossfree. In general there is no point in +sending me patches relative to production kernels. + Sponsors etc. ------------- @@ -166,7 +177,7 @@ Best regards, Hannu Hannu Savolainen -hannu@voxware.pp.fi, hannu@4front-tech.com +hannu@4front-tech.com (Please check http://www.4front-tech.com/ossfree before mailing me). Snail mail: Hannu Savolainen diff --git a/drivers/sound/Readme.cards b/drivers/sound/Readme.cards index 148afd6b0..79bbe464b 100644 --- a/drivers/sound/Readme.cards +++ b/drivers/sound/Readme.cards @@ -5,7 +5,13 @@ This document describes configuring soundcards with freeware version of Open Sound Systems (OSS/Free). Information about the commercial version (OSS/Linux) and it's configuration is available from http://www.4front-tech.com/linux.html. Information presented here is -not valid for OSS/Linux. +not valid for OSS/Linux. + +If you are unsure about how to configure OSS/Free +you can download the free evaluation version of OSS/Linux from the above +address. There is a chance that it can autodetect your soundcard. In this case +you can use the information included in soundon.log when configuring OSS/Free. + IMPORTANT! This document covers only cards that were "known" when this driver version was released. Please look at @@ -25,7 +31,7 @@ IMPORTANT! This document covers only cards that were "known" when method to use. After you have used the "new" method once it will always be used when you use any of the config programs. To return back to the "old" method you should - reinstall the kernel sources. + execute "cp Config.std Config.in" in linux/drivers/sound. The /etc/soundconf file (forget it if you don't know what this file does) contains settings that are used only by @@ -33,8 +39,8 @@ IMPORTANT! This document covers only cards that were "known" when are stored there (they really are _NOT_ stored there). Don't try to edit /etc/soundconf or any other kernel or sound driver config files manually. The _only_ - proper ways to change the settings are make config, - make menuconfig or make xconfig. + proper ways to change the settings are make config or + make menuconfig (the "old" method). When using make xconfig and/or make menuconfig, you should carefully check each sound configuration option (particularly @@ -42,7 +48,6 @@ IMPORTANT! This document covers only cards that were "known" when offered by these programs are not necessarily valid. - THE BIGGEST MISTAKES YOU CAN DO =============================== @@ -211,7 +216,8 @@ Sound Blasters is compatible just with SB Pro but there is also a non-SB- compatible 16 bit mode. Usually it's MSS/WSS but it could also be a proprietary one like MV Jazz16 or ESS ES688. OPTi - MAD16 chips are very common in so called "SB 16 bit cards". + MAD16 chips are very common in so called "SB 16 bit cards" + (try with the MAD16 driver). ====================================================================== "Supposed to be SB compatible" cards. @@ -292,10 +298,67 @@ Yamaha FM synthesizers (OPL2, OPL3 (not OPL3-SA) and OPL4) ---------------------------------------------------------------- NOTE! OPL3-SA is different chip than the ordinary OPL3. In addition to the FM synth this chip has also digital audio (WSS) and - MIDI (MPU401) capabilities. OPL3-SA is not supported by OSS/Free. - Support for it is included in OSS/Linux v3.8 and later. + MIDI (MPU401) capabilities. Support for OPL3-SA is described below. ---------------------------------------------------------------- +Yamaha OPL3-SA1 + + Yamaha OPL3-SA1 (YMF701) is an audio controller chip used on some + (Intel) motherboards and on cheap soundcards. It should not be + confused with the original OPL3 chip (YMF278) which is entirely + different chip. OPL3-SA1 has support for MSS, MPU401 and SB Pro + (not used in OSS/Free) in addition to the OPL3 FM synth. + + There are also chips called OPL3-SA2, OPL3-SA3, ..., OPL3SA-N. They + are PnP chips and will not work with the OPL3-SA1 driver. You should + use the standard MSS, MPU401 and OPL3 options with thses chips and to + activate the card using isapnptools. + +4Front Technologies SoftOSS + + SoftOSS is a software based wave table emulation which works with + any 16 bit stereo soundcard. Due to it's nature a fast CPU is + required (P133 is minumum). Althoug SoftOSS doesn _not_ use MMX + instructions it has proven out that recent processors (which appear + to have MMX) perform significantly better with SoftOSS than earlier + ones. For example a P166MMX beats a PPro200. SoftOSS should not be used + on 486 or 386 machines. + + The amount of CPU load caused by SoftOSS can be controlled by + selecting the SOFTOSS_RATE and SOFTOSS_VOICES parameters properly + (they will be prompted by make config). It's recommended to set + SOFTOSS_VOICES to 32. If you have a P166MMX or faster (PPro200 is + not faster) you can set SOFTOSS_RATE to 44100 (kHz). However with + slower systems it recommended to use sampling rates around 22050 + or even 16000 kHz. Selecting too high values for these parameters + may hang your system when playing MIDI files with hight degree of + polyphony (number of concurrently playing notes). It's also possible to + decrease SOFTOSS_VOICES. This makes it possible to use higher sampling + rates. However using fewer voices decreases playback quality more than + decreasing the sampling rate. + + SoftOSS keeps the samples loaded on system's RAM so large RAM is + required. SoftOSS should never be used on machines with less than 16M + of RAM since this is potentially dangerous (you may accidently run out + of memory which probably crashes the machine). + + SoftOSS implements the wave table API originally designed for GUS. For + this reason all applications designed for GUS should work (at least + after minor modifications). For example gmod/xgmod and playmidi -g are + known to work. + + To work SoftOSS will require GUS compatible + patch files to be installed on the system (in /dos/ultrasnd/midi). You + can use the public domain MIDIA patchset available from several ftp + sites. + + ********************************************************************* + IMPORTANT NOTICE! The original patch set distributed with Gravis + Ultrasound card is not in public domain (even it's available from + some ftp sites). You should contact Voice Crystal (www.voicecrystal.com) + if you like to use these patches with SoftOSS included in OSS/Free. + ********************************************************************* + PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC) Analog Devices and Echo Speech have together defined a soundcard architecture based on the above chips. The DSP chip is used @@ -327,7 +390,7 @@ Ensoniq SoundScape and compatibles VIVO90 cards are not compatible with Soundscapes so the Soundscape driver will not work with them. You may want to use OSS/Linux with these cards. -MAD16 and Mozart based cards +OPTi MAD16 and Mozart based cards The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929), OPTi 82C924/82C925 (in _non_ PnP mode) and OPTi 82C930 interface chips are used in many different soundcards, including some @@ -644,8 +707,12 @@ different operating systems. Sound Blasters (the original ones by Creative) --------------------------------------------- +NOTE! Check if you have a PnP Sound Blaster (cards sold after summer 1995 + are almost certainly PnP ones). With PnP cards you should use isapnptools + to activate them (see above). + It's possible to configure these cards to use different I/O, IRQ and -DMA settings. Since the available settings have changed between various +DMA settings. Since the possible/default settings have changed between various models, you have to consult manual of your card for the proper ones. It's a good idea to use the same values than with DOS/Windows. With SB and SB Pro it's the only choice. SB16 has software selectable IRQ and DMA channels but @@ -662,6 +729,15 @@ it's possible to use just one (8 bit) DMA channel by answering the 8 bit one when the configuration program asks for the 16 bit one. This may work in some systems but is likely to cause terrible noise on some other systems. +It's possible to use two SB16/32/64 at the same time. To do this you should +first configure OSS/Free for one card. Then edit local.h manually and define +SB2_BASE, SB2_IRQ, SB2_DMA and SB2_DMA2 for the second one. You can't get +the OPL3, MIDI and EMU8000 devices of the second card to work. If you are +going to use two PnP Sound Blasters, ensure that they are of different model +and have different PnP ID's. There is no way to get two cards with the same +card ID and serial number to work. The easiest way to check this is trying +if isapnptools can see both cards or just one. + NOTE! Don't enable the SM Games option (asked by the configuration program) if you are not 101% sure that your card is a Logitech Soundman Games (not a SM Wave or SM16). @@ -1185,12 +1261,10 @@ as free copies of soundcards, SDKs and operating systems. If you have any corrections and/or comments, please contact me. Hannu Savolainen -hannu@voxware.pp.fi +hannu@4front-tech.com Personal home page: http://personal.eunet.fi/pp/voxware/hannu.html www home page of OSS/Free: http://www.4front-tech.com/ossfree - European/Finnish mirror: http://personal.eunet.fi/pp/voxware www home page of commercial OSS (Open Sound System) drivers: http://www.4front-tech.com/oss.html - diff --git a/drivers/sound/Readme.linux b/drivers/sound/Readme.linux index b1121ebbe..103470869 100644 --- a/drivers/sound/Readme.linux +++ b/drivers/sound/Readme.linux @@ -67,10 +67,10 @@ Readme.cards for info about configuring the driver with your card. Also check for possible boot (insmod) time error messages in /var/adm/messages. - Other messages or problems -Please check http://www.4front-tech.com/osslite for more info. +Please check http://www.4front-tech.com/ossfree for more info. Hannu Savolainen -hannu@voxware.pp.fi +hannu@4front-tech.com ----------------- cut here ------------------------------ SURPRISE SURPRISE!!! diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 82ec86f03..fc4de23e6 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -21,36 +21,40 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include <linux/config.h> +#include <linux/module.h> +#include <linux/stddef.h> +#include "soundmodule.h" #define DEB(x) #define DEB1(x) #include "sound_config.h" -#if defined(CONFIG_AD1848) +#ifdef CONFIG_AD1848 #include "ad1848_mixer.h" typedef struct { - int base; - int irq; - int dma1, dma2; - int dual_dma; /* 1, when two DMA channels allocated */ - unsigned char MCE_bit; - unsigned char saved_regs[16]; - int debug_flag; - - int audio_flags; - int record_dev, playback_dev; - - int xfer_count; - int audio_mode; - int open_mode; - int intr_active; - char *chip_name; - int model; + int base; + int irq; + int dma1, dma2; + int dual_dma; /* 1, when two DMA channels allocated */ + unsigned char MCE_bit; + unsigned char saved_regs[16]; + int debug_flag; + + int audio_flags; + int record_dev, playback_dev; + + int xfer_count; + int audio_mode; + int open_mode; + int intr_active; + char *chip_name, *name; + int model; #define MD_1848 1 #define MD_4231 2 #define MD_4231A 3 @@ -59,30 +63,30 @@ typedef struct #define MD_C930 6 #define MD_IWAVE 7 - /* Mixer parameters */ - int recmask; - int supported_devices, orig_devices; - int supported_rec_devices, orig_rec_devices; - int *levels; - short mixer_reroute[32]; - int dev_no; - volatile unsigned long timer_ticks; - int timer_running; - int irq_ok; - mixer_ents *mix_devices; - int mixer_output_port; - int c930_password_port; + /* Mixer parameters */ + int recmask; + int supported_devices, orig_devices; + int supported_rec_devices, orig_rec_devices; + int *levels; + short mixer_reroute[32]; + int dev_no; + volatile unsigned long timer_ticks; + int timer_running; + int irq_ok; + mixer_ents *mix_devices; + int mixer_output_port; + int c930_password_port; } ad1848_info; typedef struct ad1848_port_info { - int open_mode; - int speed; - unsigned char speed_bits; - int channels; - int audio_format; - unsigned char format_bits; + int open_mode; + int speed; + unsigned char speed_bits; + int channels; + int audio_format; + unsigned char format_bits; } ad1848_port_info; @@ -98,14 +102,14 @@ static int timer_installed = -1; static int ad_format_mask[8 /*devc->model */ ] = { - 0, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM + 0, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM }; static ad1848_info adev_info[MAX_AUDIO_DEV]; @@ -115,1956 +119,1897 @@ static ad1848_info adev_info[MAX_AUDIO_DEV]; #define io_Status(d) ((d)->base+2) #define io_Polled_IO(d) ((d)->base+3) -static int ad1848_open (int dev, int mode); -static void ad1848_close (int dev); -static int ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg); -static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag); -static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag); -static int ad1848_prepare_for_output (int dev, int bsize, int bcount); -static int ad1848_prepare_for_input (int dev, int bsize, int bcount); -static void ad1848_halt (int dev); -static void ad1848_halt_input (int dev); -static void ad1848_halt_output (int dev); -static void ad1848_trigger (int dev, int bits); - -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) -static int ad1848_tmr_install (int dev); -static void ad1848_tmr_reprogram (int dev); +static int ad1848_open(int dev, int mode); +static void ad1848_close(int dev); +static int ad1848_ioctl(int dev, unsigned int cmd, caddr_t arg); +static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag); +static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag); +static int ad1848_prepare_for_output(int dev, int bsize, int bcount); +static int ad1848_prepare_for_input(int dev, int bsize, int bcount); +static void ad1848_halt(int dev); +static void ad1848_halt_input(int dev); +static void ad1848_halt_output(int dev); +static void ad1848_trigger(int dev, int bits); + +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +static int ad1848_tmr_install(int dev); +static void ad1848_tmr_reprogram(int dev); #endif static int -ad_read (ad1848_info * devc, int reg) +ad_read(ad1848_info * devc, int reg) { - unsigned long flags; - int x; - int timeout = 900000; + unsigned long flags; + int x; + int timeout = 900000; - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; + while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; - save_flags (flags); - cli (); - outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc)); - x = inb (io_Indexed_Data (devc)); + save_flags(flags); + cli(); + outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); + x = inb(io_Indexed_Data(devc)); /* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */ - restore_flags (flags); + restore_flags(flags); - return x; + return x; } static void -ad_write (ad1848_info * devc, int reg, int data) +ad_write(ad1848_info * devc, int reg, int data) { - unsigned long flags; - int timeout = 900000; - - while (timeout > 0 && - inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; - - save_flags (flags); - cli (); - outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc)); - outb (((unsigned char) (data & 0xff)), io_Indexed_Data (devc)); - /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */ - restore_flags (flags); + unsigned long flags; + int timeout = 900000; + + while (timeout > 0 && + inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; + + save_flags(flags); + cli(); + outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); + outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc)); + /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */ + restore_flags(flags); } static void -wait_for_calibration (ad1848_info * devc) +wait_for_calibration(ad1848_info * devc) { - int timeout = 0; - - /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on and then off. - */ - - timeout = 100000; - while (timeout > 0 && inb (devc->base) == 0x80) - timeout--; - if (inb (devc->base) & 0x80) - printk ("ad1848: Auto calibration timed out(1).\n"); - - timeout = 100; - while (timeout > 0 && !(ad_read (devc, 11) & 0x20)) - timeout--; - if (!(ad_read (devc, 11) & 0x20)) - return; - - timeout = 80000; - while (timeout > 0 && ad_read (devc, 11) & 0x20) - timeout--; - if (ad_read (devc, 11) & 0x20) - if (devc->model != MD_1845) - printk ("ad1848: Auto calibration timed out(3).\n"); + int timeout = 0; + + /* + * Wait until the auto calibration process has finished. + * + * 1) Wait until the chip becomes ready (reads don't return 0x80). + * 2) Wait until the ACI bit of I11 gets on and then off. + */ + + timeout = 100000; + while (timeout > 0 && inb(devc->base) == 0x80) + timeout--; + if (inb(devc->base) & 0x80) + printk("ad1848: Auto calibration timed out(1).\n"); + + timeout = 100; + while (timeout > 0 && !(ad_read(devc, 11) & 0x20)) + timeout--; + if (!(ad_read(devc, 11) & 0x20)) + return; + + timeout = 80000; + while (timeout > 0 && ad_read(devc, 11) & 0x20) + timeout--; + if (ad_read(devc, 11) & 0x20) + if (devc->model != MD_1845) + printk("ad1848: Auto calibration timed out(3).\n"); } static void -ad_mute (ad1848_info * devc) +ad_mute(ad1848_info * devc) { - int i; - unsigned char prev; + int i; + unsigned char prev; - /* - * Save old register settings and mute output channels - */ - for (i = 6; i < 8; i++) - { - prev = devc->saved_regs[i] = ad_read (devc, i); - } + /* + * Save old register settings and mute output channels + */ + for (i = 6; i < 8; i++) + { + prev = devc->saved_regs[i] = ad_read(devc, i); + } } static void -ad_unmute (ad1848_info * devc) +ad_unmute(ad1848_info * devc) { } static void -ad_enter_MCE (ad1848_info * devc) +ad_enter_MCE(ad1848_info * devc) { - unsigned long flags; - int timeout = 1000; - unsigned short prev; - - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; - - save_flags (flags); - cli (); - - devc->MCE_bit = 0x40; - prev = inb (io_Index_Addr (devc)); - if (prev & 0x40) - { - restore_flags (flags); - return; - } - - outb ((devc->MCE_bit), io_Index_Addr (devc)); - restore_flags (flags); + unsigned long flags; + int timeout = 1000; + unsigned short prev; + + while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; + + save_flags(flags); + cli(); + + devc->MCE_bit = 0x40; + prev = inb(io_Index_Addr(devc)); + if (prev & 0x40) + { + restore_flags(flags); + return; + } + outb((devc->MCE_bit), io_Index_Addr(devc)); + restore_flags(flags); } static void -ad_leave_MCE (ad1848_info * devc) +ad_leave_MCE(ad1848_info * devc) { - unsigned long flags; - unsigned char prev, acal; - int timeout = 1000; - - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; + unsigned long flags; + unsigned char prev, acal; + int timeout = 1000; - save_flags (flags); - cli (); + while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; - acal = ad_read (devc, 9); + save_flags(flags); + cli(); - devc->MCE_bit = 0x00; - prev = inb (io_Index_Addr (devc)); - outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */ + acal = ad_read(devc, 9); - if ((prev & 0x40) == 0) /* Not in MCE mode */ - { - restore_flags (flags); - return; - } + devc->MCE_bit = 0x00; + prev = inb(io_Index_Addr(devc)); + outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ - outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */ - if (acal & 0x08) /* Auto calibration is enabled */ - wait_for_calibration (devc); - restore_flags (flags); + if ((prev & 0x40) == 0) /* Not in MCE mode */ + { + restore_flags(flags); + return; + } + outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ + if (acal & 0x08) /* Auto calibration is enabled */ + wait_for_calibration(devc); + restore_flags(flags); } static int -ad1848_set_recmask (ad1848_info * devc, int mask) +ad1848_set_recmask(ad1848_info * devc, int mask) { - unsigned char recdev; - int i, n; + unsigned char recdev; + int i, n; + + mask &= devc->supported_rec_devices; + + /* Rename the mixer bits if necessary */ + for (i = 0; i < 32; i++) + if (devc->mixer_reroute[i] != i) + if (mask & (1 << i)) + { + mask &= ~(1 << i); + mask |= (1 << devc->mixer_reroute[i]); + } + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) /* Too many devices selected */ + { + mask &= ~devc->recmask; /* Filter out active settings */ - mask &= devc->supported_rec_devices; + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; - /* Rename the mixer bits if necessary */ - for (i = 0; i < 32; i++) - if (devc->mixer_reroute[i] != i) - if (mask & (1 << i)) - { - mask &= ~(1 << i); - mask |= (1 << devc->mixer_reroute[i]); - } + if (n != 1) + mask = SOUND_MASK_MIC; + } + switch (mask) + { + case SOUND_MASK_MIC: + recdev = 2; + break; - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - if (n == 0) - mask = SOUND_MASK_MIC; - else if (n != 1) /* Too many devices selected */ - { - mask &= ~devc->recmask; /* Filter out active settings */ - - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - if (n != 1) - mask = SOUND_MASK_MIC; - } - - switch (mask) - { - case SOUND_MASK_MIC: - recdev = 2; - break; - - case SOUND_MASK_LINE: - case SOUND_MASK_LINE3: - recdev = 0; - break; - - case SOUND_MASK_CD: - case SOUND_MASK_LINE1: - recdev = 1; - break; - - case SOUND_MASK_IMIX: - recdev = 3; - break; - - default: - mask = SOUND_MASK_MIC; - recdev = 2; - } - - recdev <<= 6; - ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev); - ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev); - - /* Rename the mixer bits back if necessary */ - for (i = 0; i < 32; i++) - if (devc->mixer_reroute[i] != i) - if (mask & (1 << devc->mixer_reroute[i])) - { - mask &= ~(1 << devc->mixer_reroute[i]); - mask |= (1 << i); - } + case SOUND_MASK_LINE: + case SOUND_MASK_LINE3: + recdev = 0; + break; + + case SOUND_MASK_CD: + case SOUND_MASK_LINE1: + recdev = 1; + break; - devc->recmask = mask; - return mask; + case SOUND_MASK_IMIX: + recdev = 3; + break; + + default: + mask = SOUND_MASK_MIC; + recdev = 2; + } + + recdev <<= 6; + ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); + ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + + /* Rename the mixer bits back if necessary */ + for (i = 0; i < 32; i++) + if (devc->mixer_reroute[i] != i) + if (mask & (1 << devc->mixer_reroute[i])) + { + mask &= ~(1 << devc->mixer_reroute[i]); + mask |= (1 << i); + } + devc->recmask = mask; + return mask; } static void -change_bits (ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) +change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) { - unsigned char mask; - int shift; - int mute; - int mutemask; - int set_mute_bit; - - set_mute_bit = (newval == 0); - - if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ - newval = 100 - newval; - - mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; - shift = devc->mix_devices[dev][chn].bitpos; - - if (devc->mix_devices[dev][chn].mutepos == 8) - { /* if there is no mute bit */ - mute = 0; /* No mute bit; do nothing special */ - mutemask = ~0; /* No mute bit; do nothing special */ - } - else - { - mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); - mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); - } - - newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ - *regval |= ((newval & mask) << shift) | mute; /* Set new value */ + unsigned char mask; + int shift; + int mute; + int mutemask; + int set_mute_bit; + + set_mute_bit = (newval == 0); + + if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ + newval = 100 - newval; + + mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; + shift = devc->mix_devices[dev][chn].bitpos; + + if (devc->mix_devices[dev][chn].mutepos == 8) + { /* if there is no mute bit */ + mute = 0; /* No mute bit; do nothing special */ + mutemask = ~0; /* No mute bit; do nothing special */ + } else + { + mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); + mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); + } + + newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ + *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ + *regval |= ((newval & mask) << shift) | mute; /* Set new value */ } static int -ad1848_mixer_get (ad1848_info * devc, int dev) +ad1848_mixer_get(ad1848_info * devc, int dev) { - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; + if (!((1 << dev) & devc->supported_devices)) + return -EINVAL; - dev = devc->mixer_reroute[dev]; + dev = devc->mixer_reroute[dev]; - return devc->levels[dev]; + return devc->levels[dev]; } static int -ad1848_mixer_set (ad1848_info * devc, int dev, int value) +ad1848_mixer_set(ad1848_info * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retvol; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int retvol; - int regoffs; - unsigned char val; + int regoffs; + unsigned char val; - if (dev > 31) - return -EINVAL; + if (dev > 31) + return -EINVAL; - if (!(devc->supported_devices & (1 << dev))) - return -EINVAL; + if (!(devc->supported_devices & (1 << dev))) + return -EINVAL; - dev = devc->mixer_reroute[dev]; + dev = devc->mixer_reroute[dev]; - if (left > 100) - left = 100; - if (right > 100) - right = 100; + if (left > 100) + left = 100; + if (right > 100) + right = 100; - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ - right = left; + if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ + right = left; - retvol = left | (right << 8); + retvol = left | (right << 8); - /* Scale volumes */ - left = mix_cvt[left]; - right = mix_cvt[right]; + /* Scale volumes */ + left = mix_cvt[left]; + right = mix_cvt[right]; - /* Scale it again */ - left = mix_cvt[left]; - right = mix_cvt[right]; + /* Scale it again */ + left = mix_cvt[left]; + right = mix_cvt[right]; - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; + if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) + return -EINVAL; - devc->levels[dev] = retvol; + devc->levels[dev] = retvol; - /* - * Set the left channel - */ + /* + * Set the left channel + */ - regoffs = devc->mix_devices[dev][LEFT_CHN].regno; - val = ad_read (devc, regoffs); - change_bits (devc, &val, dev, LEFT_CHN, left); - ad_write (devc, regoffs, val); - devc->saved_regs[regoffs] = val; + regoffs = devc->mix_devices[dev][LEFT_CHN].regno; + val = ad_read(devc, regoffs); + change_bits(devc, &val, dev, LEFT_CHN, left); + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; - /* - * Set the right channel - */ + /* + * Set the right channel + */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - return retvol; /* Was just a mono channel */ + if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) + return retvol; /* Was just a mono channel */ - regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; - val = ad_read (devc, regoffs); - change_bits (devc, &val, dev, RIGHT_CHN, right); - ad_write (devc, regoffs, val); - devc->saved_regs[regoffs] = val; + regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; + val = ad_read(devc, regoffs); + change_bits(devc, &val, dev, RIGHT_CHN, right); + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; - return retvol; + return retvol; } static void -ad1848_mixer_reset (ad1848_info * devc) +ad1848_mixer_reset(ad1848_info * devc) { - int i; - char name[32]; - - devc->mix_devices = &(ad1848_mix_devices[0]); - - sprintf (name, "%s_%d", devc->chip_name, nr_ad1848_devs); - - for (i = 0; i < 32; i++) - devc->mixer_reroute[i] = i; - - switch (devc->model) - { - case MD_4231: - case MD_4231A: - case MD_1845: - devc->supported_devices = MODE2_MIXER_DEVICES; - break; - - case MD_C930: - devc->supported_devices = C930_MIXER_DEVICES; - devc->mix_devices = &(c930_mix_devices[0]); - break; - - case MD_IWAVE: - devc->supported_devices = MODE3_MIXER_DEVICES; - devc->mix_devices = &(iwave_mix_devices[0]); - break; - - case MD_4232: - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - - default: - devc->supported_devices = MODE1_MIXER_DEVICES; - } - - devc->supported_rec_devices = MODE1_REC_DEVICES; - devc->orig_devices = devc->supported_devices; - devc->orig_rec_devices = devc->supported_rec_devices; - - devc->levels = load_mixer_volumes (name, default_mixer_levels, 1); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (devc->supported_devices & (1 << i)) - ad1848_mixer_set (devc, i, devc->levels[i]); - ad1848_set_recmask (devc, SOUND_MASK_MIC); - devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; - if (devc->mixer_output_port & AUDIO_SPEAKER) - ad_write (devc, 26, ad_read (devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write (devc, 26, ad_read (devc, 26) | 0x40); /* Mute mono out */ -} + int i; + char name[32]; -static int -ad1848_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) -{ - ad1848_info *devc = mixer_devs[dev]->devc; + devc->mix_devices = &(ad1848_mix_devices[0]); - if (cmd == SOUND_MIXER_PRIVATE1) - { - int val; + sprintf(name, "%s_%d", devc->chip_name, nr_ad1848_devs); - val = *(int *) arg; + for (i = 0; i < 32; i++) + devc->mixer_reroute[i] = i; - if (val == 0xffff) - return (*(int *) arg = devc->mixer_output_port); + switch (devc->model) + { + case MD_4231: + case MD_4231A: + case MD_1845: + devc->supported_devices = MODE2_MIXER_DEVICES; + break; - val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); + case MD_C930: + devc->supported_devices = C930_MIXER_DEVICES; + devc->mix_devices = &(c930_mix_devices[0]); + break; - devc->mixer_output_port = val; - val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ - devc->mixer_output_port = val; + case MD_IWAVE: + devc->supported_devices = MODE3_MIXER_DEVICES; + devc->mix_devices = &(iwave_mix_devices[0]); + break; - if (val & AUDIO_SPEAKER) - ad_write (devc, 26, ad_read (devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write (devc, 26, ad_read (devc, 26) | 0x40); /* Mute mono out */ + case MD_4232: + devc->supported_devices = MODE3_MIXER_DEVICES; + break; - return (*(int *) arg = devc->mixer_output_port); - } + default: + devc->supported_devices = MODE1_MIXER_DEVICES; + } - if (((cmd >> 8) & 0xff) == 'M') - { - int val; + devc->supported_rec_devices = MODE1_REC_DEVICES; + devc->orig_devices = devc->supported_devices; + devc->orig_rec_devices = devc->supported_rec_devices; - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - val = *(int *) arg; - return (*(int *) arg = ad1848_set_recmask (devc, val)); - break; + devc->levels = load_mixer_volumes(name, default_mixer_levels, 1); - default: - val = *(int *) arg; - return (*(int *) arg = ad1848_mixer_set (devc, cmd & 0xff, val)); - } - else - switch (cmd & 0xff) /* - * Return parameters - */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (devc->supported_devices & (1 << i)) + ad1848_mixer_set(devc, i, devc->levels[i]); + ad1848_set_recmask(devc, SOUND_MASK_MIC); + devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; + if (devc->mixer_output_port & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ +} + +static int +ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + ad1848_info *devc = mixer_devs[dev]->devc; + + if (cmd == SOUND_MIXER_PRIVATE1) { + int val; - case SOUND_MIXER_RECSRC: - return (*(int *) arg = devc->recmask); - break; + val = *(int *) arg; - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = devc->supported_devices); - break; + if (val == 0xffff) + return (*(int *) arg = devc->mixer_output_port); - case SOUND_MIXER_STEREODEVS: - if (devc->model == MD_C930) - return (*(int *) arg = devc->supported_devices); - else - return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); - break; + val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); - case SOUND_MIXER_RECMASK: - return (*(int *) arg = devc->supported_rec_devices); - break; + devc->mixer_output_port = val; + val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ + devc->mixer_output_port = val; - case SOUND_MIXER_CAPS: - return (*(int *) arg = SOUND_CAP_EXCL_INPUT); - break; + if (val & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ - default: - return (*(int *) arg = ad1848_mixer_get (devc, cmd & 0xff)); + return (*(int *) arg = devc->mixer_output_port); } - } - else - return -EINVAL; + if (((cmd >> 8) & 0xff) == 'M') + { + int val; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + val = *(int *) arg; + return (*(int *) arg = ad1848_set_recmask(devc, val)); + break; + + default: + val = *(int *) arg; + return (*(int *) arg = ad1848_mixer_set(devc, cmd & 0xff, val)); + } else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = devc->recmask); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = devc->supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + if (devc->model == MD_C930) + return (*(int *) arg = devc->supported_devices); + else + return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = devc->supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = SOUND_CAP_EXCL_INPUT); + break; + + default: + return (*(int *) arg = ad1848_mixer_get(devc, cmd & 0xff)); + } + } else + return -EINVAL; } static int -ad1848_set_speed (int dev, int arg) +ad1848_set_speed(int dev, int arg) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - /* - * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other - * three bits select the divisor (indirectly): - * - * The available speeds are in the following table. Keep the speeds in - * the increasing order. - */ - typedef struct - { - int speed; - unsigned char bits; - } - speed_struct; - - static speed_struct speed_table[] = - { - {5510, (0 << 1) | 1}, - {5510, (0 << 1) | 1}, - {6620, (7 << 1) | 1}, - {8000, (0 << 1) | 0}, - {9600, (7 << 1) | 0}, - {11025, (1 << 1) | 1}, - {16000, (1 << 1) | 0}, - {18900, (2 << 1) | 1}, - {22050, (3 << 1) | 1}, - {27420, (2 << 1) | 0}, - {32000, (3 << 1) | 0}, - {33075, (6 << 1) | 1}, - {37800, (4 << 1) | 1}, - {44100, (5 << 1) | 1}, - {48000, (6 << 1) | 0} - }; - - int i, n, selected = -1; - - n = sizeof (speed_table) / sizeof (speed_struct); - - if (arg <= 0) - return portc->speed; - - if (devc->model == MD_1845) /* AD1845 has different timer than others */ - { - if (arg < 4000) - arg = 4000; - if (arg > 50000) - arg = 50000; - - portc->speed = arg; - portc->speed_bits = speed_table[3].bits; - return portc->speed; - } - - if (arg < speed_table[0].speed) - selected = 0; - if (arg > speed_table[n - 1].speed) - selected = n - 1; - - for (i = 1 /*really */ ; selected == -1 && i < n; i++) - if (speed_table[i].speed == arg) - selected = i; - else if (speed_table[i].speed > arg) - { - int diff1, diff2; - - diff1 = arg - speed_table[i - 1].speed; - diff2 = speed_table[i].speed - arg; - - if (diff1 < diff2) - selected = i - 1; - else - selected = i; - } - - if (selected == -1) - { - printk ("ad1848: Can't find speed???\n"); - selected = 3; - } - - portc->speed = speed_table[selected].speed; - portc->speed_bits = speed_table[selected].bits; - return portc->speed; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + + /* + * The sampling speed is encoded in the least significant nibble of I8. The + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other + * three bits select the divisor (indirectly): + * + * The available speeds are in the following table. Keep the speeds in + * the increasing order. + */ + typedef struct + { + int speed; + unsigned char bits; + } + speed_struct; + + static speed_struct speed_table[] = + { + {5510, (0 << 1) | 1}, + {5510, (0 << 1) | 1}, + {6620, (7 << 1) | 1}, + {8000, (0 << 1) | 0}, + {9600, (7 << 1) | 0}, + {11025, (1 << 1) | 1}, + {16000, (1 << 1) | 0}, + {18900, (2 << 1) | 1}, + {22050, (3 << 1) | 1}, + {27420, (2 << 1) | 0}, + {32000, (3 << 1) | 0}, + {33075, (6 << 1) | 1}, + {37800, (4 << 1) | 1}, + {44100, (5 << 1) | 1}, + {48000, (6 << 1) | 0} + }; + + int i, n, selected = -1; + + n = sizeof(speed_table) / sizeof(speed_struct); + + if (arg <= 0) + return portc->speed; + + if (devc->model == MD_1845) /* AD1845 has different timer than others */ + { + if (arg < 4000) + arg = 4000; + if (arg > 50000) + arg = 50000; + + portc->speed = arg; + portc->speed_bits = speed_table[3].bits; + return portc->speed; + } + if (arg < speed_table[0].speed) + selected = 0; + if (arg > speed_table[n - 1].speed) + selected = n - 1; + + for (i = 1 /*really */ ; selected == -1 && i < n; i++) + if (speed_table[i].speed == arg) + selected = i; + else if (speed_table[i].speed > arg) + { + int diff1, diff2; + + diff1 = arg - speed_table[i - 1].speed; + diff2 = speed_table[i].speed - arg; + + if (diff1 < diff2) + selected = i - 1; + else + selected = i; + } + if (selected == -1) + { + printk("ad1848: Can't find speed???\n"); + selected = 3; + } + portc->speed = speed_table[selected].speed; + portc->speed_bits = speed_table[selected].bits; + return portc->speed; } static short -ad1848_set_channels (int dev, short arg) +ad1848_set_channels(int dev, short arg) { - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - if (arg != 1 && arg != 2) - return portc->channels; + if (arg != 1 && arg != 2) + return portc->channels; - portc->channels = arg; - return arg; + portc->channels = arg; + return arg; } static unsigned int -ad1848_set_bits (int dev, unsigned int arg) +ad1848_set_bits(int dev, unsigned int arg) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - static struct format_tbl - { - int format; - unsigned char bits; - } - format2bits[] = - { - { - 0, 0 - } - , - { - AFMT_MU_LAW, 1 - } - , - { - AFMT_A_LAW, 3 - } - , - { - AFMT_IMA_ADPCM, 5 - } - , - { - AFMT_U8, 0 - } - , - { - AFMT_S16_LE, 2 - } - , - { - AFMT_S16_BE, 6 - } - , - { - AFMT_S8, 0 - } - , - { - AFMT_U16_LE, 0 - } - , - { - AFMT_U16_BE, 0 - } - }; - int i, n = sizeof (format2bits) / sizeof (struct format_tbl); - - if (arg == 0) - return portc->audio_format; - - if (!(arg & ad_format_mask[devc->model])) - arg = AFMT_U8; - - portc->audio_format = arg; - - for (i = 0; i < n; i++) - if (format2bits[i].format == arg) - { - if ((portc->format_bits = format2bits[i].bits) == 0) - return portc->audio_format = AFMT_U8; /* Was not supported */ + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - return arg; - } + static struct format_tbl + { + int format; + unsigned char bits; + } + format2bits[] = + { + { + 0, 0 + } + , + { + AFMT_MU_LAW, 1 + } + , + { + AFMT_A_LAW, 3 + } + , + { + AFMT_IMA_ADPCM, 5 + } + , + { + AFMT_U8, 0 + } + , + { + AFMT_S16_LE, 2 + } + , + { + AFMT_S16_BE, 6 + } + , + { + AFMT_S8, 0 + } + , + { + AFMT_U16_LE, 0 + } + , + { + AFMT_U16_BE, 0 + } + }; + int i, n = sizeof(format2bits) / sizeof(struct format_tbl); + + if (arg == 0) + return portc->audio_format; - /* Still hanging here. Something must be terribly wrong */ - portc->format_bits = 0; - return portc->audio_format = AFMT_U8; + if (!(arg & ad_format_mask[devc->model])) + arg = AFMT_U8; + + portc->audio_format = arg; + + for (i = 0; i < n; i++) + if (format2bits[i].format == arg) + { + if ((portc->format_bits = format2bits[i].bits) == 0) + return portc->audio_format = AFMT_U8; /* Was not supported */ + + return arg; + } + /* Still hanging here. Something must be terribly wrong */ + portc->format_bits = 0; + return portc->audio_format = AFMT_U8; } static struct audio_driver ad1848_audio_driver = { - ad1848_open, - ad1848_close, - ad1848_output_block, - ad1848_start_input, - ad1848_ioctl, - ad1848_prepare_for_input, - ad1848_prepare_for_output, - ad1848_halt, - NULL, - NULL, - ad1848_halt_input, - ad1848_halt_output, - ad1848_trigger, - ad1848_set_speed, - ad1848_set_bits, - ad1848_set_channels + ad1848_open, + ad1848_close, + ad1848_output_block, + ad1848_start_input, + ad1848_ioctl, + ad1848_prepare_for_input, + ad1848_prepare_for_output, + ad1848_halt, + NULL, + NULL, + ad1848_halt_input, + ad1848_halt_output, + ad1848_trigger, + ad1848_set_speed, + ad1848_set_bits, + ad1848_set_channels }; static struct mixer_operations ad1848_mixer_operations = { - "SOUNDPORT", - "AD1848/CS4248/CS4231", - ad1848_mixer_ioctl + "SOUNDPORT", + "AD1848/CS4248/CS4231", + ad1848_mixer_ioctl }; static int -ad1848_open (int dev, int mode) +ad1848_open(int dev, int mode) { - ad1848_info *devc = NULL; - ad1848_port_info *portc; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (ad1848_info *) audio_devs[dev]->devc; - portc = (ad1848_port_info *) audio_devs[dev]->portc; - - save_flags (flags); - cli (); - if (portc->open_mode || (devc->open_mode & mode)) - { - restore_flags (flags); - return -EBUSY; - } - - devc->dual_dma = 0; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - devc->dual_dma = 1; - } - - devc->intr_active = 0; - devc->audio_mode = 0; - devc->open_mode |= mode; - portc->open_mode = mode; - ad1848_trigger (dev, 0); - - if (mode & OPEN_READ) - devc->record_dev = dev; - if (mode & OPEN_WRITE) - devc->playback_dev = dev; - restore_flags (flags); + ad1848_info *devc = NULL; + ad1848_port_info *portc; + unsigned long flags; + + if (dev < 0 || dev >= num_audiodevs) + return -ENXIO; + + devc = (ad1848_info *) audio_devs[dev]->devc; + portc = (ad1848_port_info *) audio_devs[dev]->portc; + + save_flags(flags); + cli(); + if (portc->open_mode || (devc->open_mode & mode)) + { + restore_flags(flags); + return -EBUSY; + } + devc->dual_dma = 0; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { + devc->dual_dma = 1; + } + devc->intr_active = 0; + devc->audio_mode = 0; + devc->open_mode |= mode; + portc->open_mode = mode; + ad1848_trigger(dev, 0); + + if (mode & OPEN_READ) + devc->record_dev = dev; + if (mode & OPEN_WRITE) + devc->playback_dev = dev; + restore_flags(flags); /* * Mute output until the playback really starts. This decreases clicking (hope so). */ - ad_mute (devc); + ad_mute(devc); - return 0; + return 0; } static void -ad1848_close (int dev) +ad1848_close(int dev) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - DEB (printk ("ad1848_close(void)\n")); + DEB(printk("ad1848_close(void)\n")); - save_flags (flags); - cli (); + save_flags(flags); + cli(); - devc->intr_active = 0; - ad1848_halt (dev); + devc->intr_active = 0; + ad1848_halt(dev); - devc->audio_mode = 0; - devc->open_mode &= ~portc->open_mode; - portc->open_mode = 0; + devc->audio_mode = 0; + devc->open_mode &= ~portc->open_mode; + portc->open_mode = 0; - ad_unmute (devc); - restore_flags (flags); + ad_unmute(devc); + restore_flags(flags); } static int -ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg) +ad1848_ioctl(int dev, unsigned int cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -ad1848_output_block (int dev, unsigned long buf, int count, int intrflag) +ad1848_output_block(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags, cnt; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - cnt = count; - - if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } - else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } - if (portc->channels > 1) - cnt >>= 1; - cnt--; - - if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - return; /* + unsigned long flags, cnt; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + + cnt = count; + + if (portc->audio_format == AFMT_IMA_ADPCM) + { + cnt /= 4; + } else + { + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } + if (portc->channels > 1) + cnt >>= 1; + cnt--; + + if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == devc->xfer_count) + { + devc->audio_mode |= PCM_ENABLE_OUTPUT; + devc->intr_active = 1; + return; /* * Auto DMA mode on. No need to react */ - } - save_flags (flags); - cli (); + } + save_flags(flags); + cli(); - ad_write (devc, 15, (unsigned char) (cnt & 0xff)); - ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); + ad_write(devc, 15, (unsigned char) (cnt & 0xff)); + ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - devc->xfer_count = cnt; - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - restore_flags (flags); + devc->xfer_count = cnt; + devc->audio_mode |= PCM_ENABLE_OUTPUT; + devc->intr_active = 1; + restore_flags(flags); } static void -ad1848_start_input (int dev, unsigned long buf, int count, int intrflag) +ad1848_start_input(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags, cnt; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - cnt = count; - if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } - else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } - if (portc->channels > 1) - cnt >>= 1; - cnt--; - - if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - return; /* - * Auto DMA mode on. No need to react - */ - } - save_flags (flags); - cli (); - - if (devc->model == MD_1848) - { - ad_write (devc, 15, (unsigned char) (cnt & 0xff)); - ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - } - else - { - ad_write (devc, 31, (unsigned char) (cnt & 0xff)); - ad_write (devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); - } - - ad_unmute (devc); - - devc->xfer_count = cnt; - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - restore_flags (flags); -} + unsigned long flags, cnt; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; -static int -ad1848_prepare_for_output (int dev, int bsize, int bcount) -{ - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + cnt = count; + if (portc->audio_format == AFMT_IMA_ADPCM) + { + cnt /= 4; + } else + { + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } + if (portc->channels > 1) + cnt >>= 1; + cnt--; - ad_mute (devc); + if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == devc->xfer_count) + { + devc->audio_mode |= PCM_ENABLE_INPUT; + devc->intr_active = 1; + return; /* + * Auto DMA mode on. No need to react + */ + } + save_flags(flags); + cli(); - save_flags (flags); - cli (); - fs = portc->speed_bits | (portc->format_bits << 5); + if (devc->model == MD_1848) + { + ad_write(devc, 15, (unsigned char) (cnt & 0xff)); + ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); + } else + { + ad_write(devc, 31, (unsigned char) (cnt & 0xff)); + ad_write(devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); + } - if (portc->channels > 1) - fs |= 0x10; + ad_unmute(devc); - ad_enter_MCE (devc); /* Enables changes to the format select reg */ + devc->xfer_count = cnt; + devc->audio_mode |= PCM_ENABLE_INPUT; + devc->intr_active = 1; + restore_flags(flags); +} - if (devc->model == MD_1845) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ +static int +ad1848_prepare_for_output(int dev, int bsize, int bcount) +{ + int timeout; + unsigned char fs, old_fs, tmp = 0; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - ad_write (devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write (devc, 23, portc->speed & 0xff); /* Speed LSB */ - } + ad_mute(devc); - old_fs = ad_read (devc, 8); + save_flags(flags); + cli(); + fs = portc->speed_bits | (portc->format_bits << 5); - if (devc->model == MD_4232) - { - tmp = ad_read (devc, 16); - ad_write (devc, 16, tmp | 0x30); - } + if (portc->channels > 1) + fs |= 0x10; - if (devc->model == MD_IWAVE) - ad_write (devc, 17, 0xc2); /* Disable variable frequency select */ + ad_enter_MCE(devc); /* Enables changes to the format select reg */ - ad_write (devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; + if (devc->model == MD_1845) /* Use alternate speed select registers */ + { + fs &= 0xf0; /* Mask off the rate select bits */ - if (devc->model == MD_4232) - ad_write (devc, 16, tmp & ~0x30); + ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ + ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ + } + old_fs = ad_read(devc, 8); - ad_leave_MCE (devc); /* + if (devc->model == MD_4232) + { + tmp = ad_read(devc, 16); + ad_write(devc, 16, tmp | 0x30); + } + if (devc->model == MD_IWAVE) + ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ + + ad_write(devc, 8, fs); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + + if (devc->model == MD_4232) + ad_write(devc, 16, tmp & ~0x30); + + ad_leave_MCE(devc); /* * Starts the calibration process. */ - restore_flags (flags); - devc->xfer_count = 0; + restore_flags(flags); + devc->xfer_count = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (dev == timer_installed && devc->timer_running) - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram (dev); - } +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + if (dev == timer_installed && devc->timer_running) + if ((fs & 0x01) != (old_fs & 0x01)) + { + ad1848_tmr_reprogram(dev); + } #endif - ad1848_halt_output (dev); - return 0; + ad1848_halt_output(dev); + return 0; } static int -ad1848_prepare_for_input (int dev, int bsize, int bcount) +ad1848_prepare_for_input(int dev, int bsize, int bcount) { - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - if (devc->audio_mode) - return 0; - - save_flags (flags); - cli (); - fs = portc->speed_bits | (portc->format_bits << 5); - - if (portc->channels > 1) - fs |= 0x10; - - ad_enter_MCE (devc); /* Enables changes to the format select reg */ - - if (devc->model == MD_1845) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ - - ad_write (devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write (devc, 23, portc->speed & 0xff); /* Speed LSB */ - } - - if (devc->model == MD_4232) - { - tmp = ad_read (devc, 16); - ad_write (devc, 16, tmp | 0x30); - } - - if (devc->model == MD_IWAVE) - ad_write (devc, 17, 0xc2); /* Disable variable frequency select */ - - /* - * If mode >= 2 (CS4231), set I28. It's the capture format register. - */ - if (devc->model != MD_1848) - { - old_fs = ad_read (devc, 28); - ad_write (devc, 28, fs); - - /* - * Write to I28 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; - - if (devc->model != MD_1848 && devc->model != MD_1845) - { - /* - * CS4231 compatible devices don't have separate sampling rate selection - * register for recording an playback. The I8 register is shared so we have to - * set the speed encoding bits of it too. - */ - unsigned char tmp = portc->speed_bits | (ad_read (devc, 8) & 0xf0); - - ad_write (devc, 8, tmp); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; - } - } - else - { /* For AD1848 set I8. */ - - old_fs = ad_read (devc, 8); - ad_write (devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; - } - - if (devc->model == MD_4232) - ad_write (devc, 16, tmp & ~0x30); - - ad_leave_MCE (devc); /* + int timeout; + unsigned char fs, old_fs, tmp = 0; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + + if (devc->audio_mode) + return 0; + + save_flags(flags); + cli(); + fs = portc->speed_bits | (portc->format_bits << 5); + + if (portc->channels > 1) + fs |= 0x10; + + ad_enter_MCE(devc); /* Enables changes to the format select reg */ + + if (devc->model == MD_1845) /* Use alternate speed select registers */ + { + fs &= 0xf0; /* Mask off the rate select bits */ + + ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ + ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ + } + if (devc->model == MD_4232) + { + tmp = ad_read(devc, 16); + ad_write(devc, 16, tmp | 0x30); + } + if (devc->model == MD_IWAVE) + ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ + + /* + * If mode >= 2 (CS4231), set I28. It's the capture format register. + */ + if (devc->model != MD_1848) + { + old_fs = ad_read(devc, 28); + ad_write(devc, 28, fs); + + /* + * Write to I28 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + + if (devc->model != MD_1848 && devc->model != MD_1845) + { + /* + * CS4231 compatible devices don't have separate sampling rate selection + * register for recording an playback. The I8 register is shared so we have to + * set the speed encoding bits of it too. + */ + unsigned char tmp = portc->speed_bits | (ad_read(devc, 8) & 0xf0); + + ad_write(devc, 8, tmp); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + } + } else + { /* For AD1848 set I8. */ + + old_fs = ad_read(devc, 8); + ad_write(devc, 8, fs); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + } + + if (devc->model == MD_4232) + ad_write(devc, 16, tmp & ~0x30); + + ad_leave_MCE(devc); /* * Starts the calibration process. */ - restore_flags (flags); - devc->xfer_count = 0; + restore_flags(flags); + devc->xfer_count = 0; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (dev == timer_installed && devc->timer_running) - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram (dev); - } + if (dev == timer_installed && devc->timer_running) + if ((fs & 0x01) != (old_fs & 0x01)) + { + ad1848_tmr_reprogram(dev); + } #endif - ad1848_halt_input (dev); - return 0; + ad1848_halt_input(dev); + return 0; } static void -ad1848_halt (int dev) +ad1848_halt(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - unsigned char bits = ad_read (devc, 9); + unsigned char bits = ad_read(devc, 9); - if (bits & 0x01 && portc->open_mode & OPEN_WRITE) - ad1848_halt_output (dev); + if (bits & 0x01 && portc->open_mode & OPEN_WRITE) + ad1848_halt_output(dev); - if (bits & 0x02 && portc->open_mode & OPEN_READ) - ad1848_halt_input (dev); - devc->audio_mode = 0; + if (bits & 0x02 && portc->open_mode & OPEN_READ) + ad1848_halt_input(dev); + devc->audio_mode = 0; } static void -ad1848_halt_input (int dev) +ad1848_halt_input(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; - if (!(ad_read (devc, 9) & 0x02)) - return; /* Capture not enabled */ + if (!(ad_read(devc, 9) & 0x02)) + return; /* Capture not enabled */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - ad_mute (devc); + ad_mute(devc); - { - int tmout; + { + int tmout; - disable_dma (audio_devs[dev]->dmap_in->dma); + disable_dma(audio_devs[dev]->dmap_in->dma); - for (tmout = 0; tmout < 100000; tmout++) - if (ad_read (devc, 11) & 0x10) - break; - ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */ + for (tmout = 0; tmout < 100000; tmout++) + if (ad_read(devc, 11) & 0x10) + break; + ad_write(devc, 9, ad_read(devc, 9) & ~0x02); /* Stop capture */ - enable_dma (audio_devs[dev]->dmap_in->dma); - devc->audio_mode &= ~PCM_ENABLE_INPUT; - } + enable_dma(audio_devs[dev]->dmap_in->dma); + devc->audio_mode &= ~PCM_ENABLE_INPUT; + } - outb ((0), io_Status (devc)); /* Clear interrupt status */ - outb ((0), io_Status (devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ - devc->audio_mode &= ~PCM_ENABLE_INPUT; + devc->audio_mode &= ~PCM_ENABLE_INPUT; - restore_flags (flags); + restore_flags(flags); } static void -ad1848_halt_output (int dev) +ad1848_halt_output(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; - if (!(ad_read (devc, 9) & 0x01)) - return; /* Playback not enabled */ + if (!(ad_read(devc, 9) & 0x01)) + return; /* Playback not enabled */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - ad_mute (devc); - { - int tmout; + ad_mute(devc); + { + int tmout; - disable_dma (audio_devs[dev]->dmap_out->dma); + disable_dma(audio_devs[dev]->dmap_out->dma); - for (tmout = 0; tmout < 100000; tmout++) - if (ad_read (devc, 11) & 0x10) - break; - ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */ + for (tmout = 0; tmout < 100000; tmout++) + if (ad_read(devc, 11) & 0x10) + break; + ad_write(devc, 9, ad_read(devc, 9) & ~0x01); /* Stop playback */ - enable_dma (audio_devs[dev]->dmap_out->dma); - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - } + enable_dma(audio_devs[dev]->dmap_out->dma); + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + } - outb ((0), io_Status (devc)); /* Clear interrupt status */ - outb ((0), io_Status (devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - restore_flags (flags); + restore_flags(flags); } static void -ad1848_trigger (int dev, int state) +ad1848_trigger(int dev, int state) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - unsigned long flags; - unsigned char tmp, old; - - save_flags (flags); - cli (); - state &= devc->audio_mode; - - tmp = old = ad_read (devc, 9); - - if (portc->open_mode & OPEN_READ) - { - if (state & PCM_ENABLE_INPUT) - tmp |= 0x02; - else - tmp &= ~0x02; - } - - if (portc->open_mode & OPEN_WRITE) - { - if (state & PCM_ENABLE_OUTPUT) - tmp |= 0x01; - else - tmp &= ~0x01; - } - - /* ad_mute(devc); */ - if (tmp != old) - { - ad_write (devc, 9, tmp); - ad_unmute (devc); - } - - restore_flags (flags); + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + unsigned long flags; + unsigned char tmp, old; + + save_flags(flags); + cli(); + state &= devc->audio_mode; + + tmp = old = ad_read(devc, 9); + + if (portc->open_mode & OPEN_READ) + { + if (state & PCM_ENABLE_INPUT) + tmp |= 0x02; + else + tmp &= ~0x02; + } + if (portc->open_mode & OPEN_WRITE) + { + if (state & PCM_ENABLE_OUTPUT) + tmp |= 0x01; + else + tmp &= ~0x01; + } + /* ad_mute(devc); */ + if (tmp != old) + { + ad_write(devc, 9, tmp); + ad_unmute(devc); + } + restore_flags(flags); } static void -ad1848_init_hw (ad1848_info * devc) +ad1848_init_hw(ad1848_info * devc) { - int i; - - /* - * Initial values for the indirect registers of CS4248/AD1848. - */ - static int init_values[] = - { - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, + int i; - /* Positions 16 to 31 just for CS4231/2 and ad1845 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + /* + * Initial values for the indirect registers of CS4248/AD1848. + */ + static int init_values[] = + { + 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; - for (i = 0; i < 16; i++) - ad_write (devc, i, init_values[i]); + for (i = 0; i < 16; i++) + ad_write(devc, i, init_values[i]); - ad_mute (devc); /* Initialize some variables */ - ad_unmute (devc); /* Leave it unmuted now */ - if (devc->model > MD_1848) - { - ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ + ad_mute(devc); /* Initialize some variables */ + ad_unmute(devc); /* Leave it unmuted now */ - if (devc->model == MD_IWAVE) - ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + if (devc->model > MD_1848) + { + ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - for (i = 16; i < 32; i++) - ad_write (devc, i, init_values[i]); + if (devc->model == MD_IWAVE) + ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - if (devc->model == MD_IWAVE) - ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */ + for (i = 16; i < 32; i++) + ad_write(devc, i, init_values[i]); - } + if (devc->model == MD_IWAVE) + ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ - if (devc->model > MD_1848) - { - if (devc->audio_flags & DMA_DUPLEX) - ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */ - else - ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ + } + if (devc->model > MD_1848) + { + if (devc->audio_flags & DMA_DUPLEX) + ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */ + else + ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ - if (devc->model == MD_1845) - ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */ + if (devc->model == MD_1845) + ad_write(devc, 27, ad_read(devc, 27) | 0x08); /* Alternate freq select enabled */ - if (devc->model == MD_IWAVE) - { /* Some magic Interwave specific initialization */ - ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ - ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */ - ad_write (devc, 17, 0xc2); /* Alternate feature enable */ - } - } - else - { - devc->audio_flags &= ~DMA_DUPLEX; - ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ - } + if (devc->model == MD_IWAVE) + { /* Some magic Interwave specific initialization */ + ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ + ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ + ad_write(devc, 17, 0xc2); /* Alternate feature enable */ + } + } else + { + devc->audio_flags &= ~DMA_DUPLEX; + ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ + } - outb ((0), io_Status (devc)); /* Clear pending interrupts */ + outb((0), io_Status(devc)); /* Clear pending interrupts */ - /* - * Toggle the MCE bit. It completes the initialization phase. - */ + /* + * Toggle the MCE bit. It completes the initialization phase. + */ - ad_enter_MCE (devc); /* In case the bit was off */ - ad_leave_MCE (devc); + ad_enter_MCE(devc); /* In case the bit was off */ + ad_leave_MCE(devc); - ad1848_mixer_reset (devc); + ad1848_mixer_reset(devc); } int -ad1848_detect (int io_base, int *ad_flags, int *osp) +ad1848_detect(int io_base, int *ad_flags, int *osp) { - unsigned char tmp; - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - unsigned char tmp1 = 0xff, tmp2 = 0xff; - int optiC930 = 0; /* OPTi 82C930 flag */ - int interwave = 0; - int ad1847_flag = 0; - int cs4248_flag = 0; + unsigned char tmp; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; + unsigned char tmp1 = 0xff, tmp2 = 0xff; + int optiC930 = 0; /* OPTi 82C930 flag */ + int interwave = 0; + int ad1847_flag = 0; + int cs4248_flag = 0; - int i; + int i; - DDB (printk ("ad1848_detect(%x)\n", io_base)); - - if (ad_flags) - { - if (*ad_flags == 0x12345678) - { - interwave = 1; - *ad_flags = 0; - } - - if (*ad_flags == 0x12345677) - { - cs4248_flag = 1; - *ad_flags = 0; - } - } - - if (nr_ad1848_devs >= MAX_AUDIO_DEV) - { - printk ("ad1848 - Too many audio devices\n"); - return 0; - } - if (check_region (io_base, 4)) - { - printk ("ad1848.c: Port %x not free.\n", io_base); - return 0; - } - - devc->base = io_base; - devc->irq_ok = 0; - devc->timer_running = 0; - devc->MCE_bit = 0x40; - devc->irq = 0; - devc->open_mode = 0; - devc->chip_name = "AD1848"; - devc->model = MD_1848; /* AD1848 or CS4248 */ - devc->levels = NULL; - devc->c930_password_port = 0; - devc->debug_flag = 0; - - /* - * Check that the I/O address is in use. - * - * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power on initialization. Just assume - * this has happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. - */ + DDB(printk("ad1848_detect(%x)\n", io_base)); + if (ad_flags) + { + if (*ad_flags == 0x12345678) + { + interwave = 1; + *ad_flags = 0; + } + if (*ad_flags == 0x12345677) + { + cs4248_flag = 1; + *ad_flags = 0; + } + } + if (nr_ad1848_devs >= MAX_AUDIO_DEV) + { + printk("ad1848 - Too many audio devices\n"); + return 0; + } + if (check_region(io_base, 4)) + { + printk("ad1848.c: Port %x not free.\n", io_base); + return 0; + } + devc->base = io_base; + devc->irq_ok = 0; + devc->timer_running = 0; + devc->MCE_bit = 0x40; + devc->irq = 0; + devc->open_mode = 0; + devc->chip_name = devc->name = "AD1848"; + devc->model = MD_1848; /* AD1848 or CS4248 */ + devc->levels = NULL; + devc->c930_password_port = 0; + devc->debug_flag = 0; + + /* + * Check that the I/O address is in use. + * + * The bit 0x80 of the base I/O port is known to be 0 after the + * chip has performed its power on initialization. Just assume + * this has happened before the OS is starting. + * + * If the I/O address is unused, it typically returns 0xff. + */ + + if (inb(devc->base) == 0xff) + { + DDB(printk("ad1848_detect: The base I/O address appears to be dead\n")); + } /* * Wait for the device to stop initialization */ - DDB (printk ("ad1848_detect() - step 0\n")); - - for (i = 0; i < 10000000; i++) - { - unsigned char x = inb (devc->base); - - if (x == 0xff || !(x & 0x80)) - break; - } - - DDB (printk ("ad1848_detect() - step A\n")); - - if (inb (devc->base) == 0x80) /* Not ready. Let's wait */ - ad_leave_MCE (devc); - - if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */ - { - DDB (printk ("ad1848 detect error - step A (%02x)\n", - (int) inb (devc->base))); - return 0; - } - - /* - * Test if it's possible to change contents of the indirect registers. - * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only - * so try to avoid using it. - */ - - DDB (printk ("ad1848_detect() - step B\n")); - ad_write (devc, 0, 0xaa); - ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ - - if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) - if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ - ad1847_flag = 1; - else - { - DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); - /* return 0; */ - } - - DDB (printk ("ad1848_detect() - step C\n")); - ad_write (devc, 0, 0x45); - ad_write (devc, 1, 0xaa); - - if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) - if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ - ad1847_flag = 1; - else - { - DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); - /* return 0; */ - } - - /* - * The indirect register I12 has some read only bits. Lets - * try to change them. - */ - - DDB (printk ("ad1848_detect() - step D\n")); - tmp = ad_read (devc, 12); - ad_write (devc, 12, (~tmp) & 0x0f); - - if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f)) - { - DDB (printk ("ad1848 detect error - step D (%x)\n", tmp1)); - return 0; - } - - /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB and 0x0A=RevC. - */ - - /* - * The original AD1848/CS4248 has just 15 indirect registers. This means - * that I0 and I16 should return the same value (etc.). - * However this doesn't work with CS4248. Actually it seems to be impossible - * to detect if the chip is a CS4231 or CS4248. - * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with CS4231. - */ + DDB(printk("ad1848_detect() - step 0\n")); -/* - * OPTi 82C930 has mode2 control bit in another place. This test will fail - * with it. Accept this situation as a possible indication of this chip. - */ + for (i = 0; i < 10000000; i++) + { + unsigned char x = inb(devc->base); - DDB (printk ("ad1848_detect() - step F\n")); - ad_write (devc, 12, 0); /* Mode2=disabled */ - - for (i = 0; i < 16; i++) - if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) - { - DDB (printk ("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); - if (!ad1847_flag) - optiC930 = 1; - break; - } - - /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). - * The bit 0x80 is always 1 in CS4248 and CS4231. - */ - - DDB (printk ("ad1848_detect() - step G\n")); - - if (ad_flags && *ad_flags == 400) - *ad_flags = 0; - else - ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ - - - if (ad_flags) - *ad_flags = 0; - - tmp1 = ad_read (devc, 12); - if (tmp1 & 0x80) - { - if (ad_flags) - *ad_flags |= AD_F_CS4248; - - devc->chip_name = "CS4248"; /* Our best knowledge just now */ - } - - if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) - { - /* - * CS4231 detected - is it? - * - * Verify that setting I0 doesn't change I16. - */ - DDB (printk ("ad1848_detect() - step H\n")); - ad_write (devc, 16, 0); /* Set I16 to known value */ - - ad_write (devc, 0, 0x45); - if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */ - { + if (x == 0xff || !(x & 0x80)) + break; + } - ad_write (devc, 0, 0xaa); - if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */ - { - DDB (printk ("ad1848 detect error - step H(%x)\n", tmp1)); - return 0; - } - - /* - * Verify that some bits of I25 are read only. - */ - - DDB (printk ("ad1848_detect() - step I\n")); - tmp1 = ad_read (devc, 25); /* Original bits */ - ad_write (devc, 25, ~tmp1); /* Invert all bits */ - if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7)) - { - int id, full_id; - - /* - * It's at least CS4231 - */ - devc->chip_name = "CS4231"; - - devc->model = MD_4231; - - /* - * It could be an AD1845 or CS4231A as well. - * CS4231 and AD1845 report the same revision info in I25 - * while the CS4231A reports different. - */ - - id = ad_read (devc, 25) & 0xe7; - full_id = ad_read (devc, 25); - if (id == 0x80) /* Device busy??? */ - id = ad_read (devc, 25) & 0xe7; - if (id == 0x80) /* Device still busy??? */ - id = ad_read (devc, 25) & 0xe7; - DDB (printk ("ad1848_detect() - step J (%02x/%02x)\n", id, - ad_read (devc, 25))); - - switch (id) - { + DDB(printk("ad1848_detect() - step A\n")); - case 0xa0: - devc->chip_name = "CS4231A"; - devc->model = MD_4231A; - break; + if (inb(devc->base) == 0x80) /* Not ready. Let's wait */ + ad_leave_MCE(devc); - case 0xa2: - devc->chip_name = "CS4232"; - devc->model = MD_4232; - break; + if ((inb(devc->base) & 0x80) != 0x00) /* Not a AD1848 */ + { + DDB(printk("ad1848 detect error - step A (%02x)\n", (int) inb(devc->base))); + return 0; + } + /* + * Test if it's possible to change contents of the indirect registers. + * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only + * so try to avoid using it. + */ + + DDB(printk("ad1848_detect() - step B\n")); + ad_write(devc, 0, 0xaa); + ad_write(devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ + + if ((tmp1 = ad_read(devc, 0)) != 0xaa || (tmp2 = ad_read(devc, 1)) != 0x45) + if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB(printk("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); + return 0; + } + DDB(printk("ad1848_detect() - step C\n")); + ad_write(devc, 0, 0x45); + ad_write(devc, 1, 0xaa); + + if ((tmp1 = ad_read(devc, 0)) != 0x45 || (tmp2 = ad_read(devc, 1)) != 0xaa) + if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB(printk("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); + return 0; + } + /* + * The indirect register I12 has some read only bits. Lets + * try to change them. + */ - case 0xb2: - devc->chip_name = "CS4232A"; - devc->model = MD_4232; - break; + DDB(printk("ad1848_detect() - step D\n")); + tmp = ad_read(devc, 12); + ad_write(devc, 12, (~tmp) & 0x0f); - case 0x03: - case 0x83: - devc->chip_name = "CS4236"; - devc->model = MD_4232; - break; + if ((tmp & 0x0f) != ((tmp1 = ad_read(devc, 12)) & 0x0f)) + { + DDB(printk("ad1848 detect error - step D (%x)\n", tmp1)); + return 0; + } + /* + * NOTE! Last 4 bits of the reg I12 tell the chip revision. + * 0x01=RevB and 0x0A=RevC. + */ + + /* + * The original AD1848/CS4248 has just 15 indirect registers. This means + * that I0 and I16 should return the same value (etc.). + * However this doesn't work with CS4248. Actually it seems to be impossible + * to detect if the chip is a CS4231 or CS4248. + * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails + * with CS4231. + */ - case 0x41: - devc->chip_name = "CS4236B"; - devc->model = MD_4232; - break; +/* + * OPTi 82C930 has mode2 control bit in another place. This test will fail + * with it. Accept this situation as a possible indication of this chip. + */ + + DDB(printk("ad1848_detect() - step F\n")); + ad_write(devc, 12, 0); /* Mode2=disabled */ - case 0x80: + for (i = 0; i < 16; i++) + if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) { - /* - * It must be a CS4231 or AD1845. The register I23 of - * CS4231 is undefined and it appears to be read only. - * AD1845 uses I23 for setting sample rate. Assume - * the chip is AD1845 if I23 is changeable. - */ - - unsigned char tmp = ad_read (devc, 23); - - ad_write (devc, 23, ~tmp); - if (interwave) - { - devc->model = MD_IWAVE; - devc->chip_name = "IWave"; - } - else if (ad_read (devc, 23) != tmp) /* AD1845 ? */ - { - devc->chip_name = "AD1845"; - devc->model = MD_1845; - } - else if (cs4248_flag) - { - if (ad_flags) - *ad_flags |= AD_F_CS4248; + DDB(printk("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); + if (!ad1847_flag) + optiC930 = 1; + break; + } + /* + * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). + * The bit 0x80 is always 1 in CS4248 and CS4231. + */ - devc->chip_name = "CS4248"; - devc->model = MD_1848; - ad_write (devc, 12, ad_read (devc, 12) & ~0x40); /* Mode2 off */ - } + DDB(printk("ad1848_detect() - step G\n")); - ad_write (devc, 23, tmp); /* Restore */ - } - break; + if (ad_flags && *ad_flags == 400) + *ad_flags = 0; + else + ad_write(devc, 12, 0x40); /* Set mode2, clear 0x80 */ - default: /* Assume CS4231 or OPTi 82C930 */ - DDB (printk ("ad1848: I25 = %02x/%02x\n", - ad_read (devc, 25), - ad_read (devc, 25) & 0xe7)); - if (optiC930) - { - devc->chip_name = "82C930"; - devc->model = MD_C930; - } - else - { - devc->model = MD_4231; - } - } - } - ad_write (devc, 25, tmp1); /* Restore bits */ + if (ad_flags) + *ad_flags = 0; - DDB (printk ("ad1848_detect() - step K\n")); - } - } + tmp1 = ad_read(devc, 12); + if (tmp1 & 0x80) + { + if (ad_flags) + *ad_flags |= AD_F_CS4248; - DDB (printk ("ad1848_detect() - step L\n")); - if (ad_flags) - { - if (devc->model != MD_1848) - *ad_flags |= AD_F_CS4231; - } + devc->chip_name = "CS4248"; /* Our best knowledge just now */ + } + if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) + { + /* + * CS4231 detected - is it? + * + * Verify that setting I0 doesn't change I16. + */ + DDB(printk("ad1848_detect() - step H\n")); + ad_write(devc, 16, 0); /* Set I16 to known value */ + + ad_write(devc, 0, 0x45); + if ((tmp1 = ad_read(devc, 16)) != 0x45) /* No change -> CS4231? */ + { - DDB (printk ("ad1848_detect() - Detected OK\n")); + ad_write(devc, 0, 0xaa); + if ((tmp1 = ad_read(devc, 16)) == 0xaa) /* Rotten bits? */ + { + DDB(printk("ad1848 detect error - step H(%x)\n", tmp1)); + return 0; + } + /* + * Verify that some bits of I25 are read only. + */ + + DDB(printk("ad1848_detect() - step I\n")); + tmp1 = ad_read(devc, 25); /* Original bits */ + ad_write(devc, 25, ~tmp1); /* Invert all bits */ + if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) + { + int id, full_id; + + /* + * It's at least CS4231 + */ + devc->chip_name = "CS4231"; + + devc->model = MD_4231; + + /* + * It could be an AD1845 or CS4231A as well. + * CS4231 and AD1845 report the same revision info in I25 + * while the CS4231A reports different. + */ + + id = ad_read(devc, 25) & 0xe7; + full_id = ad_read(devc, 25); + if (id == 0x80) /* Device busy??? */ + id = ad_read(devc, 25) & 0xe7; + if (id == 0x80) /* Device still busy??? */ + id = ad_read(devc, 25) & 0xe7; + DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25))); + + switch (id) + { + + case 0xa0: + devc->chip_name = "CS4231A"; + devc->model = MD_4231A; + break; + + case 0xa2: + devc->chip_name = "CS4232"; + devc->model = MD_4232; + break; + + case 0xb2: + devc->chip_name = "CS4232A"; + devc->model = MD_4232; + break; + + case 0x03: + case 0x83: + devc->chip_name = "CS4236"; + devc->model = MD_4232; + break; + + case 0x41: + devc->chip_name = "CS4236B"; + devc->model = MD_4232; + break; + + case 0x80: + { + /* + * It must be a CS4231 or AD1845. The register I23 of + * CS4231 is undefined and it appears to be read only. + * AD1845 uses I23 for setting sample rate. Assume + * the chip is AD1845 if I23 is changeable. + */ + + unsigned char tmp = ad_read(devc, 23); + + ad_write(devc, 23, ~tmp); + if (interwave) + { + devc->model = MD_IWAVE; + devc->chip_name = "IWave"; + } else if (ad_read(devc, 23) != tmp) /* AD1845 ? */ + { + devc->chip_name = "AD1845"; + devc->model = MD_1845; + } else if (cs4248_flag) + { + if (ad_flags) + *ad_flags |= AD_F_CS4248; + + devc->chip_name = "CS4248"; + devc->model = MD_1848; + ad_write(devc, 12, ad_read(devc, 12) & ~0x40); /* Mode2 off */ + } + ad_write(devc, 23, tmp); /* Restore */ + } + break; + + default: /* Assume CS4231 or OPTi 82C930 */ + DDB(printk("ad1848: I25 = %02x/%02x\n", ad_read(devc, 25), ad_read(devc, 25) & 0xe7)); + if (optiC930) + { + devc->chip_name = "82C930"; + devc->model = MD_C930; + } else + { + devc->model = MD_4231; + } + + } + } + ad_write(devc, 25, tmp1); /* Restore bits */ + + DDB(printk("ad1848_detect() - step K\n")); + } + } + DDB(printk("ad1848_detect() - step L\n")); + if (ad_flags) + { + if (devc->model != MD_1848) + *ad_flags |= AD_F_CS4231; + } + DDB(printk("ad1848_detect() - Detected OK\n")); - if (devc->model == MD_1848 && ad1847_flag) - devc->chip_name = "AD1847"; + if (devc->model == MD_1848 && ad1847_flag) + devc->chip_name = "AD1847"; - return 1; + return 1; } -void -ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) +int +ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) { - /* - * NOTE! If irq < 0, there is another driver which has allocated the IRQ - * so that this driver doesn't need to allocate/deallocate it. - * The actually used IRQ is ABS(irq). - */ - - - int my_dev; - char dev_name[100]; - - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - - ad1848_port_info *portc = NULL; - - request_region (devc->base, 4, devc->chip_name); - - devc->irq = (irq > 0) ? irq : 0; - devc->open_mode = 0; - devc->timer_ticks = 0; - devc->dma1 = dma_playback; - devc->dma2 = dma_capture; - devc->audio_flags = DMA_AUTOMODE; - devc->playback_dev = devc->record_dev = 0; - - if (name != NULL && name[0] != 0) - sprintf (dev_name, - "%s (%s)", name, devc->chip_name); - else - sprintf (dev_name, - "Generic audio codec (%s)", devc->chip_name); - - conf_printf2 (dev_name, - devc->base, devc->irq, dma_playback, dma_capture); - - if (devc->model == MD_1848 || devc->model == MD_C930) - devc->audio_flags |= DMA_HARDSTOP; - - if (devc->model > MD_1848) - { - if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) - devc->audio_flags &= ~DMA_DUPLEX; - else - devc->audio_flags |= DMA_DUPLEX; - } - - if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - dev_name, - &ad1848_audio_driver, - sizeof (struct audio_driver), - devc->audio_flags, - ad_format_mask[devc->model], - devc, - dma_playback, - dma_capture)) < 0) - { - return; - } - - - portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (ad1848_port_info))); - sound_mem_sizes[sound_nblocks] = sizeof (ad1848_port_info); - if (sound_nblocks < 1024) - sound_nblocks++;; - audio_devs[my_dev]->portc = portc; - memset ((char *) portc, 0, sizeof (*portc)); - - nr_ad1848_devs++; - - ad1848_init_hw (devc); - - if (irq > 0) - { - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler (devc->irq, adintr, - "SoundPort", - NULL) < 0) - { - printk ("ad1848: IRQ in use\n"); - } + /* + * NOTE! If irq < 0, there is another driver which has allocated the IRQ + * so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). + */ + + + int my_dev; + char dev_name[100]; + int e; + + ad1848_info *devc = &adev_info[nr_ad1848_devs]; + + ad1848_port_info *portc = NULL; + + devc->irq = (irq > 0) ? irq : 0; + devc->open_mode = 0; + devc->timer_ticks = 0; + devc->dma1 = dma_playback; + devc->dma2 = dma_capture; + devc->audio_flags = DMA_AUTOMODE; + devc->playback_dev = devc->record_dev = 0; + if (name != NULL) + devc->name = name; + + if (name != NULL && name[0] != 0) + sprintf(dev_name, + "%s (%s)", name, devc->chip_name); + else + sprintf(dev_name, + "Generic audio codec (%s)", devc->chip_name); - if (devc->model != MD_1848 && devc->model != MD_C930) - { - int x; - unsigned char tmp = ad_read (devc, 16); + request_region(devc->base, 4, devc->name); - devc->timer_ticks = 0; + conf_printf2(dev_name, + devc->base, devc->irq, dma_playback, dma_capture); - ad_write (devc, 21, 0x00); /* Timer MSB */ - ad_write (devc, 20, 0x10); /* Timer LSB */ + if (devc->model == MD_1848 || devc->model == MD_C930) + devc->audio_flags |= DMA_HARDSTOP; + + if (devc->model > MD_1848) + { + if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) + devc->audio_flags &= ~DMA_DUPLEX; + else + devc->audio_flags |= DMA_DUPLEX; + } + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + dev_name, + &ad1848_audio_driver, + sizeof(struct audio_driver), + devc->audio_flags, + ad_format_mask[devc->model], + devc, + dma_playback, + dma_capture)) < 0) + { + return -1; + } + portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info))); + sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info); + if (sound_nblocks < 1024) + sound_nblocks++;; + audio_devs[my_dev]->portc = portc; + memset((char *) portc, 0, sizeof(*portc)); - ad_write (devc, 16, tmp | 0x40); /* Enable timer */ - for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); - ad_write (devc, 16, tmp & ~0x40); /* Disable timer */ + nr_ad1848_devs++; - if (devc->timer_ticks == 0) - printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); - else - { - DDB (printk ("Interrupt test OK\n")); - devc->irq_ok = 1; - } - } - else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ - } - else if (irq < 0) - irq2dev[-irq] = devc->dev_no = my_dev; + ad1848_init_hw(devc); -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (devc->model != MD_1848 && - devc->model != MD_C930 && devc->irq_ok) - ad1848_tmr_install (my_dev); + if (irq > 0) + { + irq2dev[irq] = devc->dev_no = my_dev; + if (snd_set_irq_handler(devc->irq, adintr, + devc->name, + NULL) < 0) + { + printk(KERN_WARNING "ad1848: IRQ in use\n"); + } + if (devc->model != MD_1848 && devc->model != MD_C930) + { + int x; + unsigned char tmp = ad_read(devc, 16); + + devc->timer_ticks = 0; + + ad_write(devc, 21, 0x00); /* Timer MSB */ + ad_write(devc, 20, 0x10); /* Timer LSB */ + + ad_write(devc, 16, tmp | 0x40); /* Enable timer */ + for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); + 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); + else + { + DDB(printk("Interrupt test OK\n")); + devc->irq_ok = 1; + } + } else + devc->irq_ok = 1; /* Couldn't test. assume it's OK */ + } else if (irq < 0) + irq2dev[-irq] = devc->dev_no = my_dev; + +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + if (devc->model != MD_1848 && + devc->model != MD_C930 && devc->irq_ok) + ad1848_tmr_install(my_dev); #endif - if (!share_dma) - { - if (sound_alloc_dma (dma_playback, "Sound System")) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma (dma_capture, "Sound System (capture)")) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture); - } - - if (sound_install_mixer (MIXER_DRIVER_VERSION, - dev_name, - &ad1848_mixer_operations, - sizeof (struct mixer_operations), - devc) >= 0) - { - audio_devs[my_dev]->mixer_dev = num_mixers - 1; - } + if (!share_dma) + { + if (sound_alloc_dma(dma_playback, devc->name)) + printk("ad1848.c: Can't allocate DMA%d\n", dma_playback); + if (dma_capture != dma_playback) + if (sound_alloc_dma(dma_capture, devc->name)) + printk("ad1848.c: Can't allocate DMA%d\n", dma_capture); + } + if ((e = sound_install_mixer(MIXER_DRIVER_VERSION, + dev_name, + &ad1848_mixer_operations, + sizeof(struct mixer_operations), + devc)) >= 0) + { + audio_devs[my_dev]->mixer_dev = e; + } + MOD_INC_USE_COUNT; + return my_dev; } -void -ad1848_control (int cmd, int arg) +void ad1848_control(int cmd, int arg) { - ad1848_info *devc; + ad1848_info *devc; - if (nr_ad1848_devs < 1) - return; + if (nr_ad1848_devs < 1) + return; - devc = &adev_info[nr_ad1848_devs - 1]; + devc = &adev_info[nr_ad1848_devs - 1]; - switch (cmd) - { - case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845) - return; - ad_enter_MCE (devc); - ad_write (devc, 29, (ad_read (devc, 29) & 0x1f) | (arg << 5)); - ad_leave_MCE (devc); - break; - - case AD1848_MIXER_REROUTE: - { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; - - if (n == SOUND_MIXER_NONE) - { /* Just hide this control */ - ad1848_mixer_set (devc, o, 0); /* Shut up it */ - devc->supported_devices &= ~(1 << o); - devc->supported_rec_devices &= ~(1 << o); - return; - } + switch (cmd) + { + case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ + if (devc->model != MD_1845) + return; + ad_enter_MCE(devc); + ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); + ad_leave_MCE(devc); + break; - /* Make the mixer control identified by o to appear as n */ - - if (o < 0 || o > SOUND_MIXER_NRDEVICES) - return; - if (n < 0 || n > SOUND_MIXER_NRDEVICES) - return; - if (!(devc->supported_devices & (1 << o))) - return; /* Not supported */ - - devc->mixer_reroute[n] = o; /* Rename the control */ - devc->supported_devices &= ~(1 << o); - devc->supported_devices |= (1 << n); - if (devc->supported_rec_devices & (1 << o)) - devc->supported_rec_devices |= (1 << n); - devc->supported_rec_devices &= ~(1 << o); - } - break; - } + case AD1848_MIXER_REROUTE: + { + int o = (arg >> 8) & 0xff; + int n = arg & 0xff; + + if (n == SOUND_MIXER_NONE) + { /* Just hide this control */ + ad1848_mixer_set(devc, o, 0); /* Shut up it */ + devc->supported_devices &= ~(1 << o); + devc->supported_rec_devices &= ~(1 << o); + return; + } + /* Make the mixer control identified by o to appear as n */ + + if (o < 0 || o > SOUND_MIXER_NRDEVICES) + return; + if (n < 0 || n > SOUND_MIXER_NRDEVICES) + return; + if (!(devc->supported_devices & (1 << o))) + return; /* Not supported */ + + devc->mixer_reroute[n] = o; /* Rename the control */ + devc->supported_devices &= ~(1 << o); + devc->supported_devices |= (1 << n); + if (devc->supported_rec_devices & (1 << o)) + devc->supported_rec_devices |= (1 << n); + devc->supported_rec_devices &= ~(1 << o); + } + break; + } + return; } void -ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma) +ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) { - int i, dev = 0; - ad1848_info *devc = NULL; - - for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) - if (adev_info[i].base == io_base) - { - devc = &adev_info[i]; - dev = devc->dev_no; - } + int i, dev = 0; + ad1848_info *devc = NULL; - if (devc != NULL) - { - release_region (devc->base, 4); + for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) + if (adev_info[i].base == io_base) + { + devc = &adev_info[i]; + dev = devc->dev_no; + } + if (devc != NULL) + { + release_region(devc->base, 4); - if (!share_dma) - { - if (irq > 0) - snd_release_irq (devc->irq); + if (!share_dma) + { + if (irq > 0) + snd_release_irq(devc->irq); - sound_free_dma (audio_devs[dev]->dmap_out->dma); + sound_free_dma(audio_devs[dev]->dmap_out->dma); - if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma) - sound_free_dma (audio_devs[dev]->dmap_in->dma); - } - } - else - printk ("ad1848: Can't find device to be unloaded. Base=%x\n", - io_base); + if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma) + sound_free_dma(audio_devs[dev]->dmap_in->dma); + } + } else + printk("ad1848: Can't find device to be unloaded. Base=%x\n", io_base); + MOD_DEC_USE_COUNT; } -void -adintr (int irq, void *dev_id, struct pt_regs *dummy) +void adintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char status; - ad1848_info *devc; - int dev; - int alt_stat = 0xff; - unsigned char c930_stat = 0; - int cnt = 0; - - if (irq < 0 || irq > 15) - { - dev = -1; - } - else - dev = irq2dev[irq]; - - if (dev < 0 || dev >= num_audiodevs) - { - for (irq = 0; irq < 17; irq++) - if (irq2dev[irq] != -1) - break; - - if (irq > 15) - { - /* printk ("ad1848.c: Bogus interrupt %d\n", irq); */ - return; - } - - dev = irq2dev[irq]; - devc = (ad1848_info *) audio_devs[dev]->devc; - } - else - devc = (ad1848_info *) audio_devs[dev]->devc; - -interrupt_again: /* Jump back here if int status doesn't reset */ - - status = inb (io_Status (devc)); + unsigned char status; + ad1848_info *devc; + int dev; + int alt_stat = 0xff; + unsigned char c930_stat = 0; + int cnt = 0; + + if (irq < 0 || irq > 15) + { + dev = -1; + } else + dev = irq2dev[irq]; - if (status == 0x80) - printk ("adintr: Why?\n"); - if (devc->model == MD_1848) - outb ((0), io_Status (devc)); /* Clear interrupt status */ + if (dev < 0 || dev >= num_audiodevs) + { + for (irq = 0; irq < 17; irq++) + if (irq2dev[irq] != -1) + break; - if (status & 0x01) - { - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; + if (irq > 15) + { + /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ + return; + } + dev = irq2dev[irq]; + devc = (ad1848_info *) audio_devs[dev]->devc; + } else + devc = (ad1848_info *) audio_devs[dev]->devc; - save_flags (flags); - cli (); + interrupt_again: /* Jump back here if int status doesn't reset */ - alt_stat = 0; + status = inb(io_Status(devc)); - if (devc->c930_password_port) - outb ((0xe4), devc->c930_password_port); /* Password */ - outb ((11), 0xe0e); - c930_stat = inb (0xe0f); + if (status == 0x80) + printk("adintr: Why?\n"); + if (devc->model == MD_1848) + outb((0), io_Status(devc)); /* Clear interrupt status */ - if (c930_stat & 0x04) - alt_stat |= 0x10; /* Playback intr */ - if (c930_stat & 0x08) - alt_stat |= 0x20; /* Playback intr */ - restore_flags (flags); - } - else if (devc->model != MD_1848) - alt_stat = ad_read (devc, 24); - - /* Acknowledge the intr before proceeding */ - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - - save_flags (flags); - cli (); - - if (devc->c930_password_port) - outb ((0xe4), devc->c930_password_port); /* Password */ - outb ((11), 0xe0e); - outb ((~c930_stat), 0xe0f); - restore_flags (flags); - } - else if (devc->model != MD_1848) - 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) - { - DMAbuf_inputintr (devc->record_dev); - } - - 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 */ - { - devc->timer_ticks++; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (timer_installed == dev && devc->timer_running) - sound_timer_interrupt (); + if (status & 0x01) + { + if (devc->model == MD_C930) + { /* 82C930 has interrupt status register in MAD16 register MC11 */ + unsigned long flags; + + save_flags(flags); + cli(); + + alt_stat = 0; + + if (devc->c930_password_port) + outb((0xe4), devc->c930_password_port); /* Password */ + outb((11), 0xe0e); + c930_stat = inb(0xe0f); + + if (c930_stat & 0x04) + alt_stat |= 0x10; /* Playback intr */ + if (c930_stat & 0x08) + alt_stat |= 0x20; /* Playback intr */ + restore_flags(flags); + } else if (devc->model != MD_1848) + alt_stat = ad_read(devc, 24); + + /* Acknowledge the intr before proceeding */ + if (devc->model == MD_C930) + { /* 82C930 has interrupt status register in MAD16 register MC11 */ + unsigned long flags; + + save_flags(flags); + cli(); + + if (devc->c930_password_port) + outb((0xe4), devc->c930_password_port); /* Password */ + outb((11), 0xe0e); + outb((~c930_stat), 0xe0f); + restore_flags(flags); + } else if (devc->model != MD_1848) + 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) + { + DMAbuf_inputintr(devc->record_dev); + } + 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 */ + { + devc->timer_ticks++; +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + if (timer_installed == dev && devc->timer_running) + sound_timer_interrupt(); #endif - } - } - + } + } /* * Sometimes playback or capture interrupts occur while a timer interrupt * is being handled. The interrupt will not be retriggered if we don't * handle it now. Check if an interrupt is still pending and restart * the handler in this case. */ - if (inb (io_Status (devc)) & 0x01 && cnt++ < 4) - { - goto interrupt_again; - } + if (inb(io_Status(devc)) & 0x01 && cnt++ < 4) + { + goto interrupt_again; + } } #ifdef DESKPROXL @@ -2074,23 +2019,21 @@ interrupt_again: /* Jump back here if int status doesn't reset */ */ static int -init_deskpro (struct address_info *hw_config) +init_deskpro(struct address_info *hw_config) { - unsigned char tmp; - - if ((tmp = inb (0xc44)) == 0xff) - { - DDB (printk ("init_deskpro: Dead port 0xc44\n")); - return 0; - } - - outb ((tmp | 0x04), 0xc44); /* Select bank 1 */ - if (inb (0xc44) != 0x04) - { - DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n")); - return 0; - } + unsigned char tmp; + if ((tmp = inb(0xc44)) == 0xff) + { + DDB(printk("init_deskpro: Dead port 0xc44\n")); + return 0; + } + outb((tmp | 0x04), 0xc44); /* Select bank 1 */ + if (inb(0xc44) != 0x04) + { + DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n")); + return 0; + } /* * OK. It looks like a Deskpro so let's proceed. */ @@ -2123,45 +2066,44 @@ init_deskpro (struct address_info *hw_config) */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc44 (before): "); - outb ((tmp & ~0x04), 0xc44); - printk ("%02x ", inb (0xc44)); - outb ((tmp | 0x04), 0xc44); - printk ("%02x\n", inb (0xc44)); + /* Debug printing */ + printk("Port 0xc44 (before): "); + outb((tmp & ~0x04), 0xc44); + printk("%02x ", inb(0xc44)); + outb((tmp | 0x04), 0xc44); + printk("%02x\n", inb(0xc44)); #endif - /* Set bank 1 of the register */ - tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ - - switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0x604: - tmp |= 0x01; - break; - case 0xf40: - tmp |= 0x02; - break; - case 0xe80: - tmp |= 0x03; - break; - default: - DDB (printk ("init_deskpro: Invalid MSS port %x\n", - hw_config->io_base)); - return 0; - } - outb ((tmp & ~0x04), 0xc44); /* Write to bank=0 */ + /* Set bank 1 of the register */ + tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ + + switch (hw_config->io_base) + { + case 0x530: + tmp |= 0x00; + break; + case 0x604: + tmp |= 0x01; + break; + case 0xf40: + tmp |= 0x02; + break; + case 0xe80: + tmp |= 0x03; + break; + default: + DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); + return 0; + } + outb((tmp & ~0x04), 0xc44); /* Write to bank=0 */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc44 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc44)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc44)); + /* Debug printing */ + printk("Port 0xc44 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc44)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc44)); #endif /* @@ -2175,26 +2117,26 @@ init_deskpro (struct address_info *hw_config) */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc45 (before): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc45)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc45)); + /* Debug printing */ + printk("Port 0xc45 (before): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc45)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc45)); #endif - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb ((0x88), 0xc45); /* FM base 7:0 = 0x88 */ - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb ((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + outb((0x88), 0xc45); /* FM base 7:0 = 0x88 */ + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + outb((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc45 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc45)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc45)); + /* Debug printing */ + printk("Port 0xc45 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc45)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc45)); #endif @@ -2206,26 +2148,26 @@ init_deskpro (struct address_info *hw_config) */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc46 (before): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc46)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc46)); + /* Debug printing */ + printk("Port 0xc46 (before): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc46)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc46)); #endif - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb ((0x03), 0xc46); /* FM base 15:8 = 0x03 */ - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb ((0x11), 0xc46); /* ASIC ID = 0x11 */ + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + outb((0x03), 0xc46); /* FM base 15:8 = 0x03 */ + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + outb((0x11), 0xc46); /* ASIC ID = 0x11 */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc46 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc46)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc46)); + /* Debug printing */ + printk("Port 0xc46 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc46)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc46)); #endif /* @@ -2236,26 +2178,26 @@ init_deskpro (struct address_info *hw_config) */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc47 (before): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc47)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc47)); + /* Debug printing */ + printk("Port 0xc47 (before): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc47)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc47)); #endif - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb ((0x7c), 0xc47); /* FM decode enable bits = 0x7c */ - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb ((0x00), 0xc47); /* Reserved bank1 = 0x00 */ + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + outb((0x7c), 0xc47); /* FM decode enable bits = 0x7c */ + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + outb((0x00), 0xc47); /* Reserved bank1 = 0x00 */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc47 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc47)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc47)); + /* Debug printing */ + printk("Port 0xc47 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc47)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc47)); #endif /* @@ -2263,210 +2205,202 @@ init_deskpro (struct address_info *hw_config) */ #ifdef DEBUGXL - printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f)); + printk("Port 0xc6f (before) = %02x\n", inb(0xc6f)); #endif - outb ((0x80), 0xc6f); + outb((0x80), 0xc6f); #ifdef DEBUGXL - printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f)); + printk("Port 0xc6f (after) = %02x\n", inb(0xc6f)); #endif - return 1; + return 1; } #endif int -probe_ms_sound (struct address_info *hw_config) +probe_ms_sound(struct address_info *hw_config) { - unsigned char tmp; - - DDB (printk ("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); - - if (check_region (hw_config->io_base, 8)) - { - printk ("MSS: I/O port conflict\n"); - return 0; - } + unsigned char tmp; - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - /* check_opl3(0x388, hw_config); */ - return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); - } + DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); + if (check_region(hw_config->io_base, 8)) + { + printk("MSS: I/O port conflict\n"); + return 0; + } + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ + { + /* check_opl3(0x388, hw_config); */ + return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); + } #ifdef DESKPROXL - if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ - { - if (!init_deskpro (hw_config)) - return 0; - } + if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ + { + if (!init_deskpro(hw_config)) + return 0; + } #endif - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00 or 0x0f. - */ + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00 or 0x0f. + */ - if ((tmp = inb (hw_config->io_base + 3)) == 0xff) /* Bus float */ - { - int ret; + if ((tmp = inb(hw_config->io_base + 3)) == 0xff) /* Bus float */ + { + int ret; - DDB (printk ("I/O address is inactive (%x)\n", tmp)); - if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))) - return 0; - return 1; - } - DDB (printk ("MSS signature = %x\n", tmp & 0x3f)); - if ((tmp & 0x3f) != 0x04 && - (tmp & 0x3f) != 0x0f && - (tmp & 0x3f) != 0x00) - { - int ret; - - DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n", - hw_config->io_base, (int) inb (hw_config->io_base + 3))); - DDB (printk ("Trying to detect codec anyway but IRQ/DMA may not work\n")); - if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))) - return 0; + DDB(printk("I/O address is inactive (%x)\n", tmp)); + if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) + return 0; + return 1; + } + DDB(printk("MSS signature = %x\n", tmp & 0x3f)); + if ((tmp & 0x3f) != 0x04 && + (tmp & 0x3f) != 0x0f && + (tmp & 0x3f) != 0x00) + { + int ret; - hw_config->card_subtype = 1; - return 1; - } - - if (hw_config->irq > 11) - { - printk ("MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } - - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk ("MSS: Bad DMA %d\n", hw_config->dma); - return 0; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - - if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - return 0; - } - - return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); + MDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3))); + DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n")); + if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) + return 0; + + hw_config->card_subtype = 1; + return 1; + } + if (hw_config->irq > 11) + { + printk("MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk("MSS: Bad DMA %d\n", hw_config->dma); + return 0; + } + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } + if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + return 0; + } + return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); } void -attach_ms_sound (struct address_info *hw_config) +attach_ms_sound(struct address_info *hw_config) { - static char interrupt_bits[12] = - { - -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - char bits, dma2_bit = 0; + static char interrupt_bits[12] = + { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; + char bits, dma2_bit = 0; - static char dma_bits[4] = - { - 1, 2, 0, 3 - }; - - int config_port = hw_config->io_base + 0; - int version_port = hw_config->io_base + 3; - int dma = hw_config->dma; - int dma2 = hw_config->dma2; - - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - ad1848_init ("MS Sound System", hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0, hw_config->osp); - request_region (hw_config->io_base, 4, "WSS config"); - return; - } - - /* - * Set the IRQ and DMA addresses. - */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == -1) - { - printk ("MSS: Bad IRQ %d\n", hw_config->irq); - return; - } - - outb ((bits | 0x40), config_port); - if ((inb (version_port) & 0x40) == 0) - printk ("[MSS: IRQ Conflict?]"); + static char dma_bits[4] = + { + 1, 2, 0, 3 + }; + + int config_port = hw_config->io_base + 0; + int version_port = hw_config->io_base + 3; + int dma = hw_config->dma; + int dma2 = hw_config->dma2; + + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ + { + hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma2, 0, hw_config->osp); + request_region(hw_config->io_base, 4, "WSS config"); + return; + } + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + { + printk("MSS: Bad IRQ %d\n", hw_config->irq); + return; + } + outb((bits | 0x40), config_port); + if ((inb(version_port) & 0x40) == 0) + printk("[MSS: IRQ Conflict?]"); /* * Handle the capture DMA channel */ - if (dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; + if (dma2 != -1 && dma2 != dma) + { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } else + { + printk("MSS: Invalid capture DMA\n"); + dma2 = dma; + } + } else + { + dma2 = dma; + } - dma = dma2; - dma2 = tmp; - } + hw_config->dma = dma; + hw_config->dma2 = dma2; - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } - else - { - printk ("MSS: Invalid capture DMA\n"); - dma2 = dma; - } - } - else - { - dma2 = dma; - } - - hw_config->dma = dma; - hw_config->dma2 = dma2; - - outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - - ad1848_init ("MSS audio codec", hw_config->io_base + 4, - hw_config->irq, - dma, - dma2, 0, - hw_config->osp); - request_region (hw_config->io_base, 4, "WSS config"); + outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ + + hw_config->slots[0] = ad1848_init("MSS audio codec", hw_config->io_base + 4, + hw_config->irq, + dma, + dma2, 0, + hw_config->osp); + request_region(hw_config->io_base, 4, "WSS config"); } void -unload_ms_sound (struct address_info *hw_config) +unload_ms_sound(struct address_info *hw_config) { - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0); - release_region (hw_config->io_base, 4); + int mixer = audio_devs[hw_config->slots[0]]->mixer_dev; + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma, 0); + if(mixer>=0) + sound_unload_mixerdev(mixer); + sound_unload_audiodev(hw_config->slots[0]); + release_region(hw_config->io_base, 4); + } -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) /* * Timer stuff (for /dev/music). */ @@ -2474,15 +2408,15 @@ unload_ms_sound (struct address_info *hw_config) static unsigned int current_interval = 0; static unsigned int -ad1848_tmr_start (int dev, unsigned int usecs) +ad1848_tmr_start(int dev, unsigned int usecs) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ - unsigned long divider; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ + unsigned long divider; - save_flags (flags); - cli (); + save_flags(flags); + cli(); /* * Length of the timer interval (in nanoseconds) depends on the @@ -2495,91 +2429,162 @@ ad1848_tmr_start (int dev, unsigned int usecs) * the timer divider. */ - if (devc->model == MD_1845) - xtal_nsecs = 10050; - else if (ad_read (devc, 8) & 0x01) - xtal_nsecs = 9920; - else - xtal_nsecs = 9969; + if (devc->model == MD_1845) + xtal_nsecs = 10050; + else if (ad_read(devc, 8) & 0x01) + xtal_nsecs = 9920; + else + xtal_nsecs = 9969; - divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs; + divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs; - if (divider < 100) /* Don't allow shorter intervals than about 1ms */ - divider = 100; + if (divider < 100) /* Don't allow shorter intervals than about 1ms */ + divider = 100; - if (divider > 65535) /* Overflow check */ - divider = 65535; + if (divider > 65535) /* Overflow check */ + divider = 65535; - ad_write (devc, 21, (divider >> 8) & 0xff); /* Set upper bits */ - ad_write (devc, 20, divider & 0xff); /* Set lower bits */ - ad_write (devc, 16, ad_read (devc, 16) | 0x40); /* Start the timer */ - devc->timer_running = 1; - restore_flags (flags); + ad_write(devc, 21, (divider >> 8) & 0xff); /* Set upper bits */ + ad_write(devc, 20, divider & 0xff); /* Set lower bits */ + ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */ + devc->timer_running = 1; + restore_flags(flags); - return current_interval = (divider * xtal_nsecs + 500) / 1000; + return current_interval = (divider * xtal_nsecs + 500) / 1000; } static void -ad1848_tmr_reprogram (int dev) +ad1848_tmr_reprogram(int dev) { /* * Audio driver has changed sampling rate so that a different xtal * oscillator was selected. We have to reprogram the timer rate. */ - ad1848_tmr_start (dev, current_interval); - sound_timer_syncinterval (current_interval); + ad1848_tmr_start(dev, current_interval); + sound_timer_syncinterval(current_interval); } static void -ad1848_tmr_disable (int dev) +ad1848_tmr_disable(int dev) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - - save_flags (flags); - cli (); - ad_write (devc, 16, ad_read (devc, 16) & ~0x40); - devc->timer_running = 0; - restore_flags (flags); + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + save_flags(flags); + cli(); + ad_write(devc, 16, ad_read(devc, 16) & ~0x40); + devc->timer_running = 0; + restore_flags(flags); } static void -ad1848_tmr_restart (int dev) +ad1848_tmr_restart(int dev) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - if (current_interval == 0) - return; + if (current_interval == 0) + return; - save_flags (flags); - cli (); - ad_write (devc, 16, ad_read (devc, 16) | 0x40); - devc->timer_running = 1; - restore_flags (flags); + save_flags(flags); + cli(); + ad_write(devc, 16, ad_read(devc, 16) | 0x40); + devc->timer_running = 1; + restore_flags(flags); } static struct sound_lowlev_timer ad1848_tmr = { - 0, - 2, - ad1848_tmr_start, - ad1848_tmr_disable, - ad1848_tmr_restart + 0, + 2, + ad1848_tmr_start, + ad1848_tmr_disable, + ad1848_tmr_restart }; static int -ad1848_tmr_install (int dev) +ad1848_tmr_install(int dev) { - if (timer_installed != -1) - return 0; /* Don't install another timer */ + if (timer_installed != -1) + return 0; /* Don't install another timer */ - timer_installed = ad1848_tmr.dev = dev; - sound_timer_init (&ad1848_tmr, audio_devs[dev]->name); + timer_installed = ad1848_tmr.dev = dev; + sound_timer_init(&ad1848_tmr, audio_devs[dev]->name); - return 1; + return 1; } #endif + + +EXPORT_SYMBOL(ad1848_detect); +EXPORT_SYMBOL(ad1848_init); +EXPORT_SYMBOL(ad1848_unload); +EXPORT_SYMBOL(adintr); +EXPORT_SYMBOL(probe_ms_sound); +EXPORT_SYMBOL(attach_ms_sound); +EXPORT_SYMBOL(unload_ms_sound); + +#ifdef MODULE + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma2, "i"); +MODULE_PARM(type, "i"); + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; +int type = 0; + +static int loaded = 0; + +struct address_info hw_config; + + +int init_module(void) +{ + printk("ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + if(io!=-1) + { + if(irq == -1 || dma == -1) + { + printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n"); + return -EINVAL; + } + hw_config.irq = irq; + hw_config.io_base = io; + hw_config.dma = dma; + hw_config.dma2 = dma2; + hw_config.card_subtype = type; + if(!probe_ms_sound(&hw_config)) + return -ENODEV; + attach_ms_sound(&hw_config); + loaded=1; + } + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + SOUND_LOCK_END; + if(loaded) + unload_ms_sound(&hw_config); +/* unregister_symtab(&ad1848_syms); */ +} + +#else + +void +export_ad1848_syms(void) +{ + register_symtab(&ad1848_syms); +} + +#endif #endif diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c index 227f140b6..a8affde7e 100644 --- a/drivers/sound/adlib_card.c +++ b/drivers/sound/adlib_card.c @@ -12,39 +12,62 @@ * for more info. */ #include <linux/config.h> +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_YM3812) +#if defined(CONFIG_YM3812) || defined(MODULE) -void -attach_adlib_card (struct address_info *hw_config) +void attach_adlib_card(struct address_info *hw_config) { - - opl3_init (hw_config->io_base, hw_config->osp); - request_region (hw_config->io_base, 4, "OPL3/OPL2"); + hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp); + request_region(hw_config->io_base, 4, "OPL3/OPL2"); } -int -probe_adlib (struct address_info *hw_config) +int probe_adlib(struct address_info *hw_config) { - if (check_region (hw_config->io_base, 4)) - { - DDB (printk ("opl3.c: I/O port %x already in use\n", - hw_config->io_base)); - return 0; - } + if (check_region(hw_config->io_base, 4)) { + DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); + return 0; + } + return opl3_detect(hw_config->io_base, hw_config->osp); +} - return opl3_detect (hw_config->io_base, hw_config->osp); +void unload_adlib(struct address_info *hw_config) +{ + release_region(hw_config->io_base, 4); + sound_unload_synthdev(hw_config->slots[0]); } -void -unload_adlib (struct address_info *hw_config) +#ifdef MODULE + +int io = -1; +MODULE_PARM(io, "i"); + +struct address_info cfg; + +int init_module(void) { - release_region (hw_config->io_base, 4); + if (io == -1) { + printk("adlib: must specify I/O address.\n"); + return -EINVAL; + } + cfg.io_base = io; + if (probe_adlib(&cfg) == 0) + return -ENODEV; + attach_adlib_card(&cfg); + SOUND_LOCK; + return 0; } +void cleanup_module(void) +{ + unload_adlib(&cfg); + SOUND_LOCK_END; +} #endif +#endif diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index d1ba581b1..24bbaa0e0 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -16,7 +16,7 @@ #include "sound_config.h" -#ifdef CONFIG_AUDIO +#if defined(CONFIG_AUDIO) || defined(MODULE) #include "ulaw.h" #include "coproc.h" @@ -30,7 +30,7 @@ static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */ #define AM_NONE 0 #define AM_WRITE OPEN_WRITE #define AM_READ OPEN_READ -static int dma_ioctl (int dev, unsigned int cmd, caddr_t arg); +int dma_ioctl(int dev, unsigned int cmd, caddr_t arg); static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV]; @@ -38,560 +38,546 @@ static int local_conversion[MAX_AUDIO_DEV]; #define CNV_MU_LAW 0x00000001 static int -set_format (int dev, int fmt) +set_format(int dev, int fmt) { - if (fmt != AFMT_QUERY) - { - local_conversion[dev] = 0; - - if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ - if (fmt == AFMT_MU_LAW) + if (fmt != AFMT_QUERY) { - fmt = AFMT_U8; - local_conversion[dev] = CNV_MU_LAW; - } - else - fmt = AFMT_U8; /* This is always supported */ - - audio_format[dev] = audio_devs[dev]->d->set_bits (dev, fmt); - local_format[dev] = fmt; - } - else - return local_format[dev]; - - return audio_format[dev]; + local_conversion[dev] = 0; + + if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ + if (fmt == AFMT_MU_LAW) + { + fmt = AFMT_U8; + local_conversion[dev] = CNV_MU_LAW; + } else + fmt = AFMT_U8; /* This is always supported */ + + audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt); + local_format[dev] = fmt; + } else + return local_format[dev]; + + return local_format[dev]; } int -audio_open (int dev, struct fileinfo *file) +audio_open(int dev, struct fileinfo *file) { - int ret; - int bits; - int dev_type = dev & 0x0f; - int mode = file->mode & O_ACCMODE; - - dev = dev >> 4; + int ret; + int bits; + int dev_type = dev & 0x0f; + int mode = file->mode & O_ACCMODE; - if (dev_type == SND_DEV_DSP16) - bits = 16; - else - bits = 8; + dev = dev >> 4; - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; + if (dev_type == SND_DEV_DSP16) + bits = 16; + else + bits = 8; - if ((ret = DMAbuf_open (dev, mode)) < 0) - return ret; + if (dev < 0 || dev >= num_audiodevs) + return -ENXIO; - if (audio_devs[dev]->coproc) - if ((ret = audio_devs[dev]->coproc-> - open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) - { - audio_release (dev, file); - printk ("Sound: Can't access coprocessor device\n"); + if ((ret = DMAbuf_open(dev, mode)) < 0) + return ret; - return ret; - } + if (audio_devs[dev]->coproc) + if ((ret = audio_devs[dev]->coproc-> + open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) + { + audio_release(dev, file); + printk("Sound: Can't access coprocessor device\n"); - local_conversion[dev] = 0; + return ret; + } + local_conversion[dev] = 0; - if (dev_type == SND_DEV_AUDIO) - { - set_format (dev, AFMT_MU_LAW); - } - else - set_format (dev, bits); + if (dev_type == SND_DEV_AUDIO) + { + set_format(dev, AFMT_MU_LAW); + } else + set_format(dev, bits); - audio_mode[dev] = AM_NONE; - dev_nblock[dev] = 0; + audio_mode[dev] = AM_NONE; + dev_nblock[dev] = 0; - return ret; + return ret; } static void -sync_output (int dev) +sync_output(int dev) { - int p, i; - int l; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->fragment_size <= 0) - return; - dmap->flags |= DMA_POST; + int p, i; + int l; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - /* Align the write pointer with fragment boundaries */ - if ((l = dmap->user_counter % dmap->fragment_size) > 0) - { - int len; - unsigned long offs = dmap->user_counter % dmap->bytes_in_use; + if (dmap->fragment_size <= 0) + return; + dmap->flags |= DMA_POST; - len = dmap->fragment_size - l; - memset (dmap->raw_buf + offs, dmap->neutral_byte, len); - DMAbuf_move_wrpointer (dev, len); - } + /* Align the write pointer with fragment boundaries */ + if ((l = dmap->user_counter % dmap->fragment_size) > 0) + { + int len; + unsigned long offs = dmap->user_counter % dmap->bytes_in_use; + len = dmap->fragment_size - l; + memset(dmap->raw_buf + offs, dmap->neutral_byte, len); + DMAbuf_move_wrpointer(dev, len); + } /* * Clean all unused buffer fragments. */ - p = dmap->qtail; - dmap->flags |= DMA_POST; - - for (i = dmap->qlen + 1; i < dmap->nbufs; i++) - { - p = (p + 1) % dmap->nbufs; - if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > - (dmap->raw_buf + dmap->buffsize)) - printk ("audio: Buffer error 2\n"); + p = dmap->qtail; + dmap->flags |= DMA_POST; - memset (dmap->raw_buf + p * dmap->fragment_size, - dmap->neutral_byte, - dmap->fragment_size); - } + for (i = dmap->qlen + 1; i < dmap->nbufs; i++) + { + p = (p + 1) % dmap->nbufs; + if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > + (dmap->raw_buf + dmap->buffsize)) + printk("audio: Buffer error 2\n"); + + memset(dmap->raw_buf + p * dmap->fragment_size, + dmap->neutral_byte, + dmap->fragment_size); + } - dmap->flags |= DMA_DIRTY; + dmap->flags |= DMA_DIRTY; } void -audio_release (int dev, struct fileinfo *file) +audio_release(int dev, struct fileinfo *file) { - int mode; + int mode; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - audio_devs[dev]->dmap_out->closing = 1; - audio_devs[dev]->dmap_in->closing = 1; + audio_devs[dev]->dmap_out->closing = 1; + audio_devs[dev]->dmap_in->closing = 1; - sync_output (dev); + sync_output(dev); - if (audio_devs[dev]->coproc) - audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM); - DMAbuf_release (dev, mode); + if (audio_devs[dev]->coproc) + audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM); + DMAbuf_release(dev, mode); } #if defined(NO_INLINE_ASM) || !defined(i386) static void -translate_bytes (const unsigned char *table, unsigned char *buff, int n) +translate_bytes(const unsigned char *table, unsigned char *buff, int n) { - unsigned long i; + unsigned long i; - if (n <= 0) - return; + if (n <= 0) + return; - for (i = 0; i < n; ++i) - buff[i] = table[buff[i]]; + for (i = 0; i < n; ++i) + buff[i] = table[buff[i]]; } #else extern inline void -translate_bytes (const void *table, void *buff, int n) +translate_bytes(const void *table, void *buff, int n) { - if (n > 0) - { - __asm__ ("cld\n" - "1:\tlodsb\n\t" - "xlatb\n\t" - "stosb\n\t" - "loop 1b\n\t": - : "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) - : "bx", "cx", "di", "si", "ax"); - } + if (n > 0) + { + __asm__("cld\n" + "1:\tlodsb\n\t" + "xlatb\n\t" + "stosb\n\t" + "loop 1b\n\t": + : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff) + : "bx", "cx", "di", "si", "ax"); + } } #endif int -audio_write (int dev, struct fileinfo *file, const char *buf, int count) -{ - int c, p, l, buf_size; - int err; - char *dma_buf; - - dev = dev >> 4; - - p = 0; - c = count; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_WRITE; - else - audio_mode[dev] = AM_WRITE; - - if (!count) /* Flush output */ - { - sync_output (dev); - return 0; - } - - while (c) - { - if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) - { - /* Handle nonblocking mode */ - if (dev_nblock[dev] && err == -EAGAIN) - return p; /* No more space. Return # of accepted bytes */ - return err; - } - - l = c; - - if (l > buf_size) - l = buf_size; - - if (!audio_devs[dev]->d->copy_user) - { - if ((dma_buf + l) > - (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) - printk ("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", - (long) dma_buf, l, - (long) audio_devs[dev]->dmap_out->raw_buf, - (int) audio_devs[dev]->dmap_out->buffsize); - if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) - printk ("audio: Buffer error 13\n"); - copy_from_user (dma_buf, &(buf)[p], l); - } - else - audio_devs[dev]->d->copy_user (dev, - dma_buf, 0, buf, p, l); - - if (local_conversion[dev] & CNV_MU_LAW) - { - /* - * This just allows interrupts while the conversion is running - */ - sti (); - translate_bytes (ulaw_dsp, (unsigned char *) dma_buf, l); - } - - c -= l; - p += l; - DMAbuf_move_wrpointer (dev, l); - - } - - return count; -} - -int -audio_read (int dev, struct fileinfo *file, char *buf, int count) +audio_write(int dev, struct fileinfo *file, const char *buf, int count) { - int c, p, l; - char *dmabuf; - int buf_no; - - dev = dev >> 4; - p = 0; - c = count; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EPERM; - - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - { - sync_output (dev); - } - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_READ; - else - audio_mode[dev] = AM_READ; + int c, p, l, buf_size; + int err; + char *dma_buf; - while (c) - { - if ((buf_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l, - dev_nblock[dev])) < 0) - { - /* Nonblocking mode handling. Return current # of bytes */ + dev = dev >> 4; - if (dev_nblock[dev] && buf_no == -EAGAIN) - return p; + p = 0; + c = count; - return buf_no; - } - - if (l > c) - l = c; - - /* - * Insert any local processing here. - */ - - if (local_conversion[dev] & CNV_MU_LAW) - { - /* - * This just allows interrupts while the conversion is running - */ - sti (); - - translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l); - } - - { - char *fixit = dmabuf; + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EPERM; - copy_to_user (&(buf)[p], fixit, l); - }; + if (audio_devs[dev]->flags & DMA_DUPLEX) + audio_mode[dev] |= AM_WRITE; + else + audio_mode[dev] = AM_WRITE; - DMAbuf_rmchars (dev, buf_no, l); + if (!count) /* Flush output */ + { + sync_output(dev); + return 0; + } + while (c) + { + if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) + { + /* Handle nonblocking mode */ + if (dev_nblock[dev] && err == -EAGAIN) + return p; /* No more space. Return # of accepted bytes */ + return err; + } + l = c; + + if (l > buf_size) + l = buf_size; + + if (!audio_devs[dev]->d->copy_user) + { + if ((dma_buf + l) > + (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) + { + printk("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize); + return -EDOM; + } + if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) + { + printk("audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf); + return -EDOM; + } + copy_from_user(dma_buf, &(buf)[p], l); + } else + audio_devs[dev]->d->copy_user(dev, + dma_buf, 0, buf, p, l); + + if (local_conversion[dev] & CNV_MU_LAW) + { + /* + * This just allows interrupts while the conversion is running + */ + sti(); + translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); + } + c -= l; + p += l; + DMAbuf_move_wrpointer(dev, l); - p += l; - c -= l; - } + } - return count - c; + return count; } int -audio_ioctl (int dev, struct fileinfo *file_must_not_be_used, - unsigned int cmd, caddr_t arg) +audio_read(int dev, struct fileinfo *file, char *buf, int count) { - int val; - - /* printk("audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */ - - dev = dev >> 4; - - if (((cmd >> 8) & 0xff) == 'C') - { - if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ - return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0); - else - printk ("/dev/dsp%d: No coprocessor for this device\n", dev); - - return -ENXIO; - } - else - switch (cmd) - { - case SNDCTL_DSP_SYNC: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - - if (audio_devs[dev]->dmap_out->fragment_size == 0) - return 0; - sync_output (dev); - DMAbuf_sync (dev); - DMAbuf_reset (dev); - return 0; - break; - - case SNDCTL_DSP_POST: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - if (audio_devs[dev]->dmap_out->fragment_size == 0) - return 0; - audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; - sync_output (dev); - dma_ioctl (dev, SNDCTL_DSP_POST, (caddr_t) 0); - return 0; - break; - - case SNDCTL_DSP_RESET: - audio_mode[dev] = AM_NONE; - DMAbuf_reset (dev); - return 0; - break; - - case SNDCTL_DSP_GETFMTS: - return (*(int *) arg = audio_devs[dev]->format_mask); - break; + int c, p, l; + char *dmabuf; + int buf_no; - case SNDCTL_DSP_SETFMT: - val = *(int *) arg; - return (*(int *) arg = set_format (dev, val)); + dev = dev >> 4; + p = 0; + c = count; - case SNDCTL_DSP_GETISPACE: if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - - { - audio_buf_info info; - - int err = dma_ioctl (dev, cmd, (caddr_t) & info); - - if (err < 0) - return err; - - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; - } - - case SNDCTL_DSP_GETOSPACE: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - - { - audio_buf_info info; + return -EPERM; - int err = dma_ioctl (dev, cmd, (caddr_t) & info); - - if (err < 0) - return err; - - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; - } - - case SNDCTL_DSP_NONBLOCK: - dev_nblock[dev] = 1; - return 0; - break; - - case SNDCTL_DSP_GETCAPS: - { - int info = 1; /* Revision level of this ioctl() */ - - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode == OPEN_READWRITE) - info |= DSP_CAP_DUPLEX; - - if (audio_devs[dev]->coproc) - info |= DSP_CAP_COPROC; - - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - info |= DSP_CAP_BATCH; - - if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ - info |= DSP_CAP_TRIGGER; + if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + { + sync_output(dev); + } + if (audio_devs[dev]->flags & DMA_DUPLEX) + audio_mode[dev] |= AM_READ; + else + audio_mode[dev] = AM_READ; - info |= DSP_CAP_MMAP; + while (c) + { + if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, + dev_nblock[dev])) < 0) + { + /* Nonblocking mode handling. Return current # of bytes */ + + if (dev_nblock[dev] && buf_no == -EAGAIN) + return p; + + return buf_no; + } + if (l > c) + l = c; + + /* + * Insert any local processing here. + */ + + if (local_conversion[dev] & CNV_MU_LAW) + { + /* + * This just allows interrupts while the conversion is running + */ + sti(); + + translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l); + } + { + char *fixit = dmabuf; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; - } - break; + copy_to_user(&(buf)[p], fixit, l); + }; - case SOUND_PCM_WRITE_RATE: - val = *(int *) arg; - return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, val)); + DMAbuf_rmchars(dev, buf_no, l); - case SOUND_PCM_READ_RATE: - return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, 0)); + p += l; + c -= l; + } - case SNDCTL_DSP_STEREO: - { - int n; + return count - c; +} - n = *(int *) arg; - if (n > 1) - { - printk ("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", - n); - return -EINVAL; - } +int +audio_ioctl(int dev, struct fileinfo *file_must_not_be_used, + unsigned int cmd, caddr_t arg) +{ + int val; - if (n < 0) - return -EINVAL; + /* printk( "audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */ - return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, n + 1) - 1); - } + dev = dev >> 4; - case SOUND_PCM_WRITE_CHANNELS: - val = *(int *) arg; - return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, val)); + if (((cmd >> 8) & 0xff) == 'C') + { + if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ + return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk("/dev/dsp%d: No coprocessor for this device\n", dev); + + return -ENXIO; + } else + switch (cmd) + { + case SNDCTL_DSP_SYNC: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + sync_output(dev); + DMAbuf_sync(dev); + DMAbuf_reset(dev); + return 0; + break; + + case SNDCTL_DSP_POST: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; + sync_output(dev); + dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0); + return 0; + break; + + case SNDCTL_DSP_RESET: + audio_mode[dev] = AM_NONE; + DMAbuf_reset(dev); + return 0; + break; + + case SNDCTL_DSP_GETFMTS: + return (*(int *) arg = audio_devs[dev]->format_mask); + break; + + case SNDCTL_DSP_SETFMT: + val = *(int *) arg; + return (*(int *) arg = set_format(dev, val)); + + case SNDCTL_DSP_GETISPACE: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; + if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; + + { + audio_buf_info info; + + int err = dma_ioctl(dev, cmd, (caddr_t) & info); + + if (err < 0) + return err; + + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; + } + + case SNDCTL_DSP_GETOSPACE: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EPERM; + if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; + + { + audio_buf_info info; + + int err = dma_ioctl(dev, cmd, (caddr_t) & info); + + if (err < 0) + return err; + + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; + } + + case SNDCTL_DSP_NONBLOCK: + dev_nblock[dev] = 1; + return 0; + break; + + case SNDCTL_DSP_GETCAPS: + { + int info = 1; /* Revision level of this ioctl() */ + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode == OPEN_READWRITE) + info |= DSP_CAP_DUPLEX; + + if (audio_devs[dev]->coproc) + info |= DSP_CAP_COPROC; + + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ + info |= DSP_CAP_BATCH; + + if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ + info |= DSP_CAP_TRIGGER; + + info |= DSP_CAP_MMAP; + + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; + } + break; + + case SOUND_PCM_WRITE_RATE: + val = *(int *) arg; + return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val)); + + case SOUND_PCM_READ_RATE: + return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0)); + + case SNDCTL_DSP_STEREO: + { + int n; + + n = *(int *) arg; + if (n > 1) + { + printk("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n); + return -EINVAL; + } + if (n < 0) + return -EINVAL; + + return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1); + } + + case SOUND_PCM_WRITE_CHANNELS: + val = *(int *) arg; + return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val)); - case SOUND_PCM_READ_CHANNELS: - return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, 0)); + case SOUND_PCM_READ_CHANNELS: + return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0)); - case SOUND_PCM_READ_BITS: - return (*(int *) arg = audio_devs[dev]->d->set_bits (dev, 0)); + case SOUND_PCM_READ_BITS: + return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0)); + + case SNDCTL_DSP_SETDUPLEX: + if (audio_devs[dev]->open_mode != OPEN_READWRITE) + return -EPERM; + if (audio_devs[dev]->flags & DMA_DUPLEX) + return 0; + else + return -EIO; + break; - case SNDCTL_DSP_SETDUPLEX: - if (audio_devs[dev]->open_mode != OPEN_READWRITE) - return -EPERM; - if (audio_devs[dev]->flags & DMA_DUPLEX) - return 0; - else - return -EIO; - break; - - case SNDCTL_DSP_PROFILE: - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->applic_profile = *(int *) arg; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->applic_profile = *(int *) arg; - return 0; - break; - - default: - return dma_ioctl (dev, cmd, arg); - } + case SNDCTL_DSP_PROFILE: + if (audio_devs[dev]->open_mode & OPEN_WRITE) + audio_devs[dev]->dmap_out->applic_profile = *(int *) arg; + if (audio_devs[dev]->open_mode & OPEN_READ) + audio_devs[dev]->dmap_in->applic_profile = *(int *) arg; + return 0; + break; + + default: + return dma_ioctl(dev, cmd, arg); + } } void -audio_init_devices (void) +audio_init_devices(void) { - /* - * NOTE! This routine could be called several times during boot. - */ + /* + * NOTE! This routine could be called several times during boot. + */ } #endif void -reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) +reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) { - /* - * This routine breaks the physical device buffers to logical ones. - */ - - struct audio_operations *dsp_dev = audio_devs[dev]; + /* + * This routine breaks the physical device buffers to logical ones. + */ - unsigned i, n; - unsigned sr, nc, sz, bsz; + struct audio_operations *dsp_dev = audio_devs[dev]; - if (!dmap->needs_reorg) - return; + unsigned i, n; + unsigned sr, nc, sz, bsz; - sr = dsp_dev->d->set_speed (dev, 0); - nc = dsp_dev->d->set_channels (dev, 0); - sz = dsp_dev->d->set_bits (dev, 0); - dmap->needs_reorg = 0; + sr = dsp_dev->d->set_speed(dev, 0); + nc = dsp_dev->d->set_channels(dev, 0); + sz = dsp_dev->d->set_bits(dev, 0); - if (sz == 8) - dmap->neutral_byte = NEUTRAL8; - else - dmap->neutral_byte = NEUTRAL16; + if (sz == 8) + dmap->neutral_byte = NEUTRAL8; + else + dmap->neutral_byte = NEUTRAL16; - if (sr < 1 || nc < 1 || sz < 1) - { - printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", - dev, sr, nc, sz); - sr = DSP_DEFAULT_SPEED; - nc = 1; - sz = 8; - } + if (sr < 1 || nc < 1 || sz < 1) + { + printk("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz); + sr = DSP_DEFAULT_SPEED; + nc = 1; + sz = 8; + } + sz = sr * nc * sz; - sz = sr * nc * sz; + sz /= 8; /* #bits -> #bytes */ + dmap->data_rate = sz; - sz /= 8; /* #bits -> #bytes */ - dmap->data_rate = sz; + if (!dmap->needs_reorg) + return; + dmap->needs_reorg = 0; - if (dmap->fragment_size == 0) - { /* Compute the fragment size using the default algorithm */ + if (dmap->fragment_size == 0) + { /* Compute the fragment size using the default algorithm */ - /* - * Compute a buffer size for time not exceeding 1 second. - * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds - * of sound (using the current speed, sample size and #channels). - */ + /* + * Compute a buffer size for time not exceeding 1 second. + * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds + * of sound (using the current speed, sample size and #channels). + */ - bsz = dmap->buffsize; - while (bsz > sz) - bsz /= 2; + bsz = dmap->buffsize; + while (bsz > sz) + bsz /= 2; - if (bsz == dmap->buffsize) - bsz /= 2; /* Needs at least 2 buffers */ + if (bsz == dmap->buffsize) + bsz /= 2; /* Needs at least 2 buffers */ /* * Split the computed fragment to smaller parts. After 3.5a9 @@ -599,434 +585,429 @@ reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) * results when recording. */ - if (dmap->subdivision == 0) /* Not already set */ - { - dmap->subdivision = 4; /* Init to the default value */ - - if ((bsz / dmap->subdivision) > 4096) - dmap->subdivision *= 2; - if ((bsz / dmap->subdivision) < 4096) - dmap->subdivision = 1; - } - - bsz /= dmap->subdivision; - - if (bsz < 16) - bsz = 16; /* Just a sanity check */ - - dmap->fragment_size = bsz; - } - else - { - /* - * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or - * the buffer size computation has already been done. - */ - if (dmap->fragment_size > (dmap->buffsize / 2)) - dmap->fragment_size = (dmap->buffsize / 2); - bsz = dmap->fragment_size; - } - - if (audio_devs[dev]->min_fragment) - if (bsz < (1 << audio_devs[dev]->min_fragment)) - bsz = 1 << audio_devs[dev]->min_fragment; - if (audio_devs[dev]->max_fragment) - if (bsz > (1 << audio_devs[dev]->max_fragment)) - bsz = 1 << audio_devs[dev]->max_fragment; - bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ + if (dmap->subdivision == 0) /* Not already set */ + { + dmap->subdivision = 4; /* Init to the default value */ + + if ((bsz / dmap->subdivision) > 4096) + dmap->subdivision *= 2; + if ((bsz / dmap->subdivision) < 4096) + dmap->subdivision = 1; + } + bsz /= dmap->subdivision; + + if (bsz < 16) + bsz = 16; /* Just a sanity check */ + + dmap->fragment_size = bsz; + } else + { + /* + * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or + * the buffer size computation has already been done. + */ + if (dmap->fragment_size > (dmap->buffsize / 2)) + dmap->fragment_size = (dmap->buffsize / 2); + bsz = dmap->fragment_size; + } + + if (audio_devs[dev]->min_fragment) + if (bsz < (1 << audio_devs[dev]->min_fragment)) + bsz = 1 << audio_devs[dev]->min_fragment; + if (audio_devs[dev]->max_fragment) + if (bsz > (1 << audio_devs[dev]->max_fragment)) + bsz = 1 << audio_devs[dev]->max_fragment; + bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ #ifdef OS_DMA_ALIGN_CHECK - OS_DMA_ALIGN_CHECK (bsz); + OS_DMA_ALIGN_CHECK(bsz); #endif - n = dmap->buffsize / bsz; - if (n > MAX_SUB_BUFFERS) - n = MAX_SUB_BUFFERS; - if (n > dmap->max_fragments) - n = dmap->max_fragments; - - if (n < 2) - { - n = 2; - bsz /= 2; - } - - dmap->nbufs = n; - dmap->bytes_in_use = n * bsz; - dmap->fragment_size = bsz; - dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + - dmap->bytes_in_use; /* Approximately one hour */ - - if (dmap->raw_buf) - { - memset (dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); - } - - for (i = 0; i < dmap->nbufs; i++) - { - dmap->counts[i] = 0; - } - - dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; + n = dmap->buffsize / bsz; + if (n > MAX_SUB_BUFFERS) + n = MAX_SUB_BUFFERS; + if (n > dmap->max_fragments) + n = dmap->max_fragments; + + if (n < 2) + { + n = 2; + bsz /= 2; + } + dmap->nbufs = n; + dmap->bytes_in_use = n * bsz; + dmap->fragment_size = bsz; + dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + + dmap->bytes_in_use; /* Approximately one hour */ + + if (dmap->raw_buf) + { + memset(dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); + } + for (i = 0; i < dmap->nbufs; i++) + { + dmap->counts[i] = 0; + } + + dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; } static int -dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) { - if (fact == 0) - { - fact = dmap->subdivision; - if (fact == 0) - fact = 1; - return (*(int *) arg = fact); - } - - if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; - - if (fact > MAX_REALTIME_FACTOR) - return -EINVAL; - - if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return -EINVAL; - - dmap->subdivision = fact; - return (*(int *) arg = fact); + if (fact == 0) + { + fact = dmap->subdivision; + if (fact == 0) + fact = 1; + return (*(int *) arg = fact); + } + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; + + if (fact > MAX_REALTIME_FACTOR) + return -EINVAL; + + if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) + return -EINVAL; + + dmap->subdivision = fact; + return (*(int *) arg = fact); } static int -dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) { - int bytes, count; + int bytes, count; - if (fact == 0) - return -EIO; + if (fact == 0) + return -EIO; - if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; - bytes = fact & 0xffff; - count = (fact >> 16) & 0x7fff; + bytes = fact & 0xffff; + count = (fact >> 16) & 0x7fff; - if (count == 0) - count = MAX_SUB_BUFFERS; - else if (count < MAX_SUB_BUFFERS) - count++; + if (count == 0) + count = MAX_SUB_BUFFERS; + else if (count < MAX_SUB_BUFFERS) + count++; - if (bytes < 4 || bytes > 17) /* <16 || > 512k */ - return -EINVAL; + if (bytes < 4 || bytes > 17) /* <16 || > 512k */ + return -EINVAL; - if (count < 2) - return -EINVAL; + if (count < 2) + return -EINVAL; - if (audio_devs[dev]->min_fragment > 0) - if (bytes < audio_devs[dev]->min_fragment) - bytes = audio_devs[dev]->min_fragment; + if (audio_devs[dev]->min_fragment > 0) + if (bytes < audio_devs[dev]->min_fragment) + bytes = audio_devs[dev]->min_fragment; - if (audio_devs[dev]->max_fragment > 0) - if (bytes > audio_devs[dev]->max_fragment) - bytes = audio_devs[dev]->max_fragment; + if (audio_devs[dev]->max_fragment > 0) + if (bytes > audio_devs[dev]->max_fragment) + bytes = audio_devs[dev]->max_fragment; #ifdef OS_DMA_MINBITS - if (bytes < OS_DMA_MINBITS) - bytes = OS_DMA_MINBITS; + if (bytes < OS_DMA_MINBITS) + bytes = OS_DMA_MINBITS; #endif - dmap->fragment_size = (1 << bytes); - dmap->max_fragments = count; + dmap->fragment_size = (1 << bytes); + dmap->max_fragments = count; - if (dmap->fragment_size > dmap->buffsize) - dmap->fragment_size = dmap->buffsize; + if (dmap->fragment_size > dmap->buffsize) + dmap->fragment_size = dmap->buffsize; - if (dmap->fragment_size == dmap->buffsize && - audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->fragment_size /= 2; /* Needs at least 2 buffers */ + if (dmap->fragment_size == dmap->buffsize && + audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->fragment_size /= 2; /* Needs at least 2 buffers */ - dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - if (arg) - return (*(int *) arg = bytes | ((count - 1) << 16)); - else - return 0; + dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ + if (arg) + return (*(int *) arg = bytes | ((count - 1) << 16)); + else + return 0; } -static int -dma_ioctl (int dev, unsigned int cmd, caddr_t arg) +int +dma_ioctl(int dev, unsigned int cmd, caddr_t arg) { - struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; - struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; - - switch (cmd) - { - - case SNDCTL_DSP_SUBDIVIDE: - { - int fact; - int ret = 0; - - fact = *(int *) arg; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_subdivide (dev, dmap_out, arg, fact); - if (ret < 0) - return ret; - - if (audio_devs[dev]->open_mode != OPEN_WRITE || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_subdivide (dev, dmap_in, arg, fact); - - return ret; - } - break; - - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_GETOSPACE: - { - struct dma_buffparms *dmap = dmap_out; - - audio_buf_info *info = (audio_buf_info *) arg; + struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; - if (cmd == SNDCTL_DSP_GETISPACE && - !(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; + switch (cmd) + { - if (cmd == SNDCTL_DSP_GETOSPACE && - !(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; + case SNDCTL_DSP_SUBDIVIDE: + { + int fact; + int ret = 0; - if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) - dmap = dmap_in; + fact = *(int *) arg; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -EINVAL; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + ret = dma_subdivide(dev, dmap_out, arg, fact); + if (ret < 0) + return ret; - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + ret = dma_subdivide(dev, dmap_in, arg, fact); - info->fragstotal = dmap->nbufs; + return ret; + } + break; - if (cmd == SNDCTL_DSP_GETISPACE) - info->fragments = dmap->qlen; - else - { - if (!DMAbuf_space_in_queue (dev)) - info->fragments = 0; - else - { - info->fragments = DMAbuf_space_in_queue (dev); - if (audio_devs[dev]->d->local_qlen) + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_GETOSPACE: { - int tmp = audio_devs[dev]->d->local_qlen (dev); - - if (tmp && info->fragments) - tmp--; /* - * This buffer has been counted twice - */ - info->fragments -= tmp; + struct dma_buffparms *dmap = dmap_out; + + audio_buf_info *info = (audio_buf_info *) arg; + + if (cmd == SNDCTL_DSP_GETISPACE && + !(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + if (cmd == SNDCTL_DSP_GETOSPACE && + !(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) + dmap = dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return -EINVAL; + + if (!(dmap->flags & DMA_ALLOC_DONE)) + reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + + info->fragstotal = dmap->nbufs; + + if (cmd == SNDCTL_DSP_GETISPACE) + info->fragments = dmap->qlen; + else + { + if (!DMAbuf_space_in_queue(dev)) + info->fragments = 0; + else + { + info->fragments = DMAbuf_space_in_queue(dev); + if (audio_devs[dev]->d->local_qlen) + { + int tmp = audio_devs[dev]->d->local_qlen(dev); + + if (tmp && info->fragments) + tmp--; /* + * This buffer has been counted twice + */ + info->fragments -= tmp; + } + } + } + + if (info->fragments < 0) + info->fragments = 0; + else if (info->fragments > dmap->nbufs) + info->fragments = dmap->nbufs; + + info->fragsize = dmap->fragment_size; + info->bytes = info->fragments * dmap->fragment_size; + + if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) + info->bytes -= dmap->counts[dmap->qhead]; + else + { + info->fragments = info->bytes / dmap->fragment_size; + info->bytes -= dmap->user_counter % dmap->fragment_size; + } } - } - } - - if (info->fragments < 0) - info->fragments = 0; - else if (info->fragments > dmap->nbufs) - info->fragments = dmap->nbufs; - - info->fragsize = dmap->fragment_size; - info->bytes = info->fragments * dmap->fragment_size; - - if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) - info->bytes -= dmap->counts[dmap->qhead]; - } - return 0; + return 0; - case SNDCTL_DSP_SETTRIGGER: - { - unsigned long flags; + case SNDCTL_DSP_SETTRIGGER: + { + unsigned long flags; + + int bits; + int changed; + + bits = *(int *) arg; + bits &= audio_devs[dev]->open_mode; + + if (audio_devs[dev]->d->trigger == NULL) + return -EINVAL; + + if (!(audio_devs[dev]->flags & DMA_DUPLEX)) + if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) + { + printk("Sound: Device doesn't have full duplex capability\n"); + return -EINVAL; + } + save_flags(flags); + cli(); + changed = audio_devs[dev]->enable_bits ^ bits; + + if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) + { + int err; + + reorganize_buffers(dev, dmap_in, 1); + + if ((err = audio_devs[dev]->d->prepare_for_input(dev, + dmap_in->fragment_size, dmap_in->nbufs)) < 0) + return -err; + + dmap_in->dma_mode = DMODE_INPUT; + audio_devs[dev]->enable_bits = bits; + DMAbuf_activate_recording(dev, dmap_in); + } + if ((changed & bits) & PCM_ENABLE_OUTPUT && + (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && + audio_devs[dev]->go) + { + + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + { + reorganize_buffers(dev, dmap_out, 0); + } + dmap_out->dma_mode = DMODE_OUTPUT; + ; + audio_devs[dev]->enable_bits = bits; + dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; + DMAbuf_launch_output(dev, dmap_out); + ; + } + audio_devs[dev]->enable_bits = bits; + if (changed && audio_devs[dev]->d->trigger) + { + audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); + } + restore_flags(flags); + } + case SNDCTL_DSP_GETTRIGGER: + return (*(int *) arg = audio_devs[dev]->enable_bits); + break; - int bits; - int changed; + case SNDCTL_DSP_SETSYNCRO: - bits = *(int *) arg; - bits &= audio_devs[dev]->open_mode; + if (!audio_devs[dev]->d->trigger) + return -EINVAL; - if (audio_devs[dev]->d->trigger == NULL) - return -EINVAL; + audio_devs[dev]->d->trigger(dev, 0); + audio_devs[dev]->go = 0; + return 0; + break; - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) - { - printk ("Sound: Device doesn't have full duplex capability\n"); - return -EINVAL; - } + case SNDCTL_DSP_GETIPTR: + { + count_info info; + unsigned long flags; + struct dma_buffparms *dmap = dmap_in; + + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + save_flags(flags); + cli(); + info.bytes = dmap->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_INPUT) & ~3; + if (info.ptr < dmap->fragment_size && dmap->qtail != 0) + info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + + info.blocks = dmap->qlen; + info.bytes += info.ptr; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + dmap->qlen = 0; /* Reset interrupt counter */ + restore_flags(flags); + return 0; + } + break; - save_flags (flags); - cli (); - changed = audio_devs[dev]->enable_bits ^ bits; + case SNDCTL_DSP_GETOPTR: + { + count_info info; + unsigned long flags; + struct dma_buffparms *dmap = dmap_out; + + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + save_flags(flags); + cli(); + info.bytes = dmap->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT) & ~3; + if (info.ptr < dmap->fragment_size && dmap->qhead != 0) + info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + info.blocks = dmap->qlen; + info.bytes += info.ptr; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + dmap->qlen = 0; /* Reset interrupt counter */ + + restore_flags(flags); + return 0; + } + break; - if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) - { - int err; - reorganize_buffers (dev, dmap_in, 1); + case SNDCTL_DSP_POST: + ; + if (audio_devs[dev]->dmap_out->qlen > 0) + if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); + ; + return 0; + break; - if ((err = audio_devs[dev]->d->prepare_for_input (dev, - dmap_in->fragment_size, dmap_in->nbufs)) < 0) - return -err; + case SNDCTL_DSP_GETBLKSIZE: + { + int fragment_size; + struct dma_buffparms *dmap = dmap_out; + + if (audio_devs[dev]->open_mode & OPEN_WRITE) + reorganize_buffers(dev, dmap_out, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + reorganize_buffers(dev, dmap_in, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode == OPEN_READ) + dmap = dmap_in; + fragment_size = dmap->fragment_size; + return (*(int *) arg = fragment_size); + } + break; - dmap_in->dma_mode = DMODE_INPUT; - audio_devs[dev]->enable_bits = bits; - DMAbuf_activate_recording (dev, dmap_in); - } + case SNDCTL_DSP_SETFRAGMENT: + { + int fact; + int ret; + fact = *(int *) arg; + ret = dma_set_fragment(dev, dmap_out, arg, fact); + if (ret < 0) + return ret; - if ((changed & bits) & PCM_ENABLE_OUTPUT && - (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && - audio_devs[dev]->go) - { + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + ret = dma_set_fragment(dev, dmap_in, arg, fact); - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - { - reorganize_buffers (dev, dmap_out, 0); - } - - dmap_out->dma_mode = DMODE_OUTPUT; - ; - audio_devs[dev]->enable_bits = bits; - dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; - DMAbuf_launch_output (dev, dmap_out); - ; - } + return ret; + } + break; - audio_devs[dev]->enable_bits = bits; - if (changed && audio_devs[dev]->d->trigger) - { - audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); + default: + return audio_devs[dev]->d->ioctl(dev, cmd, arg); } - restore_flags (flags); - } - case SNDCTL_DSP_GETTRIGGER: - return (*(int *) arg = audio_devs[dev]->enable_bits); - break; - - case SNDCTL_DSP_SETSYNCRO: - - if (!audio_devs[dev]->d->trigger) - return -EINVAL; - - audio_devs[dev]->d->trigger (dev, 0); - audio_devs[dev]->go = 0; - return 0; - break; - - case SNDCTL_DSP_GETIPTR: - { - count_info info; - unsigned long flags; - struct dma_buffparms *dmap = dmap_in; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - - save_flags (flags); - cli (); - info.bytes = dmap->byte_counter; - info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_INPUT) & ~3; - if (info.ptr < dmap->fragment_size && dmap->qtail != 0) - info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - - info.blocks = dmap->qlen; - info.bytes += info.ptr; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - dmap->qlen = 0; /* Reset interrupt counter */ - restore_flags (flags); - return 0; - } - break; - - case SNDCTL_DSP_GETOPTR: - { - count_info info; - unsigned long flags; - struct dma_buffparms *dmap = dmap_out; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - - save_flags (flags); - cli (); - info.bytes = dmap->byte_counter; - info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT) & ~3; - if (info.ptr < dmap->fragment_size && dmap->qhead != 0) - info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - info.blocks = dmap->qlen; - info.bytes += info.ptr; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - dmap->qlen = 0; /* Reset interrupt counter */ - - restore_flags (flags); - return 0; - } - break; - - - case SNDCTL_DSP_POST: - ; - if (audio_devs[dev]->dmap_out->qlen > 0) - if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) - DMAbuf_launch_output (dev, audio_devs[dev]->dmap_out); - ; - return 0; - break; - - case SNDCTL_DSP_GETBLKSIZE: - { - int fragment_size; - struct dma_buffparms *dmap = dmap_out; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - reorganize_buffers (dev, dmap_out, - (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode != OPEN_WRITE || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - reorganize_buffers (dev, dmap_in, - (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode == OPEN_READ) - dmap = dmap_in; - fragment_size = dmap->fragment_size; - return (*(int *) arg = fragment_size); - } - break; - - case SNDCTL_DSP_SETFRAGMENT: - { - int fact; - int ret; - - fact = *(int *) arg; - ret = dma_set_fragment (dev, dmap_out, arg, fact); - if (ret < 0) - return ret; - - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ) - ret = dma_set_fragment (dev, dmap_in, arg, fact); - - return ret; - } - break; - - default: - return audio_devs[dev]->d->ioctl (dev, cmd, arg); - } } diff --git a/drivers/sound/configure.c b/drivers/sound/configure.c index 6b50a3aa5..aea32b388 100644 --- a/drivers/sound/configure.c +++ b/drivers/sound/configure.c @@ -45,18 +45,20 @@ #define OPT_MAD16 12 #define OPT_CS4232 13 #define OPT_MAUI 14 -#define OPT_SPNP 15 - -#define OPT_HIGHLEVEL 16 /* This must be same than the next one */ -#define OPT_UNUSED1 16 -#define OPT_UNUSED2 17 -#define OPT_AEDSP16 18 -#define OPT_UNUSED3 19 -#define OPT_UNUSED4 20 -#define OPT_UNUSED5 21 -#define OPT_YM3812_AUTO 22 -#define OPT_YM3812 23 -#define OPT_LAST 23 /* Last defined OPT number */ +#define OPT_SPNP 15 +#define OPT_OPL3SA1 16 +#define OPT_SOFTOSS 17 + +#define OPT_HIGHLEVEL 18 /* This must be same than the next one */ +#define OPT_UNUSED1 18 +#define OPT_UNUSED2 19 +#define OPT_AEDSP16 20 +#define OPT_UNUSED3 21 +#define OPT_UNUSED4 22 +#define OPT_UNUSED5 23 +#define OPT_YM3812_AUTO 24 +#define OPT_YM3812 25 +#define OPT_LAST 25 /* Last defined OPT number */ #define DUMMY_OPTS (B(OPT_YM3812_AUTO)) @@ -64,16 +66,17 @@ B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \ B(OPT_MSS)|B(OPT_SSCAPE)|B(OPT_UART6850)|B(OPT_TRIX)| \ B(OPT_MAD16)|B(OPT_CS4232)|B(OPT_MAUI)|B(OPT_ADLIB)| \ - B(OPT_SPNP)) + B(OPT_SPNP)|B(OPT_OPL3SA1)|B(OPT_SOFTOSS)) #define MPU_DEVS (B(OPT_PSS)|\ B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)|B(OPT_SSCAPE)) -#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SPNP)) +#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SPNP)|\ + B(OPT_OPL3SA1)) #define NON_AUDIO_CARDS (B(OPT_ADLIB)|B(OPT_MPU401)|B(OPT_UART6850)|B(OPT_MAUI)) #define AUDIO_CARDS (ANY_DEVS & ~NON_AUDIO_CARDS) #define MIDI_CARDS (ANY_DEVS & ~(B(OPT_ADLIB)|B(OPT_MSS))) #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\ B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\ - B(OPT_SPNP)) + B(OPT_SPNP)|B(OPT_OPL3SA1)) #define SBDSP_DEVS (B(OPT_SB)|B(OPT_SPNP)|B(OPT_MAD16)|B(OPT_TRIX)) #define SEQUENCER_DEVS 0x7fffffff /* @@ -84,12 +87,12 @@ typedef struct { - unsigned long conditions; - unsigned long exclusive_options; - char macro[20]; - int verify; - int alias; - int default_answ; + unsigned long conditions; + unsigned long exclusive_options; + char macro[20]; + int verify; + int alias; + int default_answ; } hw_entry; @@ -114,200 +117,209 @@ hw_entry hw_table[] = /* * 0 */ - {0, 0, "PAS", 1, 0, 0}, - {0, 0, "SB", 1, 0, 0}, - {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0}, - - {0, 0, "GUS", 1, 0, 0}, - {0, 0, "MPU401", 1, 0, 0}, - {0, 0, "UART6850", 1, 0, 0}, - {0, 0, "PSS", 1, 0, 0}, - {B (OPT_GUS), 0, "GUS16", 1, 0, 0}, - {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0}, - {0, 0, "MSS", 1, 0, 0}, - {0, 0, "SSCAPE", 1, 0, 0}, - {0, 0, "TRIX", 1, 0, 0}, - {0, 0, "MAD16", 1, 0, 0}, - {0, 0, "CS4232", 1, 0, 0}, - {0, 0, "MAUI", 1, 0, 0}, - {0, 0, "SPNP", 1, 0, 0}, - - {B (OPT_SB), B (OPT_PAS), "UNUSED1", 1, 0, 1}, - {B (OPT_SB) | B (OPT_UNUSED1), B (OPT_PAS), "UNUSED2", 1, 0, 1}, - {B (OPT_UNUSED1) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0}, - {AUDIO_CARDS, 0, "UNUSED3", 1, 0, 1}, - {B (OPT_MPU401) | B (OPT_MAUI), 0, "UNUSED4", 0, 0, 0}, - {MIDI_CARDS, 0, "UNUSED5", 1, 0, 1}, - {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, - {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1} + {0, 0, "PAS", 1, 0, 0}, + {0, 0, "SB", 1, 0, 0}, + {0, B(OPT_PAS) | B(OPT_SB), "ADLIB", 1, 0, 0}, + + {0, 0, "GUS", 1, 0, 0}, + {0, 0, "MPU401", 1, 0, 0}, + {0, 0, "UART6850", 1, 0, 0}, + {0, 0, "PSS", 1, 0, 0}, + {B(OPT_GUS), 0, "GUS16", 1, 0, 0}, + {B(OPT_GUS), B(OPT_GUS16), "GUSMAX", 1, 0, 0}, + {0, 0, "MSS", 1, 0, 0}, + {0, 0, "SSCAPE", 1, 0, 0}, + {0, 0, "TRIX", 1, 0, 0}, + {0, 0, "MAD16", 1, 0, 0}, + {0, 0, "CS4232", 1, 0, 0}, + {0, 0, "MAUI", 1, 0, 0}, + {0, 0, "SPNP", 1, 0, 0}, + {0, 0, "OPL3SA1", 1, 0, 0}, + {0, 0, "SOFTOSS", 1, 0, 0}, + + {B(OPT_SB), B(OPT_PAS), "UNUSED1", 1, 0, 1}, + {B(OPT_SB) | B(OPT_UNUSED1), B(OPT_PAS), "UNUSED2", 1, 0, 1}, + {B(OPT_UNUSED1) | B(OPT_MSS) | B(OPT_MPU401), 0, "AEDSP16", 1, 0, 0}, + {AUDIO_CARDS, 0, "UNUSED3", 1, 0, 1}, + {B(OPT_MPU401) | B(OPT_MAUI), 0, "UNUSED4", 0, 0, 0}, + {MIDI_CARDS, 0, "UNUSED5", 1, 0, 1}, + {B(OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, + {B(OPT_PSS) | B(OPT_SB) | B(OPT_PAS) | B(OPT_ADLIB) | B(OPT_MSS) | B(OPT_PSS), B(OPT_YM3812_AUTO), "YM3812", 1, 0, 1} }; char *questions[] = { - "ProAudioSpectrum 16 support", - "100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support", - "Generic OPL2/OPL3 FM synthesizer support", - "Gravis Ultrasound support", - "MPU-401 support (NOT for SB16)", - "6850 UART Midi support", - "PSS (ECHO-ADI2111) support", - "16 bit sampling option of GUS (_NOT_ GUS MAX)", - "GUS MAX support", - "Microsoft Sound System support", - "Ensoniq SoundScape support", - "MediaTrix AudioTrix Pro support", - "Support for MAD16 and/or Mozart based cards", - "Support for Crystal CS4232 based (PnP) cards", - "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers", - "Support for PnP sound cards (_EXPERIMENTAL_)", - - "*** Unused option 1 ***", - "*** Unused option 2 ***", - "Audio Excel DSP 16 initialization support", - "*** Unused option 3 ***", - "*** Unused option 4 ***", - "*** Unused option 5 ***", - "This should not be asked", - "FM synthesizer (YM3812/OPL-3) support", - "Is the sky really falling" + "ProAudioSpectrum 16 support", + "100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support", + "Generic OPL2/OPL3 FM synthesizer support", + "Gravis Ultrasound support", + "MPU-401 support (NOT for SB16)", + "6850 UART Midi support", + "PSS (ECHO-ADI2111) support", + "16 bit sampling option of GUS (_NOT_ GUS MAX)", + "GUS MAX support", + "Microsoft Sound System support", + "Ensoniq SoundScape support", + "MediaTrix AudioTrix Pro support", + "Support for OPTi MAD16 and/or Mozart based cards", + "Support for Crystal CS4232 based (PnP) cards", + "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers", + "Support for PnP sound cards (_EXPERIMENTAL_)", + "Yamaha OPL3-SA1 audio controller", + "SoftOSS software wave table engine", + + "*** Unused option 1 ***", + "*** Unused option 2 ***", + "Audio Excel DSP 16 initialization support", + "*** Unused option 3 ***", + "*** Unused option 4 ***", + "*** Unused option 5 ***", + "This should not be asked", + "FM synthesizer (YM3812/OPL-3) support", + "Is the sky really falling" }; /* help text for each option */ char *help[] = { - "Enable this option only if you have a Pro Audio Spectrum 16,\n" - "Pro Audio Studio 16, or Logitech SoundMan 16. Don't enable this if\n" - "you have some other card made by MediaVision or Logitech as\n" - "they are not PAS16 compatible.\n", + "Enable this option only if you have a Pro Audio Spectrum 16,\n" + "Pro Audio Studio 16, or Logitech SoundMan 16. Don't enable this if\n" + "you have some other card made by MediaVision or Logitech as\n" + "they are not PAS16 compatible.\n", - "Enable this if you have an original Sound Blaster card made by\n" - "Creative Labs or a 100%% hardware compatible clone. For an\n" - "unknown card you may want to try this if it claims to be\n" - "Sound Blaster compatible.\n", + "Enable this if you have an original Sound Blaster card made by\n" + "Creative Labs or a 100%% hardware compatible clone. For an\n" + "unknown card you may want to try this if it claims to be\n" + "Sound Blaster compatible.\n", - "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n" - "FM synthesizer chip.\n", + "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n" + "FM synthesizer chip.\n", - "Enable this option for any type of Gravis Ultrasound card\n" - "including the GUS or GUS MAX.\n", + "Enable this option for any type of Gravis Ultrasound card\n" + "including the GUS or GUS MAX.\n", - "The MPU401 interface is supported by almost all sound cards. However,\n" - "some natively supported cards have their own driver for\n" - "MPU401. Enabling the MPU401 option with these cards will cause a\n" - "conflict. Also enabling MPU401 on a system that doesn't really have a\n" - "MPU401 could cause some trouble. It's safe to enable this if you have a\n" - "true MPU401 MIDI interface card.\n", +"The MPU401 interface is supported by almost all sound cards. However,\n" + "some natively supported cards have their own driver for\n" + "MPU401. Enabling the MPU401 option with these cards will cause a\n" +"conflict. Also enabling MPU401 on a system that doesn't really have a\n" + "MPU401 could cause some trouble. It's safe to enable this if you have a\n" + "true MPU401 MIDI interface card.\n", - "This option enables support for MIDI interfaces based on the 6850\n" - "UART chip. This interface is rarely found on sound cards.\n", + "This option enables support for MIDI interfaces based on the 6850\n" + "UART chip. This interface is rarely found on sound cards.\n", - "Enable this option if you have an Orchid SW32, Cardinal DSP16 or other\n" - "sound card based on the PSS chipset (AD1848 codec, ADSP-2115 DSP chip,\n" - "and Echo ESC614 ASIC CHIP).\n", +"Enable this option if you have an Orchid SW32, Cardinal DSP16 or other\n" +"sound card based on the PSS chipset (AD1848 codec, ADSP-2115 DSP chip,\n" + "and Echo ESC614 ASIC CHIP).\n", - "Enable this if you have installed the 16-bit sampling daughtercard on\n" - "your GUS card. Do not use if you have a GUS MAX as enabling this option\n" - "disables GUS MAX support.\n", +"Enable this if you have installed the 16-bit sampling daughtercard on\n" + "your GUS card. Do not use if you have a GUS MAX as enabling this option\n" + "disables GUS MAX support.\n", - "Enable this option if you have a Gravis Ultrasound MAX sound\n" - "card\n", + "Enable this option if you have a Gravis Ultrasound MAX sound\n" + "card\n", - "Enable this option if you have the original Windows Sound System\n" - "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n", + "Enable this option if you have the original Windows Sound System\n" + "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n", - "Enable this if you have a sound card based on the Ensoniq\n" - "SoundScape chipset. Such cards are being manufactured by Ensoniq,\n" - "Spea and Reveal (Reveal makes other cards as well).\n", + "Enable this if you have a sound card based on the Ensoniq\n" + "SoundScape chipset. Such cards are being manufactured by Ensoniq,\n" + "Spea and Reveal (Reveal makes other cards as well).\n", - "Enable this option if you have the AudioTrix Pro sound card\n" - "manufactured by MediaTrix.\n", + "Enable this option if you have the AudioTrix Pro sound card\n" + "manufactured by MediaTrix.\n", - "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n" - "82C928 or 82C929) audio interface chip. These chips are currently\n" - "quite common so it's possible that many no-name cards have one of\n" - "them. In addition the MAD16 chip is used in some cards made by known\n" - "manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n" - "Diamond (latest ones).\n", + "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n" + "82C928 or 82C929) audio interface chip. These chips are currently\n" + "quite common so it's possible that many no-name cards have one of\n" + "them. In addition the MAD16 chip is used in some cards made by known\n" +"manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n" + "Diamond (latest ones).\n", - "Enable this if you have a card based on the Crystal CS4232 chip set.\n", +"Enable this if you have a card based on the Crystal CS4232 chip set.\n", - "Enable this option if you have a Turtle Beach Wave Front, Maui,\n" - "or Tropez sound card.\n", + "Enable this option if you have a Turtle Beach Wave Front, Maui,\n" + "or Tropez sound card.\n", - "Use this option to enable experimental support for cards that\n" - "use the Plug and Play protocol.\n", + "Use this option to enable experimental support for cards that\n" + "use the Plug and Play protocol.\n", - "Enable this option if your card is a Sound Blaster Pro or\n" - "Sound Blaster 16. It also works with many Sound Blaster Pro clones.\n", + "Use this option with Yamaha OPL3-SA1 (YMF701) chip.\n", - "Enable this if you have a Sound Blaster 16, including the AWE32.\n", +"SoftOSS is a virtual wave table engine by 4Front Technologies. It can\n" + "be used together with any 16 bit stereo soundcard.\n" - "Enable this if you have an Audio Excel DSP16 card. See the file\n" - "Readme.aedsp16 for more information.\n", + "Enable this option if your card is a Sound Blaster Pro or\n" + "Sound Blaster 16. It also works with many Sound Blaster Pro clones.\n", - "This option enables the A/D and D/A converter (PCM) devices\n" - "supported by almost all sound cards.\n", + "Enable this if you have a Sound Blaster 16, including the AWE32.\n", - "This should not be asked", + "Enable this if you have an Audio Excel DSP16 card. See the file\n" + "Readme.aedsp16 for more information.\n", - "This enables the dev/midixx devices and access to any MIDI ports\n" - "using /dev/sequencer and /dev/music. This option also affects any\n" - "MPU401 and/or General MIDI compatible devices.\n", + "This option enables the A/D and D/A converter (PCM) devices\n" + "supported by almost all sound cards.\n", - "This should not be asked", + "This should not be asked", - "This enables the Yamaha FM synthesizer chip used on many sound\n" - "cards.\n", + "This enables the dev/midixx devices and access to any MIDI ports\n" + "using /dev/sequencer and /dev/music. This option also affects any\n" + "MPU401 and/or General MIDI compatible devices.\n", - "Is the sky really falling" + "This should not be asked", + + "This enables the Yamaha FM synthesizer chip used on many sound\n" + "cards.\n", + + "Is the sky really falling" }; struct kludge { - char *name; - int mask; + char *name; + int mask; } extra_options[] = { - { - "MPU_EMU", MPU_DEVS - } - , - { - "AD1848", AD1848_DEVS - } - , - { - "SBDSP", SBDSP_DEVS - } - , - { - "UART401", UART401_DEVS - } - , - { - "GUSHW", B (OPT_GUS) | B (OPT_SPNP) - } - , - { - "SSCAPEHW", B (OPT_SSCAPE) | B (OPT_SPNP) - } - , - { - "SEQUENCER", SEQUENCER_DEVS - } - , - { - "AUDIO", AUDIO_CARDS - } - , - { - "MIDI", MIDI_CARDS - } - , - { - NULL, 0 - } + { + "MPU_EMU", MPU_DEVS + } + , + { + "AD1848", AD1848_DEVS + } + , + { + "SBDSP", SBDSP_DEVS + } + , + { + "UART401", UART401_DEVS + } + , + { + "GUSHW", B(OPT_GUS) | B(OPT_SPNP) + } + , + { + "SSCAPEHW", B(OPT_SSCAPE) | B(OPT_SPNP) + } + , + { + "SEQUENCER", SEQUENCER_DEVS + } + , + { + "AUDIO", AUDIO_CARDS + } + , + { + "MIDI", MIDI_CARDS + } + , + { + NULL, 0 + } }; char *oldconf = "/etc/soundconf"; @@ -320,1330 +332,1338 @@ int sb_dma = 0; int dump_only = 0; -void build_defines (void); +void build_defines(void); #include "hex2hex.h" -int bin2hex (char *path, char *target, char *varname); +int bin2hex(char *path, char *target, char *varname); int -can_select_option (int nr) +can_select_option(int nr) { - if (hw_table[nr].conditions) - if (!(hw_table[nr].conditions & selected_options)) - return 0; + if (hw_table[nr].conditions) + if (!(hw_table[nr].conditions & selected_options)) + return 0; - if (hw_table[nr].exclusive_options) - if (hw_table[nr].exclusive_options & selected_options) - return 0; + if (hw_table[nr].exclusive_options) + if (hw_table[nr].exclusive_options & selected_options) + return 0; - if (DISABLED_OPTIONS & B (nr)) - return 0; + if (DISABLED_OPTIONS & B(nr)) + return 0; - return 1; + return 1; } int -think_positively (char *prompt, int def_answ, char *help) +think_positively(char *prompt, int def_answ, char *help) { - char answ[512]; - int len; - -response: - fprintf (stderr, prompt); - if (def_answ) - fprintf (stderr, " [Y/n/?] "); - else - fprintf (stderr, " [N/y/?] "); - - if ((len = read (0, answ, sizeof (answ))) < 1) - { - fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); - - perror ("stdin"); - printf ("invalid_configuration__run_make_config_again\n"); - exit (-1); - } - - if (len < 2) /* - * There is an additional LF at the end - */ - return def_answ; + char answ[512]; + int len; + + response: + fprintf(stderr, prompt); + if (def_answ) + fprintf(stderr, " [Y/n/?] "); + else + fprintf(stderr, " [N/y/?] "); - if (answ[0] == '?') - { /* display help message */ - fprintf (stderr, "\n"); - fprintf (stderr, help); - fprintf (stderr, "\n"); - goto response; - } + if ((len = read(0, answ, sizeof(answ))) < 1) + { + fprintf(stderr, "\n\nERROR! Cannot read stdin\n"); - answ[len - 1] = 0; + perror("stdin"); + printf("invalid_configuration__run_make_config_again\n"); + exit(-1); + } + if (len < 2) /* + * There is an additional LF at the end + */ + return def_answ; + + if (answ[0] == '?') + { /* display help message */ + fprintf(stderr, "\n"); + fprintf(stderr, help); + fprintf(stderr, "\n"); + goto response; + } + answ[len - 1] = 0; - if (!strcmp (answ, "y") || !strcmp (answ, "Y")) - return 1; + if (!strcmp(answ, "y") || !strcmp(answ, "Y")) + return 1; - return 0; + return 0; } int -ask_value (char *format, int default_answer) +ask_value(char *format, int default_answer) { - char answ[512]; - int len, num; + char answ[512]; + int len, num; -play_it_again_Sam: + play_it_again_Sam: - if ((len = read (0, answ, sizeof (answ))) < 1) - { - fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); - - perror ("stdin"); - printf ("invalid_configuration__run_make_config_again\n"); - exit (-1); - } + if ((len = read(0, answ, sizeof(answ))) < 1) + { + fprintf(stderr, "\n\nERROR! Cannot read stdin\n"); - if (len < 2) /* + perror("stdin"); + printf("invalid_configuration__run_make_config_again\n"); + exit(-1); + } + if (len < 2) /* * There is an additional LF at the end */ - return default_answer; - - answ[len - 1] = 0; + return default_answer; - if (sscanf (answ, format, &num) != 1) - { - fprintf (stderr, "Illegal format. Try again: "); - goto play_it_again_Sam; - } + answ[len - 1] = 0; - return num; + if (sscanf(answ, format, &num) != 1) + { + fprintf(stderr, "Illegal format. Try again: "); + goto play_it_again_Sam; + } + return num; } #define FMT_HEX 1 #define FMT_INT 2 void -show_comment (int mask, char *txt) +show_comment(int mask, char *txt) { - int i; + int i; - if (dump_only) - { + if (dump_only) + { - for (i = 0; i < OPT_LAST; i++) - if (mask == B (i)) + for (i = 0; i < OPT_LAST; i++) + if (mask == B(i)) + { + printf("\n\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", + hw_table[i].macro); + printf("comment '%s'\n", txt); + printf("fi\n"); + } + } else { - printf ("\n\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", - hw_table[i].macro); - printf ("comment '%s'\n", txt); - printf ("fi\n"); + if (!(mask & selected_options)) + return; + + fprintf(stderr, "%s\n", txt); } - } - else - { - if (!(mask & selected_options)) - return; - - fprintf (stderr, "%s\n", txt); - } } void -ask_int_choice (int mask, char *macro, - char *question, - int format, - int defa, - char *choices) +ask_int_choice(int mask, char *macro, + char *question, + int format, + int defa, + char *choices) { - int num, i; + int num, i; - if (dump_only) - { + if (dump_only) + { - for (i = 0; i < OPT_LAST; i++) - if (mask == B (i)) + for (i = 0; i < OPT_LAST; i++) + if (mask == B(i)) + { + unsigned int j; + + for (j = 0; j < strlen(choices); j++) + if (choices[j] == '\'') + choices[j] = '_'; + + printf("\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", + hw_table[i].macro); + if (format == FMT_INT) + printf("int '%s %s' %s %d\n", question, choices, macro, defa); + else + printf("hex '%s %s' %s %x\n", question, choices, macro, defa); + printf("fi\n"); + } + } else { - unsigned int j; - - for (j = 0; j < strlen (choices); j++) - if (choices[j] == '\'') - choices[j] = '_'; - - printf ("\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", - hw_table[i].macro); - if (format == FMT_INT) - printf ("int '%s %s' %s %d\n", question, choices, macro, defa); - else - printf ("hex '%s %s' %s %x\n", question, choices, macro, defa); - printf ("fi\n"); - } - } - else - { - if (!(mask & selected_options)) - return; + if (!(mask & selected_options)) + return; - fprintf (stderr, "\n%s\n", question); - if (strcmp (choices, "")) - fprintf (stderr, "Possible values are: %s\n", choices); + fprintf(stderr, "\n%s\n", question); + if (strcmp(choices, "")) + fprintf(stderr, "Possible values are: %s\n", choices); - if (format == FMT_INT) - { - if (defa == -1) - fprintf (stderr, "\t(-1 disables this feature)\n"); - fprintf (stderr, "The default value is %d\n", defa); - fprintf (stderr, "Enter the value: "); - num = ask_value ("%d", defa); - if (num == -1) - return; - fprintf (stderr, "%s set to %d.\n", question, num); - printf ("#define %s %d\n", macro, num); - } - else - { - if (defa == 0) - fprintf (stderr, "\t(0 disables this feature)\n"); - fprintf (stderr, "The default value is %x\n", defa); - fprintf (stderr, "Enter the value: "); - num = ask_value ("%x", defa); - if (num == 0) - return; - fprintf (stderr, "%s set to %x.\n", question, num); - printf ("#define %s 0x%x\n", macro, num); - } - } + if (format == FMT_INT) + { + if (defa == -1) + fprintf(stderr, "\t(-1 disables this feature)\n"); + fprintf(stderr, "The default value is %d\n", defa); + fprintf(stderr, "Enter the value: "); + num = ask_value("%d", defa); + if (num == -1) + return; + fprintf(stderr, "%s set to %d.\n", question, num); + printf("#define %s %d\n", macro, num); + } else + { + if (defa == 0) + fprintf(stderr, "\t(0 disables this feature)\n"); + fprintf(stderr, "The default value is %x\n", defa); + fprintf(stderr, "Enter the value: "); + num = ask_value("%x", defa); + if (num == 0) + return; + fprintf(stderr, "%s set to %x.\n", question, num); + printf("#define %s 0x%x\n", macro, num); + } + } } void -rebuild_file (char *line) +rebuild_file(char *line) { - char *method, *next, *old, *var, *p; + char *method, *next, *old, *var, *p; - method = p = line; + method = p = line; - while (*p && *p != ' ') - p++; - *p++ = 0; + while (*p && *p != ' ') + p++; + *p++ = 0; - old = p; - while (*p && *p != ' ') - p++; - *p++ = 0; + old = p; + while (*p && *p != ' ') + p++; + *p++ = 0; - next = p; - while (*p && *p != ' ') - p++; - *p++ = 0; + next = p; + while (*p && *p != ' ') + p++; + *p++ = 0; - var = p; - while (*p && *p != ' ') - p++; - *p++ = 0; + var = p; + while (*p && *p != ' ') + p++; + *p++ = 0; - fprintf (stderr, "Rebuilding file `%s' (%s %s)\n", next, method, old); + fprintf(stderr, "Rebuilding file `%s' (%s %s)\n", next, method, old); - if (strcmp (method, "bin2hex") == 0) - { - if (!bin2hex (old, next, var)) - { - fprintf (stderr, "Rebuild failed\n"); - exit (-1); - } - } - else if (strcmp (method, "hex2hex") == 0) - { - if (!hex2hex (old, next, var)) - { - fprintf (stderr, "Rebuild failed\n"); - exit (-1); - } - } - else - { - fprintf (stderr, "Failed to build `%s' - unknown method %s\n", - next, method); - exit (-1); - } + if (strcmp(method, "bin2hex") == 0) + { + if (!bin2hex(old, next, var)) + { + fprintf(stderr, "Rebuild failed\n"); + exit(-1); + } + } else if (strcmp(method, "hex2hex") == 0) + { + if (!hex2hex(old, next, var)) + { + fprintf(stderr, "Rebuild failed\n"); + exit(-1); + } + } else + { + fprintf(stderr, "Failed to build `%s' - unknown method %s\n", + next, method); + exit(-1); + } } int -use_old_config (char *filename) +use_old_config(char *filename) { - char buf[1024]; - int i = 0; - - FILE *oldf; - - fprintf (stderr, "Copying old configuration from `%s'\n", filename); + char buf[1024]; + int i = 0; - if ((oldf = fopen (filename, "r")) == NULL) - { - fprintf (stderr, "Couldn't open previous configuration file\n"); - perror (filename); - return 0; - } - - while (fgets (buf, 1024, oldf) != NULL) - { - char tmp[100]; - - if (buf[0] != '#') - { - printf ("%s", buf); + FILE *oldf; - strncpy (tmp, buf, 8); - tmp[8] = 0; + fprintf(stderr, "Copying old configuration from `%s'\n", filename); - if (strcmp (tmp, "/*build ") == 0) - rebuild_file (&buf[8]); + if ((oldf = fopen(filename, "r")) == NULL) + { + fprintf(stderr, "Couldn't open previous configuration file\n"); + perror(filename); + return 0; + } + while (fgets(buf, 1024, oldf) != NULL) + { + char tmp[100]; - continue; - } + if (buf[0] != '#') + { + printf("%s", buf); - strncpy (tmp, buf, 8); - tmp[8] = 0; + strncpy(tmp, buf, 8); + tmp[8] = 0; - if (strcmp (tmp, "#define ") == 0) - { - char *id = &buf[8]; - - i = 0; - while (id[i] && id[i] != ' ' && - id[i] != '\t' && id[i] != '\n') - i++; - - strncpy (tmp, id, i); - tmp[i] = 0; - - if (strcmp (tmp, "SELECTED_SOUND_OPTIONS") == 0) - continue; - - if (strcmp (tmp, "KERNEL_SOUNDCARD") == 0) - continue; - - if (strcmp (tmp, "JAZZ_DMA16") == 0) /* Rename it (hack) */ - { - printf ("#define SB_DMA2 %s\n", - &buf[18]); - continue; - } - - if (strcmp (tmp, "SB16_DMA") == 0) /* Rename it (hack) */ - { - printf ("#define SB_DMA2 %s\n", - &buf[16]); - continue; - } - - tmp[8] = 0; /* Truncate the string */ - if (strcmp (tmp, "EXCLUDE_") == 0) - continue; /* Skip excludes */ - - strncpy (tmp, id, i); - tmp[7] = 0; /* Truncate the string */ - - if (strcmp (tmp, "CONFIG_") == 0) - { - strncpy (tmp, &id[7], i - 7); - tmp[i - 7] = 0; - - for (i = 0; i <= OPT_LAST; i++) - if (strcmp (hw_table[i].macro, tmp) == 0) - { - selected_options |= (1 << i); - break; - } - continue; - } - - printf ("%s", buf); - continue; - } + if (strcmp(tmp, "/*build ") == 0) + rebuild_file(&buf[8]); - if (strcmp (tmp, "#undef ") == 0) - { - char *id = &buf[8]; - - i = 0; - while (id[i] && id[i] != ' ' && - id[i] != '\t' && id[i] != '\n') - i++; - - strncpy (tmp, id, i); - tmp[7] = 0; /* Truncate the string */ - if (strcmp (tmp, "CONFIG_") == 0) - continue; - - strncpy (tmp, id, i); - - tmp[8] = 0; /* Truncate the string */ - if (strcmp (tmp, "EXCLUDE_") != 0) - continue; /* Not a #undef EXCLUDE_ line */ - strncpy (tmp, &id[8], i - 8); - tmp[i - 8] = 0; - - for (i = 0; i <= OPT_LAST; i++) - if (strcmp (hw_table[i].macro, tmp) == 0) - { - selected_options |= (1 << i); - break; - } - continue; - } + continue; + } + strncpy(tmp, buf, 8); + tmp[8] = 0; - printf ("%s", buf); - } - fclose (oldf); + if (strcmp(tmp, "#define ") == 0) + { + char *id = &buf[8]; + + i = 0; + while (id[i] && id[i] != ' ' && + id[i] != '\t' && id[i] != '\n') + i++; + + strncpy(tmp, id, i); + tmp[i] = 0; + + if (strcmp(tmp, "SELECTED_SOUND_OPTIONS") == 0) + continue; + + if (strcmp(tmp, "KERNEL_SOUNDCARD") == 0) + continue; + + if (strcmp(tmp, "JAZZ_DMA16") == 0) /* Rename it (hack) */ + { + printf("#define SB_DMA2 %s\n", + &buf[18]); + continue; + } + if (strcmp(tmp, "SB16_DMA") == 0) /* Rename it (hack) */ + { + printf("#define SB_DMA2 %s\n", + &buf[16]); + continue; + } + tmp[8] = 0; /* Truncate the string */ + if (strcmp(tmp, "EXCLUDE_") == 0) + continue; /* Skip excludes */ + + strncpy(tmp, id, i); + tmp[7] = 0; /* Truncate the string */ + + if (strcmp(tmp, "CONFIG_") == 0) + { + strncpy(tmp, &id[7], i - 7); + tmp[i - 7] = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (strcmp(hw_table[i].macro, tmp) == 0) + { + selected_options |= (1 << i); + break; + } + continue; + } + printf("%s", buf); + continue; + } + if (strcmp(tmp, "#undef ") == 0) + { + char *id = &buf[8]; + + i = 0; + while (id[i] && id[i] != ' ' && + id[i] != '\t' && id[i] != '\n') + i++; + + strncpy(tmp, id, i); + tmp[7] = 0; /* Truncate the string */ + if (strcmp(tmp, "CONFIG_") == 0) + continue; + + strncpy(tmp, id, i); + + tmp[8] = 0; /* Truncate the string */ + if (strcmp(tmp, "EXCLUDE_") != 0) + continue; /* Not a #undef EXCLUDE_ line */ + strncpy(tmp, &id[8], i - 8); + tmp[i - 8] = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (strcmp(hw_table[i].macro, tmp) == 0) + { + selected_options |= (1 << i); + break; + } + continue; + } + printf("%s", buf); + } + fclose(oldf); - for (i = 0; i <= OPT_LAST; i++) - if (!hw_table[i].alias) - if (selected_options & B (i)) - printf ("#define CONFIG_%s\n", hw_table[i].macro); - else - printf ("#undef CONFIG_%s\n", hw_table[i].macro); + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B(i)) + printf("#define CONFIG_%s\n", hw_table[i].macro); + else + printf("#undef CONFIG_%s\n", hw_table[i].macro); - printf ("\n"); + printf("\n"); - i = 0; + i = 0; - while (extra_options[i].name != NULL) - { - if (selected_options & extra_options[i].mask) - printf ("#define CONFIG_%s\n", extra_options[i].name); - else - printf ("#undef CONFIG_%s\n", extra_options[i].name); - i++; - } + while (extra_options[i].name != NULL) + { + if (selected_options & extra_options[i].mask) + printf("#define CONFIG_%s\n", extra_options[i].name); + else + printf("#undef CONFIG_%s\n", extra_options[i].name); + i++; + } - printf ("\n"); + printf("\n"); - printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); - fprintf (stderr, "Old configuration copied.\n"); + printf("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); + fprintf(stderr, "Old configuration copied.\n"); - build_defines (); - old_config_used = 1; - return 1; + build_defines(); + old_config_used = 1; + return 1; } void -build_defines (void) +build_defines(void) { - FILE *optf; - int i; + FILE *optf; + int i; - if ((optf = fopen (".defines", "w")) == NULL) - { - perror (".defines"); - exit (-1); - } - - - for (i = 0; i <= OPT_LAST; i++) - if (!hw_table[i].alias) - if (selected_options & B (i)) - fprintf (optf, "CONFIG_%s=y\n", hw_table[i].macro); + if ((optf = fopen(".defines", "w")) == NULL) + { + perror(".defines"); + exit(-1); + } + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B(i)) + fprintf(optf, "CONFIG_%s=y\n", hw_table[i].macro); - fprintf (optf, "\n"); + fprintf(optf, "\n"); - i = 0; + i = 0; - while (extra_options[i].name != NULL) - { - if (selected_options & extra_options[i].mask) - fprintf (optf, "CONFIG_%s=y\n", extra_options[i].name); - i++; - } + while (extra_options[i].name != NULL) + { + if (selected_options & extra_options[i].mask) + fprintf(optf, "CONFIG_%s=y\n", extra_options[i].name); + i++; + } - fprintf (optf, "\n"); - fclose (optf); + fprintf(optf, "\n"); + fclose(optf); } void -ask_parameters (void) +ask_parameters(void) { - int num; - - build_defines (); - /* - * IRQ and DMA settings - */ - - ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE", - "I/O base for Audio Excel DSP 16", - FMT_HEX, - 0x220, - "220 or 240"); - - ask_int_choice (B (OPT_SB), "SBC_BASE", - "I/O base for SB", - FMT_HEX, - 0x220, - "Check from manual of the card"); - - ask_int_choice (B (OPT_SB), "SBC_IRQ", - "Sound Blaster IRQ", - FMT_INT, - 7, - "Check from manual of the card"); - - ask_int_choice (B (OPT_SB), "SBC_DMA", - "Sound Blaster DMA", - FMT_INT, - 1, - "0, 1 or 3"); - - ask_int_choice (B (OPT_SB), "SB_DMA2", - "Sound Blaster 16 bit DMA (SB16, Jazz16, SMW)", - FMT_INT, - 5, - "5, 6 or 7 (use 1 for 8 bit cards)"); - - ask_int_choice (B (OPT_SB), "SB_MPU_BASE", - "MPU401 I/O base of SB16, Jazz16 and ES1688", - FMT_HEX, - 0x330, - "Check from manual of the card"); - - show_comment (B (OPT_SB), - "MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688."); - show_comment (B (OPT_SB), - "Enter -1 to the following question if you have something else such as SB16/32."); - - ask_int_choice (B (OPT_SB), "SB_MPU_IRQ", - "SB MPU401 IRQ (Jazz16, SM Wave and ES1688)", - FMT_INT, - -1, - "Check from manual of the card"); - - ask_int_choice (B (OPT_PAS), "PAS_IRQ", - "PAS16 IRQ", - FMT_INT, - 10, - "3, 4, 5, 7, 9, 10, 11, 12, 14 or 15"); - - ask_int_choice (B (OPT_PAS), "PAS_DMA", - "PAS16 DMA", - FMT_INT, - 3, - "0, 1, 3, 5, 6 or 7"); - - if (selected_options & B (OPT_PAS)) - { - if (think_positively ("Enable Joystick port on ProAudioSpectrum", 0, - "Enable this option if you want to use the joystick port provided\n" - "on the PAS sound card.\n")) - printf ("#define PAS_JOYSTICK_ENABLE\n"); - - if (think_positively ("Enable PAS16 bus clock option", 0, - "The PAS16 can be noisy with some motherboards. There is a command\n" - "line switch (:T?) in the DOS driver for PAS16 which solves this.\n" - "Don't enable this feature unless you have problems and have to use\n" - "this switch with DOS\n")) - printf ("#define BROKEN_BUS_CLOCK\n"); - - if (think_positively ("Disable SB mode of PAS16", 0, - "You should disable SB emulation of PAS16 if you want to use\n" - "Another SB compatible card in the same system\n")) - printf ("#define DISABLE_SB_EMULATION\n"); - } - - ask_int_choice (B (OPT_GUS), "GUS_BASE", - "I/O base for GUS", - FMT_HEX, - 0x220, - "210, 220, 230, 240, 250 or 260"); - - - ask_int_choice (B (OPT_GUS), "GUS_IRQ", - "GUS IRQ", - FMT_INT, - 15, - "3, 5, 7, 9, 11, 12 or 15"); - - ask_int_choice (B (OPT_GUS), "GUS_DMA", - "GUS DMA", - FMT_INT, - 6, - "1, 3, 5, 6 or 7"); - - ask_int_choice (B (OPT_GUS), "GUS_DMA2", - "Second DMA channel for GUS", - FMT_INT, - -1, - "1, 3, 5, 6 or 7"); - - ask_int_choice (B (OPT_GUS16), "GUS16_BASE", - "I/O base for the 16 bit daughtercard of GUS", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - - ask_int_choice (B (OPT_GUS16), "GUS16_IRQ", - "GUS 16 bit daughtercard IRQ", - FMT_INT, - 7, - "3, 4, 5, 7, or 9"); - - ask_int_choice (B (OPT_GUS16), "GUS16_DMA", - "GUS DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MPU401), "MPU_BASE", - "I/O base for MPU401", - FMT_HEX, - 0x330, - "Check from manual of the card"); - - ask_int_choice (B (OPT_MPU401), "MPU_IRQ", - "MPU401 IRQ", - FMT_INT, - 9, - "Check from manual of the card"); - - if (dump_only) - show_comment (B (OPT_MAUI), - "ERROR! You have to use old sound configuration method with Maui."); - - ask_int_choice (B (OPT_MAUI), "MAUI_BASE", - "I/O base for Maui", - FMT_HEX, - 0x330, - "210, 230, 260, 290, 300, 320, 338 or 330"); - - ask_int_choice (B (OPT_MAUI), "MAUI_IRQ", - "Maui IRQ", - FMT_INT, - 9, - "5, 9, 12 or 15"); - - ask_int_choice (B (OPT_UART6850), "U6850_BASE", - "I/O base for UART 6850 MIDI port", - FMT_HEX, - 0, - "(Unknown)"); - - ask_int_choice (B (OPT_UART6850), "U6850_IRQ", - "UART6850 IRQ", - FMT_INT, - -1, - "(Unknown)"); - - if (dump_only) - show_comment (B (OPT_PSS), - "ERROR! You have to use old sound configuration method with PSS cards."); - - ask_int_choice (B (OPT_PSS), "PSS_BASE", - "PSS I/O base", - FMT_HEX, - 0x220, - "220 or 240"); - - ask_int_choice (B (OPT_PSS), "PSS_MSS_BASE", - "PSS audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_PSS), "PSS_MSS_IRQ", - "PSS audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_PSS), "PSS_MSS_DMA", - "PSS audio DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_PSS), "PSS_MPU_BASE", - "PSS MIDI I/O base", - FMT_HEX, - 0x330, - ""); - - ask_int_choice (B (OPT_PSS), "PSS_MPU_IRQ", - "PSS MIDI IRQ", - FMT_INT, - 9, - "3, 4, 5, 7 or 9"); - - ask_int_choice (B (OPT_MSS), "MSS_BASE", - "MSS/WSS I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_MSS), "MSS_IRQ", - "MSS/WSS IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_MSS), "MSS_DMA", - "MSS/WSS DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MSS), "MSS_DMA2", - "MSS/WSS second DMA (if possible)", - FMT_INT, - -1, - "0, 1 or 3"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_BASE", - "SoundScape MIDI I/O base", - FMT_HEX, - 0x330, - "320, 330, 340 or 350"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ", - "SoundScape MIDI IRQ", - FMT_INT, - 9, - ""); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_DMA", - "SoundScape initialization DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_BASE", - "SoundScape audio I/O base", - FMT_HEX, - 0x534, - "534, 608, E84 or F44"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_IRQ", - "SoundScape audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - - if (selected_options & B (OPT_SSCAPE)) - { - int reveal_spea; - - reveal_spea = think_positively ( - "Is your SoundScape card made/marketed by Reveal or Spea", - 0, - "Enable if you have a SoundScape card with the Reveal or\n" - "Spea name on it.\n"); - if (reveal_spea) - printf ("#define REVEAL_SPEA\n"); - - } - - if (dump_only) - show_comment (B (OPT_TRIX), - "ERROR! You have to use old sound configuration method with AudioTrix."); - - ask_int_choice (B (OPT_TRIX), "TRIX_BASE", - "AudioTrix audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_TRIX), "TRIX_IRQ", - "AudioTrix audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_TRIX), "TRIX_DMA", - "AudioTrix audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_TRIX), "TRIX_DMA2", - "AudioTrix second (duplex) DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_TRIX), "TRIX_MPU_BASE", - "AudioTrix MIDI I/O base", - FMT_HEX, - 0x330, - "330, 370, 3B0 or 3F0"); - - ask_int_choice (B (OPT_TRIX), "TRIX_MPU_IRQ", - "AudioTrix MIDI IRQ", - FMT_INT, - 9, - "3, 4, 5, 7 or 9"); - - ask_int_choice (B (OPT_TRIX), "TRIX_SB_BASE", - "AudioTrix SB I/O base", - FMT_HEX, - 0x220, - "220, 210, 230, 240, 250, 260 or 270"); - - ask_int_choice (B (OPT_TRIX), "TRIX_SB_IRQ", - "AudioTrix SB IRQ", - FMT_INT, - 7, - "3, 4, 5 or 7"); - - ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA", - "AudioTrix SB DMA", - FMT_INT, - 1, - "1 or 3"); - - ask_int_choice (B (OPT_CS4232), "CS4232_BASE", - "CS4232 audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_CS4232), "CS4232_IRQ", - "CS4232 audio IRQ", - FMT_INT, - 11, - "5, 7, 9, 11, 12 or 15"); - - ask_int_choice (B (OPT_CS4232), "CS4232_DMA", - "CS4232 audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_CS4232), "CS4232_DMA2", - "CS4232 second (duplex) DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_CS4232), "CS4232_MPU_BASE", - "CS4232 MIDI I/O base", - FMT_HEX, - 0x330, - "330, 370, 3B0 or 3F0"); - - ask_int_choice (B (OPT_CS4232), "CS4232_MPU_IRQ", - "CS4232 MIDI IRQ", - FMT_INT, - 9, - "5, 7, 9, 11, 12 or 15"); - - ask_int_choice (B (OPT_MAD16), "MAD16_BASE", - "MAD16 audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_MAD16), "MAD16_IRQ", - "MAD16 audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_MAD16), "MAD16_DMA", - "MAD16 audio DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MAD16), "MAD16_DMA2", - "MAD16 second (duplex) DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MAD16), "MAD16_MPU_BASE", - "MAD16 MIDI I/O base", - FMT_HEX, - 0x330, - "300, 310, 320 or 330 (0 disables)"); - - ask_int_choice (B (OPT_MAD16), "MAD16_MPU_IRQ", - "MAD16 MIDI IRQ", - FMT_INT, - 9, - "5, 7, 9 or 10"); + int num; + + build_defines(); + /* + * IRQ and DMA settings + */ + + ask_int_choice(B(OPT_AEDSP16), "AEDSP16_BASE", + "I/O base for Audio Excel DSP 16", + FMT_HEX, + 0x220, + "220 or 240"); + + ask_int_choice(B(OPT_SB), "SBC_BASE", + "I/O base for SB", + FMT_HEX, + 0x220, + "Check from manual of the card"); + + ask_int_choice(B(OPT_SB), "SBC_IRQ", + "Sound Blaster IRQ", + FMT_INT, + 7, + "Check from manual of the card"); + + ask_int_choice(B(OPT_SB), "SBC_DMA", + "Sound Blaster DMA", + FMT_INT, + 1, + "0, 1 or 3"); + + ask_int_choice(B(OPT_SB), "SB_DMA2", + "Sound Blaster 16 bit DMA (SB16, Jazz16, SMW)", + FMT_INT, + 5, + "5, 6 or 7 (use 1 for 8 bit cards)"); + + ask_int_choice(B(OPT_SB), "SB_MPU_BASE", + "MPU401 I/O base of SB16, Jazz16 and ES1688", + FMT_HEX, + 0x330, + "Check from manual of the card"); + + show_comment(B(OPT_SB), + "MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688."); + show_comment(B(OPT_SB), + "Enter -1 to the following question if you have something else such as SB16/32."); + + ask_int_choice(B(OPT_SB), "SB_MPU_IRQ", + "SB MPU401 IRQ (Jazz16, SM Wave and ES1688)", + FMT_INT, + -1, + "Check from manual of the card"); + + ask_int_choice(B(OPT_PAS), "PAS_IRQ", + "PAS16 IRQ", + FMT_INT, + 10, + "3, 4, 5, 7, 9, 10, 11, 12, 14 or 15"); + + ask_int_choice(B(OPT_PAS), "PAS_DMA", + "PAS16 DMA", + FMT_INT, + 3, + "0, 1, 3, 5, 6 or 7"); + + if (selected_options & B(OPT_PAS)) + { + if (think_positively("Enable Joystick port on ProAudioSpectrum", 0, + "Enable this option if you want to use the joystick port provided\n" + "on the PAS sound card.\n")) + printf("#define PAS_JOYSTICK_ENABLE\n"); + + if (think_positively("Enable PAS16 bus clock option", 0, + "The PAS16 can be noisy with some motherboards. There is a command\n" + "line switch (:T?) in the DOS driver for PAS16 which solves this.\n" + "Don't enable this feature unless you have problems and have to use\n" + "this switch with DOS\n")) + printf("#define BROKEN_BUS_CLOCK\n"); + + if (think_positively("Disable SB mode of PAS16", 0, + "You should disable SB emulation of PAS16 if you want to use\n" + "Another SB compatible card in the same system\n")) + printf("#define DISABLE_SB_EMULATION\n"); + } + ask_int_choice(B(OPT_GUS), "GUS_BASE", + "I/O base for GUS", + FMT_HEX, + 0x220, + "210, 220, 230, 240, 250 or 260"); + + + ask_int_choice(B(OPT_GUS), "GUS_IRQ", + "GUS IRQ", + FMT_INT, + 15, + "3, 5, 7, 9, 11, 12 or 15"); + + ask_int_choice(B(OPT_GUS), "GUS_DMA", + "GUS DMA", + FMT_INT, + 6, + "1, 3, 5, 6 or 7"); + + ask_int_choice(B(OPT_GUS), "GUS_DMA2", + "Second DMA channel for GUS", + FMT_INT, + -1, + "1, 3, 5, 6 or 7"); + + ask_int_choice(B(OPT_GUS16), "GUS16_BASE", + "I/O base for the 16 bit daughtercard of GUS", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + + ask_int_choice(B(OPT_GUS16), "GUS16_IRQ", + "GUS 16 bit daughtercard IRQ", + FMT_INT, + 7, + "3, 4, 5, 7, or 9"); + + ask_int_choice(B(OPT_GUS16), "GUS16_DMA", + "GUS DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MPU401), "MPU_BASE", + "I/O base for MPU401", + FMT_HEX, + 0x330, + "Check from manual of the card"); + + ask_int_choice(B(OPT_MPU401), "MPU_IRQ", + "MPU401 IRQ", + FMT_INT, + 9, + "Check from manual of the card"); + + if (dump_only) + show_comment(B(OPT_MAUI), + "ERROR! You have to use old sound configuration method with Maui."); + + ask_int_choice(B(OPT_MAUI), "MAUI_BASE", + "I/O base for Maui", + FMT_HEX, + 0x330, + "210, 230, 260, 290, 300, 320, 338 or 330"); + + ask_int_choice(B(OPT_MAUI), "MAUI_IRQ", + "Maui IRQ", + FMT_INT, + 9, + "5, 9, 12 or 15"); + + ask_int_choice(B(OPT_UART6850), "U6850_BASE", + "I/O base for UART 6850 MIDI port", + FMT_HEX, + 0, + "(Unknown)"); + + ask_int_choice(B(OPT_UART6850), "U6850_IRQ", + "UART6850 IRQ", + FMT_INT, + -1, + "(Unknown)"); + + if (dump_only) + show_comment(B(OPT_PSS), + "ERROR! You have to use old sound configuration method with PSS cards."); + + ask_int_choice(B(OPT_PSS), "PSS_BASE", + "PSS I/O base", + FMT_HEX, + 0x220, + "220 or 240"); + + ask_int_choice(B(OPT_PSS), "PSS_MSS_BASE", + "PSS audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_PSS), "PSS_MSS_IRQ", + "PSS audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_PSS), "PSS_MSS_DMA", + "PSS audio DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_PSS), "PSS_MPU_BASE", + "PSS MIDI I/O base", + FMT_HEX, + 0x330, + ""); + + ask_int_choice(B(OPT_PSS), "PSS_MPU_IRQ", + "PSS MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice(B(OPT_MSS), "MSS_BASE", + "MSS/WSS I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_MSS), "MSS_IRQ", + "MSS/WSS IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_MSS), "MSS_DMA", + "MSS/WSS DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MSS), "MSS_DMA2", + "MSS/WSS second DMA (if possible)", + FMT_INT, + -1, + "0, 1 or 3"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_BASE", + "SoundScape MIDI I/O base", + FMT_HEX, + 0x330, + "320, 330, 340 or 350"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_IRQ", + "SoundScape MIDI IRQ", + FMT_INT, + 9, + ""); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_DMA", + "SoundScape initialization DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_MSS_BASE", + "SoundScape audio I/O base", + FMT_HEX, + 0x534, + "534, 608, E84 or F44"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_MSS_IRQ", + "SoundScape audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + + if (selected_options & B(OPT_SSCAPE)) + { + int reveal_spea; + + reveal_spea = think_positively( + "Is your SoundScape card made/marketed by Reveal or Spea", + 0, + "Enable if you have a SoundScape card with the Reveal or\n" + "Spea name on it.\n"); + if (reveal_spea) + printf("#define REVEAL_SPEA\n"); + + } + if (dump_only) + show_comment(B(OPT_TRIX), + "ERROR! You have to use old sound configuration method with OPL3-SA1."); + + ask_int_choice(B(OPT_TRIX), "TRIX_BASE", + "OPL3-SA1 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_TRIX), "TRIX_IRQ", + "OPL3-SA1 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_TRIX), "TRIX_DMA", + "OPL3-SA1 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_TRIX), "TRIX_DMA2", + "OPL3-SA1 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_TRIX), "TRIX_MPU_BASE", + "OPL3-SA1 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice(B(OPT_TRIX), "TRIX_MPU_IRQ", + "OPL3-SA1 MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice(B(OPT_TRIX), "TRIX_SB_BASE", + "OPL3-SA1 SB I/O base", + FMT_HEX, + 0x220, + "220, 210, 230, 240, 250, 260 or 270"); + + ask_int_choice(B(OPT_TRIX), "TRIX_SB_IRQ", + "OPL3-SA1 SB IRQ", + FMT_INT, + 7, + "3, 4, 5 or 7"); + + ask_int_choice(B(OPT_TRIX), "TRIX_SB_DMA", + "OPL3-SA1 SB DMA", + FMT_INT, + 1, + "1 or 3"); + + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_BASE", + "OPL3-SA1 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_IRQ", + "OPL3-SA1 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_DMA", + "OPL3-SA1 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_DMA2", + "OPL3-SA1 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_MPU_BASE", + "OPL3-SA1 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_MPU_IRQ", + "OPL3-SA1 MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice(B(OPT_CS4232), "CS4232_BASE", + "CS4232 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_CS4232), "CS4232_IRQ", + "CS4232 audio IRQ", + FMT_INT, + 11, + "5, 7, 9, 11, 12 or 15"); + + ask_int_choice(B(OPT_CS4232), "CS4232_DMA", + "CS4232 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_CS4232), "CS4232_DMA2", + "CS4232 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_CS4232), "CS4232_MPU_BASE", + "CS4232 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice(B(OPT_CS4232), "CS4232_MPU_IRQ", + "CS4232 MIDI IRQ", + FMT_INT, + 9, + "5, 7, 9, 11, 12 or 15"); + + ask_int_choice(B(OPT_MAD16), "MAD16_BASE", + "MAD16 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_MAD16), "MAD16_IRQ", + "MAD16 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_MAD16), "MAD16_DMA", + "MAD16 audio DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MAD16), "MAD16_DMA2", + "MAD16 second (duplex) DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MAD16), "MAD16_MPU_BASE", + "MAD16 MIDI I/O base", + FMT_HEX, + 0x330, + "300, 310, 320 or 330 (0 disables)"); + + ask_int_choice(B(OPT_MAD16), "MAD16_MPU_IRQ", + "MAD16 MIDI IRQ", + FMT_INT, + 9, + "5, 7, 9 or 10"); + ask_int_choice(B(OPT_SOFTOSS), "SOFTOSS_RATE", + "Sampling rate for SoftOSS", + FMT_INT, + 22050, + "8000 to 48000"); + ask_int_choice(B(OPT_SOFTOSS), "SOFTOSS_VOICES", + "Max # of concurrent voices for SoftOSS", + FMT_INT, + 32, + "4 to 32"); } void -dump_script (void) +dump_script(void) { - int i; - - for (i = 0; i <= OPT_LAST; i++) - if (!(DUMMY_OPTS & B (i))) - if (!(DISABLED_OPTIONS & B (i))) - { - printf ("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro); - } - + int i; + + for (i = 0; i <= OPT_LAST; i++) + if (!(DUMMY_OPTS & B(i))) + if (!(DISABLED_OPTIONS & B(i))) + { + printf("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro); + } /* * Some "hardcoded" options */ - dump_only = 1; - selected_options = 0; - ask_parameters (); + dump_only = 1; + selected_options = 0; + ask_parameters(); - printf ("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n"); + printf("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n"); } void -dump_fixed_local (void) +dump_fixed_local(void) { - int i = 0; - - printf ("/* Computer generated file. Please don't edit! */\n\n"); - printf ("#define KERNEL_COMPATIBLE_CONFIG\n\n"); - printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n\n", selected_options); - - while (extra_options[i].name != NULL) - { - int n = 0, j; - - printf ("#if "); - - for (j = 0; j < OPT_LAST; j++) - if (!(DISABLED_OPTIONS & B (j))) - if (extra_options[i].mask & B (j)) - { - if (n) - printf (" || "); - if (!(n++ % 2)) - printf ("\\\n "); - - printf ("defined(CONFIG_%s)", hw_table[j].macro); - } - - printf ("\n"); - printf ("#\tdefine CONFIG_%s\n", extra_options[i].name); - printf ("#endif\n\n"); - i++; - } + int i = 0; + + printf("/* Computer generated file. Please don't edit! */\n\n"); + printf("#define KERNEL_COMPATIBLE_CONFIG\n\n"); + printf("#define SELECTED_SOUND_OPTIONS\t0x%08x\n\n", selected_options); + + while (extra_options[i].name != NULL) + { + int n = 0, j; + + printf("#if "); + + for (j = 0; j < OPT_LAST; j++) + if (!(DISABLED_OPTIONS & B(j))) + if (extra_options[i].mask & B(j)) + { + if (n) + printf(" || "); + if (!(n++ % 2)) + printf("\\\n "); + + printf("defined(CONFIG_%s)", hw_table[j].macro); + } + printf("\n"); + printf("#\tdefine CONFIG_%s\n", extra_options[i].name); + printf("#endif\n\n"); + i++; + } } void -dump_fixed_defines (void) +dump_fixed_defines(void) { - int i = 0; + int i = 0; - printf ("# Computer generated file. Please don't edit\n\n"); + printf("# Computer generated file. Please don't edit\n\n"); - while (extra_options[i].name != NULL) - { - int j; - - for (j = 0; j < OPT_LAST; j++) - if (!(DISABLED_OPTIONS & B (j))) - if (extra_options[i].mask & B (j)) - { - printf ("ifdef CONFIG_%s\n", hw_table[j].macro); - printf ("CONFIG_%s=y\n", extra_options[i].name); - printf ("endif\n\n"); - } + while (extra_options[i].name != NULL) + { + int j; - i++; - } + for (j = 0; j < OPT_LAST; j++) + { + if (!(DISABLED_OPTIONS & B(j))) + { + if (extra_options[i].mask & B(j)) + { + printf("ifdef CONFIG_%s\n", hw_table[j].macro); + printf ("ifneq ($(CONFIG_%s),Y)\n", extra_options[i].name); + printf("CONFIG_%s=y\n", extra_options[i].name); + printf("endif\n"); + printf("endif\n\n"); + } + } + } + i++; + } } int -main (int argc, char *argv[]) +main(int argc, char *argv[]) { - int i, full_driver = 1; - char old_config_file[200]; + int i, full_driver = 1; + char old_config_file[200]; - if (getuid () != 0) /* Not root */ - { - char *home; - - if ((home = getenv ("HOME")) != NULL) - { - sprintf (old_config_file, "%s/.soundconf", home); - oldconf = old_config_file; - } - } - - if (argc > 1) - { - if (strcmp (argv[1], "-o") == 0 && - use_old_config (oldconf)) - exit (0); - else if (strcmp (argv[1], "script") == 0) - { - dump_script (); - exit (0); - } - else if (strcmp (argv[1], "fixedlocal") == 0) - { - dump_fixed_local (); - exit (0); - } - else if (strcmp (argv[1], "fixeddefines") == 0) - { - dump_fixed_defines (); - exit (0); - } - } + if (getuid() != 0) /* Not root */ + { + char *home; - fprintf (stderr, "\nConfiguring Sound Support\n\n"); + if ((home = getenv("HOME")) != NULL) + { + sprintf(old_config_file, "%s/.soundconf", home); + oldconf = old_config_file; + } + } + if (argc > 1) + { + if (strcmp(argv[1], "-o") == 0 && + use_old_config(oldconf)) + exit(0); + else if (strcmp(argv[1], "script") == 0) + { + dump_script(); + exit(0); + } else if (strcmp(argv[1], "fixedlocal") == 0) + { + dump_fixed_local(); + exit(0); + } else if (strcmp(argv[1], "fixeddefines") == 0) + { + dump_fixed_defines(); + exit(0); + } + } + fprintf(stderr, "\nConfiguring Sound Support\n\n"); - if (access (oldconf, R_OK) == 0) - { - char str[255]; + if (access(oldconf, R_OK) == 0) + { + char str[255]; - sprintf (str, "Old configuration exists in `%s'. Use it", oldconf); - if (think_positively (str, 1, - "Enable this option to load the previously saved configuration file\n" + sprintf(str, "Old configuration exists in `%s'. Use it", oldconf); + if (think_positively(str, 1, + "Enable this option to load the previously saved configuration file\n" "for all of the sound driver parameters.\n")) - if (use_old_config (oldconf)) - exit (0); - } + if (use_old_config(oldconf)) + exit(0); + } + printf("/*\tGenerated by configure. Don't edit!!!!\t*/\n"); + printf("/*\tMaking changes to this file is not as simple as it may look.\t*/\n\n"); + printf("/*\tIf you change the CONFIG_ settings in local.h you\t*/\n"); + printf("/*\t_have_ to edit .defines too.\t*/\n\n"); - printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n"); - printf ("/*\tMaking changes to this file is not as simple as it may look.\t*/\n\n"); - printf ("/*\tIf you change the CONFIG_ settings in local.h you\t*/\n"); - printf ("/*\t_have_ to edit .defines too.\t*/\n\n"); + { + /* + * Partial driver + */ + + full_driver = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (can_select_option(i)) + { + if (!(selected_options & B(i))) /* + * Not selected yet + */ + if (!hw_table[i].verify) + { + if (hw_table[i].alias) + selected_options |= B(hw_table[i].alias); + else + selected_options |= B(i); + } else + { + int def_answ = hw_table[i].default_answ; + + if (think_positively(questions[i], def_answ, help[i])) + if (hw_table[i].alias) + selected_options |= B(hw_table[i].alias); + else + selected_options |= B(i); + } + } + } - { - /* - * Partial driver - */ + if (selected_options & B(OPT_SB)) + { + if (think_positively( + "Support for the SG NX Pro mixer", 0, + "Enable this if you want to support the additional mixer functions\n" + "provided on Sound Galaxy NX Pro sound cards.\n")) + printf("#define __SGNXPRO__\n"); + } + if (selected_options & B(OPT_SB)) + { + if (think_positively("Support for the MV Jazz16 (ProSonic etc.)", 0, + "Enable this if you have an MV Jazz16 or ProSonic sound card.\n")) + { + if (think_positively("Do you have SoundMan Wave", 0, + "Enable this option of you have the Logitech SoundMan Wave sound card.\n")) + { + printf("#define SM_WAVE\n"); + + midi0001_again: + if (think_positively( + "Do you have access to the MIDI0001.BIN file", 1, + "The Logitech SoundMan Wave has a microcontroller which must be\n" + "initialized before MIDI emulation works. This is possible only if the\n" + "microcode file is compiled into the driver.\n")) + { + char path[512]; + + fprintf(stderr, + "Enter full name of the MIDI0001.BIN file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including microcode file %s\n", path); + + if (!bin2hex(path, "smw-midi0001.h", "smw_ucode")) + { + fprintf(stderr, "Couldn't open file %s\n", + path); + if (think_positively("Try again with correct path", 1, + "The specified file could not be opened. Enter the correct path to the\n" + "file.\n")) + goto midi0001_again; + } else + { + printf("#define SMW_MIDI0001_INCLUDED\n"); + printf("/*build bin2hex %s smw-midi0001.h smw_ucode */\n", path); + } + } + } + } + } + if (selected_options & B(OPT_SB)) + { + if (think_positively("Do you have a Logitech SoundMan Games", 0, + "The Logitech SoundMan Games supports 44 kHz in stereo while the\n" + "standard SB Pro supports just 22 kHz stereo. You have the option of\n" + "enabling SM Games mode. However, enable it only if you are sure that\n" + "your card is an SM Games. Enabling this feature with a plain old SB\n" + "Pro will cause troubles with stereo mode.\n\n" + "DANGER! Read the above once again before answering 'y'\n" + "Answer 'n' if you are unsure what to do!\n")) + printf("#define SM_GAMES\n"); + } + if (selected_options & B(OPT_AEDSP16)) + { + int sel1 = 0; - full_driver = 0; + if (selected_options & B(OPT_SB)) + { - for (i = 0; i <= OPT_LAST; i++) - if (can_select_option (i)) - { - if (!(selected_options & B (i))) /* - * Not selected yet - */ - if (!hw_table[i].verify) - { - if (hw_table[i].alias) - selected_options |= B (hw_table[i].alias); - else - selected_options |= B (i); - } - else - { - int def_answ = hw_table[i].default_answ; - - if (think_positively (questions[i], def_answ, help[i])) - if (hw_table[i].alias) - selected_options |= B (hw_table[i].alias); - else - selected_options |= B (i); - } - } - } + if (think_positively( + "Do you want support for the Audio Excel Sound Blaster Pro mode", + 1, + "Enable this option if you want the Audio Excel sound card to operate\n" + "in Sound Blaster Pro mode.\n")) + { + printf("#define AEDSP16_SBPRO\n"); + sel1 = 1; + } + } + if ((selected_options & B(OPT_MSS)) && (sel1 == 0)) + { - if (selected_options & B (OPT_SB)) - { - if (think_positively ( - "Support for the SG NX Pro mixer", 0, - "Enable this if you want to support the additional mixer functions\n" - "provided on Sound Galaxy NX Pro sound cards.\n")) - printf ("#define __SGNXPRO__\n"); - } - - if (selected_options & B (OPT_SB)) - { - if (think_positively ("Support for the MV Jazz16 (ProSonic etc.)", 0, - "Enable this if you have an MV Jazz16 or ProSonic sound card.\n")) - { - if (think_positively ("Do you have SoundMan Wave", 0, - "Enable this option of you have the Logitech SoundMan Wave sound card.\n")) - { - printf ("#define SM_WAVE\n"); - - midi0001_again: - if (think_positively ( - "Do you have access to the MIDI0001.BIN file", 1, - "The Logitech SoundMan Wave has a microcontroller which must be\n" - "initialized before MIDI emulation works. This is possible only if the\n" - "microcode file is compiled into the driver.\n")) - { - char path[512]; + if (think_positively( + "Do you want support for the Audio Excel Microsoft Sound System mode", + 1, + "Enable this option if you want the Audio Excel sound card to operate\n" + "in Microsoft Sound System mode.\n")) + { + printf("#define AEDSP16_MSS\n"); + sel1 = 1; + } + } + if (sel1 == 0) + { + printf("invalid_configuration__run_make_config_again\n"); + fprintf(stderr, "ERROR!!!!!\nYou must select at least one mode when using Audio Excel!\n"); + exit(-1); + } + if (selected_options & B(OPT_MPU401)) + printf("#define AEDSP16_MPU401\n"); + } + if (selected_options & B(OPT_PSS)) + { + genld_again: + if (think_positively("Do you wish to include an LD file", 1, + "If you want to emulate the Sound Blaster card and you have a DSPxxx.LD\n" + "file then you must include the LD in the kernel.\n")) + { + char path[512]; + + fprintf(stderr, + "Enter the path to your LD file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including LD file %s\n", path); + + if (!bin2hex(path, "synth-ld.h", "pss_synth")) + { + fprintf(stderr, "couldn't open `%s' as the LD file\n", path); + if (think_positively("try again with correct path", 1, + "The given LD file could not opened.\n")) + goto genld_again; + } else + { + printf("#define PSS_HAVE_LD\n"); + printf("/*build bin2hex %s synth-ld.h pss_synth */\n", path); + } + } else + { + FILE *sf = fopen("synth-ld.h", "w"); - fprintf (stderr, - "Enter full name of the MIDI0001.BIN file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including microcode file %s\n", path); + fprintf(sf, "/* automatically generated by configure */\n"); + fprintf(sf, "unsigned char pss_synth[1];\n" + "#define pss_synthLen 0\n"); + fclose(sf); + } + } + if (selected_options & B(OPT_TRIX)) + { + hex2hex_again: + + if (think_positively("Do you want to include TRXPRO.HEX in your kernel", + 1, + "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n" + "needs to be initialized by downloading the code from the file TRXPRO.HEX\n" + "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n" + "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n" + "Pro will not work without this file!\n")) + { + char path[512]; - if (!bin2hex (path, "smw-midi0001.h", "smw_ucode")) + fprintf(stderr, + "Enter the path to your TRXPRO.HEX file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including HEX file `%s'\n", path); + + if (!hex2hex(path, "trix_boot.h", "trix_boot")) + goto hex2hex_again; + printf("/*build hex2hex %s trix_boot.h trix_boot */\n", path); + printf("#define INCLUDE_TRIX_BOOT\n"); + } + } + if (selected_options & B(OPT_MSS)) + { + if (think_positively("Support for builtin sound of Compaq Deskpro XL", 0, + "Enable this if you have Compaq Deskpro XL.\n")) { - fprintf (stderr, "Couldn't open file %s\n", - path); - if (think_positively ("Try again with correct path", 1, - "The specified file could not be opened. Enter the correct path to the\n" - "file.\n")) - goto midi0001_again; + printf("#define DESKPROXL\n"); } - else + } + if (selected_options & B(OPT_MAUI)) + { + oswf_again: + if (think_positively( + "Do you have access to the OSWF.MOT file", 1, + "TB Maui and Tropez have a microcontroller which needs to be initialized\n" + "prior use. OSWF.MOT is a file distributed with card's DOS/Windows drivers\n" + "which is required during initialization\n")) { - printf ("#define SMW_MIDI0001_INCLUDED\n"); - printf ("/*build bin2hex %s smw-midi0001.h smw_ucode */\n", path); + char path[512]; + + fprintf(stderr, + "Enter full name of the OSWF.MOT file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including microcode file %s\n", path); + + if (!bin2hex(path, "maui_boot.h", "maui_os")) + { + fprintf(stderr, "Couldn't open file %s\n", + path); + if (think_positively("Try again with correct path", 1, + "The specified file could not be opened. Enter the correct path to the\n" + "file.\n")) + goto oswf_again; + } else + { + printf("#define HAVE_MAUI_BOOT\n"); + printf("/*build bin2hex %s maui_boot.h maui_os */\n", path); + } } - } - } - } - } - - if (selected_options & B (OPT_SB)) - { - if (think_positively ("Do you have a Logitech SoundMan Games", 0, - "The Logitech SoundMan Games supports 44 kHz in stereo while the\n" - "standard SB Pro supports just 22 kHz stereo. You have the option of\n" - "enabling SM Games mode. However, enable it only if you are sure that\n" - "your card is an SM Games. Enabling this feature with a plain old SB\n" - "Pro will cause troubles with stereo mode.\n\n" - "DANGER! Read the above once again before answering 'y'\n" - "Answer 'n' if you are unsure what to do!\n")) - printf ("#define SM_GAMES\n"); - } - - if (selected_options & B (OPT_AEDSP16)) - { - int sel1 = 0; - - if (selected_options & B (OPT_SB)) - { + } + if (!(selected_options & ANY_DEVS)) + { + printf("invalid_configuration__run_make_config_again\n"); + fprintf(stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device ***\n\n"); + exit(0); + } + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B(i)) + printf("#define CONFIG_%s\n", hw_table[i].macro); + else + printf("#undef CONFIG_%s\n", hw_table[i].macro); - if (think_positively ( - "Do you want support for the Audio Excel Sound Blaster Pro mode", - 1, - "Enable this option if you want the Audio Excel sound card to operate\n" - "in Sound Blaster Pro mode.\n")) - { - printf ("#define AEDSP16_SBPRO\n"); - sel1 = 1; - } - } + printf("\n"); - if ((selected_options & B (OPT_MSS)) && (sel1 == 0)) - { + i = 0; - if (think_positively ( - "Do you want support for the Audio Excel Microsoft Sound System mode", - 1, - "Enable this option if you want the Audio Excel sound card to operate\n" - "in Microsoft Sound System mode.\n")) - { - printf ("#define AEDSP16_MSS\n"); - sel1 = 1; - } - } + while (extra_options[i].name != NULL) + { + if (selected_options & extra_options[i].mask) + printf("#define CONFIG_%s\n", extra_options[i].name); + else + printf("#undef CONFIG_%s\n", extra_options[i].name); + i++; + } - if (sel1 == 0) - { - printf ("invalid_configuration__run_make_config_again\n"); - fprintf (stderr, "ERROR!!!!!\nYou must select at least one mode when using Audio Excel!\n"); - exit (-1); - } - if (selected_options & B (OPT_MPU401)) - printf ("#define AEDSP16_MPU401\n"); - } - - if (selected_options & B (OPT_PSS)) - { - genld_again: - if (think_positively ("Do you wish to include an LD file", 1, - "If you want to emulate the Sound Blaster card and you have a DSPxxx.LD\n" - "file then you must include the LD in the kernel.\n")) - { - char path[512]; - - fprintf (stderr, - "Enter the path to your LD file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including LD file %s\n", path); - - if (!bin2hex (path, "synth-ld.h", "pss_synth")) - { - fprintf (stderr, "couldn't open `%s' as the LD file\n", path); - if (think_positively ("try again with correct path", 1, - "The given LD file could not opened.\n")) - goto genld_again; - } - else - { - printf ("#define PSS_HAVE_LD\n"); - printf ("/*build bin2hex %s synth-ld.h pss_synth */\n", path); - } - } - else - { - FILE *sf = fopen ("synth-ld.h", "w"); + printf("\n"); - fprintf (sf, "/* automatically generated by configure */\n"); - fprintf (sf, "unsigned char pss_synth[1];\n" - "#define pss_synthLen 0\n"); - fclose (sf); - } - } - - if (selected_options & B (OPT_TRIX)) - { - hex2hex_again: - - if (think_positively ("Do you want to include TRXPRO.HEX in your kernel", - 1, - "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n" - "needs to be initialized by downloading the code from the file TRXPRO.HEX\n" - "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n" - "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n" - "Pro will not work without this file!\n")) - { - char path[512]; + ask_parameters(); - fprintf (stderr, - "Enter the path to your TRXPRO.HEX file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including HEX file `%s'\n", path); + printf("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options); + fprintf(stderr, "\nThe sound driver is now configured.\n"); - if (!hex2hex (path, "trix_boot.h", "trix_boot")) - goto hex2hex_again; - printf ("/*build hex2hex %s trix_boot.h trix_boot */\n", path); - printf ("#define INCLUDE_TRIX_BOOT\n"); - } - } + if (!old_config_used) + { + char str[255]; - if (selected_options & B (OPT_MSS)) - { - if (think_positively ("Support for builtin sound of Compaq Deskpro XL", 0, - "Enable this if you have Compaq Deskpro XL.\n")) - { - printf ("#define DESKPROXL\n"); - } - } - - if (selected_options & B (OPT_MAUI)) - { - oswf_again: - if (think_positively ( - "Do you have access to the OSWF.MOT file", 1, - "TB Maui and Tropez have a microcontroller which needs to be initialized\n" - "prior use. OSWF.MOT is a file distributed with card's DOS/Windows drivers\n" - "which is required during initialization\n")) - { - char path[512]; - - fprintf (stderr, - "Enter full name of the OSWF.MOT file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including microcode file %s\n", path); - - if (!bin2hex (path, "maui_boot.h", "maui_os")) - { - fprintf (stderr, "Couldn't open file %s\n", - path); - if (think_positively ("Try again with correct path", 1, - "The specified file could not be opened. Enter the correct path to the\n" - "file.\n")) - goto oswf_again; - } - else - { - printf ("#define HAVE_MAUI_BOOT\n"); - printf ("/*build bin2hex %s maui_boot.h maui_os */\n", path); - } - } - } - - if (!(selected_options & ANY_DEVS)) - { - printf ("invalid_configuration__run_make_config_again\n"); - fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device ***\n\n"); - exit (0); - } - - for (i = 0; i <= OPT_LAST; i++) - if (!hw_table[i].alias) - if (selected_options & B (i)) - printf ("#define CONFIG_%s\n", hw_table[i].macro); - else - printf ("#undef CONFIG_%s\n", hw_table[i].macro); - - printf ("\n"); - - i = 0; - - while (extra_options[i].name != NULL) - { - if (selected_options & extra_options[i].mask) - printf ("#define CONFIG_%s\n", extra_options[i].name); - else - printf ("#undef CONFIG_%s\n", extra_options[i].name); - i++; - } - - printf ("\n"); - - ask_parameters (); - - printf ("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options); - fprintf (stderr, "\nThe sound driver is now configured.\n"); - - if (!old_config_used) - { - char str[255]; - - sprintf (str, "Save copy of this configuration to `%s'", oldconf); - if (think_positively (str, 1, - "If you enable this option then the sound driver configuration is\n" - "saved to a file. If you later need to recompile the kernel you have\n" - "the option of using the saved configuration.\n")) - { - char cmd[200]; + sprintf(str, "Save copy of this configuration to `%s'", oldconf); + if (think_positively(str, 1, + "If you enable this option then the sound driver configuration is\n" + "saved to a file. If you later need to recompile the kernel you have\n" + "the option of using the saved configuration.\n")) + { + char cmd[200]; - sprintf (cmd, "cp local.h %s", oldconf); + sprintf(cmd, "cp local.h %s", oldconf); - fclose (stdout); - if (system (cmd) != 0) - perror (cmd); - } - } - exit (0); + fclose(stdout); + if (system(cmd) != 0) + perror(cmd); + } + } + exit(0); } int -bin2hex (char *path, char *target, char *varname) +bin2hex(char *path, char *target, char *varname) { - int fd; - int count; - char c; - int i = 0; - - if ((fd = open (path, 0)) > 0) - { - FILE *sf = fopen (target, "w"); - - fprintf (sf, "/* automatically generated by configure */\n"); - fprintf (sf, "static unsigned char %s[] = {\n", varname); - while (1) - { - count = read (fd, &c, 1); - if (count == 0) - break; - if (i != 0 && (i % 10) == 0) - fprintf (sf, "\n"); - fprintf (sf, "0x%02lx,", c & 0xFFL); - i++; - } - fprintf (sf, "};\n" - "#define %sLen %d\n", varname, i); - fclose (sf); - close (fd); - return 1; - } - - return 0; + int fd; + int count; + char c; + int i = 0; + + if ((fd = open(path, 0)) > 0) + { + FILE *sf = fopen(target, "w"); + + fprintf(sf, "/* automatically generated by configure */\n"); + fprintf(sf, "static unsigned char %s[] = {\n", varname); + while (1) + { + count = read(fd, &c, 1); + if (count == 0) + break; + if (i != 0 && (i % 10) == 0) + fprintf(sf, "\n"); + fprintf(sf, "0x%02lx,", c & 0xFFL); + i++; + } + fprintf(sf, "};\n" + "#define %sLen %d\n", varname, i); + fclose(sf); + close(fd); + return 1; + } + return 0; } diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index 1946cd427..eb2a5eb05 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -21,19 +21,20 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_CS4232) +#if defined(CONFIG_CS4232) || defined (MODULE) #define KEY_PORT 0x279 /* Same as LPT1 status port */ #define CSN_NUM 0x99 /* Just a random number */ -static void -CS_OUT (unsigned char a) +static void +CS_OUT(unsigned char a) { - outb ((a), KEY_PORT); + outb((a), KEY_PORT); } #define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);} #define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);} @@ -42,55 +43,54 @@ static int mpu_base = 0, mpu_irq = 0; static int mpu_detected = 0; int -probe_cs4232_mpu (struct address_info *hw_config) +probe_cs4232_mpu(struct address_info *hw_config) { /* * Just write down the config values. */ - mpu_base = hw_config->io_base; - mpu_irq = hw_config->irq; + mpu_base = hw_config->io_base; + mpu_irq = hw_config->irq; - return 1; + return 1; } void -attach_cs4232_mpu (struct address_info *hw_config) +attach_cs4232_mpu(struct address_info *hw_config) { } static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ { - 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, - 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2, - 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13, - 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a + 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, + 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2, + 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13, + 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a }; int -probe_cs4232 (struct address_info *hw_config) +probe_cs4232(struct address_info *hw_config) { - int i, n; - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int i, n; + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; - static struct wait_queue *cs_sleeper = NULL; - static volatile struct snd_wait cs_sleep_flag = - {0}; + static struct wait_queue *cs_sleeper = NULL; + static volatile struct snd_wait cs_sleep_flag = + {0}; /* * Verify that the I/O port range is free. */ - if (check_region (base, 4)) - { - printk ("cs4232.c: I/O port 0x%03x not free\n", base); - return 0; - } - - if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp)) - return 1; /* The card is already active */ + if (check_region(base, 4)) + { + printk("cs4232.c: I/O port 0x%03x not free\n", base); + return 0; + } + if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) + return 1; /* The card is already active */ /* * This version of the driver doesn't use the PnP method when configuring @@ -105,241 +105,287 @@ probe_cs4232 (struct address_info *hw_config) * first time. */ - for (n = 0; n < 4; n++) - { - cs_sleep_flag.opts = WK_NONE; + for (n = 0; n < 4; n++) + { + cs_sleep_flag.opts = WK_NONE; /* * Wake up the card by sending a 32 byte Crystal key to the key port. */ - for (i = 0; i < 32; i++) - CS_OUT (crystal_key[i]); - - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ + for (i = 0; i < 32; i++) + CS_OUT(crystal_key[i]); + + + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Delay */ /* * Now set the CSN (Card Select Number). */ - CS_OUT2 (0x06, CSN_NUM); + CS_OUT2(0x06, CSN_NUM); /* * Then set some config bytes. First logical device 0 */ - CS_OUT2 (0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ - CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ + CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ + CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ - if (check_region (0x388, 4)) /* Not free */ - CS_OUT3 (0x48, 0x00, 0x00) /* FM base off */ - else - CS_OUT3 (0x48, 0x03, 0x88); /* FM base 0x388 */ + if (check_region(0x388, 4)) /* Not free */ + CS_OUT3(0x48, 0x00, 0x00) /* FM base off */ + else + CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */ - CS_OUT3 (0x42, 0x00, 0x00); /* SB base off */ - CS_OUT2 (0x22, irq); /* SB+WSS IRQ */ - CS_OUT2 (0x2a, dma1); /* SB+WSS DMA */ + CS_OUT3(0x42, 0x00, 0x00); /* SB base off */ + CS_OUT2(0x22, irq); /* SB+WSS IRQ */ + CS_OUT2(0x2a, dma1); /* SB+WSS DMA */ - if (dma2 != -1) - CS_OUT2 (0x25, dma2) /* WSS DMA2 */ - else - CS_OUT2 (0x25, 4); /* No WSS DMA2 */ + if (dma2 != -1) + CS_OUT2(0x25, dma2) /* WSS DMA2 */ + else + CS_OUT2(0x25, 4); /* No WSS DMA2 */ - CS_OUT2 (0x33, 0x01); /* Activate logical dev 0 */ + CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */ - { - unsigned long tlimit; + { + unsigned long tlimit; - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Delay */ /* * Initialize logical device 3 (MPU) */ #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0) - { - CS_OUT2 (0x15, 0x03); /* Select logical device 3 (MPU) */ - CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ - CS_OUT2 (0x22, mpu_irq); /* MPU IRQ */ - CS_OUT2 (0x33, 0x01); /* Activate logical dev 3 */ - } + if (mpu_base != 0 && mpu_irq != 0) + { + CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ + CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ + CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ + CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ + } #endif /* * Finally activate the chip */ - CS_OUT (0x79); - - - { - unsigned long tlimit; - - if (HZ / 5) - current->timeout = tlimit = jiffies + (HZ / 5); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ + CS_OUT(0x79); + + + { + unsigned long tlimit; + + if (HZ / 5) + current->timeout = tlimit = jiffies + (HZ / 5); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Delay */ /* * Then try to detect the codec part of the chip */ - if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp)) - return 1; - + if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) + return 1; + + + { + unsigned long tlimit; + + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Longer delay */ + } - { - unsigned long tlimit; + return 0; +} - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) +void +attach_cs4232(struct address_info *hw_config) +{ + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int old_num_mixers = num_mixers; + + if (dma2 == -1) + dma2 = dma1; + + hw_config->slots[0] = ad1848_init("Crystal audio controller", base, + irq, + dma1, /* Playback DMA */ + dma2, /* Capture DMA */ + 0, + hw_config->osp); + + if (num_mixers > old_num_mixers) + { /* Assume the mixer map is as suggested in the CS4232 databook */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ + } +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + if (mpu_base != 0 && mpu_irq != 0) { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; + static struct address_info hw_config2 = + {0}; /* Ensure it's initialized */ + + hw_config2.io_base = mpu_base; + hw_config2.irq = mpu_irq; + hw_config2.dma = -1; + hw_config2.dma2 = -1; + hw_config2.always_detect = 0; + hw_config2.name = NULL; + hw_config2.driver_use_1 = 0; + hw_config2.driver_use_2 = 0; + hw_config2.card_subtype = 0; + + if (probe_uart401(&hw_config2)) + { + mpu_detected = 1; + attach_uart401(&hw_config2); + } else + { + mpu_base = mpu_irq = 0; + } + hw_config->slots[1] = hw_config2.slots[1]; } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Longer delay */ - } - - return 0; +#endif } void -attach_cs4232 (struct address_info *hw_config) +unload_cs4232(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; - - if (dma2 == -1) - dma2 = dma1; - - ad1848_init ("Crystal audio controller", base, - irq, - dma1, /* Playback DMA */ - dma2, /* Capture DMA */ - 0, - hw_config->osp); - - if (num_mixers > old_num_mixers) - { /* Assume the mixer map is as suggested in the CS4232 databook */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ - } - + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + + if (dma2 == -1) + dma2 = dma1; + + ad1848_unload(base, + irq, + dma1, /* Playback DMA */ + dma2, /* Capture DMA */ + 0); + sound_unload_audiodev(hw_config->slots[0]); #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0) - { - static struct address_info hw_config2 = - {0}; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - - if (probe_uart401 (&hw_config2)) - { - mpu_detected = 1; - attach_uart401 (&hw_config2); - } - else - { - mpu_base = mpu_irq = 0; - } - } + if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) + { + static struct address_info hw_config2 = + {0}; /* Ensure it's initialized */ + + hw_config2.io_base = mpu_base; + hw_config2.irq = mpu_irq; + hw_config2.dma = -1; + hw_config2.dma2 = -1; + hw_config2.always_detect = 0; + hw_config2.name = NULL; + hw_config2.driver_use_1 = 0; + hw_config2.driver_use_2 = 0; + hw_config2.card_subtype = 0; + hw_config2.slots[1] = hw_config->slots[1]; + + unload_uart401(&hw_config2); + } #endif } void -unload_cs4232 (struct address_info *hw_config) +unload_cs4232_mpu(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; + /* Not required. Handled by cs4232_unload */ +} - if (dma2 == -1) - dma2 = dma1; +#ifdef MODULE - ad1848_unload (base, - irq, - dma1, /* Playback DMA */ - dma2, /* Capture DMA */ - 0); +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) - { - static struct address_info hw_config2 = - {0}; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - - unload_uart401 (&hw_config2); - } -#endif +struct address_info cfg; + +/* + * Install a CS4232 based card. Need to have ad1848 and mpu401 + * loaded ready. + */ + +int +init_module(void) +{ + if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) + { + printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + if (probe_cs4232(&cfg) == 0) + return -ENODEV; + + probe_cs4232_mpu(&cfg); /* Bug always returns 0 not OK -- AC */ + + attach_cs4232(&cfg); + attach_cs4232_mpu(&cfg); + SOUND_LOCK; + return 0; } void -unload_cs4232_mpu (struct address_info *hw_config) +cleanup_module(void) { - /* Not required. Handled by cs4232_unload */ + unload_cs4232_mpu(&cfg); + unload_cs4232(&cfg); + SOUND_LOCK_END; } - +#endif #endif diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 10daa50ad..1a1f230c2 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -16,537 +16,646 @@ #define _DEV_TABLE_C_ #include "sound_config.h" int sb_be_quiet = 0; +int softoss_dev = 0; int sound_started = 0; -int sndtable_get_cardcount (void); +int sndtable_get_cardcount(void); int -snd_find_driver (int type) +snd_find_driver(int type) { - int i, n = num_sound_drivers; + int i, n = num_sound_drivers; - for (i = 0; i < n; i++) - if (sound_drivers[i].card_type == type) - return i; + for (i = 0; i < n; i++) + if (sound_drivers[i].card_type == type) + return i; - return -1; + return -1; } static void -start_services (void) +start_services(void) { - int soundcards_installed; + int soundcards_installed; - if (!(soundcards_installed = sndtable_get_cardcount ())) - return; /* No cards detected */ +#ifdef FIXME + if (!(soundcards_installed = sndtable_get_cardcount())) + return; /* No cards detected */ +#endif #ifdef CONFIG_AUDIO - if (num_audiodevs) /* Audio devices present */ - { - int dev; + if (num_audiodevs) /* Audio devices present */ + { + int dev; - for (dev = 0; dev < num_audiodevs; dev++) - { - } - audio_init_devices (); - } + for (dev = 0; dev < num_audiodevs; dev++) + { + } + audio_init_devices(); + } #endif - return; + return; } static void -start_cards (void) +start_cards(void) { - int i, n = num_sound_cards; - int drv; + int i, n = num_sound_cards; + int drv; - sound_started = 1; - if (trace_init) - printk ("Sound initialization started\n"); + sound_started = 1; + if (trace_init) + printk("Sound initialization started\n"); #ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_preinit_lowlevel_drivers (void); + { + extern void sound_preinit_lowlevel_drivers(void); - sound_preinit_lowlevel_drivers (); - } +#ifdef FIXME + sound_preinit_lowlevel_drivers(); +#endif + } #endif /* * Check the number of cards actually defined in the table */ - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - num_sound_cards = i + 1; - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].enabled) - { - snd_installed_cards[i].for_driver_use = NULL; - - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - { - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - continue; - } - - snd_installed_cards[i].config.card_subtype = - sound_drivers[drv].card_subtype; - - if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) - { - - sound_drivers[drv].attach (&snd_installed_cards[i].config); - - } - else - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - } + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + num_sound_cards = i + 1; + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + if (snd_installed_cards[i].enabled) + { + snd_installed_cards[i].for_driver_use = NULL; + + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) + { + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + continue; + } + snd_installed_cards[i].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe(&snd_installed_cards[i].config)) + { + + sound_drivers[drv].attach(&snd_installed_cards[i].config); + + } else + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + } #ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_init_lowlevel_drivers (void); + { + extern void sound_init_lowlevel_drivers(void); - sound_init_lowlevel_drivers (); - } + sound_init_lowlevel_drivers(); + } #endif - if (trace_init) - printk ("Sound initialization complete\n"); + if (trace_init) + printk("Sound initialization complete\n"); } void -sndtable_init (void) +sndtable_init(void) { - start_cards (); + start_cards(); } void -sound_unload_drivers (void) +sound_unload_drivers(void) { - int i, n = num_sound_cards; - int drv; + int i, n = num_sound_cards; + int drv; - if (!sound_started) - return; + if (!sound_started) + return; - if (trace_init) - printk ("Sound unload started\n"); + if (trace_init) + printk("Sound unload started\n"); - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].enabled) - { - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) - { - if (sound_drivers[drv].unload) - { - sound_drivers[drv].unload (&snd_installed_cards[i].config); - snd_installed_cards[i].enabled = 0; - } - } - } + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + if (snd_installed_cards[i].enabled) + { + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1) + { + if (sound_drivers[drv].unload) + { + sound_drivers[drv].unload(&snd_installed_cards[i].config); + snd_installed_cards[i].enabled = 0; + } + } + } + for (i=0;i<num_audiodevs;i++) + DMAbuf_deinit(i); - if (trace_init) - printk ("Sound unload complete\n"); + if (trace_init) + printk("Sound unload complete\n"); } void -sound_unload_driver (int type) +sound_unload_driver(int type) { - int i, drv = -1, n = num_sound_cards; + int i, drv = -1, n = num_sound_cards; - unsigned long flags; + DEB(printk("unload driver %d: ", type)); - DEB (printk ("unload driver %d: ", type)); - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].card_type == type) - { - if (snd_installed_cards[i].enabled) - { - if ((drv = snd_find_driver (type)) != -1) - { - DEB (printk (" card %d", i)); - if (sound_drivers[drv].unload) + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + if (snd_installed_cards[i].card_type == type) { - sound_drivers[drv].unload (&snd_installed_cards[i].config); - snd_installed_cards[i].enabled = 0; + if (snd_installed_cards[i].enabled) + { + if ((drv = snd_find_driver(type)) != -1) + { + DEB(printk(" card %d", i)); + if (sound_drivers[drv].unload) + { + sound_drivers[drv].unload(&snd_installed_cards[i].config); + snd_installed_cards[i].enabled = 0; + } + } + } } - } + DEB(printk("\n")); +} + + +int +sndtable_probe(int unit, struct address_info *hw_config) +{ + int sel = -1; + + DEB(printk("sndtable_probe(%d)\n", unit)); + + if (!unit) + return 1; + + + if (sel == -1 && num_sound_cards < max_sound_cards) + { + int i; + + i = sel = (num_sound_cards++); + + snd_installed_cards[sel].card_type = unit; + snd_installed_cards[sel].enabled = 1; } - } - DEB (printk ("\n")); + if (sel != -1) + { + int drv; + + snd_installed_cards[sel].for_driver_use = NULL; + snd_installed_cards[sel].config.io_base = hw_config->io_base; + snd_installed_cards[sel].config.irq = hw_config->irq; + snd_installed_cards[sel].config.dma = hw_config->dma; + snd_installed_cards[sel].config.dma2 = hw_config->dma2; + snd_installed_cards[sel].config.name = hw_config->name; + snd_installed_cards[sel].config.always_detect = hw_config->always_detect; + snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + + if ((drv = snd_find_driver(snd_installed_cards[sel].card_type)) == -1) + { + snd_installed_cards[sel].enabled = 0; + DEB(printk("Failed to find driver\n")); + return 0; + } + DEB(printk("Driver name '%s'\n", sound_drivers[drv].name)); + + hw_config->card_subtype = + snd_installed_cards[sel].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe(hw_config)) + { + DEB(printk("Hardware probed OK\n")); + return 1; + } + DEB(printk("Failed to find hardware\n")); + snd_installed_cards[sel].enabled = 0; /* + * Mark as not detected + */ + return 0; + } + return 0; +} - save_flags (flags); - cli (); - restore_flags (flags); +int +sndtable_init_card(int unit, struct address_info *hw_config) +{ + int i, n = num_sound_cards; + + DEB(printk("sndtable_init_card(%d) entered\n", unit)); + + if (!unit) + { + sndtable_init(); + return 1; + } + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + if (snd_installed_cards[i].card_type == unit) + { + int drv; + + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + snd_installed_cards[i].config.dma2 = hw_config->dma2; + snd_installed_cards[i].config.name = hw_config->name; + snd_installed_cards[i].config.always_detect = hw_config->always_detect; + snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; + + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + else + { + + DEB(printk("Located card - calling attach routine\n")); + sound_drivers[drv].attach(hw_config); + + DEB(printk("attach routine finished\n")); + } + start_services(); + return 1; + } + DEB(printk("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards)); + return 0; } +int +sndtable_get_cardcount(void) +{ + return num_audiodevs + num_mixers + num_synths + num_midis; +} int -sndtable_probe (int unit, struct address_info *hw_config) +sndtable_identify_card(char *name) { - int sel = -1; + int i, n = num_sound_drivers; - DEB (printk ("sndtable_probe(%d)\n", unit)); + if (name == NULL) + return 0; - if (!unit) - return 1; + for (i = 0; i < n; i++) + if (sound_drivers[i].driver_id != NULL) + { + char *id = sound_drivers[i].driver_id; + int j; + for (j = 0; j < 80 && name[j] == id[j]; j++) + if (id[j] == 0 && name[j] == 0) /* Match */ + return sound_drivers[i].card_type; + } + return 0; +} - if (sel == -1 && num_sound_cards < max_sound_cards) - { - int i; +void +sound_setup(char *str, int *ints) +{ + int i, n = num_sound_cards; - i = sel = (num_sound_cards++); + /* + * First disable all drivers + */ - snd_installed_cards[sel].card_type = unit; - snd_installed_cards[sel].enabled = 1; - } + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + snd_installed_cards[i].enabled = 0; - if (sel != -1) - { - int drv; + if (ints[0] == 0 || ints[1] == 0) + return; + /* + * Then enable them one by time + */ - snd_installed_cards[sel].for_driver_use = NULL; - snd_installed_cards[sel].config.io_base = hw_config->io_base; - snd_installed_cards[sel].config.irq = hw_config->irq; - snd_installed_cards[sel].config.dma = hw_config->dma; - snd_installed_cards[sel].config.dma2 = hw_config->dma2; - snd_installed_cards[sel].config.name = hw_config->name; - snd_installed_cards[sel].config.always_detect = hw_config->always_detect; - snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + for (i = 1; i <= ints[0]; i++) + { + int card_type, ioaddr, irq, dma, dma2, + ptr, j; + unsigned int val; + + val = (unsigned int) ints[i]; + + card_type = (val & 0x0ff00000) >> 20; + + if (card_type > 127) + { + /* + * Add any future extensions here + */ + return; + } + ioaddr = (val & 0x000fff00) >> 8; + irq = (val & 0x000000f0) >> 4; + dma = (val & 0x0000000f); + dma2 = (val & 0xf0000000) >> 28; + + ptr = -1; + for (j = 0; j < n && ptr == -1; j++) + if (snd_installed_cards[j].card_type == card_type && + !snd_installed_cards[j].enabled) /* + * Not already found + */ + ptr = j; + + if (ptr == -1) + printk("Sound: Invalid setup parameter 0x%08x\n", val); + else + { + snd_installed_cards[ptr].enabled = 1; + snd_installed_cards[ptr].config.io_base = ioaddr; + snd_installed_cards[ptr].config.irq = irq; + snd_installed_cards[ptr].config.dma = dma; + snd_installed_cards[ptr].config.dma2 = dma2; + snd_installed_cards[ptr].config.name = NULL; + snd_installed_cards[ptr].config.always_detect = 0; + snd_installed_cards[ptr].config.driver_use_1 = 0; + snd_installed_cards[ptr].config.driver_use_2 = 0; + snd_installed_cards[ptr].config.card_subtype = 0; + } + } +} - if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1) - { - snd_installed_cards[sel].enabled = 0; - DEB (printk ("Failed to find driver\n")); - return 0; - } - DEB (printk ("Driver name '%s'\n", sound_drivers[drv].name)); - hw_config->card_subtype = - snd_installed_cards[sel].config.card_subtype = - sound_drivers[drv].card_subtype; +struct address_info + * +sound_getconf(int card_type) +{ + int j, ptr; + int n = num_sound_cards; - if (sound_drivers[drv].probe (hw_config)) - { - DEB (printk ("Hardware probed OK\n")); - return 1; - } + ptr = -1; + for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) + if (snd_installed_cards[j].card_type == card_type) + ptr = j; - DEB (printk ("Failed to find hardware\n")); - snd_installed_cards[sel].enabled = 0; /* - * Mark as not detected - */ - return 0; - } + if (ptr == -1) + return (struct address_info *) NULL; - return 0; + return &snd_installed_cards[ptr].config; } + int -sndtable_init_card (int unit, struct address_info *hw_config) +sound_install_audiodrv(int vers, + char *name, + struct audio_driver *driver, + int driver_size, + int flags, + unsigned int format_mask, + void *devc, + int dma1, + int dma2) { - int i, n = num_sound_cards; +#ifdef CONFIG_AUDIO + struct audio_driver *d; + struct audio_operations *op; + int l, num; - DEB (printk ("sndtable_init_card(%d) entered\n", unit)); + if (vers != AUDIO_DRIVER_VERSION || + driver_size > sizeof(struct audio_driver)) + { + printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name); + return -(EINVAL); + } + num = sound_alloc_audiodev(); - if (!unit) - { - sndtable_init (); - return 1; - } + if (num == -1) + { + printk(KERN_ERR "sound: Too many audio drivers\n"); + return -(EBUSY); + } + d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver))); + sound_mem_sizes[sound_nblocks] = sizeof(struct audio_driver); - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].card_type == unit) - { - int drv; + if (sound_nblocks < 1024) + sound_nblocks++;; - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - snd_installed_cards[i].config.dma2 = hw_config->dma2; - snd_installed_cards[i].config.name = hw_config->name; - snd_installed_cards[i].config.always_detect = hw_config->always_detect; - snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; - - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - else + op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct audio_operations); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (d == NULL || op == NULL) { + printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name); + sound_unload_audiodev(num); + return -(ENOMEM); + } + memset((char *) op, 0, sizeof(struct audio_operations)); + if (driver_size < sizeof(struct audio_driver)) + memset((char *) d, 0, sizeof(struct audio_driver)); - DEB (printk ("Located card - calling attach routine\n")); - sound_drivers[drv].attach (hw_config); + memcpy((char *) d, (char *) driver, driver_size); - DEB (printk ("attach routine finished\n")); - } - start_services (); - return 1; - } + op->d = d; - DEB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n", - unit, num_sound_cards)); - return 0; -} + l = strlen(name) + 1; + if (l > sizeof(op->name)) + l = sizeof(op->name); + strncpy(op->name, name, l); + op->name[l - 1] = 0; + op->flags = flags; + op->format_mask = format_mask; + op->devc = devc; -int -sndtable_get_cardcount (void) -{ - return num_audiodevs + num_mixers + num_synths + num_midis; +/* + * Hardcoded defaults + */ + audio_devs[num] = op; + + DMAbuf_init(num, dma1, dma2); + + audio_init_devices(); + return num; +#else + return -EINVAL; +#endif } int -sndtable_identify_card (char *name) +sound_install_mixer(int vers, + char *name, + struct mixer_operations *driver, + int driver_size, + void *devc) { - int i, n = num_sound_drivers; + struct mixer_operations *op; + int l; - if (name == NULL) - return 0; + int n = sound_alloc_mixerdev(); - for (i = 0; i < n; i++) - if (sound_drivers[i].driver_id != NULL) - { - char *id = sound_drivers[i].driver_id; - int j; + if (n == -1) + { + printk(KERN_ERR "Sound: Too many mixer drivers\n"); + return -(EBUSY); + } + if (vers != MIXER_DRIVER_VERSION || + driver_size > sizeof(struct mixer_operations)) + { + printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name); + return -(EINVAL); + } + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations); - for (j = 0; j < 80 && name[j] == id[j]; j++) - if (id[j] == 0 && name[j] == 0) /* Match */ - return sound_drivers[i].card_type; - } + if (sound_nblocks < 1024) + sound_nblocks++;; + if (op == NULL) + { + printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); + return -(ENOMEM); + } + memset((char *) op, 0, sizeof(struct mixer_operations)); - return 0; + memcpy((char *) op, (char *) driver, driver_size); + + l = strlen(name) + 1; + if (l > sizeof(op->name)) + l = sizeof(op->name); + strncpy(op->name, name, l); + op->name[l - 1] = 0; + op->devc = devc; + + mixer_devs[n] = op; + return n; } void -sound_setup (char *str, int *ints) +sound_unload_audiodev(int dev) { - int i, n = num_sound_cards; - - /* - * First disable all drivers - */ - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - snd_installed_cards[i].enabled = 0; - - if (ints[0] == 0 || ints[1] == 0) - return; - /* - * Then enable them one by time - */ + if (dev != -1) + audio_devs[dev] = NULL; +} - for (i = 1; i <= ints[0]; i++) - { - int card_type, ioaddr, irq, dma, dma2, ptr, j; - unsigned int val; +int +sound_alloc_audiodev(void) +{ + int i; - val = (unsigned int) ints[i]; + for (i = 0; i < MAX_AUDIO_DEV; i++) + { + if (audio_devs[i] == NULL) + { + if (i >= num_audiodevs) + num_audiodevs = i + 1; + return i; + } + } + return -1; +} - card_type = (val & 0x0ff00000) >> 20; +int +sound_alloc_mididev(void) +{ + int i; - if (card_type > 127) - { - /* - * Add any future extensions here - */ - return; - } + for (i = 0; i < MAX_MIDI_DEV; i++) + { + if (midi_devs[i] == NULL) + { + if (i >= num_midis) + num_midis++; + return i; + } + } - ioaddr = (val & 0x000fff00) >> 8; - irq = (val & 0x000000f0) >> 4; - dma = (val & 0x0000000f); - dma2 = (val & 0xf0000000) >> 28; - - ptr = -1; - for (j = 0; j < n && ptr == -1; j++) - if (snd_installed_cards[j].card_type == card_type && - !snd_installed_cards[j].enabled) /* - * Not already found - */ - ptr = j; - - if (ptr == -1) - printk ("Sound: Invalid setup parameter 0x%08x\n", val); - else - { - snd_installed_cards[ptr].enabled = 1; - snd_installed_cards[ptr].config.io_base = ioaddr; - snd_installed_cards[ptr].config.irq = irq; - snd_installed_cards[ptr].config.dma = dma; - snd_installed_cards[ptr].config.dma2 = dma2; - snd_installed_cards[ptr].config.name = NULL; - snd_installed_cards[ptr].config.always_detect = 0; - snd_installed_cards[ptr].config.driver_use_1 = 0; - snd_installed_cards[ptr].config.driver_use_2 = 0; - snd_installed_cards[ptr].config.card_subtype = 0; - } - } + return -1; } - -struct address_info - * -sound_getconf (int card_type) +int +sound_alloc_synthdev(void) { - int j, ptr; - int n = num_sound_cards; + int i; - ptr = -1; - for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) - if (snd_installed_cards[j].card_type == card_type) - ptr = j; - - if (ptr == -1) - return (struct address_info *) NULL; - - return &snd_installed_cards[ptr].config; + for (i = 0; i < MAX_SYNTH_DEV; i++) + { + if (synth_devs[i] == NULL) + { + if (i >= num_synths) + num_synths++; + return i; + } + } + return -1; } +int +sound_alloc_mixerdev(void) +{ + int i; + for (i = 0; i < MAX_MIXER_DEV; i++) + { + if (mixer_devs[i] == NULL) + { + if (i >= num_mixers) + num_mixers++; + return i; + } + } + return -1; +} int -sound_install_audiodrv (int vers, - char *name, - struct audio_driver *driver, - int driver_size, - int flags, - unsigned int format_mask, - void *devc, - int dma1, - int dma2) +sound_alloc_timerdev(void) { -#ifdef CONFIG_AUDIO - struct audio_driver *d; - struct audio_operations *op; - int l, num; - - if (num_audiodevs >= MAX_AUDIO_DEV) - { - printk ("Sound: Too many audio drivers\n"); - return -EIO; - } - - if (vers != AUDIO_DRIVER_VERSION || - driver_size > sizeof (struct audio_driver)) - { - printk ("Sound: Incompatible audio driver for %s\n", name); - return -EIO; - } - - - d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_driver))); - sound_mem_sizes[sound_nblocks] = sizeof (struct audio_driver); - - if (sound_nblocks < 1024) - sound_nblocks++;; - - op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct audio_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - if (d == NULL || op == NULL) - { - printk ("Sound: Can't allocate driver for (%s)\n", name); - return -ENOSPC; - } - - memset ((char *) op, 0, sizeof (struct audio_operations)); - if (driver_size < sizeof (struct audio_driver)) - memset ((char *) d, 0, sizeof (struct audio_driver)); - - memcpy ((char *) d, (char *) driver, driver_size); - - op->d = d; - - l = strlen (name) + 1; - if (l > sizeof (op->name)) - l = sizeof (op->name); - strncpy (op->name, name, l); - op->name[l - 1] = 0; - op->flags = flags; - op->format_mask = format_mask; - op->devc = devc; + int i; -/* - * Hardcoded defaults - */ - audio_devs[num_audiodevs] = op; - num = num_audiodevs++; + for (i = 0; i < MAX_TIMER_DEV; i++) + { + if (sound_timer_devs[i] == NULL) + { + if (i >= num_sound_timers) + num_sound_timers++; + return i; + } + } + return -1; +} - DMAbuf_init (num, dma1, dma2); +void +sound_unload_mixerdev(int dev) +{ + if (dev != -1) + mixer_devs[dev] = NULL; +} - audio_init_devices (); - return num; -#else - return -EINVAL; +void +sound_unload_mididev(int dev) +{ +#ifdef CONFIG_MIDI + if (dev != -1) + midi_devs[dev] = NULL; #endif } -int -sound_install_mixer (int vers, - char *name, - struct mixer_operations *driver, - int driver_size, - void *devc) +void +sound_unload_synthdev(int dev) +{ + if (dev != -1) + synth_devs[dev] = NULL; +} + +void +sound_unload_timerdev(int dev) { - struct mixer_operations *op; - int l; - - if (num_mixers >= MAX_MIXER_DEV) - { - printk ("Sound: Too many mixer drivers\n"); - return -EIO; - } - - if (vers != MIXER_DRIVER_VERSION || - driver_size > sizeof (struct mixer_operations)) - { - printk ("Sound: Incompatible mixer driver for %s\n", name); - return -EIO; - } - - - op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct mixer_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - if (op == NULL) - { - printk ("Sound: Can't allocate mixer driver for (%s)\n", name); - return -ENOSPC; - } - - memset ((char *) op, 0, sizeof (struct mixer_operations)); - - memcpy ((char *) op, (char *) driver, driver_size); - - l = strlen (name) + 1; - if (l > sizeof (op->name)) - l = sizeof (op->name); - strncpy (op->name, name, l); - op->name[l - 1] = 0; - op->devc = devc; - - mixer_devs[num_mixers] = op; - return num_mixers++; + if (dev != -1) + sound_timer_devs[dev] = NULL; } diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index a7e4026e8..a146614c8 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -15,7 +15,6 @@ #ifndef _DEV_TABLE_H_ #define _DEV_TABLE_H_ -#include <linux/config.h> /* * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) @@ -23,6 +22,23 @@ */ #define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ #define SNDCARD_SBPNP 29 +#define SNDCARD_OPL3SA1 38 +#define SNDCARD_OPL3SA1_SB 39 +#define SNDCARD_OPL3SA1_MPU 40 +#define SNDCARD_SOFTOSS 36 + +void attach_opl3sa_wss (struct address_info *hw_config); +int probe_opl3sa_wss (struct address_info *hw_config); +void attach_opl3sa_sb (struct address_info *hw_config); +int probe_opl3sa_sb (struct address_info *hw_config); +void attach_opl3sa_mpu (struct address_info *hw_config); +int probe_opl3sa_mpu (struct address_info *hw_config); +void unload_opl3sa_wss(struct address_info *hw_info); +void unload_opl3sa_sb(struct address_info *hw_info); +void unload_opl3sa_mpu(struct address_info *hw_info); +void attach_softsyn_card (struct address_info *hw_config); +int probe_softsyn (struct address_info *hw_config); +void unload_softsyn (struct address_info *hw_config); /* * NOTE! NOTE! NOTE! NOTE! @@ -125,6 +141,10 @@ struct dma_buffparms { OS_DMA_PARMS #endif int applic_profile; /* Application profile (APF_*) */ + /* Interrupt callback stuff */ + void (*audio_callback) (int dev, int parm); + int callback_parm; + int buf_flags[MAX_SUB_BUFFERS]; #define BUFF_EOF 0x00000001 /* Increment eof count */ #define BUFF_DIRTY 0x00000002 /* Buffer written */ @@ -318,12 +338,13 @@ struct sound_timer_operations { */ struct driver_info sound_drivers[] = { -#ifdef CONFIG_PSS +#if defined(CONFIG_PSS) && !defined(CONFIG_PSS_MODULE) {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif +#if defined(CONFIG_GUS) && !defined(CONFIG_GUS_MODULE) #ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif @@ -331,8 +352,9 @@ struct sound_timer_operations { {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif +#endif -#ifdef CONFIG_MSS +#if defined(CONFIG_MSS) && !defined(CONFIG_MSS_MODULE) {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* Compaq Deskpro XL */ {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, @@ -345,30 +367,30 @@ struct sound_timer_operations { {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif -#if defined(CONFIG_YM3812) +#if defined(CONFIG_YM3812) && !defined(CONFIG_YM3812_MODULE) {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, #endif -#ifdef CONFIG_PAS +#if defined(CONFIG_PAS) && !defined(CONFIG_PAS_MODULE) {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) && !defined(CONFIG_MPU401_MODULE) {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) && !defined(CONFIG_UART401_MODULE) {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", attach_uart401, probe_uart401, unload_uart401}, #endif -#if defined(CONFIG_MAUI) +#if defined(CONFIG_MAUI) && !defined(CONFIG_MAUI_MODULE) {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif -#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) && !defined(CONFIG_UART6850_MODULE) {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif -#ifdef CONFIG_SBDSP +#if defined(CONFIG_SBDSP) && !defined(CONFIG_SBDSP_MODULE) {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, @@ -381,12 +403,23 @@ struct sound_timer_operations { {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, #endif -#ifdef CONFIG_TRIX + +#ifdef CONFIG_OPL3SA1 + {"OPL3SA", 0, SNDCARD_OPL3SA1, "Yamaha OPL3-SA", attach_opl3sa_wss, probe_opl3sa_wss, unload_opl3sa_wss}, +/* {"OPL3SASB", 0, SNDCARD_OPL3SA1_SB, "OPL3-SA (SB mode)", attach_opl3sa_sb, probe_opl3sa_sb, unload_opl3sa_sb}, */ + {"OPL3SAMPU", 0, SNDCARD_OPL3SA1_MPU, "OPL3-SA MIDI", attach_opl3sa_mpu, probe_opl3sa_mpu, unload_opl3sa_mpu}, +#endif + +#if defined (CONFIG_TRIX) && !defined(CONFIG_TRIX_MODULE) {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif +#if defined(CONFIG_SOFTOSS) && !defined(CONFIG_SOFTOSS_MODULE) + {"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table", + attach_softsyn_card, probe_softsyn, unload_softsyn}, +#endif @@ -427,6 +460,18 @@ struct sound_timer_operations { {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, # endif #endif + +#ifdef CONFIG_OPL3SA1 + {SNDCARD_OPL3SA1, {OPL3SA1_BASE, OPL3SA1_IRQ, OPL3SA1_DMA, OPL3SA1_DMA2}, SND_DEFAULT_ENABLE}, +# ifdef OPL3SA1_MPU_BASE + {SNDCARD_OPL3SA1_MPU, {OPL3SA1_MPU_BASE, OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +# endif +#endif + +#ifdef CONFIG_SOFTOSS + {SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE}, +#endif + #ifdef CONFIG_SSCAPE {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, @@ -518,7 +563,7 @@ struct sound_timer_operations { {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE}, #endif -#ifdef CONFIG_YM3812 +#if defined(CONFIG_YM3812) {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif {0, {0}, 0} @@ -595,4 +640,15 @@ int sound_install_mixer(int vers, int driver_size, void *devc); +void sound_unload_audiodev(int dev); +void sound_unload_mixerdev(int dev); +void sound_unload_mididev(int dev); +void sound_unload_synthdev(int dev); +void sound_unload_timerdev(int dev); +int sound_alloc_audiodev(void); +int sound_alloc_mixerdev(void); +int sound_alloc_timerdev(void); +int sound_alloc_synthdev(void); +int sound_alloc_mididev(void); #endif /* _DEV_TABLE_H_ */ + diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 54523d88f..609831377 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -22,12 +22,12 @@ static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = {NULL}; static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = { - {0}}; + {0}}; static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = {NULL}; static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = { - {0}}; + {0}}; static int ndmaps = 0; @@ -35,721 +35,700 @@ static int ndmaps = 0; static struct dma_buffparms dmaps[MAX_DMAP] = { - {0}}; + {0}}; -static void dma_reset_output (int dev); -static void dma_reset_input (int dev); -static int local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); +static void dma_reset_output(int dev); +static void dma_reset_input(int dev); +static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode); static void -dma_init_buffers (int dev, struct dma_buffparms *dmap) +dma_init_buffers(int dev, struct dma_buffparms *dmap) { - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->bytes_in_use = dmap->buffsize; - - dmap->dma_mode = DMODE_NONE; - dmap->mapping_flags = 0; - dmap->neutral_byte = 0x80; - dmap->data_rate = 8000; - dmap->cfrag = -1; - dmap->closing = 0; - dmap->nbufs = 1; - dmap->flags = DMA_BUSY; /* Other flags off */ + dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + dmap->byte_counter = 0; + dmap->max_byte_counter = 8000 * 60 * 60; + dmap->bytes_in_use = dmap->buffsize; + + dmap->dma_mode = DMODE_NONE; + dmap->mapping_flags = 0; + dmap->neutral_byte = 0x80; + dmap->data_rate = 8000; + dmap->cfrag = -1; + dmap->closing = 0; + dmap->nbufs = 1; + dmap->flags = DMA_BUSY; /* Other flags off */ } static int -open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) +open_dmap(int dev, int mode, struct dma_buffparms *dmap, int chan) { - if (dmap->flags & DMA_BUSY) - return -EBUSY; - - { - int err; - - if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0) - return err; - } - - if (dmap->raw_buf == NULL) - { - printk ("Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - - if (sound_open_dma (chan, audio_devs[dev]->name)) - { - printk ("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; - } - - dma_init_buffers (dev, dmap); - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->applic_profile = APF_NORMAL; - dmap->needs_reorg = 1; - - - if (dmap->dma_mode & DMODE_OUTPUT) - { - out_sleep_flag[dev].opts = WK_NONE; - } - else - { - in_sleep_flag[dev].opts = WK_NONE; - } - - return 0; + if (dmap->flags & DMA_BUSY) + return -EBUSY; + + { + int err; + + if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0) + return err; + } + + if (dmap->raw_buf == NULL) + { + printk("Sound: DMA buffers not available\n"); + return -ENOSPC; /* Memory allocation failed during boot */ + } + if (sound_open_dma(chan, audio_devs[dev]->name)) + { + printk("Unable to grab(2) DMA%d for the audio driver\n", chan); + return -EBUSY; + } + dma_init_buffers(dev, dmap); + dmap->open_mode = mode; + dmap->subdivision = dmap->underrun_count = 0; + dmap->fragment_size = 0; + dmap->max_fragments = 65536; /* Just a large value */ + dmap->byte_counter = 0; + dmap->max_byte_counter = 8000 * 60 * 60; + dmap->applic_profile = APF_NORMAL; + dmap->needs_reorg = 1; + dmap->audio_callback = NULL; + dmap->callback_parm = 0; + + + if (dmap->dma_mode & DMODE_OUTPUT) + { + out_sleep_flag[dev].opts = WK_NONE; + } else + { + in_sleep_flag[dev].opts = WK_NONE; + } + + return 0; } static void -close_dmap (int dev, struct dma_buffparms *dmap, int chan) +close_dmap(int dev, struct dma_buffparms *dmap, int chan) { - sound_close_dma (chan); + sound_close_dma(chan); - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; + if (dmap->flags & DMA_BUSY) + dmap->dma_mode = DMODE_NONE; + dmap->flags &= ~DMA_BUSY; - disable_dma (dmap->dma); + disable_dma(dmap->dma); } static unsigned int -default_set_bits (int dev, unsigned int bits) +default_set_bits(int dev, unsigned int bits) { - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits); + return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits); } static int -default_set_speed (int dev, int speed) +default_set_speed(int dev, int speed) { - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) & speed); + return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t) & speed); } static short -default_set_channels (int dev, short channels) +default_set_channels(int dev, short channels) { - int c = channels; + int c = channels; - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c); + return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c); } static void -check_driver (struct audio_driver *d) +check_driver(struct audio_driver *d) { - if (d->set_speed == NULL) - d->set_speed = default_set_speed; - if (d->set_bits == NULL) - d->set_bits = default_set_bits; - if (d->set_channels == NULL) - d->set_channels = default_set_channels; + if (d->set_speed == NULL) + d->set_speed = default_set_speed; + if (d->set_bits == NULL) + d->set_bits = default_set_bits; + if (d->set_channels == NULL) + d->set_channels = default_set_channels; } int -DMAbuf_open (int dev, int mode) +DMAbuf_open(int dev, int mode) { - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (dev >= num_audiodevs) - { - return -ENXIO; - } - - if (!audio_devs[dev]) - { - return -ENXIO; - } - - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; - } - - check_driver (audio_devs[dev]->d); - - if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) - return retval; - - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; - - if (dmap_in == dmap_out) - audio_devs[dev]->flags &= ~DMA_DUPLEX; + int retval; + struct dma_buffparms *dmap_in = NULL; + struct dma_buffparms *dmap_out = NULL; - if (mode & OPEN_WRITE) - { - if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) - { - audio_devs[dev]->d->close (dev); - return retval; - } - } - - audio_devs[dev]->enable_bits = mode; + if (dev >= num_audiodevs || audio_devs[dev] == NULL) + { + return -ENXIO; + } + if (!audio_devs[dev]) + { + return -ENXIO; + } + if (!(audio_devs[dev]->flags & DMA_DUPLEX)) + { + audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; + audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; + } + check_driver(audio_devs[dev]->d); - if (mode == OPEN_READ || (mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) - { - audio_devs[dev]->d->close (dev); + if ((retval = audio_devs[dev]->d->open(dev, mode)) < 0) + return retval; - if (mode & OPEN_WRITE) - { - close_dmap (dev, dmap_out, audio_devs[dev]->dmap_out->dma); - } + dmap_out = audio_devs[dev]->dmap_out; + dmap_in = audio_devs[dev]->dmap_in; - return retval; - } - } + if (dmap_in == dmap_out) + audio_devs[dev]->flags &= ~DMA_DUPLEX; - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; + if (mode & OPEN_WRITE) + { + if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) + { + audio_devs[dev]->d->close(dev); + return retval; + } + } + audio_devs[dev]->enable_bits = mode; - if (mode & OPEN_READ) - in_sleep_flag[dev].opts = WK_NONE; + if (mode == OPEN_READ || (mode != OPEN_WRITE && + audio_devs[dev]->flags & DMA_DUPLEX)) + { + if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) + { + audio_devs[dev]->d->close(dev); + + if (mode & OPEN_WRITE) + { + close_dmap(dev, dmap_out, audio_devs[dev]->dmap_out->dma); + } + return retval; + } + } + audio_devs[dev]->open_mode = mode; + audio_devs[dev]->go = 1; - if (mode & OPEN_WRITE) - out_sleep_flag[dev].opts = WK_NONE; + if (mode & OPEN_READ) + in_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->d->set_bits (dev, 8); - audio_devs[dev]->d->set_channels (dev, 1); - audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); + if (mode & OPEN_WRITE) + out_sleep_flag[dev].opts = WK_NONE; - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } + audio_devs[dev]->d->set_bits(dev, 8); + audio_devs[dev]->d->set_channels(dev, 1); + audio_devs[dev]->d->set_speed(dev, DSP_DEFAULT_SPEED); - return 0; + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + { + memset(audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + } + return 0; } void -DMAbuf_reset (int dev) +DMAbuf_reset(int dev) { - if (audio_devs[dev]->open_mode & OPEN_WRITE) - dma_reset_output (dev); + if (audio_devs[dev]->open_mode & OPEN_WRITE) + dma_reset_output(dev); - if (audio_devs[dev]->open_mode & OPEN_READ) - dma_reset_input (dev); + if (audio_devs[dev]->open_mode & OPEN_READ) + dma_reset_input(dev); } static void -dma_reset_output (int dev) +dma_reset_output(int dev) { - unsigned long flags; - int tmout; + unsigned long flags; + int tmout; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ - return; + if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ + return; /* * First wait until the current fragment has been played completely */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 10; /* Some safety distance */ + tmout += HZ / 5; /* Some safety distance */ - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - audio_devs[dev]->dmap_out->underrun_count = 0; - if (!(current->signal & ~current->blocked) - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + audio_devs[dev]->dmap_out->underrun_count = 0; + if (!(current->signal & ~current->blocked) + && audio_devs[dev]->dmap_out->qlen + && audio_devs[dev]->dmap_out->underrun_count == 0) { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* * Finally shut the device off */ - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_output) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_output (dev); - audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; - restore_flags (flags); - - clear_dma_ff (dmap->dma); - disable_dma (dmap->dma); - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0); - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + if (!(audio_devs[dev]->flags & DMA_DUPLEX) || + !audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->halt_io(dev); + else + audio_devs[dev]->d->halt_output(dev); + audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; + restore_flags(flags); + + clear_dma_ff(dmap->dma); + disable_dma(dmap->dma); + dmap->byte_counter = 0; + reorganize_buffers(dev, audio_devs[dev]->dmap_out, 0); + dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; } static void -dma_reset_input (int dev) +dma_reset_input(int dev) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - save_flags (flags); - cli (); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_input) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_input (dev); - audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; - restore_flags (flags); - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1); + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + + save_flags(flags); + cli(); + if (!(audio_devs[dev]->flags & DMA_DUPLEX) || + !audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->halt_io(dev); + else + audio_devs[dev]->d->halt_input(dev); + audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; + restore_flags(flags); + + dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + dmap->byte_counter = 0; + reorganize_buffers(dev, audio_devs[dev]->dmap_in, 1); } void -DMAbuf_launch_output (int dev, struct dma_buffparms *dmap) +DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) { - if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ + if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) + return; /* Don't start DMA yet */ - dmap->dma_mode = DMODE_OUTPUT; + dmap->dma_mode = DMODE_OUTPUT; - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - if (!(dmap->flags & DMA_STARTED)) - { - reorganize_buffers (dev, dmap, 0); - - if (audio_devs[dev]->d->prepare_for_output (dev, - dmap->fragment_size, dmap->nbufs)) - return; - - if (!(dmap->flags & DMA_NODMA)) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_WRITE); - } - dmap->flags |= DMA_STARTED; - } - if (dmap->counts[dmap->qhead] == 0) - dmap->counts[dmap->qhead] = dmap->fragment_size; - - dmap->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - dmap->flags |= DMA_ACTIVE; + if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) + { + if (!(dmap->flags & DMA_STARTED)) + { + reorganize_buffers(dev, dmap, 0); + + if (audio_devs[dev]->d->prepare_for_output(dev, + dmap->fragment_size, dmap->nbufs)) + return; + + if (!(dmap->flags & DMA_NODMA)) + { + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_WRITE); + } + dmap->flags |= DMA_STARTED; + } + if (dmap->counts[dmap->qhead] == 0) + dmap->counts[dmap->qhead] = dmap->fragment_size; + + dmap->dma_mode = DMODE_OUTPUT; + audio_devs[dev]->d->output_block(dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1); + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; } int -DMAbuf_sync (int dev) +DMAbuf_sync(int dev) { - unsigned long flags; - int tmout, n = 0; - - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 10; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - ; - if (dmap->qlen > 0) - if (!(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output (dev, dmap); - ; + unsigned long flags; + int tmout, n = 0; - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - while (!(current->signal & ~current->blocked) - && n++ <= audio_devs[dev]->dmap_out->nbufs - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { + if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + return 0; + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; - restore_flags (flags); - return audio_devs[dev]->dmap_out->qlen; - } - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - restore_flags (flags); - /* - * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait until the device has finished playing. - */ - - save_flags (flags); - cli (); - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - { - while (!((current->signal & ~current->blocked)) - && audio_devs[dev]->d->local_qlen (dev)) - { - - { - unsigned long tlimit; - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - } - restore_flags (flags); - } - audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; - return audio_devs[dev]->dmap_out->qlen; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + save_flags(flags); + cli(); + + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 5; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + + ; + if (dmap->qlen > 0) + if (!(dmap->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, dmap); + ; + + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; + + audio_devs[dev]->dmap_out->underrun_count = 0; + while (!(current->signal & ~current->blocked) + && n++ <= audio_devs[dev]->dmap_out->nbufs + && audio_devs[dev]->dmap_out->qlen + && audio_devs[dev]->dmap_out->underrun_count == 0) + { + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) + { + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; + restore_flags(flags); + return audio_devs[dev]->dmap_out->qlen; + } + } + audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + restore_flags(flags); + /* + * Some devices such as GUS have huge amount of on board RAM for the + * audio data. We have to wait until the device has finished playing. + */ + + save_flags(flags); + cli(); + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ + { + while (!((current->signal & ~current->blocked)) + && audio_devs[dev]->d->local_qlen(dev)) + { + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + } + } + restore_flags(flags); + } + audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; + return audio_devs[dev]->dmap_out->qlen; } int -DMAbuf_release (int dev, int mode) +DMAbuf_release(int dev, int mode) { - unsigned long flags; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->closing = 1; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->closing = 1; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) - if (!((current->signal & ~current->blocked)) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) - { - DMAbuf_sync (dev); - } - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } - - save_flags (flags); - cli (); + unsigned long flags; + + if (audio_devs[dev]->open_mode & OPEN_WRITE) + audio_devs[dev]->dmap_out->closing = 1; + if (audio_devs[dev]->open_mode & OPEN_READ) + audio_devs[dev]->dmap_in->closing = 1; + + if (audio_devs[dev]->open_mode & OPEN_WRITE) + if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) + if (!((current->signal & ~current->blocked)) + && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) + { + DMAbuf_sync(dev); + } + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + { + memset(audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + } + save_flags(flags); + cli(); - DMAbuf_reset (dev); - audio_devs[dev]->d->close (dev); + DMAbuf_reset(dev); + audio_devs[dev]->d->close(dev); - if (audio_devs[dev]->open_mode & OPEN_WRITE) - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + if (audio_devs[dev]->open_mode & OPEN_WRITE) + close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->open_mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); - audio_devs[dev]->open_mode = 0; + if (audio_devs[dev]->open_mode == OPEN_READ || + (audio_devs[dev]->open_mode != OPEN_WRITE && + audio_devs[dev]->flags & DMA_DUPLEX)) + close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); + audio_devs[dev]->open_mode = 0; - restore_flags (flags); + restore_flags(flags); - return 0; + return 0; } int -DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap) +DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) { - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) - return 0; - - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ - { - DMAbuf_sync (dev); - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - if (!dmap->dma_mode) - { - int err; - - reorganize_buffers (dev, dmap, 1); - if ((err = audio_devs[dev]->d->prepare_for_input (dev, - dmap->fragment_size, dmap->nbufs)) < 0) - { - return err; - } - dmap->dma_mode = DMODE_INPUT; - } - - if (!(dmap->flags & DMA_ACTIVE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - return 0; -} + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; -int -DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) -{ - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EIO; - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - save_flags (flags); - cli (); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (1)\n"); - return -EINVAL; - } - else - while (dmap->qlen <= 0 && n++ < 10) - { - int tmout; + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) + return 0; - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || - !audio_devs[dev]->go) + if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ { - restore_flags (flags); - return -EAGAIN; + DMAbuf_sync(dev); + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; } - - if ((err = DMAbuf_activate_recording (dev, dmap)) < 0) + if (!dmap->dma_mode) { - restore_flags (flags); - return err; + int err; + + reorganize_buffers(dev, dmap, 1); + if ((err = audio_devs[dev]->d->prepare_for_input(dev, + dmap->fragment_size, dmap->nbufs)) < 0) + { + return err; + } + dmap->dma_mode = DMODE_INPUT; } - - /* Wait for the next block */ - - if (dontblock) + if (!(dmap->flags & DMA_ACTIVE)) { - restore_flags (flags); - return -EAGAIN; + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_READ); + audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 0); + dmap->flags |= DMA_ACTIVE; + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); } + return 0; +} - if (!audio_devs[dev]->go) - tmout = 0; - else +int +DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) +{ + unsigned long flags; + int err = 0, n = 0; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EIO; + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + + save_flags(flags); + cli(); + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 10; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - + printk("Sound: Can't read from mmapped device (1)\n"); + restore_flags(flags); + return -EINVAL; + } else + while (dmap->qlen <= 0 && n++ < 10) + { + int tmout; + + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || + !audio_devs[dev]->go) + { + restore_flags(flags); + return -EAGAIN; + } + if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) + { + restore_flags(flags); + return err; + } + /* Wait for the next block */ + + if (dontblock) + { + restore_flags(flags); + return -EAGAIN; + } + if (!audio_devs[dev]->go) + tmout = 0; + else + { + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 5; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + } + + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + in_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&in_sleeper[dev]); + if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + in_sleep_flag[dev].opts |= WK_TIMEOUT; + } + in_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) + { + err = -EIO; + printk("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); + dma_reset_input(dev); + ; + } else + err = -EINTR; + } + restore_flags(flags); - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; - } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) + if (dmap->qlen <= 0) { - err = -EIO; - printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input (dev); - ; + if (err == 0) + err = -EINTR; + return err; } - else - err = -EINTR; - } - restore_flags (flags); + *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; + *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - if (dmap->qlen <= 0) - { - if (err == 0) - err = -EINTR; - return err; - } - - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; + return dmap->qhead; } int -DMAbuf_rmchars (int dev, int buff_no, int c) +DMAbuf_rmchars(int dev, int buff_no, int c) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - int p = dmap->counts[dmap->qhead] + c; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; - } - else if (dmap->qlen <= 0) - return -EIO; - else if (p >= dmap->fragment_size) - { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } - else - dmap->counts[dmap->qhead] = p; - - return 0; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + + int p = dmap->counts[dmap->qhead] + c; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + printk("Sound: Can't read from mmapped device (2)\n"); + return -EINVAL; + } else if (dmap->qlen <= 0) + return -EIO; + else if (p >= dmap->fragment_size) + { /* This buffer is completely empty */ + dmap->counts[dmap->qhead] = 0; + dmap->qlen--; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + } else + dmap->counts[dmap->qhead] = p; + + return 0; } int -DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction) +DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction) { /* * Try to approximate the active byte position of the DMA pointer within the * buffer area as well as possible. */ - int pos; - unsigned long flags; - - save_flags (flags); - cli (); - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else - { - int chan = dmap->dma; - - 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)) - if (direction == DMODE_OUTPUT) - { - if (dmap->qhead == 0) - if (pos > dmap->fragment_size) + int pos; + unsigned long flags; + + save_flags(flags); + cli(); + if (!(dmap->flags & DMA_ACTIVE)) pos = 0; - } else { - if (dmap->qtail == 0) - if (pos > dmap->fragment_size) - pos = 0; + int chan = dmap->dma; + + 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)) + if (direction == DMODE_OUTPUT) + { + if (dmap->qhead == 0) + if (pos > dmap->fragment_size) + pos = 0; + } else + { + if (dmap->qtail == 0) + if (pos > dmap->fragment_size) + pos = 0; + } + if (pos < 0) + pos = 0; + if (pos >= dmap->bytes_in_use) + pos = 0; + enable_dma(dmap->dma); } + restore_flags(flags); + /* printk( "%04x ", pos); */ - if (pos < 0) - pos = 0; - if (pos >= dmap->bytes_in_use) - pos = 0; - enable_dma (dmap->dma); - } - restore_flags (flags); - /* printk ("%04x ", pos); */ - - return pos; + return pos; } /* @@ -757,824 +736,816 @@ DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction) * one or more audio devices at desired moment. */ static void -DMAbuf_start_device (int dev) +DMAbuf_start_device(int dev) { - if (audio_devs[dev]->open_mode != 0) - if (!audio_devs[dev]->go) - { - /* OK to start the device */ - audio_devs[dev]->go = 1; + if (audio_devs[dev]->open_mode != 0) + if (!audio_devs[dev]->go) + { + /* OK to start the device */ + audio_devs[dev]->go = 1; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } } void -DMAbuf_start_devices (unsigned int devmask) +DMAbuf_start_devices(unsigned int devmask) { - int dev; + int dev; - for (dev = 0; dev < num_audiodevs; dev++) - if (devmask & (1 << dev)) - DMAbuf_start_device (dev); + for (dev = 0; dev < num_audiodevs; dev++) + if ((devmask & (1 << dev)) && audio_devs[dev] != NULL) + DMAbuf_start_device(dev); } int -DMAbuf_space_in_queue (int dev) +DMAbuf_space_in_queue(int dev) { - int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int len, max, tmp; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - int lim = dmap->nbufs; + int lim = dmap->nbufs; - if (lim < 2) - lim = 2; + if (lim < 2) + lim = 2; - if (dmap->qlen >= lim) /* No space at all */ - return 0; + if (dmap->qlen >= lim) /* No space at all */ + return 0; - /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ + /* + * Verify that there are no more pending buffers than the limit + * defined by the process. + */ - max = dmap->max_fragments; - if (max > dmap->nbufs) - max = dmap->nbufs; - len = dmap->qlen; + max = dmap->max_fragments; + if (max > lim) + max = lim; + len = dmap->qlen; - if (audio_devs[dev]->d->local_qlen) - { - tmp = audio_devs[dev]->d->local_qlen (dev); - if (tmp && len) - tmp--; /* - * This buffer has been counted twice - */ - len += tmp; - } + if (audio_devs[dev]->d->local_qlen) + { + tmp = audio_devs[dev]->d->local_qlen(dev); + if (tmp && len) + tmp--; /* + * This buffer has been counted twice + */ + len += tmp; + } + if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ + len = len + 1; - if (len >= max) - return 0; - return max - len; + if (len >= max) + return 0; + return max - len; } static int -output_sleep (int dev, int dontblock) +output_sleep(int dev, int dontblock) { - int tmout; - int err = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dontblock) - { - return -EAGAIN; - } - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - { - return -EAGAIN; - } - - /* - * Wait for free space - */ - if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 10; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - if ((current->signal & ~current->blocked)) - return -EIO; - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - ; - dma_reset_output (dev); - } - else if ((current->signal & ~current->blocked)) - { - err = -EINTR; - } - - return err; + int tmout; + int err = 0; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (dontblock) + { + return -EAGAIN; + } + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + { + return -EAGAIN; + } + /* + * Wait for free space + */ + if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) + tmout = 0; + else + { + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 5; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + } + + if ((current->signal & ~current->blocked)) + return -EIO; + + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) + { + printk("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); + ; + dma_reset_output(dev); + } else if ((current->signal & ~current->blocked)) + { + err = -EINTR; + } + return err; } static int -find_output_space (int dev, char **buf, int *size) +find_output_space(int dev, char **buf, int *size) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - unsigned long offs, active_offs; - long len; - int maxfrags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long flags; + unsigned long active_offs; + long len, offs; + int maxfrags; + int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - if (!(maxfrags = DMAbuf_space_in_queue (dev))) - { - return 0; - } + *buf = dmap->raw_buf; - save_flags (flags); - cli (); + if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) + { + return 0; + } + save_flags(flags); + cli(); #ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; + active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; #else - active_offs = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - /* Check for pointer wrapping situation */ - if (active_offs < 0 || active_offs >= dmap->bytes_in_use) - active_offs = 0; - active_offs += dmap->byte_counter; + active_offs = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT); + /* Check for pointer wrapping situation */ + if (active_offs < 0 || active_offs >= dmap->bytes_in_use) + active_offs = 0; + active_offs += dmap->byte_counter; #endif - offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; - *buf = dmap->raw_buf + offs; - - len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - - if ((offs + len) > dmap->bytes_in_use) - len = dmap->bytes_in_use - offs; - - if (len < 0) - { - restore_flags (flags); - return 0; - } + offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; + if (offs < 0 || offs >= dmap->bytes_in_use) + { + printk("OSS: Got unexpected offs %ld. Giving up.\n", offs); + printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); + return 0; + } + *buf = dmap->raw_buf + offs; - if (len > maxfrags * dmap->fragment_size) - len = maxfrags * dmap->fragment_size; + len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - *size = len & ~3; + if ((offs + len) > dmap->bytes_in_use) + { + len = dmap->bytes_in_use - offs; + } + if (len < 0) + { + restore_flags(flags); + return 0; + } + if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) + { + len = (maxfrags * dmap->fragment_size) - occupied_bytes; + } + *size = len & ~3; - restore_flags (flags); - return (len > 0); + restore_flags(flags); + return (len > 0); } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) +DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) { - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); + unsigned long flags; + int err = -EIO; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; - } + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); - if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ - { - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - dmap->dma_mode = DMODE_OUTPUT; + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + printk("Sound: Can't write to mmapped device (3)\n"); + return -EINVAL; + } + if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ + { + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; + } + dmap->dma_mode = DMODE_OUTPUT; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - while (!find_output_space (dev, buf, size)) - { - if ((err = output_sleep (dev, dontblock)) < 0) - { - restore_flags (flags); - return err; - } - } + while (find_output_space(dev, buf, size) <= 0) + { + if ((err = output_sleep(dev, dontblock)) < 0) + { + restore_flags(flags); + return err; + } + } - restore_flags (flags); + restore_flags(flags); - return 0; + return 0; } int -DMAbuf_move_wrpointer (int dev, int l) +DMAbuf_move_wrpointer(int dev, int l) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long ptr = (dmap->user_counter / dmap->fragment_size) - * dmap->fragment_size; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long ptr = (dmap->user_counter / dmap->fragment_size) + * dmap->fragment_size; - unsigned long end_ptr, p; - int post = (dmap->flags & DMA_POST); + unsigned long end_ptr, p; + int post = (dmap->flags & DMA_POST); - ; + ; - dmap->flags &= ~DMA_POST; + dmap->flags &= ~DMA_POST; - dmap->cfrag = -1; + dmap->cfrag = -1; - dmap->user_counter += l; - dmap->flags |= DMA_DIRTY; + dmap->user_counter += l; + dmap->flags |= DMA_DIRTY; - if (dmap->user_counter >= dmap->max_byte_counter) - { /* Wrap the byte counters */ - long decr = dmap->user_counter; + if (dmap->user_counter >= dmap->max_byte_counter) + { /* Wrap the byte counters */ + long decr = dmap->user_counter; - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->user_counter; - dmap->byte_counter -= decr; - } - - end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; + dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->user_counter; + dmap->byte_counter -= decr; + } + end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - p = (dmap->user_counter - 1) % dmap->bytes_in_use; - dmap->neutral_byte = dmap->raw_buf[p]; + p = (dmap->user_counter - 1) % dmap->bytes_in_use; + dmap->neutral_byte = dmap->raw_buf[p]; - /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) - { - dmap->counts[dmap->qtail] = dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - ptr += dmap->fragment_size; - } + /* Update the fragment based bookkeeping too */ + while (ptr < end_ptr) + { + dmap->counts[dmap->qtail] = dmap->fragment_size; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + dmap->qlen++; + ptr += dmap->fragment_size; + } - dmap->counts[dmap->qtail] = dmap->user_counter - ptr; + dmap->counts[dmap->qtail] = dmap->user_counter - ptr; /* * Let the low level driver to perform some postprocessing to * the written data. */ - if (audio_devs[dev]->d->postprocess_write) - audio_devs[dev]->d->postprocess_write (dev); - - if (!(dmap->flags & DMA_ACTIVE)) - if (dmap->qlen > 1 || - (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - { - DMAbuf_launch_output (dev, dmap); - } - - ; - return 0; + if (audio_devs[dev]->d->postprocess_write) + audio_devs[dev]->d->postprocess_write(dev); + + if (!(dmap->flags & DMA_ACTIVE)) + if (dmap->qlen > 1 || + (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) + { + DMAbuf_launch_output(dev, dmap); + }; + return 0; } int -DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) +DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(1) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, - (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (chan < 0) - return 0; - - sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0); - - return count; + int chan; + struct dma_buffparms *dmap; + + if (dma_mode == DMA_MODE_WRITE) + { + chan = audio_devs[dev]->dmap_out->dma; + dmap = audio_devs[dev]->dmap_out; + } else + { + chan = audio_devs[dev]->dmap_in->dma; + dmap = audio_devs[dev]->dmap_in; + } + + if (dmap->raw_buf == NULL) + { + printk("sound: DMA buffer(1) == NULL\n"); + printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); + return 0; + } + if (chan < 0) + return 0; + + sound_start_dma(dev, dmap, chan, physaddr, count, dma_mode, 0); + + return count; } static int -local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) +local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(2) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, - (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (dmap->flags & DMA_NODMA) - { - return 1; - } - - if (chan < 0) - return 0; - - sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); - dmap->flags |= DMA_STARTED; - - return count; + int chan; + struct dma_buffparms *dmap; + + if (dma_mode == DMA_MODE_WRITE) + { + chan = audio_devs[dev]->dmap_out->dma; + dmap = audio_devs[dev]->dmap_out; + } else + { + chan = audio_devs[dev]->dmap_in->dma; + dmap = audio_devs[dev]->dmap_in; + } + + if (dmap->raw_buf == NULL) + { + printk("sound: DMA buffer(2) == NULL\n"); + printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); + return 0; + } + if (dmap->flags & DMA_NODMA) + { + return 1; + } + if (chan < 0) + return 0; + + sound_start_dma(dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); + dmap->flags |= DMA_STARTED; + + return count; } static void -finish_output_interrupt (int dev, struct dma_buffparms *dmap) +finish_output_interrupt(int dev, struct dma_buffparms *dmap) { - unsigned long flags; - - save_flags (flags); - cli (); - if ((out_sleep_flag[dev].opts & WK_SLEEP)) - { - { - out_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&out_sleeper[dev]); - }; - } - restore_flags (flags); + unsigned long flags; + + if (dmap->audio_callback != NULL) + dmap->audio_callback(dev, dmap->callback_parm); + + save_flags(flags); + cli(); + if ((out_sleep_flag[dev].opts & WK_SLEEP)) + { + { + out_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&out_sleeper[dev]); + }; + } + restore_flags(flags); } static void -do_outputintr (int dev, int dummy) +do_outputintr(int dev, int dummy) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - int this_fragment; + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int this_fragment; #ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_out->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + if (audio_devs[dev]->dmap_out->dma >= 0) + sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); #endif - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ - { - /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - - DMAbuf_launch_output (dev, dmap); - finish_output_interrupt (dev, dmap); - return; - } - - save_flags (flags); - cli (); - - dmap->qlen--; - this_fragment = dmap->qhead; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } + if (dmap->raw_buf == NULL) + { + printk("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ + { + /* mmapped access */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + if (dmap->qhead == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + dmap->qlen++; /* Yes increment it (don't decrement) */ + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + dmap->flags &= ~DMA_ACTIVE; + dmap->counts[dmap->qhead] = dmap->fragment_size; + + DMAbuf_launch_output(dev, dmap); + finish_output_interrupt(dev, dmap); + return; + } + save_flags(flags); + cli(); - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; + dmap->qlen--; + this_fragment = dmap->qhead; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - while (dmap->qlen < 0) - { - dmap->underrun_count++; + if (dmap->qhead == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + dmap->flags &= ~DMA_ACTIVE; - dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) - { - dmap->flags &= ~DMA_DIRTY; - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->buffsize); - } - dmap->user_counter += dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } + while (dmap->qlen < 0) + { + dmap->underrun_count++; + + dmap->qlen++; + if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) + { + dmap->flags &= ~DMA_DIRTY; + memset(audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->buffsize); + } + dmap->user_counter += dmap->fragment_size; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } - if (dmap->qlen > 0) - DMAbuf_launch_output (dev, dmap); + if (dmap->qlen > 0) + DMAbuf_launch_output(dev, dmap); - restore_flags (flags); - finish_output_interrupt (dev, dmap); + restore_flags(flags); + finish_output_interrupt(dev, dmap); } void -DMAbuf_outputintr (int dev, int notify_only) +DMAbuf_outputintr(int dev, int notify_only) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); + save_flags(flags); + cli(); - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qhead != pos && n++ < dmap->nbufs) - { - do_outputintr (dev, notify_only); - } - } - else - do_outputintr (dev, notify_only); - restore_flags (flags); + if (!(dmap->flags & DMA_NODMA)) + { + int chan = dmap->dma, pos, n; + + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue(chan); + enable_dma(dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qhead != pos && n++ < dmap->nbufs) + { + do_outputintr(dev, notify_only); + } + } else + do_outputintr(dev, notify_only); + restore_flags(flags); } static void -do_inputintr (int dev) +do_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; #ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_in->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); + if (audio_devs[dev]->dmap_in->dma >= 0) + sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); #endif - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - } - else if (dmap->qlen >= (dmap->nbufs - 1)) - { - /* printk ("Sound: Recording overrun\n"); */ - dmap->underrun_count++; - - /* Just throw away the oldest fragment but keep the engine running */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) - { - dmap->qlen++; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - } + if (dmap->raw_buf == NULL) + { + printk("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + dmap->qlen++; + + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_READ); + audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1); + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; + } else if (dmap->qlen >= (dmap->nbufs - 1)) + { + printk("Sound: Recording overrun\n"); + dmap->underrun_count++; - if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + /* Just throw away the oldest fragment but keep the engine running */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) + { + dmap->qlen++; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + } + if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) + { + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_READ); + audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - - save_flags (flags); - cli (); - if (dmap->qlen > 0) - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { - { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&in_sleeper[dev]); - }; - } - restore_flags (flags); + dmap->fragment_size, 1); + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; + + save_flags(flags); + cli(); + if (dmap->qlen > 0) + if ((in_sleep_flag[dev].opts & WK_SLEEP)) + { + { + in_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&in_sleeper[dev]); + }; + } + restore_flags(flags); } void -DMAbuf_inputintr (int dev) +DMAbuf_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - - save_flags (flags); - cli (); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); + save_flags(flags); + cli(); - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qtail != pos && ++n < dmap->nbufs) - { - do_inputintr (dev); - } - } - else - do_inputintr (dev); - restore_flags (flags); + if (!(dmap->flags & DMA_NODMA)) + { + int chan = dmap->dma, pos, n; + + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue(chan); + enable_dma(dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qtail != pos && ++n < dmap->nbufs) + { + do_inputintr(dev); + } + } else + do_inputintr(dev); + restore_flags(flags); } int -DMAbuf_open_dma (int dev) +DMAbuf_open_dma(int dev) { /* * NOTE! This routine opens only the primary DMA channel (output). */ - int chan = audio_devs[dev]->dmap_out->dma; - int err; - - if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) - { - return -EBUSY; - } - dma_init_buffers (dev, audio_devs[dev]->dmap_out); - out_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; - - if (chan >= 0) - { - unsigned long flags; - - save_flags (flags); - cli (); - disable_dma (audio_devs[dev]->dmap_out->dma); - clear_dma_ff (chan); - restore_flags (flags); - } - - return 0; + int chan = audio_devs[dev]->dmap_out->dma; + int err; + + if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) + { + return -EBUSY; + } + dma_init_buffers(dev, audio_devs[dev]->dmap_out); + out_sleep_flag[dev].opts = WK_NONE; + audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; + audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; + + if (chan >= 0) + { + unsigned long flags; + + save_flags(flags); + cli(); + disable_dma(audio_devs[dev]->dmap_out->dma); + clear_dma_ff(chan); + restore_flags(flags); + } + return 0; } void -DMAbuf_close_dma (int dev) +DMAbuf_close_dma(int dev) { - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); } void -DMAbuf_init (int dev, int dma1, int dma2) +DMAbuf_init(int dev, int dma1, int dma2) { - /* - * NOTE! This routine could be called several times. - */ + /* + * NOTE! This routine could be called several times. + */ - if (audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) - panic ("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; - - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } - else - { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_out->dma = dma1; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_in->dma = dma2; - } - } - } + if (audio_devs[dev] && audio_devs[dev]->dmap_out == NULL) + { + if (audio_devs[dev]->d == NULL) + panic("OSS: audio_devs[%d]->d == NULL\n", dev); + + if (audio_devs[dev]->parent_dev) + { /* Use DMA map of the parent dev */ + int parent = audio_devs[dev]->parent_dev - 1; + + audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; + audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; + } else + { + audio_devs[dev]->dmap_out = + audio_devs[dev]->dmap_in = + &dmaps[ndmaps++]; + audio_devs[dev]->dmap_out->dma = dma1; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { + audio_devs[dev]->dmap_in = + &dmaps[ndmaps++]; + audio_devs[dev]->dmap_in->dma = dma2; + } + } + } } int -DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) +DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) { - struct dma_buffparms *dmap; - unsigned long flags; - - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - dmap = audio_devs[dev]->dmap_in; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } + struct dma_buffparms *dmap; + unsigned long flags; - if (dmap->dma_mode != DMODE_INPUT) - { - if (dmap->dma_mode == DMODE_NONE && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && - audio_devs[dev]->go) - { - unsigned long flags; - - save_flags (flags); - cli (); - DMAbuf_activate_recording (dev, dmap); - restore_flags (flags); - } - return 0; - } - - if (!dmap->qlen) - { - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_OUT: - dmap = audio_devs[dev]->dmap_out; + switch (sel_type) + { + case SEL_IN: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; + + dmap = audio_devs[dev]->dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags(flags); + cli(); + + in_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&in_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + if (dmap->dma_mode != DMODE_INPUT) + { + if (dmap->dma_mode == DMODE_NONE && + audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && + !dmap->qlen && + audio_devs[dev]->go) + { + unsigned long flags; + + save_flags(flags); + cli(); + DMAbuf_activate_recording(dev, dmap); + restore_flags(flags); + } + return 0; + } + if (!dmap->qlen) + { + save_flags(flags); + cli(); + + in_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&in_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + return 1; + break; + + case SEL_OUT: + dmap = audio_devs[dev]->dmap_out; + + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags(flags); + cli(); + + out_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&out_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + if (dmap->dma_mode == DMODE_INPUT) + { + return 0; + } + if (dmap->dma_mode == DMODE_NONE) + { + return 1; + } + if (!DMAbuf_space_in_queue(dev)) + { + save_flags(flags); + cli(); + + out_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&out_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; + } - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return 0; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode == DMODE_INPUT) - { - return 0; - } - - if (dmap->dma_mode == DMODE_NONE) - { - return 1; - } - - if (!DMAbuf_space_in_queue (dev)) - { - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } - - return 0; } +void +DMAbuf_deinit(int dev) +{ +/* This routine is called when driver is being unloaded */ +#ifdef RUNTIME_DMA_ALLOC + sound_free_dmap (dev, audio_devs[dev]->dmap_out, + audio_devs[dev]->dmap_out->dma); + + if (audio_devs[dev]->flags & DMA_DUPLEX) + sound_free_dmap (dev, audio_devs[dev]->dmap_in, + audio_devs[dev]->dmap_in->dma); +#endif +} #endif diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index 1c37f9f5a..e7768f07f 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -3,76 +3,76 @@ /* -OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k + OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k -(c) 1995 by Michael Schlueter & Michael Marte + (c) 1995 by Michael Schlueter & Michael Marte -Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS -interface and the u-law to signed byte conversion. + Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS + interface and the u-law to signed byte conversion. -Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, -/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like -to thank: -Michael Schlueter for initial ideas and documentation on the MFP and -the DMA sound hardware. -Therapy? for their CD 'Troublegum' which really made me rock. + Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, + /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like + to thank: + Michael Schlueter for initial ideas and documentation on the MFP and + the DMA sound hardware. + Therapy? for their CD 'Troublegum' which really made me rock. -/dev/sndstat is based on code by Hannu Savolainen, the author of the -VoxWare family of drivers. + /dev/sndstat is based on code by Hannu Savolainen, the author of the + VoxWare family of drivers. -This file is subject to the terms and conditions of the GNU General Public -License. See the file COPYING in the main directory of this archive -for more details. + This file is subject to the terms and conditions of the GNU General Public + License. See the file COPYING in the main directory of this archive + for more details. -History: -1995/8/25 first release + History: + 1995/8/25 first release -1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming - and several race conditions + 1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming + and several race conditions -1995/9/14 ++roman: After some discussion with Michael Schlueter, revised - the interrupt disabling - Slightly speeded up U8->S8 translation by using long - operations where possible - Added 4:3 interpolation for /dev/audio + 1995/9/14 ++roman: After some discussion with Michael Schlueter, revised + the interrupt disabling + Slightly speeded up U8->S8 translation by using long + operations where possible + Added 4:3 interpolation for /dev/audio -1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio - converting to play at 12517Hz instead of 6258Hz. + 1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio + converting to play at 12517Hz instead of 6258Hz. -1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program - the DMA for another frame while there's still one - running. This allows the IRQ response to be - arbitrarily delayed and playing will still continue. + 1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program + the DMA for another frame while there's still one + running. This allows the IRQ response to be + arbitrarily delayed and playing will still continue. -1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for - Falcon audio (the Falcon doesn't raise an IRQ at the - end of a frame, but at the beginning instead!). uses - 'if (codec_dma)' in lots of places to simply switch - between Falcon and TT code. + 1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for + Falcon audio (the Falcon doesn't raise an IRQ at the + end of a frame, but at the beginning instead!). uses + 'if (codec_dma)' in lots of places to simply switch + between Falcon and TT code. -1995/11/06 ++TeSche: started introducing a hardware abstraction scheme - (may perhaps also serve for Amigas?), can now play - samples at almost all frequencies by means of a more - generalized expand routine, takes a good deal of care - to cut data only at sample sizes, buffer size is now - a kernel runtime option, implemented fsync() & several - minor improvements - ++Guenther: useful hints and bug fixes, cross-checked it for - Falcons + 1995/11/06 ++TeSche: started introducing a hardware abstraction scheme + (may perhaps also serve for Amigas?), can now play + samples at almost all frequencies by means of a more + generalized expand routine, takes a good deal of care + to cut data only at sample sizes, buffer size is now + a kernel runtime option, implemented fsync() & several + minor improvements + ++Guenther: useful hints and bug fixes, cross-checked it for + Falcons -1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. - Unification to drivers/sound/dmasound.c. + 1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. + Unification to drivers/sound/dmasound.c. -1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. + 1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. -1996/6/13 ++topi: fixed things that were broken (mainly the amiga - 14-bit routines), /dev/sndstat shows now the real - hardware frequency, the lowpass filter is disabled - by default now. + 1996/6/13 ++topi: fixed things that were broken (mainly the amiga + 14-bit routines), /dev/sndstat shows now the real + hardware frequency, the lowpass filter is disabled + by default now. -1996/9/25 ++geert: modularization + 1996/9/25 ++geert: modularization -*/ + */ #include <linux/module.h> @@ -94,53 +94,55 @@ History: #ifdef CONFIG_ATARI #include <asm/atarihw.h> #include <asm/atariints.h> -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA #include <asm/amigahw.h> #include <asm/amigaints.h> -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ #include "dmasound.h" #include <linux/soundcard.h> #ifdef MODULE -static int chrdev_registered = 0; -static int irq_installed = 0; -#endif /* MODULE */ -static char **sound_buffers = NULL; +static int chrdev_registered = 0; +static int irq_installed = 0; + +#endif /* MODULE */ +static char **sound_buffers = NULL; #ifdef CONFIG_ATARI -extern void atari_microwire_cmd(int cmd); -#endif /* CONFIG_ATARI */ +extern void atari_microwire_cmd(int cmd); + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA /* - * The minimum period for audio depends on htotal (for OCS/ECS/AGA) - * (Imported from arch/m68k/amiga/amisound.c) + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * (Imported from arch/m68k/amiga/amisound.c) */ extern volatile u_short amiga_audio_min_period; /* - * amiga_mksound() should be able to restore the period after beeping - * (Imported from arch/m68k/amiga/amisound.c) + * amiga_mksound() should be able to restore the period after beeping + * (Imported from arch/m68k/amiga/amisound.c) */ -extern u_short amiga_audio_period; +extern u_short amiga_audio_period; /* - * Audio DMA masks + * Audio DMA masks */ #define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3) #define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1) #define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3) -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Some declarations *******************************************************/ @@ -155,7 +157,7 @@ extern u_short amiga_audio_period; #define MIN_BUFSIZE 4 #define MAX_BUFSIZE 128 /* Limit for Amiga */ -static int catchRadius = 0, numBufs = 4, bufSize = 32; +static int catchRadius = 0, numBufs = 4, bufSize = 32; #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -175,76 +177,78 @@ static int catchRadius = 0, numBufs = 4, bufSize = 32; /* 8 bit mu-law */ -static char ulaw2dma8[] = { - -126, -122, -118, -114, -110, -106, -102, -98, - -94, -90, -86, -82, -78, -74, -70, -66, - -63, -61, -59, -57, -55, -53, -51, -49, - -47, -45, -43, -41, -39, -37, -35, -33, - -31, -30, -29, -28, -27, -26, -25, -24, - -23, -22, -21, -20, -19, -18, -17, -16, - -16, -15, -15, -14, -14, -13, -13, -12, - -12, -11, -11, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -7, -6, -6, - -6, -6, -5, -5, -5, -5, -4, -4, - -4, -4, -4, -4, -3, -3, -3, -3, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 0, - 125, 121, 117, 113, 109, 105, 101, 97, - 93, 89, 85, 81, 77, 73, 69, 65, - 62, 60, 58, 56, 54, 52, 50, 48, - 46, 44, 42, 40, 38, 36, 34, 32, - 30, 29, 28, 27, 26, 25, 24, 23, - 22, 21, 20, 19, 18, 17, 16, 15, - 15, 14, 14, 13, 13, 12, 12, 11, - 11, 10, 10, 9, 9, 8, 8, 7, - 7, 7, 6, 6, 6, 6, 5, 5, - 5, 5, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 +static char ulaw2dma8[] = +{ + -126, -122, -118, -114, -110, -106, -102, -98, + -94, -90, -86, -82, -78, -74, -70, -66, + -63, -61, -59, -57, -55, -53, -51, -49, + -47, -45, -43, -41, -39, -37, -35, -33, + -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, + -16, -15, -15, -14, -14, -13, -13, -12, + -12, -11, -11, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -7, -6, -6, + -6, -6, -5, -5, -5, -5, -4, -4, + -4, -4, -4, -4, -3, -3, -3, -3, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, + 125, 121, 117, 113, 109, 105, 101, 97, + 93, 89, 85, 81, 77, 73, 69, 65, + 62, 60, 58, 56, 54, 52, 50, 48, + 46, 44, 42, 40, 38, 36, 34, 32, + 30, 29, 28, 27, 26, 25, 24, 23, + 22, 21, 20, 19, 18, 17, 16, 15, + 15, 14, 14, 13, 13, 12, 12, 11, + 11, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 5, 5, + 5, 5, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; /* 8 bit A-law */ -static char alaw2dma8[] = { - -22, -21, -24, -23, -18, -17, -20, -19, - -30, -29, -32, -31, -26, -25, -28, -27, - -11, -11, -12, -12, -9, -9, -10, -10, - -15, -15, -16, -16, -13, -13, -14, -14, - -86, -82, -94, -90, -70, -66, -78, -74, - -118, -114, -126, -122, -102, -98, -110, -106, - -43, -41, -47, -45, -35, -33, -39, -37, - -59, -57, -63, -61, -51, -49, -55, -53, - -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -6, -6, -6, -6, -5, -5, -5, -5, - -8, -8, -8, -8, -7, -7, -7, -7, - -3, -3, -3, -3, -3, -3, -3, -3, - -4, -4, -4, -4, -4, -4, -4, -4, - 21, 20, 23, 22, 17, 16, 19, 18, - 29, 28, 31, 30, 25, 24, 27, 26, - 10, 10, 11, 11, 8, 8, 9, 9, - 14, 14, 15, 15, 12, 12, 13, 13, - 86, 82, 94, 90, 70, 66, 78, 74, - 118, 114, 126, 122, 102, 98, 110, 106, - 43, 41, 47, 45, 35, 33, 39, 37, - 59, 57, 63, 61, 51, 49, 55, 53, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 4, 4, 4, 4, - 7, 7, 7, 7, 6, 6, 6, 6, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 +static char alaw2dma8[] = +{ + -22, -21, -24, -23, -18, -17, -20, -19, + -30, -29, -32, -31, -26, -25, -28, -27, + -11, -11, -12, -12, -9, -9, -10, -10, + -15, -15, -16, -16, -13, -13, -14, -14, + -86, -82, -94, -90, -70, -66, -78, -74, + -118, -114, -126, -122, -102, -98, -110, -106, + -43, -41, -47, -45, -35, -33, -39, -37, + -59, -57, -63, -61, -51, -49, -55, -53, + -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -6, -6, -6, -6, -5, -5, -5, -5, + -8, -8, -8, -8, -7, -7, -7, -7, + -3, -3, -3, -3, -3, -3, -3, -3, + -4, -4, -4, -4, -4, -4, -4, -4, + 21, 20, 23, 22, 17, 16, 19, 18, + 29, 28, 31, 30, 25, 24, 27, 26, + 10, 10, 11, 11, 8, 8, 9, 9, + 14, 14, 15, 15, 12, 12, 13, 13, + 86, 82, 94, 90, 70, 66, 78, 74, + 118, 114, 126, 122, 102, 98, 110, 106, + 43, 41, 47, 45, 35, 33, 39, 37, + 59, 57, 63, 61, 51, 49, 55, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 4, 4, 4, 4, + 7, 7, 7, 7, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }; @@ -252,378 +256,403 @@ static char alaw2dma8[] = { /* 16 bit mu-law */ -static char ulaw2dma16[] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, - -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, - -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, - -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0, +static char ulaw2dma16[] = +{ + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, }; /* 16 bit A-law */ -static char alaw2dma16[] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848, +static char alaw2dma16[] = +{ + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, }; -#endif /* HAS_16BIT_TABLES */ + +#endif /* HAS_16BIT_TABLES */ #ifdef HAS_14BIT_TABLES /* 14 bit mu-law (LSB) */ -static char alaw2dma14l[] = { - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 49, 17, 49, 17, 49, 17, 49, 17, - 49, 17, 49, 17, 49, 17, 49, 17, - 41, 57, 9, 25, 41, 57, 9, 25, - 41, 57, 9, 25, 41, 57, 9, 25, - 37, 45, 53, 61, 5, 13, 21, 29, - 37, 45, 53, 61, 5, 13, 21, 29, - 35, 39, 43, 47, 51, 55, 59, 63, - 3, 7, 11, 15, 19, 23, 27, 31, - 34, 36, 38, 40, 42, 44, 46, 48, - 50, 52, 54, 56, 58, 60, 62, 0, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 15, 47, 15, 47, 15, 47, 15, 47, - 15, 47, 15, 47, 15, 47, 15, 47, - 23, 7, 55, 39, 23, 7, 55, 39, - 23, 7, 55, 39, 23, 7, 55, 39, - 27, 19, 11, 3, 59, 51, 43, 35, - 27, 19, 11, 3, 59, 51, 43, 35, - 29, 25, 21, 17, 13, 9, 5, 1, - 61, 57, 53, 49, 45, 41, 37, 33, - 30, 28, 26, 24, 22, 20, 18, 16, - 14, 12, 10, 8, 6, 4, 2, 0 +static char alaw2dma14l[] = +{ + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 49, 17, 49, 17, 49, 17, 49, 17, + 49, 17, 49, 17, 49, 17, 49, 17, + 41, 57, 9, 25, 41, 57, 9, 25, + 41, 57, 9, 25, 41, 57, 9, 25, + 37, 45, 53, 61, 5, 13, 21, 29, + 37, 45, 53, 61, 5, 13, 21, 29, + 35, 39, 43, 47, 51, 55, 59, 63, + 3, 7, 11, 15, 19, 23, 27, 31, + 34, 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, 0, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 15, 47, 15, 47, 15, 47, 15, 47, + 15, 47, 15, 47, 15, 47, 15, 47, + 23, 7, 55, 39, 23, 7, 55, 39, + 23, 7, 55, 39, 23, 7, 55, 39, + 27, 19, 11, 3, 59, 51, 43, 35, + 27, 19, 11, 3, 59, 51, 43, 35, + 29, 25, 21, 17, 13, 9, 5, 1, + 61, 57, 53, 49, 45, 41, 37, 33, + 30, 28, 26, 24, 22, 20, 18, 16, + 14, 12, 10, 8, 6, 4, 2, 0 }; /* 14 bit A-law (LSB) */ -static char alaw2dma14l[] = { - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 16, 48, 16, 48, 16, 48, 16, 48, - 16, 48, 16, 48, 16, 48, 16, 48, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 40, 56, 8, 24, 40, 56, 8, 24, - 40, 56, 8, 24, 40, 56, 8, 24, - 20, 28, 4, 12, 52, 60, 36, 44, - 20, 28, 4, 12, 52, 60, 36, 44, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 48, 16, 48, 16, 48, 16, 48, 16, - 48, 16, 48, 16, 48, 16, 48, 16, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 24, 8, 56, 40, 24, 8, 56, 40, - 24, 8, 56, 40, 24, 8, 56, 40, - 44, 36, 60, 52, 12, 4, 28, 20, - 44, 36, 60, 52, 12, 4, 28, 20 +static char alaw2dma14l[] = +{ + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 48, 16, 48, 16, 48, 16, 48, + 16, 48, 16, 48, 16, 48, 16, 48, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 40, 56, 8, 24, 40, 56, 8, 24, + 40, 56, 8, 24, 40, 56, 8, 24, + 20, 28, 4, 12, 52, 60, 36, 44, + 20, 28, 4, 12, 52, 60, 36, 44, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 48, 16, 48, 16, 48, 16, 48, 16, + 48, 16, 48, 16, 48, 16, 48, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 24, 8, 56, 40, 24, 8, 56, 40, + 24, 8, 56, 40, 24, 8, 56, 40, + 44, 36, 60, 52, 12, 4, 28, 20, + 44, 36, 60, 52, 12, 4, 28, 20 }; -#endif /* HAS_14BIT_TABLES */ + +#endif /* HAS_14BIT_TABLES */ /*** Translations ************************************************************/ #ifdef CONFIG_ATARI -static long ata_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, +static long ata_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16be(const u_char * userPtr, unsigned long userCount, u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -#endif /* CONFIG_ATARI */ +static long ata_ctx_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static long ami_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -#endif /* CONFIG_AMIGA */ +static long ami_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); + +#endif /* CONFIG_AMIGA */ /*** Machine definitions *****************************************************/ -typedef struct { - int type; - void *(*dma_alloc)(unsigned int, int); - void (*dma_free)(void *, unsigned int); - int (*irqinit)(void); +typedef struct + { + int type; + void *(*dma_alloc) (unsigned int, int); + void (*dma_free) (void *, unsigned int); + int (*irqinit) (void); #ifdef MODULE - void (*irqcleanup)(void); -#endif /* MODULE */ - void (*init)(void); - void (*silence)(void); - int (*setFormat)(int); - int (*setVolume)(int); - int (*setBass)(int); - int (*setTreble)(int); - void (*play)(void); -} MACHINE; + void (*irqcleanup) (void); +#endif /* MODULE */ + void (*init) (void); + void (*silence) (void); + int (*setFormat) (int); + int (*setVolume) (int); + int (*setBass) (int); + int (*setTreble) (int); + void (*play) (void); + } +MACHINE; /*** Low level stuff *********************************************************/ -typedef struct { - int format; /* AFMT_* */ - int stereo; /* 0 = mono, 1 = stereo */ - int size; /* 8/16 bit*/ - int speed; /* speed */ -} SETTINGS; - -typedef struct { - long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long); -} TRANS; - -struct sound_settings { - MACHINE mach; /* machine dependent things */ - SETTINGS hard; /* hardware settings */ - SETTINGS soft; /* software settings */ - SETTINGS dsp; /* /dev/dsp default settings */ - TRANS *trans; /* supported translations */ - int volume_left; /* volume (range is machine dependent) */ - int volume_right; - int bass; /* tone (range is machine dependent) */ - int treble; - int minDev; /* minor device number currently open */ +typedef struct + { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit */ + int speed; /* speed */ + } +SETTINGS; + +typedef struct + { + long (*ct_ulaw) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_alaw) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s8) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u8) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16be) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16be) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16le) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16le) (const u_char *, unsigned long, u_char *, long *, long); + } +TRANS; + +struct sound_settings + { + MACHINE mach; /* machine dependent things */ + SETTINGS hard; /* hardware settings */ + SETTINGS soft; /* software settings */ + SETTINGS dsp; /* /dev/dsp default settings */ + TRANS *trans; /* supported translations */ + int volume_left; /* volume (range is machine dependent) */ + int volume_right; + int bass; /* tone (range is machine dependent) */ + int treble; + int minDev; /* minor device number currently open */ #ifdef CONFIG_ATARI - int bal; /* balance factor for expanding (not volume!) */ - u_long data; /* data for expanding */ -#endif /* CONFIG_ATARI */ -}; + int bal; /* balance factor for expanding (not volume!) */ + u_long data; /* data for expanding */ +#endif /* CONFIG_ATARI */ + }; static struct sound_settings sound; #ifdef CONFIG_ATARI -static void *AtaAlloc(unsigned int size, int flags); -static void AtaFree(void *, unsigned int size); -static int AtaIrqInit(void); +static void *AtaAlloc(unsigned int size, int flags); +static void AtaFree(void *, unsigned int size); +static int AtaIrqInit(void); + #ifdef MODULE -static void AtaIrqCleanUp(void); -#endif /* MODULE */ -static int AtaSetBass(int bass); -static int AtaSetTreble(int treble); -static void TTSilence(void); -static void TTInit(void); -static int TTSetFormat(int format); -static int TTSetVolume(int volume); -static void FalconSilence(void); -static void FalconInit(void); -static int FalconSetFormat(int format); -static int FalconSetVolume(int volume); -static void ata_sq_play_next_frame(int index); -static void AtaPlay(void); -static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); -#endif /* CONFIG_ATARI */ +static void AtaIrqCleanUp(void); + +#endif /* MODULE */ +static int AtaSetBass(int bass); +static int AtaSetTreble(int treble); +static void TTSilence(void); +static void TTInit(void); +static int TTSetFormat(int format); +static int TTSetVolume(int volume); +static void FalconSilence(void); +static void FalconInit(void); +static int FalconSetFormat(int format); +static int FalconSetVolume(int volume); +static void ata_sq_play_next_frame(int index); +static void AtaPlay(void); +static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static void *AmiAlloc(unsigned int size, int flags); -static void AmiFree(void *, unsigned int); -static int AmiIrqInit(void); +static void *AmiAlloc(unsigned int size, int flags); +static void AmiFree(void *, unsigned int); +static int AmiIrqInit(void); + #ifdef MODULE -static void AmiIrqCleanUp(void); -#endif /* MODULE */ -static void AmiSilence(void); -static void AmiInit(void); -static int AmiSetFormat(int format); -static int AmiSetVolume(int volume); -static int AmiSetTreble(int treble); -static void ami_sq_play_next_frame(int index); -static void AmiPlay(void); -static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); -#endif /* CONFIG_AMIGA */ +static void AmiIrqCleanUp(void); + +#endif /* MODULE */ +static void AmiSilence(void); +static void AmiInit(void); +static int AmiSetFormat(int format); +static int AmiSetVolume(int volume); +static int AmiSetTreble(int treble); +static void ami_sq_play_next_frame(int index); +static void AmiPlay(void); +static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); + +#endif /* CONFIG_AMIGA */ /*** Mid level stuff *********************************************************/ -static void sound_silence(void); -static void sound_init(void); -static int sound_set_format(int format); -static int sound_set_speed(int speed); -static int sound_set_stereo(int stereo); -static int sound_set_volume(int volume); +static void sound_silence(void); +static void sound_init(void); +static int sound_set_format(int format); +static int sound_set_speed(int speed); +static int sound_set_stereo(int stereo); +static int sound_set_volume(int volume); + #ifdef CONFIG_ATARI -static int sound_set_bass(int bass); -#endif /* CONFIG_ATARI */ -static int sound_set_treble(int treble); -static long sound_copy_translate(const u_char *userPtr, - unsigned long userCount, - u_char frame[], long *frameUsed, - long frameLeft); +static int sound_set_bass(int bass); + +#endif /* CONFIG_ATARI */ +static int sound_set_treble(int treble); +static long sound_copy_translate(const u_char * userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft); /* * /dev/mixer abstraction */ -struct sound_mixer { - int busy; -}; +struct sound_mixer + { + int busy; + }; static struct sound_mixer mixer; -static void mixer_init(void); -static int mixer_open(int open_mode); -static int mixer_release(void); -static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg); +static void mixer_init(void); +static int mixer_open(int open_mode); +static int mixer_release(void); +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); /* * Sound queue stuff, the heart of the driver */ -struct sound_queue { - int max_count, block_size; - char **buffers; - - /* it shouldn't be necessary to declare any of these volatile */ - int front, rear, count; - int rear_size; - /* - * The use of the playing field depends on the hardware - * - * Atari: The number of frames that are loaded/playing - * - * Amiga: Bit 0 is set: a frame is loaded - * Bit 1 is set: a frame is playing - */ - int playing; - struct wait_queue *write_queue, *open_queue, *sync_queue; - int open_mode; - int busy, syncing; +struct sound_queue + { + int max_count, block_size; + char **buffers; + + /* it shouldn't be necessary to declare any of these volatile */ + int front, rear, count; + int rear_size; + /* + * The use of the playing field depends on the hardware + * + * Atari: The number of frames that are loaded/playing + * + * Amiga: Bit 0 is set: a frame is loaded + * Bit 1 is set: a frame is playing + */ + int playing; + struct wait_queue *write_queue, *open_queue, *sync_queue; + int open_mode; + int busy, syncing; #ifdef CONFIG_ATARI - int ignore_int; /* ++TeSche: used for Falcon */ -#endif /* CONFIG_ATARI */ + int ignore_int; /* ++TeSche: used for Falcon */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - int block_size_half, block_size_quarter; -#endif /* CONFIG_AMIGA */ -}; + int block_size_half, block_size_quarter; +#endif /* CONFIG_AMIGA */ + }; static struct sound_queue sq; @@ -637,69 +666,72 @@ static struct sound_queue sq; interruptible_sleep_on(&queue); #define WAKE_UP(queue) (wake_up_interruptible(&queue)) -static void sq_init(int numBufs, int bufSize, char **buffers); -static void sq_play(void); -static long sq_write(const char *src, unsigned long uLeft); -static int sq_open(int open_mode); -static void sq_reset(void); -static int sq_sync(void); -static int sq_release(void); +static void sq_init(int numBufs, int bufSize, char **buffers); +static void sq_play(void); +static long sq_write(const char *src, unsigned long uLeft); +static int sq_open(int open_mode); +static void sq_reset(void); +static int sq_sync(void); +static int sq_release(void); /* * /dev/sndstat */ -struct sound_state { - int busy; - char buf[512]; - int len, ptr; -}; +struct sound_state + { + int busy; + char buf[512]; + int len, ptr; + }; static struct sound_state state; -static void state_init(void); -static int state_open(int open_mode); -static int state_release(void); -static long state_read(char *dest, unsigned long count); +static void state_init(void); +static int state_open(int open_mode); +static int state_release(void); +static long state_read(char *dest, unsigned long count); /*** High level stuff ********************************************************/ -static int sound_open(struct inode *inode, struct file *file); -static int sound_fsync(struct file *filp, struct dentry *dentry); -static void sound_release(struct inode *inode, struct file *file); -static long long sound_lseek(struct file *file, long long offset, int orig); -static long sound_read(struct inode *inode, struct file *file, char *buf, - unsigned long count); -static long sound_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count); -static inline int ioctl_return(int *addr, int value) +static int sound_open(struct inode *inode, struct file *file); +static int sound_fsync(struct inode *inode, struct file *filp); +static void sound_release(struct inode *inode, struct file *file); +static long long sound_lseek(struct inode *inode, struct file *file, + long long offset, int orig); +static long sound_read(struct inode *inode, struct file *file, char *buf, + unsigned long count); +static long sound_write(struct inode *inode, struct file *file, + const char *buf, unsigned long count); +static inline int +ioctl_return(int *addr, int value) { - if (value < 0) - return(value); + if (value < 0) + return (value); - return put_user(value, addr); + return put_user(value, addr); } -static int unknown_minor_dev(char *fname, int dev); -static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg); +static int unknown_minor_dev(char *fname, int dev); +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); /*** Config & Setup **********************************************************/ -void soundcard_init(void); -void dmasound_setup(char *str, int *ints); -void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ +void soundcard_init(void); +void dmasound_setup(char *str, int *ints); +void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ /*** Translations ************************************************************/ /* ++TeSche: radically changed for new expanding purposes... - * + * These two routines now deal with copying/expanding/translating the samples * from user space into our buffer at the right frequency. They take care about * how much data there's actually to read, how much buffer space there is and @@ -723,849 +755,1014 @@ void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ */ #ifdef CONFIG_ATARI -static long ata_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - long count, used; - u_char *p = &frame[*frameUsed]; + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - if (sound.soft.stereo) - count &= ~1; - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = table[data]; - count--; - } - *frameUsed += used; - return(used); + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + *frameUsed += used; + return (used); } -static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - void *p = &frame[*frameUsed]; + long count, used; + void *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - if (sound.soft.stereo) - count &= ~1; - used = count; - copy_from_user(p, userPtr, count); - *frameUsed += used; - return(used); + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + return (used); } -static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; + long count, used; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = data ^ 0x80; - count--; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - u_short data; - get_user(data, ((u_short *)userPtr)++); - *p++ = data ^ 0x8080; - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft); + used = count; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + u_short data; + + get_user(data, ((u_short *) userPtr)++); + *p++ = data ^ 0x8080; + count--; + } + } + *frameUsed += used; + return (used); } -static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; + u_long data; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used*2; - } else { - void *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft) & ~3; - used = count; - copy_from_user(p, userPtr, count); - *frameUsed += used; - } - return(used); + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used * 2; + } else + { + void *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~3; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + } + return (used); } -static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; + u_long data; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used*2; - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>2; - used = count*4; - while (count > 0) { - get_user(data, ((u_int *)userPtr)++); - *p++ = data ^ 0x80008000; - count--; - } - *frameUsed += used; - } - return(used); + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used * 2; + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 2; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_int *) userPtr)++); + *p++ = data ^ 0x80008000; + count--; + } + *frameUsed += used; + } + return (used); } -static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; + u_long data; - count = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used*2; - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>2; - used = count*4; - while (count > 0) { - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data); - *p++ = data; - count--; - } + count = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used * 2; + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 2; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data); + *p++ = data; + count--; + } + *frameUsed += used; + } + return (used); +} + + +static long +ata_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *p++ = data; + *p++ = data; + } + *frameUsed += used * 2; + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 2; + used = count; + while (count > 0) + { + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + *p++ = data; + count--; + } + *frameUsed += used; + } + return (used); +} + + +static long +ata_ctx_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + while (frameLeft) + { + u_char c; + + if (bal < 0) + { + if (!userCount) + break; + get_user(c, userPtr++); + data = table[c]; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 2) + { + u_char c; + + if (bal < 0) + { + if (userCount < 2) + break; + get_user(c, userPtr++); + data = table[c] << 8; + get_user(c, userPtr++); + data |= table[c]; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} + + +static long +ata_ctx_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + while (frameLeft) + { + if (bal < 0) + { + if (!userCount) + break; + get_user(data, userPtr++); + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 2) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} + + +static long +ata_ctx_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + while (frameLeft) + { + if (bal < 0) + { + if (!userCount) + break; + get_user(data, userPtr++); + data ^= 0x80; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 2) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8080; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} + + +static long +ata_ctx_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} + + +static long +ata_ctx_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + data ^= 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} + + +static long +ata_ctx_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} + + +static long +ata_ctx_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} +#endif /* CONFIG_ATARI */ + + +#ifdef CONFIG_AMIGA +static long +ami_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + } else + { + u_char *left = &frame[*frameUsed >> 1]; + u_char *right = left + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *left++ = table[data]; + get_user(data, userPtr++); + *right++ = table[data]; + count--; + } + } *frameUsed += used; - } - return(used); + return (used); } -static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; - count = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *p++ = data; - *p++ = data; - } - *frameUsed += used*2; - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>2; - used = count; - while (count > 0) { - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data) ^ 0x80008000; - *p++ = data; - count--; - } + if (!sound.soft.stereo) + { + void *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~1; + used = count; + copy_from_user(p, userPtr, count); + } else + { + u_char *left = &frame[*frameUsed >> 1]; + u_char *right = left + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(*left++, userPtr++); + get_user(*right++, userPtr++); + count--; + } + } *frameUsed += used; - } - return(used); -} - - -static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (!userCount) - break; - get_user(c, userPtr++); - data = table[c]; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 2) { - u_char c; - if (bal < 0) { - if (userCount < 2) - break; - get_user(c, userPtr++); - data = table[c] << 8; - get_user(c, userPtr++); - data |= table[c]; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); -} - - -static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - while (frameLeft) { - if (bal < 0) { - if (!userCount) - break; - get_user(data, userPtr++); - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 2) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); -} - - -static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - while (frameLeft) { - if (bal < 0) { - if (!userCount) - break; - get_user(data, userPtr++); - data ^= 0x80; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 2) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8080; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); -} - - -static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); -} - - -static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - data ^= 0x80008000; - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); -} - - -static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data); - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); -} - - -static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data) ^ 0x80008000; - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); + return (used); } -#endif /* CONFIG_ATARI */ -#ifdef CONFIG_AMIGA -static long ami_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - long count, used; + long count, used; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft) & ~1; - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = table[data]; - count--; - } - } else { - u_char *left = &frame[*frameUsed>>1]; - u_char *right = left+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *left++ = table[data]; - get_user(data, userPtr++); - *right++ = table[data]; - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else + { + u_char *left = &frame[*frameUsed >> 1]; + u_char *right = left + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *left++ = data ^ 0x80; + get_user(data, userPtr++); + *right++ = data ^ 0x80; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; + long count, used; + u_long data; - if (!sound.soft.stereo) { - void *p = &frame[*frameUsed]; - count = min(userCount, frameLeft) & ~1; - used = count; - copy_from_user(p, userPtr, count); - } else { - u_char *left = &frame[*frameUsed>>1]; - u_char *right = left+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(*left++, userPtr++); - get_user(*right++, userPtr++); - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; + long count, used; + u_long data; - if (!sound.soft.stereo) { - char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft) & ~1; - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = data ^ 0x80; - count--; - } - } else { - u_char *left = &frame[*frameUsed>>1]; - u_char *right = left+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *left++ = data ^ 0x80; - get_user(data, userPtr++); - *right++ = data ^ 0x80; - count--; - } - } - *frameUsed += used; - return(used); -} - - -static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); -} - - -static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; + u_long data; - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; + u_long data; - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ #ifdef CONFIG_ATARI -static TRANS transTTNormal = { - ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL +static TRANS transTTNormal = +{ + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL }; -static TRANS transTTExpanding = { - ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL +static TRANS transTTExpanding = +{ + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL }; -static TRANS transFalconNormal = { - ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, - ata_ct_s16le, ata_ct_u16le +static TRANS transFalconNormal = +{ +ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, + ata_ct_s16le, ata_ct_u16le }; -static TRANS transFalconExpanding = { - ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, - ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le +static TRANS transFalconExpanding = +{ + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, + ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le }; -#endif /* CONFIG_ATARI */ + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static TRANS transAmiga = { - ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, - ami_ct_s16le, ami_ct_u16le +static TRANS transAmiga = +{ +ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, + ami_ct_s16le, ami_ct_u16le }; -#endif /* CONFIG_AMIGA */ + +#endif /* CONFIG_AMIGA */ /*** Low level stuff *********************************************************/ @@ -1577,60 +1774,68 @@ static TRANS transAmiga = { * Atari (TT/Falcon) */ -static void *AtaAlloc(unsigned int size, int flags) -{ - int order; - unsigned int a_size; - order = 0; - a_size = PAGE_SIZE; - while (a_size < size) { - order++; - a_size <<= 1; - } - return (void *) __get_dma_pages(flags, order); -} - -static void AtaFree(void *obj, unsigned int size) -{ - int order; - unsigned int a_size; - order = 0; - a_size = PAGE_SIZE; - while (a_size < size) { - order++; - a_size <<= 1; - } - free_pages ((unsigned long) obj, order); -} - -static int AtaIrqInit(void) -{ - /* Set up timer A. Timer A - will receive a signal upon end of playing from the sound - hardware. Furthermore Timer A is able to count events - and will cause an interrupt after a programmed number - of events. So all we need to keep the music playing is - to provide the sound hardware with new data upon - an interrupt from timer A. */ - mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ - mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ - mfp.tim_ct_a = 8; /* Turn on event counting. */ - /* Register interrupt handler. */ - request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, - "DMA sound", ata_sq_interrupt); - mfp.int_en_a |= 0x20; /* Turn interrupt on. */ - mfp.int_mk_a |= 0x20; - return(1); +static void * +AtaAlloc(unsigned int size, int flags) +{ + int order; + unsigned int a_size; + + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) + { + order++; + a_size <<= 1; + } + return (void *) __get_dma_pages(flags, order); +} + +static void +AtaFree(void *obj, unsigned int size) +{ + int order; + unsigned int a_size; + + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) + { + order++; + a_size <<= 1; + } + free_pages((unsigned long) obj, order); +} + +static int +AtaIrqInit(void) +{ + /* Set up timer A. Timer A + will receive a signal upon end of playing from the sound + hardware. Furthermore Timer A is able to count events + and will cause an interrupt after a programmed number + of events. So all we need to keep the music playing is + to provide the sound hardware with new data upon + an interrupt from timer A. */ + mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ + mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ + mfp.tim_ct_a = 8; /* Turn on event counting. */ + /* Register interrupt handler. */ + request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, + "DMA sound", ata_sq_interrupt); + mfp.int_en_a |= 0x20; /* Turn interrupt on. */ + mfp.int_mk_a |= 0x20; + return (1); } #ifdef MODULE -static void AtaIrqCleanUp(void) +static void +AtaIrqCleanUp(void) { - mfp.tim_ct_a = 0; /* stop timer */ - mfp.int_en_a &= ~0x20; /* turn interrupt off */ - free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); + mfp.tim_ct_a = 0; /* stop timer */ + mfp.int_en_a &= ~0x20; /* turn interrupt off */ + free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); } -#endif /* MODULE */ +#endif /* MODULE */ #define TONE_VOXWARE_TO_DB(v) \ @@ -1638,19 +1843,21 @@ static void AtaIrqCleanUp(void) #define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) -static int AtaSetBass(int bass) +static int +AtaSetBass(int bass) { - sound.bass = TONE_VOXWARE_TO_DB(bass); - atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); - return(TONE_DB_TO_VOXWARE(sound.bass)); + sound.bass = TONE_VOXWARE_TO_DB(bass); + atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); + return (TONE_DB_TO_VOXWARE(sound.bass)); } -static int AtaSetTreble(int treble) +static int +AtaSetTreble(int treble) { - sound.treble = TONE_VOXWARE_TO_DB(treble); - atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); - return(TONE_DB_TO_VOXWARE(sound.treble)); + sound.treble = TONE_VOXWARE_TO_DB(treble); + atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); + return (TONE_DB_TO_VOXWARE(sound.treble)); } @@ -1660,88 +1867,100 @@ static int AtaSetTreble(int treble) */ -static void TTSilence(void) +static void +TTSilence(void) { - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ } -static void TTInit(void) +static void +TTInit(void) { - int mode, i, idx; - const int freq[4] = {50066, 25033, 12517, 6258}; + int mode, i, idx; + const int freq[4] = + {50066, 25033, 12517, 6258}; - /* search a frequency that fits into the allowed error range */ + /* search a frequency that fits into the allowed error range */ - idx = -1; - for (i = 0; i < arraysize(freq); i++) - /* this isn't as much useful for a TT than for a Falcon, but - * then it doesn't hurt very much to implement it for a TT too. - */ - if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) - idx = i; - if (idx > -1) { - sound.soft.speed = freq[idx]; - sound.trans = &transTTNormal; - } else - sound.trans = &transTTExpanding; - - TTSilence(); - sound.hard = sound.soft; - - if (sound.hard.speed > 50066) { - /* we would need to squeeze the sound, but we won't do that */ - sound.hard.speed = 50066; - mode = DMASND_MODE_50KHZ; - sound.trans = &transTTNormal; - } else if (sound.hard.speed > 25033) { - sound.hard.speed = 50066; - mode = DMASND_MODE_50KHZ; - } else if (sound.hard.speed > 12517) { - sound.hard.speed = 25033; - mode = DMASND_MODE_25KHZ; - } else if (sound.hard.speed > 6258) { - sound.hard.speed = 12517; - mode = DMASND_MODE_12KHZ; - } else { - sound.hard.speed = 6258; - mode = DMASND_MODE_6KHZ; - } - - tt_dmasnd.mode = (sound.hard.stereo ? - DMASND_MODE_STEREO : DMASND_MODE_MONO) | - DMASND_MODE_8BIT | mode; - - sound.bal = -sound.soft.speed; -} - - -static int TTSetFormat(int format) -{ - /* TT sound DMA supports only 8bit modes */ - - switch (format) { - case AFMT_QUERY: - return(sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_S8: - case AFMT_U8: - break; - default: - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = 8; - if (sound.minDev == SND_DEV_DSP) { - sound.dsp.format = format; - sound.dsp.size = 8; - } - TTInit(); + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* this isn't as much useful for a TT than for a Falcon, but + * then it doesn't hurt very much to implement it for a TT too. + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) + { + sound.soft.speed = freq[idx]; + sound.trans = &transTTNormal; + } else + sound.trans = &transTTExpanding; + + TTSilence(); + sound.hard = sound.soft; + + if (sound.hard.speed > 50066) + { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + sound.trans = &transTTNormal; + } else if (sound.hard.speed > 25033) + { + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + } else if (sound.hard.speed > 12517) + { + sound.hard.speed = 25033; + mode = DMASND_MODE_25KHZ; + } else if (sound.hard.speed > 6258) + { + sound.hard.speed = 12517; + mode = DMASND_MODE_12KHZ; + } else + { + sound.hard.speed = 6258; + mode = DMASND_MODE_6KHZ; + } + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + DMASND_MODE_8BIT | mode; - return(format); + sound.bal = -sound.soft.speed; +} + + +static int +TTSetFormat(int format) +{ + /* TT sound DMA supports only 8bit modes */ + + switch (format) + { + case AFMT_QUERY: + return (sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_S8: + case AFMT_U8: + break; + default: + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = 8; + if (sound.minDev == SND_DEV_DSP) + { + sound.dsp.format = format; + sound.dsp.size = 8; + } + TTInit(); + + return (format); } @@ -1750,14 +1969,15 @@ static int TTSetFormat(int format) #define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) -static int TTSetVolume(int volume) +static int +TTSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); - atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); - sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); - atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); - return(VOLUME_DB_TO_VOXWARE(sound.volume_left) | - (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); + sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); + atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); + sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); + atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); + return (VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); } @@ -1767,135 +1987,151 @@ static int TTSetVolume(int volume) */ -static void FalconSilence(void) +static void +FalconSilence(void) { - /* stop playback, set sample rate 50kHz for PSG sound */ - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; - tt_dmasnd.int_div = 0; /* STE compatible divider */ - tt_dmasnd.int_ctrl = 0x0; - tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ - tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ - tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ - tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ + /* stop playback, set sample rate 50kHz for PSG sound */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; + tt_dmasnd.int_div = 0; /* STE compatible divider */ + tt_dmasnd.int_ctrl = 0x0; + tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ + tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ + tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ + tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ } -static void FalconInit(void) +static void +FalconInit(void) { - int divider, i, idx; - const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; + int divider, i, idx; + const int freq[8] = + {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; - /* search a frequency that fits into the allowed error range */ + /* search a frequency that fits into the allowed error range */ - idx = -1; - for (i = 0; i < arraysize(freq); i++) - /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would - * be playable without expanding, but that now a kernel runtime - * option - */ - if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) - idx = i; - if (idx > -1) { - sound.soft.speed = freq[idx]; - sound.trans = &transFalconNormal; - } else - sound.trans = &transFalconExpanding; - - FalconSilence(); - sound.hard = sound.soft; - - if (sound.hard.size == 16) { - /* the Falcon can play 16bit samples only in stereo */ - sound.hard.stereo = 1; - } - - if (sound.hard.speed > 49170) { - /* we would need to squeeze the sound, but we won't do that */ - sound.hard.speed = 49170; - divider = 1; - sound.trans = &transFalconNormal; - } else if (sound.hard.speed > 32780) { - sound.hard.speed = 49170; - divider = 1; - } else if (sound.hard.speed > 24585) { - sound.hard.speed = 32780; - divider = 2; - } else if (sound.hard.speed > 19668) { - sound.hard.speed = 24585; - divider = 3; - } else if (sound.hard.speed > 16390) { - sound.hard.speed = 19668; - divider = 4; - } else if (sound.hard.speed > 12292) { - sound.hard.speed = 16390; - divider = 5; - } else if (sound.hard.speed > 9834) { - sound.hard.speed = 12292; - divider = 7; - } else if (sound.hard.speed > 8195) { - sound.hard.speed = 9834; - divider = 9; - } else { - sound.hard.speed = 8195; - divider = 11; - } - tt_dmasnd.int_div = divider; - - /* Setup Falcon sound DMA for playback */ - tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ - tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ - tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ - tt_dmasnd.cbar_dst = 0x0000; - tt_dmasnd.rec_track_select = 0; - tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ - tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ - - tt_dmasnd.mode = (sound.hard.stereo ? - DMASND_MODE_STEREO : DMASND_MODE_MONO) | - ((sound.hard.size == 8) ? - DMASND_MODE_8BIT : DMASND_MODE_16BIT) | - DMASND_MODE_6KHZ; - - sound.bal = -sound.soft.speed; -} - - -static int FalconSetFormat(int format) -{ - int size; - /* Falcon sound DMA supports 8bit and 16bit modes */ - - switch (format) { - case AFMT_QUERY: - return(sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_BE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_U16_LE: - size = 16; - break; - default: /* :-) */ - size = 8; - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = size; - if (sound.minDev == SND_DEV_DSP) { - sound.dsp.format = format; - sound.dsp.size = sound.soft.size; - } - - FalconInit(); - - return(format); + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would + * be playable without expanding, but that now a kernel runtime + * option + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) + { + sound.soft.speed = freq[idx]; + sound.trans = &transFalconNormal; + } else + sound.trans = &transFalconExpanding; + + FalconSilence(); + sound.hard = sound.soft; + + if (sound.hard.size == 16) + { + /* the Falcon can play 16bit samples only in stereo */ + sound.hard.stereo = 1; + } + if (sound.hard.speed > 49170) + { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 49170; + divider = 1; + sound.trans = &transFalconNormal; + } else if (sound.hard.speed > 32780) + { + sound.hard.speed = 49170; + divider = 1; + } else if (sound.hard.speed > 24585) + { + sound.hard.speed = 32780; + divider = 2; + } else if (sound.hard.speed > 19668) + { + sound.hard.speed = 24585; + divider = 3; + } else if (sound.hard.speed > 16390) + { + sound.hard.speed = 19668; + divider = 4; + } else if (sound.hard.speed > 12292) + { + sound.hard.speed = 16390; + divider = 5; + } else if (sound.hard.speed > 9834) + { + sound.hard.speed = 12292; + divider = 7; + } else if (sound.hard.speed > 8195) + { + sound.hard.speed = 9834; + divider = 9; + } else + { + sound.hard.speed = 8195; + divider = 11; + } + tt_dmasnd.int_div = divider; + + /* Setup Falcon sound DMA for playback */ + tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ + tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ + tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ + tt_dmasnd.cbar_dst = 0x0000; + tt_dmasnd.rec_track_select = 0; + tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ + tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + ((sound.hard.size == 8) ? + DMASND_MODE_8BIT : DMASND_MODE_16BIT) | + DMASND_MODE_6KHZ; + + sound.bal = -sound.soft.speed; +} + + +static int +FalconSetFormat(int format) +{ + int size; + + /* Falcon sound DMA supports 8bit and 16bit modes */ + + switch (format) + { + case AFMT_QUERY: + return (sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) + { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + FalconInit(); + + return (format); } @@ -1907,168 +2143,181 @@ static int FalconSetFormat(int format) #define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) -static int FalconSetVolume(int volume) +static int +FalconSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); - sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); - tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; - return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) | - VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); + sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); + sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); + tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; + return (VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); } -static void ata_sq_play_next_frame(int index) +static void +ata_sq_play_next_frame(int index) { - char *start, *end; + char *start, *end; - /* used by AtaPlay() if all doubts whether there really is something - * to be played are already wiped out. - */ - start = sq_block_address(sq.front); - end = start+((sq.count == index) ? sq.rear_size : sq.block_size); - /* end might not be a legal virtual address. */ - DMASNDSetEnd(VTOP(end - 1) + 1); - DMASNDSetBase(VTOP(start)); - /* Since only an even number of samples per frame can - be played, we might lose one byte here. (TO DO) */ - sq.front = (sq.front+1) % sq.max_count; - sq.playing++; - tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; -} - - -static void AtaPlay(void) -{ - /* ++TeSche: Note that sq.playing is no longer just a flag but holds - * the number of frames the DMA is currently programmed for instead, - * may be 0, 1 (currently being played) or 2 (pre-programmed). - * - * Changes done to sq.count and sq.playing are a bit more subtle again - * so now I must admit I also prefer disabling the irq here rather - * than considering all possible situations. But the point is that - * disabling the irq doesn't have any bad influence on this version of - * the driver as we benefit from having pre-programmed the DMA - * wherever possible: There's no need to reload the DMA at the exact - * time of an interrupt but only at some time while the pre-programmed - * frame is playing! - */ - atari_disable_irq(IRQ_MFP_TIMA); - - if (sq.playing == 2 || /* DMA is 'full' */ - sq.count <= 0) { /* nothing to do */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - - if (sq.playing == 0) { - /* looks like there's nothing 'in' the DMA yet, so try - * to put two frames into it (at least one is available). + /* used by AtaPlay() if all doubts whether there really is something + * to be played are already wiped out. */ - if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(1); - if (sq.count == 1) { - /* no more frames */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, there were two frames, but the second - * one is not yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(2); - } else { - /* there's already a frame being played so we may only stuff - * one new into the DMA, but even if this may be the last - * frame existing the previous one is still on sq.count. + start = sq_block_address(sq.front); + end = start + ((sq.count == index) ? sq.rear_size : sq.block_size); + /* end might not be a legal virtual address. */ + DMASNDSetEnd(VTOP(end - 1) + 1); + DMASNDSetBase(VTOP(start)); + /* Since only an even number of samples per frame can + be played, we might lose one byte here. (TO DO) */ + sq.front = (sq.front + 1) % sq.max_count; + sq.playing++; + tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; +} + + +static void +AtaPlay(void) +{ + /* ++TeSche: Note that sq.playing is no longer just a flag but holds + * the number of frames the DMA is currently programmed for instead, + * may be 0, 1 (currently being played) or 2 (pre-programmed). + * + * Changes done to sq.count and sq.playing are a bit more subtle again + * so now I must admit I also prefer disabling the irq here rather + * than considering all possible situations. But the point is that + * disabling the irq doesn't have any bad influence on this version of + * the driver as we benefit from having pre-programmed the DMA + * wherever possible: There's no need to reload the DMA at the exact + * time of an interrupt but only at some time while the pre-programmed + * frame is playing! */ - if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(2); - } - atari_enable_irq(IRQ_MFP_TIMA); + atari_disable_irq(IRQ_MFP_TIMA); + + if (sq.playing == 2 || /* DMA is 'full' */ + sq.count <= 0) + { /* nothing to do */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.playing == 0) + { + /* looks like there's nothing 'in' the DMA yet, so try + * to put two frames into it (at least one is available). + */ + if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(1); + if (sq.count == 1) + { + /* no more frames */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, there were two frames, but the second + * one is not yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } else + { + /* there's already a frame being played so we may only stuff + * one new into the DMA, but even if this may be the last + * frame existing the previous one is still on sq.count. + */ + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } + atari_enable_irq(IRQ_MFP_TIMA); } -static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +static void +ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) { #if 0 - /* ++TeSche: if you should want to test this... */ - static int cnt = 0; - if (sq.playing == 2) - if (++cnt == 10) { - /* simulate losing an interrupt */ - cnt = 0; - return; - } + /* ++TeSche: if you should want to test this... */ + static int cnt = 0; + + if (sq.playing == 2) + if (++cnt == 10) + { + /* simulate losing an interrupt */ + cnt = 0; + return; + } #endif - if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) { - /* ++TeSche: Falcon only: ignore first irq because it comes - * immediately after starting a frame. after that, irqs come - * (almost) like on the TT. - */ - sq.ignore_int = 0; - return; - } - - if (!sq.playing) { - /* playing was interrupted and sq_reset() has already cleared - * the sq variables, so better don't do anything here. + if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) + { + /* ++TeSche: Falcon only: ignore first irq because it comes + * immediately after starting a frame. after that, irqs come + * (almost) like on the TT. + */ + sq.ignore_int = 0; + return; + } + if (!sq.playing) + { + /* playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + /* Probably ;) one frame is finished. Well, in fact it may be that a + * pre-programmed one is also finished because there has been a long + * delay in interrupt delivery and we've completely lost one, but + * there's no way to detect such a situation. In such a case the last + * frame will be played more than once and the situation will recover + * as soon as the irq gets through. */ - WAKE_UP(sq.sync_queue); - return; - } - - /* Probably ;) one frame is finished. Well, in fact it may be that a - * pre-programmed one is also finished because there has been a long - * delay in interrupt delivery and we've completely lost one, but - * there's no way to detect such a situation. In such a case the last - * frame will be played more than once and the situation will recover - * as soon as the irq gets through. - */ - sq.count--; - sq.playing--; - - if (!sq.playing) { - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - sq.ignore_int = 1; - } + sq.count--; + sq.playing--; - WAKE_UP(sq.write_queue); + if (!sq.playing) + { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + sq.ignore_int = 1; + } + WAKE_UP(sq.write_queue); /* At least one block of the queue is free now - so wake up a writing process blocked because - of a full queue. */ - - if ((sq.playing != 1) || (sq.count != 1)) - /* We must be a bit carefully here: sq.count indicates the - * number of buffers used and not the number of frames to - * be played. If sq.count==1 and sq.playing==1 that means - * the only remaining frame was already programmed earlier - * (and is currently running) so we mustn't call AtaPlay() - * here, otherwise we'll play one frame too much. - */ - AtaPlay(); + so wake up a writing process blocked because + of a full queue. */ + + if ((sq.playing != 1) || (sq.count != 1)) + /* We must be a bit carefully here: sq.count indicates the + * number of buffers used and not the number of frames to + * be played. If sq.count==1 and sq.playing==1 that means + * the only remaining frame was already programmed earlier + * (and is currently running) so we mustn't call AtaPlay() + * here, otherwise we'll play one frame too much. + */ + AtaPlay(); - if (!sq.playing) WAKE_UP(sq.sync_queue); + if (!sq.playing) + WAKE_UP(sq.sync_queue); /* We are not playing after AtaPlay(), so there - is nothing to play any more. Wake up a process - waiting for audio output to drain. */ + is nothing to play any more. Wake up a process + waiting for audio output to drain. */ } -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA @@ -2078,109 +2327,120 @@ static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) */ -static void *AmiAlloc(unsigned int size, int flags) +static void * +AmiAlloc(unsigned int size, int flags) { - return(amiga_chip_alloc((long)size)); + return (amiga_chip_alloc((long) size)); } -static void AmiFree(void *obj, unsigned int size) +static void +AmiFree(void *obj, unsigned int size) { - amiga_chip_free (obj); + amiga_chip_free(obj); } -static int AmiIrqInit(void) +static int +AmiIrqInit(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; - /* Register interrupt handler. */ - if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, - "DMA sound", ami_sq_interrupt)) - return(0); - return(1); + /* Register interrupt handler. */ + if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, + "DMA sound", ami_sq_interrupt)) + return (0); + return (1); } #ifdef MODULE -static void AmiIrqCleanUp(void) +static void +AmiIrqCleanUp(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; - /* release the interrupt */ - free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; + /* release the interrupt */ + free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); } -#endif /* MODULE */ +#endif /* MODULE */ -static void AmiSilence(void) +static void +AmiSilence(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; } -static void AmiInit(void) +static void +AmiInit(void) { - int period, i; + int period, i; - AmiSilence(); + AmiSilence(); - if (sound.soft.speed) - period = amiga_colorclock/sound.soft.speed-1; - else - period = amiga_audio_min_period; - sound.hard = sound.soft; - sound.trans = &transAmiga; + if (sound.soft.speed) + period = amiga_colorclock / sound.soft.speed - 1; + else + period = amiga_audio_min_period; + sound.hard = sound.soft; + sound.trans = &transAmiga; - if (period < amiga_audio_min_period) { - /* we would need to squeeze the sound, but we won't do that */ - period = amiga_audio_min_period; - } else if (period > 65535) { - period = 65535; - } - sound.hard.speed = amiga_colorclock/(period+1); + if (period < amiga_audio_min_period) + { + /* we would need to squeeze the sound, but we won't do that */ + period = amiga_audio_min_period; + } else if (period > 65535) + { + period = 65535; + } + sound.hard.speed = amiga_colorclock / (period + 1); - for (i = 0; i < 4; i++) - custom.aud[i].audper = period; - amiga_audio_period = period; + for (i = 0; i < 4; i++) + custom.aud[i].audper = period; + amiga_audio_period = period; - AmiSetTreble(50); /* recommended for newer amiga models */ + AmiSetTreble(50); /* recommended for newer amiga models */ } -static int AmiSetFormat(int format) +static int +AmiSetFormat(int format) { - int size; + int size; - /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ + /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ - switch (format) { - case AFMT_QUERY: - return(sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_BE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_U16_LE: - size = 16; - break; - default: /* :-) */ - size = 8; - format = AFMT_S8; - } + switch (format) + { + case AFMT_QUERY: + return (sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } - sound.soft.format = format; - sound.soft.size = size; - if (sound.minDev == SND_DEV_DSP) { - sound.dsp.format = format; - sound.dsp.size = sound.soft.size; - } - AmiInit(); + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) + { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + AmiInit(); - return(format); + return (format); } @@ -2188,24 +2448,26 @@ static int AmiSetFormat(int format) (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100) #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64) -static int AmiSetVolume(int volume) +static int +AmiSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); - custom.aud[0].audvol = sound.volume_left; - sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); - custom.aud[1].audvol = sound.volume_right; - return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) | - (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); + sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); + custom.aud[0].audvol = sound.volume_left; + sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); + custom.aud[1].audvol = sound.volume_right; + return (VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); } -static int AmiSetTreble(int treble) +static int +AmiSetTreble(int treble) { - sound.treble = treble; - if (treble < 50) - ciaa.pra &= ~0x02; - else - ciaa.pra |= 0x02; - return(treble); + sound.treble = treble; + if (treble < 50) + ciaa.pra &= ~0x02; + else + ciaa.pra |= 0x02; + return (treble); } @@ -2214,279 +2476,302 @@ static int AmiSetTreble(int treble) #define AMI_PLAY_MASK 3 -static void ami_sq_play_next_frame(int index) -{ - u_char *start, *ch0, *ch1, *ch2, *ch3; - u_long size; - - /* used by AmiPlay() if all doubts whether there really is something - * to be played are already wiped out. - */ - start = sq_block_address(sq.front); - size = (sq.count == index ? sq.rear_size : sq.block_size)>>1; - - if (sound.hard.stereo) { - ch0 = start; - ch1 = start+sq.block_size_half; - size >>= 1; - } else { - ch0 = start; - ch1 = start; - } - if (sound.hard.size == 8) { - custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); - custom.aud[0].audlen = size; - custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); - custom.aud[1].audlen = size; - custom.dmacon = AMI_AUDIO_8; - } else { - size >>= 1; - custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); - custom.aud[0].audlen = size; - custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); - custom.aud[1].audlen = size; - if (sound.volume_left == 64 && sound.volume_right == 64) { - /* We can play pseudo 14-bit only with the maximum volume */ - ch3 = ch0+sq.block_size_quarter; - ch2 = ch1+sq.block_size_quarter; - custom.aud[2].audvol = 1; /* we are being affected by the beeps */ - custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ - custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2); - custom.aud[2].audlen = size; - custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3); - custom.aud[3].audlen = size; - custom.dmacon = AMI_AUDIO_14; - } else - custom.dmacon = AMI_AUDIO_8; - } - sq.front = (sq.front+1) % sq.max_count; - sq.playing |= AMI_PLAY_LOADED; -} - - -static void AmiPlay(void) +static void +ami_sq_play_next_frame(int index) { - int minframes = 1; - - custom.intena = IF_AUD0; - - if (sq.playing & AMI_PLAY_LOADED) { - /* There's already a frame loaded */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } - - if (sq.playing & AMI_PLAY_PLAYING) - /* Increase threshold: frame 1 is already being played */ - minframes = 2; + u_char *start, *ch0, *ch1, *ch2, *ch3; + u_long size; - if (sq.count < minframes) { - /* Nothing to do */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } - - if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? + /* used by AmiPlay() if all doubts whether there really is something + * to be played are already wiped out. */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } - - ami_sq_play_next_frame(minframes); + start = sq_block_address(sq.front); + size = (sq.count == index ? sq.rear_size : sq.block_size) >> 1; + + if (sound.hard.stereo) + { + ch0 = start; + ch1 = start + sq.block_size_half; + size >>= 1; + } else + { + ch0 = start; + ch1 = start; + } + if (sound.hard.size == 8) + { + custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + custom.dmacon = AMI_AUDIO_8; + } else + { + size >>= 1; + custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + if (sound.volume_left == 64 && sound.volume_right == 64) + { + /* We can play pseudo 14-bit only with the maximum volume */ + ch3 = ch0 + sq.block_size_quarter; + ch2 = ch1 + sq.block_size_quarter; + custom.aud[2].audvol = 1; /* we are being affected by the beeps */ + custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ + custom.aud[2].audlc = (u_short *) ZTWO_PADDR(ch2); + custom.aud[2].audlen = size; + custom.aud[3].audlc = (u_short *) ZTWO_PADDR(ch3); + custom.aud[3].audlen = size; + custom.dmacon = AMI_AUDIO_14; + } else + custom.dmacon = AMI_AUDIO_8; + } + sq.front = (sq.front + 1) % sq.max_count; + sq.playing |= AMI_PLAY_LOADED; +} + + +static void +AmiPlay(void) +{ + int minframes = 1; + + custom.intena = IF_AUD0; + + if (sq.playing & AMI_PLAY_LOADED) + { + /* There's already a frame loaded */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + if (sq.playing & AMI_PLAY_PLAYING) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + if (sq.count < minframes) + { + /* Nothing to do */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + ami_sq_play_next_frame(minframes); - custom.intena = IF_SETCLR | IF_AUD0; + custom.intena = IF_SETCLR | IF_AUD0; } -static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +static void +ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) { - int minframes = 1; + int minframes = 1; - if (!sq.playing) { - /* Playing was interrupted and sq_reset() has already cleared - * the sq variables, so better don't do anything here. - */ - WAKE_UP(sq.sync_queue); - return; - } + if (!sq.playing) + { + /* Playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + if (sq.playing & AMI_PLAY_PLAYING) + { + /* We've just finished a frame */ + sq.count--; + WAKE_UP(sq.write_queue); + } + if (sq.playing & AMI_PLAY_LOADED) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; - if (sq.playing & AMI_PLAY_PLAYING) { - /* We've just finished a frame */ - sq.count--; - WAKE_UP(sq.write_queue); - } + /* Shift the flags */ + sq.playing = (sq.playing << 1) & AMI_PLAY_MASK; - if (sq.playing & AMI_PLAY_LOADED) - /* Increase threshold: frame 1 is already being played */ - minframes = 2; + if (!sq.playing) + /* No frame is playing, disable audio DMA */ + custom.dmacon = AMI_AUDIO_OFF; - /* Shift the flags */ - sq.playing = (sq.playing<<1) & AMI_PLAY_MASK; + if (sq.count >= minframes) + /* Try to play the next frame */ + AmiPlay(); - if (!sq.playing) - /* No frame is playing, disable audio DMA */ - custom.dmacon = AMI_AUDIO_OFF; - - if (sq.count >= minframes) - /* Try to play the next frame */ - AmiPlay(); - - if (!sq.playing) - /* Nothing to play anymore. - Wake up a process waiting for audio output to drain. */ - WAKE_UP(sq.sync_queue); + if (!sq.playing) + /* Nothing to play anymore. + Wake up a process waiting for audio output to drain. */ + WAKE_UP(sq.sync_queue); } -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Machine definitions *****************************************************/ #ifdef CONFIG_ATARI -static MACHINE machTT = { - DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, +static MACHINE machTT = +{ + DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, #ifdef MODULE - AtaIrqCleanUp, -#endif /* MODULE */ - TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, - AtaPlay + AtaIrqCleanUp, +#endif /* MODULE */ + TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, + AtaPlay }; -static MACHINE machFalcon = { - DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, +static MACHINE machFalcon = +{ + DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, #ifdef MODULE - AtaIrqCleanUp, -#endif /* MODULE */ - FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, - AtaSetTreble, AtaPlay + AtaIrqCleanUp, +#endif /* MODULE */ + FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, + AtaSetTreble, AtaPlay }; -#endif /* CONFIG_ATARI */ + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static MACHINE machAmiga = { - DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, +static MACHINE machAmiga = +{ + DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, #ifdef MODULE - AmiIrqCleanUp, -#endif /* MODULE */ - AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, - AmiPlay + AmiIrqCleanUp, +#endif /* MODULE */ + AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, + AmiPlay }; -#endif /* CONFIG_AMIGA */ + +#endif /* CONFIG_AMIGA */ /*** Mid level stuff *********************************************************/ -static void sound_silence(void) +static void +sound_silence(void) { - /* update hardware settings one more */ - (*sound.mach.init)(); + /* update hardware settings one more */ + (*sound.mach.init) (); - (*sound.mach.silence)(); + (*sound.mach.silence) (); } -static void sound_init(void) +static void +sound_init(void) { - (*sound.mach.init)(); + (*sound.mach.init) (); } -static int sound_set_format(int format) +static int +sound_set_format(int format) { - return(*sound.mach.setFormat)(format); + return (*sound.mach.setFormat) (format); } -static int sound_set_speed(int speed) +static int +sound_set_speed(int speed) { - if (speed < 0) - return(sound.soft.speed); + if (speed < 0) + return (sound.soft.speed); - sound.soft.speed = speed; - (*sound.mach.init)(); - if (sound.minDev == SND_DEV_DSP) - sound.dsp.speed = sound.soft.speed; + sound.soft.speed = speed; + (*sound.mach.init) (); + if (sound.minDev == SND_DEV_DSP) + sound.dsp.speed = sound.soft.speed; - return(sound.soft.speed); + return (sound.soft.speed); } -static int sound_set_stereo(int stereo) +static int +sound_set_stereo(int stereo) { - if (stereo < 0) - return(sound.soft.stereo); + if (stereo < 0) + return (sound.soft.stereo); - stereo = !!stereo; /* should be 0 or 1 now */ + stereo = !!stereo; /* should be 0 or 1 now */ - sound.soft.stereo = stereo; - if (sound.minDev == SND_DEV_DSP) - sound.dsp.stereo = stereo; - (*sound.mach.init)(); + sound.soft.stereo = stereo; + if (sound.minDev == SND_DEV_DSP) + sound.dsp.stereo = stereo; + (*sound.mach.init) (); - return(stereo); + return (stereo); } -static int sound_set_volume(int volume) +static int +sound_set_volume(int volume) { - return(*sound.mach.setVolume)(volume); + return (*sound.mach.setVolume) (volume); } #ifdef CONFIG_ATARI -static int sound_set_bass(int bass) -{ - return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50); -} -#endif /* CONFIG_ATARI */ - - -static int sound_set_treble(int treble) -{ - return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50); -} - - -static long sound_copy_translate(const u_char *userPtr, - unsigned long userCount, - u_char frame[], long *frameUsed, - long frameLeft) -{ - long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL; - - switch (sound.soft.format) { - case AFMT_MU_LAW: - ct_func = sound.trans->ct_ulaw; - break; - case AFMT_A_LAW: - ct_func = sound.trans->ct_alaw; - break; - case AFMT_S8: - ct_func = sound.trans->ct_s8; - break; - case AFMT_U8: - ct_func = sound.trans->ct_u8; - break; - case AFMT_S16_BE: - ct_func = sound.trans->ct_s16be; - break; - case AFMT_U16_BE: - ct_func = sound.trans->ct_u16be; - break; - case AFMT_S16_LE: - ct_func = sound.trans->ct_s16le; - break; - case AFMT_U16_LE: - ct_func = sound.trans->ct_u16le; - break; - } - if (ct_func) - return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); - else - return(0); +static int +sound_set_bass(int bass) +{ + return (sound.mach.setBass ? (*sound.mach.setBass) (bass) : 50); +} +#endif /* CONFIG_ATARI */ + + +static int +sound_set_treble(int treble) +{ + return (sound.mach.setTreble ? (*sound.mach.setTreble) (treble) : 50); +} + + +static long +sound_copy_translate(const u_char * userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft) +{ + long (*ct_func) (const u_char *, unsigned long, u_char *, long *, long) = NULL; + + switch (sound.soft.format) + { + case AFMT_MU_LAW: + ct_func = sound.trans->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans->ct_u16le; + break; + } + if (ct_func) + return (ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); + else + return (0); } @@ -2500,199 +2785,215 @@ static long sound_copy_translate(const u_char *userPtr, #define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3) -static void mixer_init(void) +static void +mixer_init(void) { - mixer.busy = 0; - sound.treble = 0; - sound.bass = 0; - switch (sound.mach.type) { + mixer.busy = 0; + sound.treble = 0; + sound.bass = 0; + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - atari_microwire_cmd(MW_LM1992_VOLUME(0)); - sound.volume_left = 0; - atari_microwire_cmd(MW_LM1992_BALLEFT(0)); - sound.volume_right = 0; - atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); - atari_microwire_cmd(MW_LM1992_TREBLE(0)); - atari_microwire_cmd(MW_LM1992_BASS(0)); - break; - case DMASND_FALCON: - sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; - sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + atari_microwire_cmd(MW_LM1992_VOLUME(0)); + sound.volume_left = 0; + atari_microwire_cmd(MW_LM1992_BALLEFT(0)); + sound.volume_right = 0; + atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); + atari_microwire_cmd(MW_LM1992_TREBLE(0)); + atari_microwire_cmd(MW_LM1992_BASS(0)); + break; + case DMASND_FALCON: + sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; + sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - sound.volume_left = 64; - sound.volume_right = 64; - custom.aud[0].audvol = sound.volume_left; - custom.aud[3].audvol = 1; /* For pseudo 14bit */ - custom.aud[1].audvol = sound.volume_right; - custom.aud[2].audvol = 1; /* For pseudo 14bit */ - sound.treble = 50; - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + sound.volume_left = 64; + sound.volume_right = 64; + custom.aud[0].audvol = sound.volume_left; + custom.aud[3].audvol = 1; /* For pseudo 14bit */ + custom.aud[1].audvol = sound.volume_right; + custom.aud[2].audvol = 1; /* For pseudo 14bit */ + sound.treble = 50; + break; +#endif /* CONFIG_AMIGA */ + } } -static int mixer_open(int open_mode) +static int +mixer_open(int open_mode) { - if (mixer.busy) - return(-EBUSY); - mixer.busy = 1; - return(0); + if (mixer.busy) + return (-EBUSY); + mixer.busy = 1; + return (0); } -static int mixer_release(void) +static int +mixer_release(void) { - mixer.busy = 0; - return(0); + mixer.busy = 0; + return (0); } -static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg) +static int +mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) { - int data; - switch (sound.mach.type) { + int data; + + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_FALCON: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); - case SOUND_MIXER_READ_RECMASK: - return(IOCTL_OUT(arg, SOUND_MASK_MIC)); - case SOUND_MIXER_READ_STEREODEVS: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); - case SOUND_MIXER_READ_CAPS: - return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); - case SOUND_MIXER_READ_VOLUME: - return(IOCTL_OUT(arg, - VOLUME_ATT_TO_VOXWARE(sound.volume_left) | - VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - tt_dmasnd.input_gain = - RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | - RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); - /* fall thru, return set value */ - case SOUND_MIXER_READ_MIC: - return(IOCTL_OUT(arg, - RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | - RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); - case SOUND_MIXER_READ_SPEAKER: + case DMASND_FALCON: + switch (cmd) { - int porta; - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = sound_ym.rd_data_reg_sel; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + case SOUND_MIXER_READ_DEVMASK: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + case SOUND_MIXER_READ_RECMASK: + return (IOCTL_OUT(arg, SOUND_MASK_MIC)); + case SOUND_MIXER_READ_STEREODEVS: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); + case SOUND_MIXER_READ_CAPS: + return (IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); + case SOUND_MIXER_READ_VOLUME: + return (IOCTL_OUT(arg, + VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + tt_dmasnd.input_gain = + RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | + RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); + /* fall thru, return set value */ + case SOUND_MIXER_READ_MIC: + return (IOCTL_OUT(arg, + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_SPEAKER: + { + int porta; + + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } } - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_WRITE_SPEAKER: + break; + + case DMASND_TT: + switch (cmd) { - int porta; - IOCTL_IN(arg, data); - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = (sound_ym.rd_data_reg_sel & ~0x40) | - (data < 50 ? 0x40 : 0); - sound_ym.wd_data = porta; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + case SOUND_MIXER_READ_DEVMASK: + return (IOCTL_OUT(arg, + SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | + ((atari_mch_cookie >> 16) == ATARI_MCH_TT ? + SOUND_MASK_SPEAKER : 0))); + case SOUND_MIXER_READ_RECMASK: + return (IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return (IOCTL_OUT(arg, + VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); + case SOUND_MIXER_READ_BASS: + return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); + case SOUND_MIXER_READ_TREBLE: + return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + + if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) + { + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return (-EINVAL); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_BASS: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_bass(data))); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_treble(data))); + case SOUND_MIXER_WRITE_SPEAKER: + if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) + { + int porta; + + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return (-EINVAL); } - } - break; - - case DMASND_TT: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - return(IOCTL_OUT(arg, - SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | - ((atari_mch_cookie >> 16) == ATARI_MCH_TT ? - SOUND_MASK_SPEAKER : 0))); - case SOUND_MIXER_READ_RECMASK: - return(IOCTL_OUT(arg, 0)); - case SOUND_MIXER_READ_STEREODEVS: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); - case SOUND_MIXER_READ_VOLUME: - return(IOCTL_OUT(arg, - VOLUME_DB_TO_VOXWARE(sound.volume_left) | - (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); - case SOUND_MIXER_READ_BASS: - return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); - case SOUND_MIXER_READ_TREBLE: - return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); - case SOUND_MIXER_READ_SPEAKER: + break; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + switch (cmd) { - int porta; - if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) { - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = sound_ym.rd_data_reg_sel; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } else - return(-EINVAL); + case SOUND_MIXER_READ_DEVMASK: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); + case SOUND_MIXER_READ_RECMASK: + return (IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return (IOCTL_OUT(arg, + VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_READ_TREBLE: + return (IOCTL_OUT(arg, sound.treble)); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_treble(data))); } - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_WRITE_BASS: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_bass(data))); - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_treble(data))); - case SOUND_MIXER_WRITE_SPEAKER: - if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) { - int porta; - IOCTL_IN(arg, data); - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = (sound_ym.rd_data_reg_sel & ~0x40) | - (data < 50 ? 0x40 : 0); - sound_ym.wd_data = porta; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } else - return(-EINVAL); - } - break; -#endif /* CONFIG_ATARI */ + break; +#endif /* CONFIG_AMIGA */ + } -#ifdef CONFIG_AMIGA - case DMASND_AMIGA: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); - case SOUND_MIXER_READ_RECMASK: - return(IOCTL_OUT(arg, 0)); - case SOUND_MIXER_READ_STEREODEVS: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); - case SOUND_MIXER_READ_VOLUME: - return(IOCTL_OUT(arg, - VOLUME_AMI_TO_VOXWARE(sound.volume_left) | - VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_READ_TREBLE: - return(IOCTL_OUT(arg, sound.treble)); - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_treble(data))); - } - break; -#endif /* CONFIG_AMIGA */ - } - - return(-EINVAL); + return (-EINVAL); } @@ -2702,198 +3003,216 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, */ -static void sq_init(int numBufs, int bufSize, char **buffers) +static void +sq_init(int numBufs, int bufSize, char **buffers) { - sq.max_count = numBufs; - sq.block_size = bufSize; - sq.buffers = buffers; + sq.max_count = numBufs; + sq.block_size = bufSize; + sq.buffers = buffers; - sq.front = sq.count = 0; - sq.rear = -1; - sq.write_queue = sq.open_queue = sq.sync_queue = 0; - sq.busy = 0; - sq.syncing = 0; + sq.front = sq.count = 0; + sq.rear = -1; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + sq.syncing = 0; - sq.playing = 0; + sq.playing = 0; #ifdef CONFIG_ATARI - sq.ignore_int = 0; -#endif /* CONFIG_ATARI */ + sq.ignore_int = 0; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - sq.block_size_half = sq.block_size>>1; - sq.block_size_quarter = sq.block_size_half>>1; -#endif /* CONFIG_AMIGA */ - - sound_silence(); - - /* whatever you like as startup mode for /dev/dsp, - * (/dev/audio hasn't got a startup mode). note that - * once changed a new open() will *not* restore these! - */ - sound.dsp.format = AFMT_S8; - sound.dsp.stereo = 0; - sound.dsp.size = 8; - - /* set minimum rate possible without expanding */ - switch (sound.mach.type) { + sq.block_size_half = sq.block_size >> 1; + sq.block_size_quarter = sq.block_size_half >> 1; +#endif /* CONFIG_AMIGA */ + + sound_silence(); + + /* whatever you like as startup mode for /dev/dsp, + * (/dev/audio hasn't got a startup mode). note that + * once changed a new open() will *not* restore these! + */ + sound.dsp.format = AFMT_S8; + sound.dsp.stereo = 0; + sound.dsp.size = 8; + + /* set minimum rate possible without expanding */ + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - sound.dsp.speed = 6258; - break; - case DMASND_FALCON: - sound.dsp.speed = 8195; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + sound.dsp.speed = 6258; + break; + case DMASND_FALCON: + sound.dsp.speed = 8195; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - sound.dsp.speed = 8000; - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + sound.dsp.speed = 8000; + break; +#endif /* CONFIG_AMIGA */ + } - /* before the first open to /dev/dsp this wouldn't be set */ - sound.soft = sound.dsp; - sound.hard = sound.dsp; + /* before the first open to /dev/dsp this wouldn't be set */ + sound.soft = sound.dsp; + sound.hard = sound.dsp; } -static void sq_play(void) +static void +sq_play(void) { - (*sound.mach.play)(); + (*sound.mach.play) (); } /* ++TeSche: radically changed this one too */ -static long sq_write(const char *src, unsigned long uLeft) -{ - long uWritten = 0; - u_char *dest; - long uUsed, bUsed, bLeft; - - /* ++TeSche: Is something like this necessary? - * Hey, that's an honest question! Or does any other part of the - * filesystem already checks this situation? I really don't know. - */ - if (uLeft == 0) - return(0); - - /* The interrupt doesn't start to play the last, incomplete frame. - * Thus we can append to it without disabling the interrupts! (Note - * also that sq.rear isn't affected by the interrupt.) - */ - - if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { - dest = sq_block_address(sq.rear); - bUsed = sq.rear_size; - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); - src += uUsed; - uWritten += uUsed; - uLeft -= uUsed; - sq.rear_size = bUsed; - } - - do { - while (sq.count == sq.max_count) { - sq_play(); - if (NON_BLOCKING(sq.open_mode)) - return(uWritten > 0 ? uWritten : -EAGAIN); - SLEEP(sq.write_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - return(uWritten > 0 ? uWritten : -EINTR); - } +static long +sq_write(const char *src, unsigned long uLeft) +{ + long uWritten = 0; + u_char *dest; + long uUsed, bUsed, bLeft; - /* Here, we can avoid disabling the interrupt by first - * copying and translating the data, and then updating - * the sq variables. Until this is done, the interrupt - * won't see the new frame and we can work on it - * undisturbed. + /* ++TeSche: Is something like this necessary? + * Hey, that's an honest question! Or does any other part of the + * filesystem already checks this situation? I really don't know. */ + if (uLeft == 0) + return (0); - dest = sq_block_address((sq.rear+1) % sq.max_count); - bUsed = 0; - bLeft = sq.block_size; - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); - src += uUsed; - uWritten += uUsed; - uLeft -= uUsed; - if (bUsed) { - sq.rear = (sq.rear+1) % sq.max_count; - sq.rear_size = bUsed; - sq.count++; - } - } while (bUsed); /* uUsed may have been 0 */ + /* The interrupt doesn't start to play the last, incomplete frame. + * Thus we can append to it without disabling the interrupts! (Note + * also that sq.rear isn't affected by the interrupt.) + */ + + if (sq.count > 0 && (bLeft = sq.block_size - sq.rear_size) > 0) + { + dest = sq_block_address(sq.rear); + bUsed = sq.rear_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + sq.rear_size = bUsed; + } + do + { + while (sq.count == sq.max_count) + { + sq_play(); + if (NON_BLOCKING(sq.open_mode)) + return (uWritten > 0 ? uWritten : -EAGAIN); + SLEEP(sq.write_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return (uWritten > 0 ? uWritten : -EINTR); + } - sq_play(); + /* Here, we can avoid disabling the interrupt by first + * copying and translating the data, and then updating + * the sq variables. Until this is done, the interrupt + * won't see the new frame and we can work on it + * undisturbed. + */ + + dest = sq_block_address((sq.rear + 1) % sq.max_count); + bUsed = 0; + bLeft = sq.block_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + if (bUsed) + { + sq.rear = (sq.rear + 1) % sq.max_count; + sq.rear_size = bUsed; + sq.count++; + } + } + while (bUsed); /* uUsed may have been 0 */ - return(uWritten); + sq_play(); + + return (uWritten); } -static int sq_open(int open_mode) +static int +sq_open(int open_mode) { - if (sq.busy) { - if (NON_BLOCKING(open_mode)) - return(-EBUSY); - while (sq.busy) { - SLEEP(sq.open_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - return(-EINTR); - } - } - sq.open_mode = open_mode; - sq.busy = 1; + if (sq.busy) + { + if (NON_BLOCKING(open_mode)) + return (-EBUSY); + while (sq.busy) + { + SLEEP(sq.open_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return (-EINTR); + } + } + sq.open_mode = open_mode; + sq.busy = 1; #ifdef CONFIG_ATARI - sq.ignore_int = 1; -#endif /* CONFIG_ATARI */ - return(0); + sq.ignore_int = 1; +#endif /* CONFIG_ATARI */ + return (0); } -static void sq_reset(void) +static void +sq_reset(void) { - sound_silence(); - sq.playing = 0; - sq.count = 0; - sq.front = (sq.rear+1) % sq.max_count; + sound_silence(); + sq.playing = 0; + sq.count = 0; + sq.front = (sq.rear + 1) % sq.max_count; } -static int sq_sync(void) +static int +sq_sync(void) { - int rc = 0; + int rc = 0; - sq.syncing = 1; - sq_play(); /* there may be an incomplete frame waiting */ + sq.syncing = 1; + sq_play(); /* there may be an incomplete frame waiting */ - while (sq.playing) { - SLEEP(sq.sync_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) { - /* While waiting for audio output to drain, an interrupt occurred. - Stop audio output immediately and clear the queue. */ - sq_reset(); - rc = -EINTR; - break; - } - } + while (sq.playing) + { + SLEEP(sq.sync_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + { + /* While waiting for audio output to drain, an interrupt occurred. + Stop audio output immediately and clear the queue. */ + sq_reset(); + rc = -EINTR; + break; + } + } - sq.syncing = 0; - return(rc); + sq.syncing = 0; + return (rc); } -static int sq_release(void) +static int +sq_release(void) { - int rc = 0; - if (sq.busy) { - rc = sq_sync(); - sq.busy = 0; - WAKE_UP(sq.open_queue); - /* Wake up a process waiting for the queue being released. - Note: There may be several processes waiting for a call to open() - returning. */ - } - return(rc); + int rc = 0; + + if (sq.busy) + { + rc = sq_sync(); + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue being released. + Note: There may be several processes waiting for a call to open() + returning. */ + } + return (rc); } @@ -2903,128 +3222,136 @@ static int sq_release(void) */ -static void state_init(void) +static void +state_init(void) { - state.busy = 0; + state.busy = 0; } /* state.buf should not overflow! */ -static int state_open(int open_mode) +static int +state_open(int open_mode) { - char *buffer = state.buf, *mach = ""; - int len = 0; + char *buffer = state.buf, *mach = ""; + int len = 0; - if (state.busy) - return(-EBUSY); + if (state.busy) + return (-EBUSY); - state.ptr = 0; - state.busy = 1; + state.ptr = 0; + state.busy = 1; - switch (sound.mach.type) { + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - case DMASND_FALCON: - mach = "Atari "; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + case DMASND_FALCON: + mach = "Atari "; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - mach = "Amiga "; - break; -#endif /* CONFIG_AMIGA */ - } - len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); - - len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); - switch (sound.soft.format) { - case AFMT_MU_LAW: - len += sprintf(buffer+len, " (mu-law)"); - break; - case AFMT_A_LAW: - len += sprintf(buffer+len, " (A-law)"); - break; - case AFMT_U8: - len += sprintf(buffer+len, " (unsigned 8 bit)"); - break; - case AFMT_S8: - len += sprintf(buffer+len, " (signed 8 bit)"); - break; - case AFMT_S16_BE: - len += sprintf(buffer+len, " (signed 16 bit big)"); - break; - case AFMT_U16_BE: - len += sprintf(buffer+len, " (unsigned 16 bit big)"); - break; - case AFMT_S16_LE: - len += sprintf(buffer+len, " (signed 16 bit little)"); - break; - case AFMT_U16_LE: - len += sprintf(buffer+len, " (unsigned 16 bit little)"); - break; - } - len += sprintf(buffer+len, "\n"); - len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", - sound.soft.speed, sound.hard.speed); - len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", - sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); - switch (sound.mach.type) { + case DMASND_AMIGA: + mach = "Amiga "; + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer + len, "%sDMA sound driver:\n", mach); + + len += sprintf(buffer + len, "\tsound.format = 0x%x", sound.soft.format); + switch (sound.soft.format) + { + case AFMT_MU_LAW: + len += sprintf(buffer + len, " (mu-law)"); + break; + case AFMT_A_LAW: + len += sprintf(buffer + len, " (A-law)"); + break; + case AFMT_U8: + len += sprintf(buffer + len, " (unsigned 8 bit)"); + break; + case AFMT_S8: + len += sprintf(buffer + len, " (signed 8 bit)"); + break; + case AFMT_S16_BE: + len += sprintf(buffer + len, " (signed 16 bit big)"); + break; + case AFMT_U16_BE: + len += sprintf(buffer + len, " (unsigned 16 bit big)"); + break; + case AFMT_S16_LE: + len += sprintf(buffer + len, " (signed 16 bit little)"); + break; + case AFMT_U16_LE: + len += sprintf(buffer + len, " (unsigned 16 bit little)"); + break; + } + len += sprintf(buffer + len, "\n"); + len += sprintf(buffer + len, "\tsound.speed = %dHz (phys. %dHz)\n", + sound.soft.speed, sound.hard.speed); + len += sprintf(buffer + len, "\tsound.stereo = 0x%x (%s)\n", + sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n", - sound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n", - sound.volume_right); - len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n", - sound.bass); - len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n", - sound.treble); - break; - case DMASND_FALCON: - len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n", - sound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n", - sound.volume_right); - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-40...0]\n", + sound.volume_left); + len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-40...0]\n", + sound.volume_right); + len += sprintf(buffer + len, "\tsound.bass = %ddB [-12...+12]\n", + sound.bass); + len += sprintf(buffer + len, "\tsound.treble = %ddB [-12...+12]\n", + sound.treble); + break; + case DMASND_FALCON: + len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-22.5...0]\n", + sound.volume_left); + len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-22.5...0]\n", + sound.volume_right); + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", - sound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", - sound.volume_right); - break; -#endif /* CONFIG_AMIGA */ - } - len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n", - sq.block_size, sq.max_count); - len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, - sq.rear_size); - len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n", - sq.playing, sq.syncing); - state.len = len; - return(0); + case DMASND_AMIGA: + len += sprintf(buffer + len, "\tsound.volume_left = %d [0...64]\n", + sound.volume_left); + len += sprintf(buffer + len, "\tsound.volume_right = %d [0...64]\n", + sound.volume_right); + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer + len, "\tsq.block_size = %d sq.max_count = %d\n", + sq.block_size, sq.max_count); + len += sprintf(buffer + len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, + sq.rear_size); + len += sprintf(buffer + len, "\tsq.playing = %d sq.syncing = %d\n", + sq.playing, sq.syncing); + state.len = len; + return (0); } -static int state_release(void) +static int +state_release(void) { - state.busy = 0; - return(0); + state.busy = 0; + return (0); } -static long state_read(char *dest, unsigned long count) +static long +state_read(char *dest, unsigned long count) { - int n = state.len-state.ptr; - if (n > count) - n = count; - if (n <= 0) - return(0); - copy_to_user(dest, &state.buf[state.ptr], n); - state.ptr += n; - return(n); + int n = state.len - state.ptr; + + if (n > count) + n = count; + if (n <= 0) + return (0); + copy_to_user(dest, &state.buf[state.ptr], n); + state.ptr += n; + return (n); } @@ -3032,230 +3359,241 @@ static long state_read(char *dest, unsigned long count) /*** High level stuff ********************************************************/ -static int sound_open(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - int rc = 0; - - switch (dev) { - case SND_DEV_STATUS: - rc = state_open(file->f_flags); - break; - case SND_DEV_CTL: - rc = mixer_open(file->f_flags); - break; - case SND_DEV_DSP: - case SND_DEV_AUDIO: - rc = sq_open(file->f_flags); - if (rc == 0) { - sound.minDev = dev; - sound.soft = sound.dsp; - sound.hard = sound.dsp; - sound_init(); - if (dev == SND_DEV_AUDIO) { - sound_set_speed(8000); - sound_set_stereo(0); - sound_set_format(AFMT_MU_LAW); - } - } - break; - default: - rc = -ENXIO; - } +static int +sound_open(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev) & 0x0f; + int rc = 0; + + switch (dev) + { + case SND_DEV_STATUS: + rc = state_open(file->f_flags); + break; + case SND_DEV_CTL: + rc = mixer_open(file->f_flags); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + rc = sq_open(file->f_flags); + if (rc == 0) + { + sound.minDev = dev; + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_init(); + if (dev == SND_DEV_AUDIO) + { + sound_set_speed(8000); + sound_set_stereo(0); + sound_set_format(AFMT_MU_LAW); + } + } + break; + default: + rc = -ENXIO; + } #ifdef MODULE - if (rc >= 0) - MOD_INC_USE_COUNT; + if (rc >= 0) + MOD_INC_USE_COUNT; #endif - return(rc); -} - - -static int sound_fsync(struct file *filp, struct dentry *dentry) -{ - int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f; - - switch (dev) { - case SND_DEV_STATUS: - case SND_DEV_CTL: - return(0); - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return(sq_sync()); - default: - return(unknown_minor_dev("sound_fsync", dev)); - } -} - - -static void sound_release(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - - switch (dev & 0x0f) { - case SND_DEV_STATUS: - state_release(); - break; - case SND_DEV_CTL: - mixer_release(); - break; - case SND_DEV_DSP: - case SND_DEV_AUDIO: - sq_release(); - sound.soft = sound.dsp; - sound.hard = sound.dsp; - sound_silence(); - break; - default: - unknown_minor_dev("sound_release", dev); - return; - } + return (rc); +} + + +static int +sound_fsync(struct inode *inode, struct file *filp) +{ + int dev = MINOR(inode->i_rdev) & 0x0f; + + switch (dev) + { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return (0); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return (sq_sync()); + default: + return (unknown_minor_dev("sound_fsync", dev)); + } +} + + +static void +sound_release(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + state_release(); + break; + case SND_DEV_CTL: + mixer_release(); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + sq_release(); + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_silence(); + break; + default: + unknown_minor_dev("sound_release", dev); + return; + } #ifdef MODULE - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #endif } -static long long sound_lseek(struct file *file, long long offset, int orig) +static long long +sound_lseek(struct inode *inode, struct file *file, + long long offset, int orig) { - return -ESPIPE; + return -ESPIPE; } -static long sound_read(struct inode *inode, struct file *file, char *buf, - unsigned long count) +static ssize_t sound_read(struct file *file, char *buf, szie_t count, loff_t *ppos) { - int dev = MINOR(inode->i_rdev); + int dev = MINOR(file->f_dentry->d_inode->i_rdev); - switch (dev & 0x0f) { - case SND_DEV_STATUS: - return(state_read(buf, count)); - case SND_DEV_CTL: - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return(-EPERM); - default: - return(unknown_minor_dev("sound_read", dev)); - } + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return (state_read(buf, count)); + case SND_DEV_CTL: + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return (-EPERM); + default: + return (unknown_minor_dev("sound_read", dev)); + } } -static long sound_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int dev = MINOR(inode->i_rdev); + int dev = MINOR(file->f_dentry->d_inode->i_rdev); - switch (dev & 0x0f) { - case SND_DEV_STATUS: - case SND_DEV_CTL: - return(-EPERM); - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return(sq_write(buf, count)); - default: - return(unknown_minor_dev("sound_write", dev)); - } + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return (-EPERM); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return (sq_write(buf, count)); + default: + return (unknown_minor_dev("sound_write", dev)); + } } static int unknown_minor_dev(char *fname, int dev) { - /* printk("%s: Unknown minor device %d\n", fname, dev); */ - return(-ENXIO); -} - - -static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg) -{ - int dev = MINOR(inode->i_rdev); - u_long fmt; - int data; - - switch (dev & 0x0f) { - case SND_DEV_STATUS: - return(-EPERM); - case SND_DEV_CTL: - return(mixer_ioctl(inode, file, cmd, arg)); - case SND_DEV_AUDIO: - case SND_DEV_DSP: - switch (cmd) { - case SNDCTL_DSP_RESET: - sq_reset(); - return(0); - case SNDCTL_DSP_POST: - case SNDCTL_DSP_SYNC: - return(sound_fsync(file, file->f_dentry)); - - /* ++TeSche: before changing any of these it's probably wise to - * wait until sound playing has settled down - */ - case SNDCTL_DSP_SPEED: - sound_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_speed(data))); - case SNDCTL_DSP_STEREO: - sound_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_stereo(data))); - case SOUND_PCM_WRITE_CHANNELS: - sound_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1)); - case SNDCTL_DSP_SETFMT: - sound_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_format(data))); - case SNDCTL_DSP_GETFMTS: - fmt = 0; - if (sound.trans) { - if (sound.trans->ct_ulaw) - fmt |= AFMT_MU_LAW; - if (sound.trans->ct_alaw) - fmt |= AFMT_A_LAW; - if (sound.trans->ct_s8) - fmt |= AFMT_S8; - if (sound.trans->ct_u8) - fmt |= AFMT_U8; - if (sound.trans->ct_s16be) - fmt |= AFMT_S16_BE; - if (sound.trans->ct_u16be) - fmt |= AFMT_U16_BE; - if (sound.trans->ct_s16le) - fmt |= AFMT_S16_LE; - if (sound.trans->ct_u16le) - fmt |= AFMT_U16_LE; - } - return(IOCTL_OUT(arg, fmt)); - case SNDCTL_DSP_GETBLKSIZE: - return(IOCTL_OUT(arg, 10240)); - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - break; + /* printk("%s: Unknown minor device %d\n", fname, dev); */ + return (-ENXIO); +} + + +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +{ + int dev = MINOR(inode->i_rdev); + u_long fmt; + int data; + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return (-EPERM); + case SND_DEV_CTL: + return (mixer_ioctl(inode, file, cmd, arg)); + case SND_DEV_AUDIO: + case SND_DEV_DSP: + switch (cmd) + { + case SNDCTL_DSP_RESET: + sq_reset(); + return (0); + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + return (sound_fsync(inode, file)); + + /* ++TeSche: before changing any of these it's probably wise to + * wait until sound playing has settled down + */ + case SNDCTL_DSP_SPEED: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_speed(data))); + case SNDCTL_DSP_STEREO: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_stereo(data))); + case SOUND_PCM_WRITE_CHANNELS: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_stereo(data - 1) + 1)); + case SNDCTL_DSP_SETFMT: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_format(data))); + case SNDCTL_DSP_GETFMTS: + fmt = 0; + if (sound.trans) + { + if (sound.trans->ct_ulaw) + fmt |= AFMT_MU_LAW; + if (sound.trans->ct_alaw) + fmt |= AFMT_A_LAW; + if (sound.trans->ct_s8) + fmt |= AFMT_S8; + if (sound.trans->ct_u8) + fmt |= AFMT_U8; + if (sound.trans->ct_s16be) + fmt |= AFMT_S16_BE; + if (sound.trans->ct_u16be) + fmt |= AFMT_U16_BE; + if (sound.trans->ct_s16le) + fmt |= AFMT_S16_LE; + if (sound.trans->ct_u16le) + fmt |= AFMT_U16_LE; + } + return (IOCTL_OUT(arg, fmt)); + case SNDCTL_DSP_GETBLKSIZE: + return (IOCTL_OUT(arg, 10240)); + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + break; + default: + return (mixer_ioctl(inode, file, cmd, arg)); + } + break; default: - return(mixer_ioctl(inode, file, cmd, arg)); - } - break; - - default: - return(unknown_minor_dev("sound_ioctl", dev)); - } - return(-EINVAL); + return (unknown_minor_dev("sound_ioctl", dev)); + } + return (-EINVAL); } static struct file_operations sound_fops = { - sound_lseek, - sound_read, - sound_write, - NULL, - NULL, /* select */ - sound_ioctl, - NULL, - sound_open, - sound_release, - sound_fsync + sound_lseek, + sound_read, + sound_write, + NULL, + NULL, /* select */ + sound_ioctl, + NULL, + sound_open, + sound_release, + sound_fsync }; @@ -3263,171 +3601,186 @@ static struct file_operations sound_fops = /*** Config & Setup **********************************************************/ -void soundcard_init(void) +void +soundcard_init(void) { - int has_sound = 0; - int i; + int has_sound = 0; + int i; - switch (m68k_machtype) { + switch (m68k_machtype) + { #ifdef CONFIG_ATARI - case MACH_ATARI: - if (ATARIHW_PRESENT(PCM_8BIT)) { - if (ATARIHW_PRESENT(CODEC)) - sound.mach = machFalcon; - else if (ATARIHW_PRESENT(MICROWIRE)) - sound.mach = machTT; - else - break; - if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) - has_sound = 1; - else - printk("DMA sound driver: Timer A interrupt already in use\n"); - } - break; - -#endif /* CONFIG_ATARI */ + case MACH_ATARI: + if (ATARIHW_PRESENT(PCM_8BIT)) + { + if (ATARIHW_PRESENT(CODEC)) + sound.mach = machFalcon; + else if (ATARIHW_PRESENT(MICROWIRE)) + sound.mach = machTT; + else + break; + if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) + has_sound = 1; + else + printk(KERN_ERR "DMA sound driver: Timer A interrupt already in use\n"); + } + break; + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case MACH_AMIGA: - if (AMIGAHW_PRESENT(AMI_AUDIO)) { - sound.mach = machAmiga; - has_sound = 1; - } - break; -#endif /* CONFIG_AMIGA */ - } - if (!has_sound) - return; + case MACH_AMIGA: + if (AMIGAHW_PRESENT(AMI_AUDIO)) + { + sound.mach = machAmiga; + has_sound = 1; + } + break; +#endif /* CONFIG_AMIGA */ + } + if (!has_sound) + return; - /* Set up sound queue, /dev/audio and /dev/dsp. */ - sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); - if (!sound_buffers) { + /* Set up sound queue, /dev/audio and /dev/dsp. */ + sound_buffers = kmalloc(numBufs * sizeof(char *), GFP_KERNEL); + + if (!sound_buffers) + { out_of_memory: - printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); - return; - } - for (i = 0; i < numBufs; i++) { - sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); - if (!sound_buffers[i]) { - while (i--) - sound.mach.dma_free (sound_buffers[i], bufSize << 10); - kfree (sound_buffers); - sound_buffers = 0; - goto out_of_memory; - } - } + printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); + return; + } + for (i = 0; i < numBufs; i++) + { + sound_buffers[i] = sound.mach.dma_alloc(bufSize << 10, GFP_KERNEL); + if (!sound_buffers[i]) + { + while (i--) + sound.mach.dma_free(sound_buffers[i], bufSize << 10); + kfree(sound_buffers); + sound_buffers = 0; + goto out_of_memory; + } + } #ifndef MODULE - /* Register driver with the VFS. */ - register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + /* Register driver with the VFS. */ + register_chrdev(SOUND_MAJOR, "sound", &sound_fops); #endif - sq_init(numBufs, bufSize << 10, sound_buffers); + sq_init(numBufs, bufSize << 10, sound_buffers); - /* Set up /dev/sndstat. */ - state_init(); + /* Set up /dev/sndstat. */ + state_init(); - /* Set up /dev/mixer. */ - mixer_init(); + /* Set up /dev/mixer. */ + mixer_init(); - if (!sound.mach.irqinit()) { - printk("DMA sound driver: Interrupt initialization failed\n"); - return; - } + if (!sound.mach.irqinit()) + { + printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); + return; + } #ifdef MODULE - irq_installed = 1; + irq_installed = 1; #endif - printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, - bufSize); + printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", numBufs, + bufSize); - return; + return; } void sound_setup(char *str, int *ints) { - /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ + /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ } #define MAXARGS 8 /* Should be sufficient for now */ -void dmasound_setup(char *str, int *ints) -{ - /* check the bootstrap parameter for "dmasound=" */ - - switch (ints[0]) { - case 3: - if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) - printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); - else - catchRadius = ints[3]; - /* fall through */ - case 2: - if (ints[1] < MIN_BUFFERS) - printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); - else - numBufs = ints[1]; - if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) - printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize); - else - bufSize = ints[2]; - break; - case 0: - break; - default: - printk("dmasound_setup: illegal number of arguments\n"); - } +void +dmasound_setup(char *str, int *ints) +{ + /* check the bootstrap parameter for "dmasound=" */ + + switch (ints[0]) + { + case 3: + if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) + printk(KERN_WARNING "dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[3]; + /* fall through */ + case 2: + if (ints[1] < MIN_BUFFERS) + printk(KERN_WARNING "dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); + else + numBufs = ints[1]; + if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) + printk(KERN_WARNING "dmasound_setup: illegal buffer size, using default = %d\n", bufSize); + else + bufSize = ints[2]; + break; + case 0: + break; + default: + printk(KERN_WARNING "dmasound_setup: illegal number of arguments\n"); + } } #ifdef MODULE -static int dmasound[MAXARGS] = { 0 }; +static int dmasound[MAXARGS] = { + 0 +}; int init_module(void) { - int err, i = 0; - int ints[MAXARGS+1]; + int err, i = 0; + int ints[MAXARGS + 1]; - while (i < MAXARGS && dmasound[i]) - ints[i + 1] = dmasound[i++]; - ints[0] = i; + while (i < MAXARGS && dmasound[i]) + ints[i + 1] = dmasound[i++]; + ints[0] = i; - if (i) - dmasound_setup("dmasound=", ints); + if (i) + dmasound_setup("dmasound=", ints); - err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); - if (err) { - printk("dmasound: driver already loaded/included in kernel\n"); - return err; - } - chrdev_registered = 1; - soundcard_init(); + err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + if (err) + { + printk(KERN_ERR "dmasound: driver already loaded/included in kernel\n"); + return err; + } + chrdev_registered = 1; + soundcard_init(); - return 0; + return 0; } void cleanup_module(void) { - int i; - - if (MOD_IN_USE) - return; + int i; - if (chrdev_registered) - unregister_chrdev(SOUND_MAJOR, "sound"); + if (MOD_IN_USE) + return; - if (irq_installed) { - sound_silence(); - sound.mach.irqcleanup(); - } + if (chrdev_registered) + unregister_chrdev(SOUND_MAJOR, "sound"); - if (sound_buffers) { - for (i = 0; i < numBufs; i++) - sound.mach.dma_free(sound_buffers[i], bufSize << 10); - kfree(sound_buffers); - } + if (irq_installed) + { + sound_silence(); + sound.mach.irqcleanup(); + } + if (sound_buffers) + { + for (i = 0; i < numBufs; i++) + sound.mach.dma_free(sound_buffers[i], bufSize << 10); + kfree(sound_buffers); + } } -#endif /* MODULE */ +#endif /* MODULE */ diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index 1c8881684..eba6072d6 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -11,159 +11,154 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_GUSHW) +#if defined(CONFIG_GUSHW) || defined(MODULE) #include "gus_hw.h" -void gusintr (int irq, void *dev_id, struct pt_regs *dummy); +void gusintr(int irq, void *dev_id, struct pt_regs *dummy); -int gus_base, gus_irq, gus_dma; +int gus_base = 0, gus_irq = 0, gus_dma = 0; extern int gus_wave_volume; extern int gus_pcm_volume; extern int have_gus_max; int gus_pnp_flag = 0; void -attach_gus_card (struct address_info *hw_config) +attach_gus_card(struct address_info *hw_config) { - snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); + snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); - gus_wave_init (hw_config); + gus_wave_init(hw_config); - request_region (hw_config->io_base, 16, "GUS"); - request_region (hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ + request_region(hw_config->io_base, 16, "GUS"); + request_region(hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ - if (sound_alloc_dma (hw_config->dma, "GUS")) - printk ("gus_card.c: Can't allocate DMA channel\n"); - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - if (sound_alloc_dma (hw_config->dma2, "GUS(2)")) - printk ("gus_card.c: Can't allocate DMA channel2\n"); -#ifdef CONFIG_MIDI - gus_midi_init (); + if (sound_alloc_dma(hw_config->dma, "GUS")) + printk("gus_card.c: Can't allocate DMA channel\n"); + if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) + if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) + printk("gus_card.c: Can't allocate DMA channel 2\n"); +#if defined(CONFIG_MIDI) + gus_midi_init(hw_config); #endif } int -probe_gus (struct address_info *hw_config) +probe_gus(struct address_info *hw_config) { - int irq; - int io_addr; - - if (hw_config->card_subtype == 1) - gus_pnp_flag = 1; - - irq = hw_config->irq; - - if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */ - if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && - irq != 11 && irq != 12 && irq != 15) - { - printk ("GUS: Unsupported IRQ %d\n", irq); - return 0; - } - - if (check_region (hw_config->io_base, 16)) - printk ("GUS: I/O range conflict (1)\n"); - else if (check_region (hw_config->io_base + 0x100, 16)) - printk ("GUS: I/O range conflict (2)\n"); - else if (gus_wave_detect (hw_config->io_base)) - return 1; + int irq; + int io_addr; + + if (hw_config->card_subtype == 1) + gus_pnp_flag = 1; + + irq = hw_config->irq; + + if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */ + if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && + irq != 11 && irq != 12 && irq != 15) + { + printk("GUS: Unsupported IRQ %d\n", irq); + return 0; + } + if (check_region(hw_config->io_base, 16)) + printk("GUS: I/O range conflict (1)\n"); + else if (check_region(hw_config->io_base + 0x100, 16)) + printk("GUS: I/O range conflict (2)\n"); + else if (gus_wave_detect(hw_config->io_base)) + return 1; #ifndef EXCLUDE_GUS_IODETECT - /* - * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) - */ - - for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) - if (io_addr != hw_config->io_base) /* - * Already tested - */ - if (!check_region (io_addr, 16)) - if (!check_region (io_addr + 0x100, 16)) - if (gus_wave_detect (io_addr)) - { - hw_config->io_base = io_addr; - return 1; - } - + /* + * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) + */ + + for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) + if (io_addr != hw_config->io_base) /* + * Already tested + */ + if (!check_region(io_addr, 16)) + if (!check_region(io_addr + 0x100, 16)) + if (gus_wave_detect(io_addr)) + { + hw_config->io_base = io_addr; + return 1; + } #endif - return 0; + return 0; } void -unload_gus (struct address_info *hw_config) +unload_gus(struct address_info *hw_config) { - DDB (printk ("unload_gus(%x)\n", hw_config->io_base)); + DDB(printk("unload_gus(%x)\n", hw_config->io_base)); - gus_wave_unload (); + gus_wave_unload(hw_config); - release_region (hw_config->io_base, 16); - release_region (hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ - snd_release_irq (hw_config->irq); + release_region(hw_config->io_base, 16); + release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ + snd_release_irq(hw_config->irq); - sound_free_dma (hw_config->dma); + sound_free_dma(hw_config->dma); - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - sound_free_dma (hw_config->dma2); + if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) + sound_free_dma(hw_config->dma2); } void -gusintr (int irq, void *dev_id, struct pt_regs *dummy) +gusintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char src; - extern int gus_timer_enabled; + unsigned char src; + extern int gus_timer_enabled; - sti (); + sti(); #ifdef CONFIG_GUSMAX - if (have_gus_max) - adintr (irq, NULL, NULL); + if (have_gus_max) + adintr(irq, NULL, NULL); #endif - while (1) - { - if (!(src = inb (u_IrqStatus))) - return; - - if (src & DMA_TC_IRQ) - { - guswave_dma_irq (); - } - - if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) - { -#ifdef CONFIG_MIDI - gus_midi_interrupt (0); + while (1) + { + if (!(src = inb(u_IrqStatus))) + return; + + if (src & DMA_TC_IRQ) + { + guswave_dma_irq(); + } + if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) + { +#if defined(CONFIG_MIDI) + gus_midi_interrupt(0); #endif - } - - if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) - { -#ifdef CONFIG_SEQUENCER - if (gus_timer_enabled) - { - sound_timer_interrupt (); - } - - gus_write8 (0x45, 0); /* Ack IRQ */ - gus_timer_command (4, 0x80); /* Reset IRQ flags */ + } + if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) + { +#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) + if (gus_timer_enabled) + { + sound_timer_interrupt(); + } + gus_write8(0x45, 0); /* Ack IRQ */ + gus_timer_command(4, 0x80); /* Reset IRQ flags */ #else - gus_write8 (0x45, 0); /* Stop timers */ + gus_write8(0x45, 0); /* Stop timers */ #endif - } - - if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) - { - gus_voice_irq (); - } - } + } + if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) + { + gus_voice_irq(); + } + } } #endif @@ -171,36 +166,103 @@ gusintr (int irq, void *dev_id, struct pt_regs *dummy) /* * Some extra code for the 16 bit sampling option */ -#if defined(CONFIG_GUS16) +#ifdef CONFIG_GUS16 int -probe_gus_db16 (struct address_info *hw_config) +probe_gus_db16(struct address_info *hw_config) { - return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); + return ad1848_detect(hw_config->io_base, NULL, hw_config->osp); } void -attach_gus_db16 (struct address_info *hw_config) +attach_gus_db16(struct address_info *hw_config) { -#ifdef CONFIG_GUSHW - gus_pcm_volume = 100; - gus_wave_volume = 90; +#if defined(CONFIG_GUSHW) || defined(MODULE) + gus_pcm_volume = 100; + gus_wave_volume = 90; #endif - ad1848_init ("GUS 16 bit sampling", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0, - hw_config->osp); + hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, 0, + hw_config->osp); } void -unload_gus_db16 (struct address_info *hw_config) +unload_gus_db16(struct address_info *hw_config) +{ + + ad1848_unload(hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, 0); + sound_unload_audiodev(hw_config->slots[3]); +} +#endif + +#ifdef MODULE + +static struct address_info config; + +/* + * Note DMA2 of -1 has the right meaning in the GUS driver as well + * as here. + */ + +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* 1 for PnP */ +int gus16 = 0; +static int db16 = 0; /* Has a Gus16 AD1848 on it */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(gus16, "i"); +MODULE_PARM(db16, "i"); + +int +init_module(void) { + printk("Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, IRQ, and DMA are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + config.card_subtype = type; - ad1848_unload (hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0); +#if defined(CONFIG_GUS16) + if (probe_gus_db16(&config) && gus16) + { + attach_gus_db16(&config); + db16 = 1; + } +#endif + if (probe_gus(&config) == 0) + return -ENODEV; + attach_gus_card(&config); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (db16) + unload_gus_db16(&config); + unload_gus(&config); + SOUND_LOCK_END; } + #endif diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 9fc38fc88..fdbde32fd 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -17,7 +17,7 @@ #include "gus_hw.h" -#if defined(CONFIG_GUSHW) && defined(CONFIG_MIDI) +#if ( defined(CONFIG_GUSHW) && defined(CONFIG_MIDI) ) || defined (MODULE) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -33,183 +33,178 @@ static volatile unsigned char qhead, qtail; extern int gus_base, gus_irq, gus_dma; extern int *gus_osp; -static int -GUS_MIDI_STATUS (void) +static int +GUS_MIDI_STATUS(void) { - return inb (u_MidiStatus); + return inb(u_MidiStatus); } static int -gus_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +gus_midi_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - if (midi_busy) - { - printk ("GUS: Midi busy\n"); - return -EBUSY; - } - - outb ((MIDI_RESET), u_MidiControl); - gus_delay (); - - gus_midi_control = 0; - input_opened = 0; - - if (mode == OPEN_READ || mode == OPEN_READWRITE) - if (!gus_pnp_flag) - { - gus_midi_control |= MIDI_ENABLE_RCV; - input_opened = 1; - } - - - outb ((gus_midi_control), u_MidiControl); /* Enable */ - - midi_busy = 1; - qlen = qhead = qtail = output_used = 0; - midi_input_intr = input; - - return 0; + if (midi_busy) + { + printk("GUS: Midi busy\n"); + return -EBUSY; + } + outb((MIDI_RESET), u_MidiControl); + gus_delay(); + + gus_midi_control = 0; + input_opened = 0; + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + if (!gus_pnp_flag) + { + gus_midi_control |= MIDI_ENABLE_RCV; + input_opened = 1; + } + outb((gus_midi_control), u_MidiControl); /* Enable */ + + midi_busy = 1; + qlen = qhead = qtail = output_used = 0; + midi_input_intr = input; + + return 0; } static int -dump_to_midi (unsigned char midi_byte) +dump_to_midi(unsigned char midi_byte) { - unsigned long flags; - int ok = 0; - - output_used = 1; - - save_flags (flags); - cli (); - - if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY) - { - ok = 1; - outb ((midi_byte), u_MidiData); - } - else - { - /* - * Enable Midi xmit interrupts (again) - */ - gus_midi_control |= MIDI_ENABLE_XMIT; - outb ((gus_midi_control), u_MidiControl); - } - - restore_flags (flags); - return ok; + unsigned long flags; + int ok = 0; + + output_used = 1; + + save_flags(flags); + cli(); + + if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) + { + ok = 1; + outb((midi_byte), u_MidiData); + } else + { + /* + * Enable Midi xmit interrupts (again) + */ + gus_midi_control |= MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + } + + restore_flags(flags); + return ok; } static void -gus_midi_close (int dev) +gus_midi_close(int dev) { - /* - * Reset FIFO pointers, disable intrs - */ + /* + * Reset FIFO pointers, disable intrs + */ - outb ((MIDI_RESET), u_MidiControl); - midi_busy = 0; + outb((MIDI_RESET), u_MidiControl); + midi_busy = 0; } static int -gus_midi_out (int dev, unsigned char midi_byte) +gus_midi_out(int dev, unsigned char midi_byte) { - unsigned long flags; + unsigned long flags; - /* - * Drain the local queue first - */ + /* + * Drain the local queue first + */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } - restore_flags (flags); + restore_flags(flags); - /* - * Output the byte if the local queue is empty. - */ + /* + * Output the byte if the local queue is empty. + */ - if (!qlen) - if (dump_to_midi (midi_byte)) - return 1; /* - * OK - */ + if (!qlen) + if (dump_to_midi(midi_byte)) + return 1; /* + * OK + */ - /* - * Put to the local queue - */ + /* + * Put to the local queue + */ - if (qlen >= 256) - return 0; /* + if (qlen >= 256) + return 0; /* * Local queue full */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; + tmp_queue[qtail] = midi_byte; + qlen++; + qtail++; - restore_flags (flags); + restore_flags(flags); - return 1; + return 1; } static int -gus_midi_start_read (int dev) +gus_midi_start_read(int dev) { - return 0; + return 0; } static int -gus_midi_end_read (int dev) +gus_midi_end_read(int dev) { - return 0; + return 0; } static int -gus_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +gus_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -gus_midi_kick (int dev) +gus_midi_kick(int dev) { } static int -gus_midi_buffer_status (int dev) +gus_midi_buffer_status(int dev) { - unsigned long flags; - - if (!output_used) - return 0; + unsigned long flags; - save_flags (flags); - cli (); + if (!output_used) + return 0; - if (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } + save_flags(flags); + cli(); - restore_flags (flags); + if (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } + restore_flags(flags); - return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY); + return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY); } #define MIDI_SYNTH_NAME "Gravis Ultrasound Midi" @@ -218,81 +213,81 @@ gus_midi_buffer_status (int dev) static struct midi_operations gus_midi_operations = { - {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, - &std_midi_synth, - {0}, - gus_midi_open, - gus_midi_close, - gus_midi_ioctl, - gus_midi_out, - gus_midi_start_read, - gus_midi_end_read, - gus_midi_kick, - NULL, /* + {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + &std_midi_synth, + {0}, + gus_midi_open, + gus_midi_close, + gus_midi_ioctl, + gus_midi_out, + gus_midi_start_read, + gus_midi_end_read, + gus_midi_kick, + NULL, /* * command */ - gus_midi_buffer_status, - NULL + gus_midi_buffer_status, + NULL }; void -gus_midi_init (void) +gus_midi_init(struct address_info *hw_config) { - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - outb ((MIDI_RESET), u_MidiControl); - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &gus_midi_operations; - sequencer_init (); - return; + int dev = sound_alloc_mididev(); + + if (dev == -1) + { + printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); + return; + } + outb((MIDI_RESET), u_MidiControl); + + std_midi_synth.midi_dev = my_dev = dev; + hw_config->slots[2] = dev; + midi_devs[dev] = &gus_midi_operations; + sequencer_init(); + return; } void -gus_midi_interrupt (int dummy) +gus_midi_interrupt(int dummy) { - volatile unsigned char stat, data; - unsigned long flags; - int timeout = 10; - - save_flags (flags); - cli (); - - while (timeout-- > 0 && (stat = GUS_MIDI_STATUS ()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) - { - if (stat & MIDI_RCV_FULL) - { - data = inb (u_MidiData); - if (input_opened) - midi_input_intr (my_dev, data); - } - - if (stat & MIDI_XMIT_EMPTY) - { - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - if (!qlen) - { - /* - * Disable Midi output interrupts, since no data in the buffer - */ - gus_midi_control &= ~MIDI_ENABLE_XMIT; - outb ((gus_midi_control), u_MidiControl); - outb ((gus_midi_control), u_MidiControl); - } - } - - } - - restore_flags (flags); + volatile unsigned char stat, data; + unsigned long flags; + int timeout = 10; + + save_flags(flags); + cli(); + + while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) + { + if (stat & MIDI_RCV_FULL) + { + data = inb(u_MidiData); + if (input_opened) + midi_input_intr(my_dev, data); + } + if (stat & MIDI_XMIT_EMPTY) + { + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + if (!qlen) + { + /* + * Disable Midi output interrupts, since no data in the buffer + */ + gus_midi_control &= ~MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + outb((gus_midi_control), u_MidiControl); + } + } + } + + restore_flags(flags); } #endif diff --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c index 5eaecc4e3..a42c5c6e1 100644 --- a/drivers/sound/gus_vol.c +++ b/drivers/sound/gus_vol.c @@ -1,3 +1,4 @@ + /* * gus_vol.c - Compute volume for GUS. */ @@ -11,7 +12,7 @@ #include <linux/config.h> #include "sound_config.h" -#ifdef CONFIG_GUSHW +#if defined(CONFIG_GUSHW) || defined(MODULE) #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume @@ -34,87 +35,85 @@ extern int gus_wave_volume; * basses. The normal value is 64. Strings are assigned lower values. */ unsigned short -gus_adagio_vol (int vel, int mainv, int xpn, int voicev) +gus_adagio_vol(int vel, int mainv, int xpn, int voicev) { - int i, m, n, x; + int i, m, n, x; - /* - * A voice volume of 64 is considered neutral, so adjust the main volume if - * something other than this neutral value was assigned in the patch - * library. - */ - x = 256 + 6 * (voicev - 64); + /* + * A voice volume of 64 is considered neutral, so adjust the main volume if + * something other than this neutral value was assigned in the patch + * library. + */ + x = 256 + 6 * (voicev - 64); - /* - * Boost expression by voice volume above neutral. - */ - if (voicev > 65) - xpn += voicev - 64; - xpn += (voicev - 64) / 2; + /* + * Boost expression by voice volume above neutral. + */ + if (voicev > 65) + xpn += voicev - 64; + xpn += (voicev - 64) / 2; - /* - * Combine multiplicative and level components. - */ - x = vel * xpn * 6 + (voicev / 4) * x; + /* + * Combine multiplicative and level components. + */ + x = vel * xpn * 6 + (voicev / 4) * x; #ifdef GUS_VOLUME - /* - * Further adjustment by installation-specific master volume control - * (default 60). - */ - x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; + /* + * Further adjustment by installation-specific master volume control + * (default 60). + */ + x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; #endif #ifdef GUS_USE_CHN_MAIN_VOLUME - /* - * Experimental support for the channel main volume - */ + /* + * Experimental support for the channel main volume + */ - mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ - x = (x * mainv * mainv) / 16384; + mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ + x = (x * mainv * mainv) / 16384; #endif - if (x < 2) - return (0); - else if (x >= 65535) - return ((15 << 8) | 255); - - /* - * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit - * mantissa m. - */ - n = x; - i = 7; - if (n < 128) - { - while (i > 0 && n < (1 << i)) - i--; - } - else - while (n > 255) - { - n >>= 1; - i++; - } - /* - * Mantissa is part of linear volume not expressed in exponent. (This is - * not quite like real logs -- I wonder if it's right.) - */ - m = x - (1 << i); - - /* - * Adjust mantissa to 8 bits. - */ - if (m > 0) - { - if (i > 8) - m >>= i - 8; - else if (i < 8) - m <<= 8 - i; - } - - return ((i << 8) + m); + if (x < 2) + return (0); + else if (x >= 65535) + return ((15 << 8) | 255); + + /* + * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit + * mantissa m. + */ + n = x; + i = 7; + if (n < 128) + { + while (i > 0 && n < (1 << i)) + i--; + } else + while (n > 255) + { + n >>= 1; + i++; + } + /* + * Mantissa is part of linear volume not expressed in exponent. (This is + * not quite like real logs -- I wonder if it's right.) + */ + m = x - (1 << i); + + /* + * Adjust mantissa to 8 bits. + */ + if (m > 0) + { + if (i > 8) + m >>= i - 8; + else if (i < 8) + m <<= 8 - i; + } + return ((i << 8) + m); } /* @@ -124,31 +123,31 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) */ unsigned short -gus_linear_vol (int vol, int mainvol) +gus_linear_vol(int vol, int mainvol) { - int mixer_mainvol; + int mixer_mainvol; - if (vol <= 0) - vol = 0; - else if (vol >= 127) - vol = 127; + if (vol <= 0) + vol = 0; + else if (vol >= 127) + vol = 127; #ifdef GUS_VOLUME - mixer_mainvol = GUS_VOLUME; + mixer_mainvol = GUS_VOLUME; #else - mixer_mainvol = 100; + mixer_mainvol = 100; #endif #ifdef GUS_USE_CHN_MAIN_VOLUME - if (mainvol <= 0) - mainvol = 0; - else if (mainvol >= 127) - mainvol = 127; + if (mainvol <= 0) + mainvol = 0; + else if (mainvol >= 127) + mainvol = 127; #else - mainvol = 127; + mainvol = 127; #endif - return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; + return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } #endif diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 8c1523750..2814ffe12 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -19,7 +19,7 @@ #include <linux/ultrasound.h> #include "gus_hw.h" -#if defined(CONFIG_GUSHW) +#if defined(CONFIG_GUSHW) || defined(MODULE) #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) @@ -30,38 +30,39 @@ struct voice_info { - unsigned long orig_freq; - unsigned long current_freq; - unsigned long mode; - int fixed_pitch; - int bender; - int bender_range; - int panning; - int midi_volume; - unsigned int initial_volume; - unsigned int current_volume; - int loop_irq_mode, loop_irq_parm; + unsigned long orig_freq; + unsigned long current_freq; + unsigned long mode; + int fixed_pitch; + int bender; + int bender_range; + int panning; + int midi_volume; + unsigned int initial_volume; + unsigned int current_volume; + int loop_irq_mode, loop_irq_parm; #define LMODE_FINISH 1 #define LMODE_PCM 2 #define LMODE_PCM_STOP 3 - int volume_irq_mode, volume_irq_parm; + int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 #define VMODE_START_NOTE 3 - int env_phase; - unsigned char env_rate[6]; - unsigned char env_offset[6]; + int env_phase; + unsigned char env_rate[6]; + unsigned char env_offset[6]; - /* - * Volume computation parameters for gus_adagio_vol() - */ - int main_vol, expression_vol, patch_vol; + /* + * Volume computation parameters for gus_adagio_vol() + */ + int main_vol, expression_vol, patch_vol; - /* Variables for "Ultraclick" removal */ - int dev_pending, note_pending, volume_pending, sample_pending; - char kill_pending; - long offset_pending; + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, + sample_pending; + char kill_pending; + long offset_pending; }; @@ -73,7 +74,6 @@ extern int gus_pnp_flag; static int gus_dma2 = -1; static int dual_dma_mode = 0; static long gus_mem_size = 0; -static long gus_rom_size = 0; static long free_mem_ptr = 0; static int gus_busy = 0; static int gus_no_dma = 0; @@ -137,26 +137,26 @@ static struct voice_info voices[32]; static int freq_div_table[] = { - 44100, - 44100, /* 14 */ - 41160, /* 15 */ - 38587, /* 16 */ - 36317, /* 17 */ - 34300, /* 18 */ - 32494, /* 19 */ - 30870, /* 20 */ - 29400, /* 21 */ - 28063, /* 22 */ - 26843, /* 23 */ - 25725, /* 24 */ - 24696, /* 25 */ - 23746, /* 26 */ - 22866, /* 27 */ - 22050, /* 28 */ - 21289, /* 29 */ - 20580, /* 30 */ - 19916, /* 31 */ - 19293 /* 32 */ + 44100, + 44100, /* 14 */ + 41160, /* 15 */ + 38587, /* 16 */ + 36317, /* 17 */ + 34300, /* 18 */ + 32494, /* 19 */ + 30870, /* 20 */ + 29400, /* 21 */ + 28063, /* 22 */ + 26843, /* 23 */ + 25725, /* 24 */ + 24696, /* 25 */ + 23746, /* 26 */ + 22866, /* 27 */ + 22050, /* 28 */ + 21289, /* 29 */ + 20580, /* 30 */ + 19916, /* 31 */ + 19293 /* 32 */ }; static struct patch_info *samples; @@ -172,720 +172,711 @@ static int patch_map[32]; static struct synth_info gus_info = {"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; -static void gus_poke (long addr, unsigned char data); -static void compute_and_set_volume (int voice, int volume, int ramp_time); -extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev); -extern unsigned short gus_linear_vol (int vol, int mainvol); -static void compute_volume (int voice, int volume); -static void do_volume_irq (int voice); -static void set_input_volumes (void); -static void gus_tmr_install (int io_base); +static void gus_poke(long addr, unsigned char data); +static void compute_and_set_volume(int voice, int volume, int ramp_time); +extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev); +extern unsigned short gus_linear_vol(int vol, int mainvol); +static void compute_volume(int voice, int volume); +static void do_volume_irq(int voice); +static void set_input_volumes(void); +static void gus_tmr_install(int io_base); #define INSTANT_RAMP -1 /* Instant change. No ramping */ #define FAST_RAMP 0 /* Fastest possible ramp */ static void -reset_sample_memory (void) +reset_sample_memory(void) { - int i; + int i; - for (i = 0; i <= MAX_SAMPLE; i++) - sample_ptrs[i] = -1; - for (i = 0; i < 32; i++) - sample_map[i] = -1; - for (i = 0; i < 32; i++) - patch_map[i] = -1; + for (i = 0; i <= MAX_SAMPLE; i++) + sample_ptrs[i] = -1; + for (i = 0; i < 32; i++) + sample_map[i] = -1; + for (i = 0; i < 32; i++) + patch_map[i] = -1; - gus_poke (0, 0); /* Put a silent sample to the beginning */ - gus_poke (1, 0); - free_mem_ptr = 2; + gus_poke(0, 0); /* Put a silent sample to the beginning */ + gus_poke(1, 0); + free_mem_ptr = 2; - free_sample = 0; + free_sample = 0; - for (i = 0; i < MAX_PATCH; i++) - patch_table[i] = NOT_SAMPLE; + for (i = 0; i < MAX_PATCH; i++) + patch_table[i] = NOT_SAMPLE; } void -gus_delay (void) +gus_delay(void) { - int i; + int i; - for (i = 0; i < 7; i++) - inb (u_DRAMIO); + for (i = 0; i < 7; i++) + inb(u_DRAMIO); } static void -gus_poke (long addr, unsigned char data) +gus_poke(long addr, unsigned char data) { /* Writes a byte to the DRAM */ - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - outb ((0x43), u_Command); - outb ((addr & 0xff), u_DataLo); - outb (((addr >> 8) & 0xff), u_DataHi); + save_flags(flags); + cli(); + outb((0x43), u_Command); + outb((addr & 0xff), u_DataLo); + outb(((addr >> 8) & 0xff), u_DataHi); - outb ((0x44), u_Command); - outb (((addr >> 16) & 0xff), u_DataHi); - outb ((data), u_DRAMIO); - restore_flags (flags); + outb((0x44), u_Command); + outb(((addr >> 16) & 0xff), u_DataHi); + outb((data), u_DRAMIO); + restore_flags(flags); } static unsigned char -gus_peek (long addr) +gus_peek(long addr) { /* Reads a byte from the DRAM */ - unsigned long flags; - unsigned char tmp; + unsigned long flags; + unsigned char tmp; - save_flags (flags); - cli (); - outb ((0x43), u_Command); - outb ((addr & 0xff), u_DataLo); - outb (((addr >> 8) & 0xff), u_DataHi); + save_flags(flags); + cli(); + outb((0x43), u_Command); + outb((addr & 0xff), u_DataLo); + outb(((addr >> 8) & 0xff), u_DataHi); - outb ((0x44), u_Command); - outb (((addr >> 16) & 0xff), u_DataHi); - tmp = inb (u_DRAMIO); - restore_flags (flags); + outb((0x44), u_Command); + outb(((addr >> 16) & 0xff), u_DataHi); + tmp = inb(u_DRAMIO); + restore_flags(flags); - return tmp; + return tmp; } void -gus_write8 (int reg, unsigned int data) +gus_write8(int reg, unsigned int data) { /* Writes to an indirect register (8 bit) */ - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg), u_Command); - outb (((unsigned char) (data & 0xff)), u_DataHi); + outb((reg), u_Command); + outb(((unsigned char) (data & 0xff)), u_DataHi); - restore_flags (flags); + restore_flags(flags); } static unsigned char -gus_read8 (int reg) +gus_read8(int reg) { /* Reads from an indirect register (8 bit). Offset 0x80. */ - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); - outb ((reg | 0x80), u_Command); - val = inb (u_DataHi); - restore_flags (flags); + save_flags(flags); + cli(); + outb((reg | 0x80), u_Command); + val = inb(u_DataHi); + restore_flags(flags); - return val; + return val; } static unsigned char -gus_look8 (int reg) +gus_look8(int reg) { /* Reads from an indirect register (8 bit). No additional offset. */ - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); - outb ((reg), u_Command); - val = inb (u_DataHi); - restore_flags (flags); + save_flags(flags); + cli(); + outb((reg), u_Command); + val = inb(u_DataHi); + restore_flags(flags); - return val; + return val; } static void -gus_write16 (int reg, unsigned int data) +gus_write16(int reg, unsigned int data) { /* Writes to an indirect register (16 bit) */ - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg), u_Command); + outb((reg), u_Command); - outb (((unsigned char) (data & 0xff)), u_DataLo); - outb (((unsigned char) ((data >> 8) & 0xff)), u_DataHi); + outb(((unsigned char) (data & 0xff)), u_DataLo); + outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi); - restore_flags (flags); + restore_flags(flags); } static unsigned short -gus_read16 (int reg) +gus_read16(int reg) { /* Reads from an indirect register (16 bit). Offset 0x80. */ - unsigned long flags; - unsigned char hi, lo; + unsigned long flags; + unsigned char hi, lo; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg | 0x80), u_Command); + outb((reg | 0x80), u_Command); - lo = inb (u_DataLo); - hi = inb (u_DataHi); + lo = inb(u_DataLo); + hi = inb(u_DataHi); - restore_flags (flags); + restore_flags(flags); - return ((hi << 8) & 0xff00) | lo; + return ((hi << 8) & 0xff00) | lo; } static unsigned short -gus_look16 (int reg) +gus_look16(int reg) { /* Reads from an indirect register (16 bit). No additional offset. */ - unsigned long flags; - unsigned char hi, lo; + unsigned long flags; + unsigned char hi, lo; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg), u_Command); + outb((reg), u_Command); - lo = inb (u_DataLo); - hi = inb (u_DataHi); + lo = inb(u_DataLo); + hi = inb(u_DataHi); - restore_flags (flags); + restore_flags(flags); - return ((hi << 8) & 0xff00) | lo; + return ((hi << 8) & 0xff00) | lo; } static void -gus_write_addr (int reg, unsigned long address, int frac, int is16bit) +gus_write_addr(int reg, unsigned long address, int frac, int is16bit) { /* Writes an 24 bit memory address */ - unsigned long hold_address; - unsigned long flags; - - save_flags (flags); - cli (); - if (is16bit) - { - if (iw_mode) - { - /* Interwave spesific address translations */ - address >>= 1; - } - else - { - /* - * Special processing required for 16 bit patches - */ + unsigned long hold_address; + unsigned long flags; - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - } - - gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) - + (frac << 5)); - /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ - gus_delay (); - gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) - + (frac << 5)); - restore_flags (flags); + save_flags(flags); + cli(); + if (is16bit) + { + if (iw_mode) + { + /* Interwave spesific address translations */ + address >>= 1; + } else + { + /* + * Special processing required for 16 bit patches + */ + + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + } + gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); + gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); + /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ + gus_delay(); + gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); + gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); + restore_flags(flags); } static void -gus_select_voice (int voice) +gus_select_voice(int voice) { - if (voice < 0 || voice > 31) - return; + if (voice < 0 || voice > 31) + return; - outb ((voice), u_Voice); + outb((voice), u_Voice); } static void -gus_select_max_voices (int nvoices) +gus_select_max_voices(int nvoices) { - if (iw_mode) - nvoices = 32; - if (nvoices < 14) - nvoices = 14; - if (nvoices > 32) - nvoices = 32; + if (iw_mode) + nvoices = 32; + if (nvoices < 14) + nvoices = 14; + if (nvoices > 32) + nvoices = 32; - voice_alloc->max_voice = nr_voices = nvoices; + voice_alloc->max_voice = nr_voices = nvoices; - gus_write8 (0x0e, (nvoices - 1) | 0xc0); + gus_write8(0x0e, (nvoices - 1) | 0xc0); } static void -gus_voice_on (unsigned int mode) +gus_voice_on(unsigned int mode) { - gus_write8 (0x00, (unsigned char) (mode & 0xfc)); - gus_delay (); - gus_write8 (0x00, (unsigned char) (mode & 0xfc)); + gus_write8(0x00, (unsigned char) (mode & 0xfc)); + gus_delay(); + gus_write8(0x00, (unsigned char) (mode & 0xfc)); } static void -gus_voice_off (void) +gus_voice_off(void) { - gus_write8 (0x00, gus_read8 (0x00) | 0x03); + gus_write8(0x00, gus_read8(0x00) | 0x03); } static void -gus_voice_mode (unsigned int m) +gus_voice_mode(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | - (mode & 0xfc)); /* Don't touch last two bits */ - gus_delay (); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); + gus_write8(0x00, (gus_read8(0x00) & 0x03) | + (mode & 0xfc)); /* Don't touch last two bits */ + gus_delay(); + gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc)); } static void -gus_voice_freq (unsigned long freq) +gus_voice_freq(unsigned long freq) { - unsigned long divisor = freq_div_table[nr_voices - 14]; - unsigned short fc; + unsigned long divisor = freq_div_table[nr_voices - 14]; + unsigned short fc; - /* Interwave plays at 44100 Hz with any number of voices */ - if (iw_mode) - fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); - else - fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); - fc = fc << 1; + /* Interwave plays at 44100 Hz with any number of voices */ + if (iw_mode) + fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); + else + fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); + fc = fc << 1; - gus_write16 (0x01, fc); + gus_write16(0x01, fc); } static void -gus_voice_volume (unsigned int vol) +gus_voice_volume(unsigned int vol) { - gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */ - gus_write16 (0x09, (unsigned short) (vol << 4)); + gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */ + gus_write16(0x09, (unsigned short) (vol << 4)); } static void -gus_voice_balance (unsigned int balance) +gus_voice_balance(unsigned int balance) { - gus_write8 (0x0c, (unsigned char) (balance & 0xff)); + gus_write8(0x0c, (unsigned char) (balance & 0xff)); } static void -gus_ramp_range (unsigned int low, unsigned int high) +gus_ramp_range(unsigned int low, unsigned int high) { - gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff)); - gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff)); + gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff)); + gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff)); } static void -gus_ramp_rate (unsigned int scale, unsigned int rate) +gus_ramp_rate(unsigned int scale, unsigned int rate) { - gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); + gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); } static void -gus_rampon (unsigned int m) +gus_rampon(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x0d, mode & 0xfc); - gus_delay (); - gus_write8 (0x0d, mode & 0xfc); + gus_write8(0x0d, mode & 0xfc); + gus_delay(); + gus_write8(0x0d, mode & 0xfc); } static void -gus_ramp_mode (unsigned int m) +gus_ramp_mode(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | - (mode & 0xfc)); /* Leave the last 2 bits alone */ - gus_delay (); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); + gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | + (mode & 0xfc)); /* Leave the last 2 bits alone */ + gus_delay(); + gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); } static void -gus_rampoff (void) +gus_rampoff(void) { - gus_write8 (0x0d, 0x03); + gus_write8(0x0d, 0x03); } static void -gus_set_voice_pos (int voice, long position) +gus_set_voice_pos(int voice, long position) { - int sample_no; + int sample_no; - if ((sample_no = sample_map[voice]) != -1) - if (position < samples[sample_no].len) - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - voices[voice].offset_pending = position; - else - gus_write_addr (0x0a, sample_ptrs[sample_no] + position, 0, - samples[sample_no].mode & WAVE_16_BITS); + if ((sample_no = sample_map[voice]) != -1) + if (position < samples[sample_no].len) + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].offset_pending = position; + else + gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0, + samples[sample_no].mode & WAVE_16_BITS); } static void -gus_voice_init (int voice) +gus_voice_init(int voice) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_volume (0); - gus_voice_off (); - gus_write_addr (0x0a, 0, 0, 0); /* Set current position to 0 */ - gus_write8 (0x00, 0x03); /* Voice off */ - gus_write8 (0x0d, 0x03); /* Ramping off */ - voice_alloc->map[voice] = 0; - voice_alloc->alloc_times[voice] = 0; - restore_flags (flags); + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(0); + gus_voice_off(); + gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */ + gus_write8(0x00, 0x03); /* Voice off */ + gus_write8(0x0d, 0x03); /* Ramping off */ + voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; + restore_flags(flags); } static void -gus_voice_init2 (int voice) -{ - voices[voice].panning = 0; - voices[voice].mode = 0; - voices[voice].orig_freq = 20000; - voices[voice].current_freq = 20000; - voices[voice].bender = 0; - voices[voice].bender_range = 200; - voices[voice].initial_volume = 0; - voices[voice].current_volume = 0; - voices[voice].loop_irq_mode = 0; - voices[voice].loop_irq_parm = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].volume_irq_parm = 0; - voices[voice].env_phase = 0; - voices[voice].main_vol = 127; - voices[voice].patch_vol = 127; - voices[voice].expression_vol = 127; - voices[voice].sample_pending = -1; - voices[voice].fixed_pitch = 0; +gus_voice_init2(int voice) +{ + voices[voice].panning = 0; + voices[voice].mode = 0; + voices[voice].orig_freq = 20000; + voices[voice].current_freq = 20000; + voices[voice].bender = 0; + voices[voice].bender_range = 200; + voices[voice].initial_volume = 0; + voices[voice].current_volume = 0; + voices[voice].loop_irq_mode = 0; + voices[voice].loop_irq_parm = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].volume_irq_parm = 0; + voices[voice].env_phase = 0; + voices[voice].main_vol = 127; + voices[voice].patch_vol = 127; + voices[voice].expression_vol = 127; + voices[voice].sample_pending = -1; + voices[voice].fixed_pitch = 0; } static void -step_envelope (int voice) -{ - unsigned vol, prev_vol, phase; - unsigned char rate; - long int flags; - - if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) - { - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_rampoff (); - restore_flags (flags); - return; - /* - * Sustain phase begins. Continue envelope after receiving note off. - */ - } - - if (voices[voice].env_phase >= 5) - { /* Envelope finished. Shoot the voice down */ - gus_voice_init (voice); - return; - } - - prev_vol = voices[voice].current_volume; - phase = ++voices[voice].env_phase; - compute_volume (voice, voices[voice].midi_volume); - vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; - rate = voices[voice].env_rate[phase]; - - save_flags (flags); - cli (); - gus_select_voice (voice); - - gus_voice_volume (prev_vol); - - - gus_write8 (0x06, rate); /* Ramping rate */ - - voices[voice].volume_irq_mode = VMODE_ENVELOPE; - - if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ - { - restore_flags (flags); - step_envelope (voice); /* Continue the envelope on the next step */ - return; - } - - if (vol > prev_vol) - { - if (vol >= (4096 - 64)) - vol = 4096 - 65; - gus_ramp_range (0, vol); - gus_rampon (0x20); /* Increasing volume, with IRQ */ - } - else - { - if (vol <= 64) - vol = 65; - gus_ramp_range (vol, 4030); - gus_rampon (0x60); /* Decreasing volume, with IRQ */ - } - voices[voice].current_volume = vol; - restore_flags (flags); +step_envelope(int voice) +{ + unsigned vol, prev_vol, phase; + unsigned char rate; + long int flags; + + if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + return; + /* + * Sustain phase begins. Continue envelope after receiving note off. + */ + } + if (voices[voice].env_phase >= 5) + { /* Envelope finished. Shoot the voice down */ + gus_voice_init(voice); + return; + } + prev_vol = voices[voice].current_volume; + phase = ++voices[voice].env_phase; + compute_volume(voice, voices[voice].midi_volume); + vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; + rate = voices[voice].env_rate[phase]; + + save_flags(flags); + cli(); + gus_select_voice(voice); + + gus_voice_volume(prev_vol); + + + gus_write8(0x06, rate); /* Ramping rate */ + + voices[voice].volume_irq_mode = VMODE_ENVELOPE; + + if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ + { + restore_flags(flags); + step_envelope(voice); /* Continue the envelope on the next step */ + return; + } + if (vol > prev_vol) + { + if (vol >= (4096 - 64)) + vol = 4096 - 65; + gus_ramp_range(0, vol); + gus_rampon(0x20); /* Increasing volume, with IRQ */ + } else + { + if (vol <= 64) + vol = 65; + gus_ramp_range(vol, 4030); + gus_rampon(0x60); /* Decreasing volume, with IRQ */ + } + voices[voice].current_volume = vol; + restore_flags(flags); } static void -init_envelope (int voice) +init_envelope(int voice) { - voices[voice].env_phase = -1; - voices[voice].current_volume = 64; + voices[voice].env_phase = -1; + voices[voice].current_volume = 64; - step_envelope (voice); + step_envelope(voice); } static void -start_release (int voice, long int flags) +start_release(int voice, long int flags) { - if (gus_read8 (0x00) & 0x03) - return; /* Voice already stopped */ + if (gus_read8(0x00) & 0x03) + return; /* Voice already stopped */ - voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ + voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ - voices[voice].current_volume = - voices[voice].initial_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + voices[voice].current_volume = + voices[voice].initial_volume = + gus_read16(0x09) >> 4; /* Get current volume */ - voices[voice].mode &= ~WAVE_SUSTAIN_ON; - gus_rampoff (); - restore_flags (flags); - step_envelope (voice); + voices[voice].mode &= ~WAVE_SUSTAIN_ON; + gus_rampoff(); + restore_flags(flags); + step_envelope(voice); } static void -gus_voice_fade (int voice) -{ - int instr_no = sample_map[voice], is16bits; - long int flags; - - save_flags (flags); - cli (); - gus_select_voice (voice); - - if (instr_no < 0 || instr_no > MAX_SAMPLE) - { - gus_write8 (0x00, 0x03); /* Hard stop */ - voice_alloc->map[voice] = 0; - restore_flags (flags); - return; - } - - is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ - - if (voices[voice].mode & WAVE_ENVELOPES) - { - start_release (voice, flags); - return; - } - - /* - * Ramp the volume down but not too quickly. - */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* Get current volume */ - { - gus_voice_off (); - gus_rampoff (); - gus_voice_init (voice); - return; - } - - gus_ramp_range (65, 4030); - gus_ramp_rate (2, 4); - gus_rampon (0x40 | 0x20); /* Down, once, with IRQ */ - voices[voice].volume_irq_mode = VMODE_HALT; - restore_flags (flags); +gus_voice_fade(int voice) +{ + int instr_no = sample_map[voice], is16bits; + long int flags; + + save_flags(flags); + cli(); + gus_select_voice(voice); + + if (instr_no < 0 || instr_no > MAX_SAMPLE) + { + gus_write8(0x00, 0x03); /* Hard stop */ + voice_alloc->map[voice] = 0; + restore_flags(flags); + return; + } + is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ + + if (voices[voice].mode & WAVE_ENVELOPES) + { + start_release(voice, flags); + restore_flags(flags); + return; + } + /* + * Ramp the volume down but not too quickly. + */ + if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */ + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + restore_flags(flags); + return; + } + gus_ramp_range(65, 4030); + gus_ramp_rate(2, 4); + gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */ + voices[voice].volume_irq_mode = VMODE_HALT; + restore_flags(flags); } static void -gus_reset (void) +gus_reset(void) { - int i; + int i; - gus_select_max_voices (24); - volume_base = 3071; - volume_scale = 4; - volume_method = VOL_METHOD_ADAGIO; + gus_select_max_voices(24); + volume_base = 3071; + volume_scale = 4; + volume_method = VOL_METHOD_ADAGIO; - for (i = 0; i < 32; i++) - { - gus_voice_init (i); /* Turn voice off */ - gus_voice_init2 (i); - } + for (i = 0; i < 32; i++) + { + gus_voice_init(i); /* Turn voice off */ + gus_voice_init2(i); + } } static void -gus_initialize (void) +gus_initialize(void) { - unsigned long flags; - unsigned char dma_image, irq_image, tmp; + unsigned long flags; + unsigned char dma_image, irq_image, tmp; + + static unsigned char gus_irq_map[16] = + {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; - static unsigned char gus_irq_map[16] = - {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; - - static unsigned char gus_dma_map[8] = - {0, 1, 0, 2, 0, 3, 4, 5}; + static unsigned char gus_dma_map[8] = + {0, 1, 0, 2, 0, 3, 4, 5}; - save_flags (flags); - cli (); - gus_write8 (0x4c, 0); /* Reset GF1 */ - gus_delay (); - gus_delay (); + save_flags(flags); + cli(); + gus_write8(0x4c, 0); /* Reset GF1 */ + gus_delay(); + gus_delay(); - gus_write8 (0x4c, 1); /* Release Reset */ - gus_delay (); - gus_delay (); + gus_write8(0x4c, 1); /* Release Reset */ + gus_delay(); + gus_delay(); - /* - * Clear all interrupts - */ + /* + * Clear all interrupts + */ - gus_write8 (0x41, 0); /* DMA control */ - gus_write8 (0x45, 0); /* Timer control */ - gus_write8 (0x49, 0); /* Sample control */ + gus_write8(0x41, 0); /* DMA control */ + gus_write8(0x45, 0); /* Timer control */ + gus_write8(0x49, 0); /* Sample control */ - gus_select_max_voices (24); + gus_select_max_voices(24); - inb (u_Status); /* Touch the status register */ + inb(u_Status); /* Touch the status register */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - gus_reset (); /* Resets all voices */ + gus_reset(); /* Resets all voices */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */ + gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */ - /* - * Set up for Digital ASIC - */ + /* + * Set up for Digital ASIC + */ - outb ((0x05), gus_base + 0x0f); + outb((0x05), gus_base + 0x0f); - mix_image |= 0x02; /* Disable line out (for a moment) */ - outb ((mix_image), u_Mixer); + mix_image |= 0x02; /* Disable line out (for a moment) */ + outb((mix_image), u_Mixer); - outb ((0x00), u_IRQDMAControl); + outb((0x00), u_IRQDMAControl); - outb ((0x00), gus_base + 0x0f); + outb((0x00), gus_base + 0x0f); - /* - * Now set up the DMA and IRQ interface - * - * The GUS supports two IRQs and two DMAs. - * - * Just one DMA channel is used. This prevents simultaneous ADC and DAC. - * Adding this support requires significant changes to the dmabuf.c, dsp.c - * and audio.c also. - */ + /* + * Now set up the DMA and IRQ interface + * + * The GUS supports two IRQs and two DMAs. + * + * Just one DMA channel is used. This prevents simultaneous ADC and DAC. + * Adding this support requires significant changes to the dmabuf.c, dsp.c + * and audio.c also. + */ - irq_image = 0; - tmp = gus_irq_map[gus_irq]; - if (!gus_pnp_flag && !tmp) - printk ("Warning! GUS IRQ not selected\n"); - irq_image |= tmp; - irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ + irq_image = 0; + tmp = gus_irq_map[gus_irq]; + if (!gus_pnp_flag && !tmp) + printk("Warning! GUS IRQ not selected\n"); + irq_image |= tmp; + irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ - dual_dma_mode = 1; - if (gus_dma2 == gus_dma || gus_dma2 == -1) - { - dual_dma_mode = 0; - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + dual_dma_mode = 1; + if (gus_dma2 == gus_dma || gus_dma2 == -1) + { + dual_dma_mode = 0; + dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk ("Warning! GUS DMA not selected\n"); + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk("Warning! GUS DMA not selected\n"); - dma_image |= tmp; - } - else - /* Setup dual DMA channel mode for GUS MAX */ - { - dma_image = gus_dma_map[gus_dma]; - if (!dma_image) - printk ("Warning! GUS DMA not selected\n"); + dma_image |= tmp; + } else + /* Setup dual DMA channel mode for GUS MAX */ + { + dma_image = gus_dma_map[gus_dma]; + if (!dma_image) + printk("Warning! GUS DMA not selected\n"); + + tmp = gus_dma_map[gus_dma2] << 3; + if (!tmp) + { + printk("Warning! Invalid GUS MAX DMA\n"); + tmp = 0x40; /* Combine DMA channels */ + dual_dma_mode = 0; + } + dma_image |= tmp; + } - tmp = gus_dma_map[gus_dma2] << 3; - if (!tmp) - { - printk ("Warning! Invalid GUS MAX DMA\n"); - tmp = 0x40; /* Combine DMA channels */ - dual_dma_mode = 0; - } + /* + * For some reason the IRQ and DMA addresses must be written twice + */ - dma_image |= tmp; - } + /* + * Doing it first time + */ - /* - * For some reason the IRQ and DMA addresses must be written twice - */ - - /* - * Doing it first time - */ - - outb ((mix_image), u_Mixer); /* Select DMA control */ - outb ((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */ + outb((mix_image), u_Mixer); /* Select DMA control */ + outb((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */ - outb ((mix_image | 0x40), u_Mixer); /* Select IRQ control */ - outb ((irq_image), u_IRQDMAControl); /* Set IRQ address */ + outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */ + outb((irq_image), u_IRQDMAControl); /* Set IRQ address */ - /* - * Doing it second time - */ + /* + * Doing it second time + */ - outb ((mix_image), u_Mixer); /* Select DMA control */ - outb ((dma_image), u_IRQDMAControl); /* Set DMA address */ + outb((mix_image), u_Mixer); /* Select DMA control */ + outb((dma_image), u_IRQDMAControl); /* Set DMA address */ - outb ((mix_image | 0x40), u_Mixer); /* Select IRQ control */ - outb ((irq_image), u_IRQDMAControl); /* Set IRQ address */ + outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */ + outb((irq_image), u_IRQDMAControl); /* Set IRQ address */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - mix_image &= ~0x02; /* Enable line out */ - mix_image |= 0x08; /* Enable IRQ */ - outb ((mix_image), u_Mixer); /* - * Turn mixer channels on - * Note! Mic in is left off. - */ + mix_image &= ~0x02; /* Enable line out */ + mix_image |= 0x08; /* Enable IRQ */ + outb((mix_image), u_Mixer); /* + * Turn mixer channels on + * Note! Mic in is left off. + */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + gusintr(gus_irq, NULL, NULL); /* Serve pending interrupts */ - inb (u_Status); /* Touch the status register */ + inb(u_Status); /* Touch the status register */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - if (iw_mode) - gus_write8 (0x19, gus_read8 (0x19) | 0x01); - restore_flags (flags); + if (iw_mode) + gus_write8(0x19, gus_read8(0x19) | 0x01); + restore_flags(flags); } static void -pnp_mem_init (void) +pnp_mem_init(void) { #include "iwmem.h" #define CHUNK_SIZE (256*1024) #define BANK_SIZE (4*1024*1024) #define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) - int bank, chunk, addr, total = 0; - int bank_sizes[4]; - int i, j, bits = -1, nbanks = 0; + int bank, chunk, addr, total = 0; + int bank_sizes[4]; + int i, j, bits = -1, nbanks = 0; /* * This routine determines what kind of RAM is installed in each of the four @@ -895,68 +886,68 @@ pnp_mem_init (void) /* * Place the chip into enhanced mode */ - gus_write8 (0x19, gus_read8 (0x19) | 0x01); - gus_write8 (0x53, gus_look8 (0x53) & ~0x02); /* Select DRAM I/O access */ + gus_write8(0x19, gus_read8(0x19) | 0x01); + gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */ /* * Set memory configuration to 4 DRAM banks of 4M in each (16M total). */ - gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | 0x000c); + gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c); /* * Perform the DRAM size detection for each bank individually. */ - for (bank = 0; bank < 4; bank++) - { - int size = 0; - - addr = bank * BANK_SIZE; - - /* Clean check points of each chunk */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - /* Write a value to each chunk point and verify the result */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x55); - gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0xAA); - - if (gus_peek (addr + chunk * CHUNK_SIZE + 0L) == 0x55 && - gus_peek (addr + chunk * CHUNK_SIZE + 1L) == 0xAA) - { /* OK. There is RAM. Now check for possible shadows */ - int ok = 1, chunk2; - - for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) - if (gus_peek (addr + chunk2 * CHUNK_SIZE + 0L) || - gus_peek (addr + chunk2 * CHUNK_SIZE + 1L)) - ok = 0; /* Addressing wraps */ - - if (ok) - size = (chunk + 1) * CHUNK_SIZE; - } - gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - bank_sizes[bank] = size; - if (size) - nbanks = bank + 1; - DDB (printk ("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); - } - - if (nbanks == 0) /* No RAM - Give up */ - { - printk ("Sound: An Interwave audio chip detected but no DRAM\n"); - printk ("Sound: Unable to work with this card.\n"); - gus_write8 (0x19, gus_read8 (0x19) & ~0x01); - gus_mem_size = 0; - return; - } + for (bank = 0; bank < 4; bank++) + { + int size = 0; + + addr = bank * BANK_SIZE; + + /* Clean check points of each chunk */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + /* Write a value to each chunk point and verify the result */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); + + if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && + gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA) + { /* OK. There is RAM. Now check for possible shadows */ + int ok = 1, chunk2; + + for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) + if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || + gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) + ok = 0; /* Addressing wraps */ + + if (ok) + size = (chunk + 1) * CHUNK_SIZE; + } + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + bank_sizes[bank] = size; + if (size) + nbanks = bank + 1; + DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); + } + + if (nbanks == 0) /* No RAM - Give up */ + { + printk("Sound: An Interwave audio chip detected but no DRAM\n"); + printk("Sound: Unable to work with this card.\n"); + gus_write8(0x19, gus_read8(0x19) & ~0x01); + gus_mem_size = 0; + return; + } /* * Now we know how much DRAM there is in each bank. The next step is * to find a DRAM size encoding (0 to 12) which is best for the combination @@ -966,668 +957,640 @@ pnp_mem_init (void) * of memory we have. */ - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; - for (j = 0; bits != -1 && j < 4; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } + for (j = 0; bits != -1 && j < 4; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } /* * If necessary, try to find a combination where other than the last * bank matches our configuration and the last bank is left oversized. * In this way we don't leave holes in the middle of memory. */ - 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 (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) - bits = -1; /* The last bank is too small */ - } - + 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 (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) + bits = -1; /* The last bank is too small */ + } /* * 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) - { - printk ("Interwave: Can't use all installed RAM.\n"); - printk ("Interwave: Try reordering SIMMS.\n"); - } - } - - if (bits == -1) - { - printk ("Interwave: Can't find working DRAM encoding.\n"); - printk ("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); - bits = 0; - } - - DDB (printk ("Interwave: Selecting DRAM addressing mode %d\n", bits)); - - for (bank = 0; bank < 4; bank++) - { - DDB (printk (" Bank %d, mem=%dk (limit %dk)\n", - bank, bank_sizes[bank] / 1024, - mem_decode[bits][bank] / 1024)); - - if (bank_sizes[bank] > mem_decode[bits][bank]) - total += mem_decode[bits][bank]; - else - total += bank_sizes[bank]; - } - - DDB (printk ("Total %dk of DRAM (enhanced mode)\n", total / 1024)); + 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) + { + printk("Interwave: Can't use all installed RAM.\n"); + printk("Interwave: Try reordering SIMMS.\n"); + } + } + if (bits == -1) + { + printk("Interwave: Can't find working DRAM encoding.\n"); + printk("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); + bits = 0; + } + DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits)); + + for (bank = 0; bank < 4; bank++) + { + DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); + + if (bank_sizes[bank] > mem_decode[bits][bank]) + total += mem_decode[bits][bank]; + else + total += bank_sizes[bank]; + } + + DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024)); /* * Set the memory addressing mode. */ - gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits); + gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits); /* Leave the chip into enhanced mode. Disable LFO */ - gus_mem_size = total; - iw_mode = 1; - gus_write8 (0x19, (gus_read8 (0x19) | 0x01) & ~0x02); + gus_mem_size = total; + iw_mode = 1; + gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02); } int -gus_wave_detect (int baseaddr) +gus_wave_detect(int baseaddr) { - unsigned long i, max_mem = 1024L; - unsigned long loc; - unsigned char val; + unsigned long i, max_mem = 1024L; + unsigned long loc; + unsigned char val; - gus_base = baseaddr; + gus_base = baseaddr; - gus_write8 (0x4c, 0); /* Reset GF1 */ - gus_delay (); - gus_delay (); + gus_write8(0x4c, 0); /* Reset GF1 */ + gus_delay(); + gus_delay(); - gus_write8 (0x4c, 1); /* Release Reset */ - gus_delay (); - gus_delay (); + gus_write8(0x4c, 1); /* Release Reset */ + gus_delay(); + gus_delay(); #ifdef GUSPNP_AUTODETECT - val = gus_look8 (0x5b); /* Version number register */ - gus_write8 (0x5b, ~val); /* Invert all bits */ - - if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0)) /* No change */ - if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ - { - DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); - gus_pnp_flag = 1; - } - else - { - DDB (printk ("Not an Interwave chip (%x)\n", gus_look8 (0x5b))); - gus_pnp_flag = 0; - } - gus_write8 (0x5b, val); /* Restore all bits */ + val = gus_look8(0x5b); /* Version number register */ + gus_write8(0x5b, ~val); /* Invert all bits */ + + if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */ + if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ + { + DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); + gus_pnp_flag = 1; + } else + { + DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); + gus_pnp_flag = 0; + } + gus_write8(0x5b, val); /* Restore all bits */ #endif - if (gus_pnp_flag) - pnp_mem_init (); - if (iw_mode) - return 1; - - /* See if there is first block there.... */ - gus_poke (0L, 0xaa); - if (gus_peek (0L) != 0xaa) - return (0); - - /* Now zero it out so that I can check for mirroring .. */ - gus_poke (0L, 0x00); - for (i = 1L; i < max_mem; i++) - { - int n, failed; - - /* check for mirroring ... */ - if (gus_peek (0L) != 0) - break; - loc = i << 10; - - for (n = loc - 1, failed = 0; n <= loc; n++) - { - gus_poke (loc, 0xaa); - if (gus_peek (loc) != 0xaa) - failed = 1; - - gus_poke (loc, 0x55); - if (gus_peek (loc) != 0x55) - failed = 1; - } - - if (failed) - break; - } - gus_mem_size = i << 10; - return 1; + if (gus_pnp_flag) + pnp_mem_init(); + if (iw_mode) + return 1; + + /* See if there is first block there.... */ + gus_poke(0L, 0xaa); + if (gus_peek(0L) != 0xaa) + return (0); + + /* Now zero it out so that I can check for mirroring .. */ + gus_poke(0L, 0x00); + for (i = 1L; i < max_mem; i++) + { + int n, failed; + + /* check for mirroring ... */ + if (gus_peek(0L) != 0) + break; + loc = i << 10; + + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke(loc, 0xaa); + if (gus_peek(loc) != 0xaa) + failed = 1; + + gus_poke(loc, 0x55); + if (gus_peek(loc) != 0x55) + failed = 1; + } + + if (failed) + break; + } + gus_mem_size = i << 10; + return 1; } static int -guswave_ioctl (int dev, - unsigned int cmd, caddr_t arg) +guswave_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - switch (cmd) - { - case SNDCTL_SYNTH_INFO: - gus_info.nr_voices = nr_voices; - memcpy ((&((char *) arg)[0]), (char *) &gus_info, sizeof (gus_info)); - return 0; - break; + switch (cmd) + { + case SNDCTL_SYNTH_INFO: + gus_info.nr_voices = nr_voices; + memcpy((&((char *) arg)[0]), (char *) &gus_info, sizeof(gus_info)); + return 0; + break; - case SNDCTL_SEQ_RESETSAMPLES: - reset_sample_memory (); - return 0; - break; + case SNDCTL_SEQ_RESETSAMPLES: + reset_sample_memory(); + return 0; + break; - case SNDCTL_SEQ_PERCMODE: - return 0; - break; + case SNDCTL_SEQ_PERCMODE: + return 0; + break; - case SNDCTL_SYNTH_MEMAVL: - return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; + case SNDCTL_SYNTH_MEMAVL: + return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } static int -guswave_set_instr (int dev, int voice, int instr_no) +guswave_set_instr(int dev, int voice, int instr_no) { - int sample_no; + int sample_no; - if (instr_no < 0 || instr_no > MAX_PATCH) - instr_no = 0; /* Default to acoustic piano */ + if (instr_no < 0 || instr_no > MAX_PATCH) + instr_no = 0; /* Default to acoustic piano */ - if (voice < 0 || voice > 31) - return -EINVAL; + if (voice < 0 || voice > 31) + return -EINVAL; - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].sample_pending = instr_no; - return 0; - } - - sample_no = patch_table[instr_no]; - patch_map[voice] = -1; - - if (sample_no == NOT_SAMPLE) - { - printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return -EINVAL; /* Patch not defined */ - } - - if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ - { - printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", - sample_no, instr_no, voice); - return -EINVAL; - } + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].sample_pending = instr_no; + return 0; + } + sample_no = patch_table[instr_no]; + patch_map[voice] = -1; - sample_map[voice] = sample_no; - patch_map[voice] = instr_no; - return 0; + if (sample_no == NOT_SAMPLE) + { + printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice); + return -EINVAL; /* Patch not defined */ + } + if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ + { + printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); + return -EINVAL; + } + sample_map[voice] = sample_no; + patch_map[voice] = instr_no; + return 0; } static int -guswave_kill_note (int dev, int voice, int note, int velocity) +guswave_kill_note(int dev, int voice, int note, int velocity) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - /* voice_alloc->map[voice] = 0xffff; */ - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].kill_pending = 1; - restore_flags (flags); - } - else - { - restore_flags (flags); - gus_voice_fade (voice); - } + save_flags(flags); + cli(); + /* voice_alloc->map[voice] = 0xffff; */ + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].kill_pending = 1; + restore_flags(flags); + } else + { + restore_flags(flags); + gus_voice_fade(voice); + } - restore_flags (flags); - return 0; + restore_flags(flags); + return 0; } static void -guswave_aftertouch (int dev, int voice, int pressure) +guswave_aftertouch(int dev, int voice, int pressure) { } static void -guswave_panning (int dev, int voice, int value) +guswave_panning(int dev, int voice, int value) { - if (voice >= 0 || voice < 32) - voices[voice].panning = value; + if (voice >= 0 || voice < 32) + voices[voice].panning = value; } static void -guswave_volume_method (int dev, int mode) +guswave_volume_method(int dev, int mode) { - if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) - volume_method = mode; + if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) + volume_method = mode; } static void -compute_volume (int voice, int volume) +compute_volume(int voice, int volume) { - if (volume < 128) - voices[voice].midi_volume = volume; - - switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; + if (volume < 128) + voices[voice].midi_volume = volume; - case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ - voices[voice].initial_volume = - gus_linear_vol (volume, voices[voice].main_vol); - break; + switch (volume_method) + { + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; + + case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ + voices[voice].initial_volume = + gus_linear_vol(volume, voices[voice].main_vol); + break; - default: - voices[voice].initial_volume = volume_base + - (voices[voice].midi_volume * volume_scale); - } + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); + } - if (voices[voice].initial_volume > 4030) - voices[voice].initial_volume = 4030; + if (voices[voice].initial_volume > 4030) + voices[voice].initial_volume = 4030; } static void -compute_and_set_volume (int voice, int volume, int ramp_time) -{ - int curr, target, rate; - unsigned long flags; - - compute_volume (voice, volume); - voices[voice].current_volume = voices[voice].initial_volume; - - save_flags (flags); - cli (); - /* - * CAUTION! Interrupts disabled. Enable them before returning - */ - - gus_select_voice (voice); - - curr = gus_read16 (0x09) >> 4; - target = voices[voice].initial_volume; - - if (ramp_time == INSTANT_RAMP) - { - gus_rampoff (); - gus_voice_volume (target); - restore_flags (flags); - return; - } - - if (ramp_time == FAST_RAMP) - rate = 63; - else - rate = 16; - gus_ramp_rate (0, rate); - - if ((target - curr) / 64 == 0) /* Close enough to target. */ - { - gus_rampoff (); - gus_voice_volume (target); - restore_flags (flags); - return; - } - - if (target > curr) - { - if (target > (4095 - 65)) - target = 4095 - 65; - gus_ramp_range (curr, target); - gus_rampon (0x00); /* Ramp up, once, no IRQ */ - } - else - { - if (target < 65) - target = 65; - - gus_ramp_range (target, curr); - gus_rampon (0x40); /* Ramp down, once, no irq */ - } - restore_flags (flags); +compute_and_set_volume(int voice, int volume, int ramp_time) +{ + int curr, target, rate; + unsigned long flags; + + compute_volume(voice, volume); + voices[voice].current_volume = voices[voice].initial_volume; + + save_flags(flags); + cli(); + /* + * CAUTION! Interrupts disabled. Enable them before returning + */ + + gus_select_voice(voice); + + curr = gus_read16(0x09) >> 4; + target = voices[voice].initial_volume; + + if (ramp_time == INSTANT_RAMP) + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } + if (ramp_time == FAST_RAMP) + rate = 63; + else + rate = 16; + gus_ramp_rate(0, rate); + + if ((target - curr) / 64 == 0) /* Close enough to target. */ + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } + if (target > curr) + { + if (target > (4095 - 65)) + target = 4095 - 65; + gus_ramp_range(curr, target); + gus_rampon(0x00); /* Ramp up, once, no IRQ */ + } else + { + if (target < 65) + target = 65; + + gus_ramp_range(target, curr); + gus_rampon(0x40); /* Ramp down, once, no irq */ + } + restore_flags(flags); } static void -dynamic_volume_change (int voice) +dynamic_volume_change(int voice) { - unsigned char status; - unsigned long flags; - - save_flags (flags); - cli (); - gus_select_voice (voice); - status = gus_read8 (0x00); /* Get voice status */ - restore_flags (flags); + unsigned char status; + unsigned long flags; - if (status & 0x03) - return; /* Voice was not running */ + save_flags(flags); + cli(); + gus_select_voice(voice); + status = gus_read8(0x00); /* Get voice status */ + restore_flags(flags); - if (!(voices[voice].mode & WAVE_ENVELOPES)) - { - compute_and_set_volume (voice, voices[voice].midi_volume, 1); - return; - } + if (status & 0x03) + return; /* Voice was not running */ - /* - * Voice is running and has envelopes. - */ - - save_flags (flags); - cli (); - gus_select_voice (voice); - status = gus_read8 (0x0d); /* Ramping status */ - restore_flags (flags); + if (!(voices[voice].mode & WAVE_ENVELOPES)) + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + /* + * Voice is running and has envelopes. + */ - if (status & 0x03) /* Sustain phase? */ - { - compute_and_set_volume (voice, voices[voice].midi_volume, 1); - return; - } + save_flags(flags); + cli(); + gus_select_voice(voice); + status = gus_read8(0x0d); /* Ramping status */ + restore_flags(flags); - if (voices[voice].env_phase < 0) - return; + if (status & 0x03) /* Sustain phase? */ + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + if (voices[voice].env_phase < 0) + return; - compute_volume (voice, voices[voice].midi_volume); + compute_volume(voice, voices[voice].midi_volume); } static void -guswave_controller (int dev, int voice, int ctrl_num, int value) -{ - unsigned long flags; - unsigned long freq; - - if (voice < 0 || voice > 31) - return; - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - voices[voice].bender = value; - - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - { - freq = compute_finetune (voices[voice].orig_freq, value, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_freq (freq); - restore_flags (flags); - } - break; - - case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - if (volume_method == VOL_METHOD_ADAGIO) - { - voices[voice].expression_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change (voice); - } - break; - - case CTL_PAN: - voices[voice].panning = (value * 2) - 128; - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - voices[voice].main_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change (voice); - break; - - default: - break; - } +guswave_controller(int dev, int voice, int ctrl_num, int value) +{ + unsigned long flags; + unsigned long freq; + + if (voice < 0 || voice > 31) + return; + + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; + + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune(voices[voice].orig_freq, value, + voices[voice].bender_range, 0); + voices[voice].current_freq = freq; + + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(freq); + restore_flags(flags); + } + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + if (volume_method == VOL_METHOD_ADAGIO) + { + voices[voice].expression_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + } + break; + + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + voices[voice].main_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + break; + + default: + break; + } } static int -guswave_start_note2 (int dev, int voice, int note_num, int volume) -{ - int sample, best_sample, best_delta, delta_freq; - int is16bits, samplep, patch, pan; - unsigned long note_freq, base_note, freq, flags; - unsigned char mode = 0; - - if (voice < 0 || voice > 31) - { - printk ("GUS: Invalid voice\n"); - return -EINVAL; - } - - if (note_num == 255) - { - if (voices[voice].mode & WAVE_ENVELOPES) - { - voices[voice].midi_volume = volume; - dynamic_volume_change (voice); - return 0; - } - - compute_and_set_volume (voice, volume, 1); - return 0; - } - - if ((patch = patch_map[voice]) == -1) - { - return -EINVAL; - } - - if ((samplep = patch_table[patch]) == NOT_SAMPLE) - { - return -EINVAL; - } - - note_freq = note_to_freq (note_num); - - /* - * Find a sample within a patch so that the note_freq is between low_note - * and high_note. - */ - sample = -1; - - best_sample = samplep; - best_delta = 1000000; - while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) - { - delta_freq = note_freq - samples[samplep].base_note; - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = samplep; - best_delta = delta_freq; - } - if (samples[samplep].low_note <= note_freq && - note_freq <= samples[samplep].high_note) - sample = samplep; - else - samplep = samples[samplep].key; /* Link to next sample */ - } - if (sample == -1) - sample = best_sample; - - if (sample == -1) - { - printk ("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ - } - - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; - voices[voice].mode = samples[sample].mode; - voices[voice].patch_vol = samples[sample].volume; - - if (iw_mode) - gus_write8 (0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ - - if (voices[voice].mode & WAVE_ENVELOPES) - { - int i; - - for (i = 0; i < 6; i++) - { - voices[voice].env_rate[i] = samples[sample].env_rate[i]; - voices[voice].env_offset[i] = samples[sample].env_offset[i]; - } - } - - sample_map[voice] = sample; - - if (voices[voice].fixed_pitch) /* Fixed pitch */ - { - freq = samples[sample].base_freq; - } - else - { - base_note = samples[sample].base_note / 100; - note_freq /= 100; - - freq = samples[sample].base_freq * note_freq / base_note; - } - - voices[voice].orig_freq = freq; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - pan = (samples[sample].panning + voices[voice].panning) / 32; - pan += 7; - if (pan < 0) - pan = 0; - if (pan > 15) - pan = 15; - - if (samples[sample].mode & WAVE_16_BITS) - { - mode |= 0x04; /* 16 bits */ - if ((sample_ptrs[sample] / GUS_BANK_SIZE) != - ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) - printk ("GUS: Sample address error\n"); - } +guswave_start_note2(int dev, int voice, int note_num, int volume) +{ + int sample, best_sample, best_delta, delta_freq; + int is16bits, samplep, patch, pan; + unsigned long note_freq, base_note, freq, flags; + unsigned char mode = 0; + + if (voice < 0 || voice > 31) + { + printk("GUS: Invalid voice\n"); + return -EINVAL; + } + if (note_num == 255) + { + if (voices[voice].mode & WAVE_ENVELOPES) + { + voices[voice].midi_volume = volume; + dynamic_volume_change(voice); + return 0; + } + compute_and_set_volume(voice, volume, 1); + return 0; + } + if ((patch = patch_map[voice]) == -1) + { + return -EINVAL; + } + if ((samplep = patch_table[patch]) == NOT_SAMPLE) + { + return -EINVAL; + } + note_freq = note_to_freq(note_num); + + /* + * Find a sample within a patch so that the note_freq is between low_note + * and high_note. + */ + sample = -1; + + best_sample = samplep; + best_delta = 1000000; + while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) + { + delta_freq = note_freq - samples[samplep].base_note; + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = samplep; + best_delta = delta_freq; + } + if (samples[samplep].low_note <= note_freq && + note_freq <= samples[samplep].high_note) + sample = samplep; + else + samplep = samples[samplep].key; /* Link to next sample */ + } + if (sample == -1) + sample = best_sample; + + if (sample == -1) + { + printk("GUS: Patch %d not defined for note %d\n", patch, note_num); + return 0; /* Should play default patch ??? */ + } + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; + voices[voice].mode = samples[sample].mode; + voices[voice].patch_vol = samples[sample].volume; + + if (iw_mode) + gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ + + if (voices[voice].mode & WAVE_ENVELOPES) + { + int i; + + for (i = 0; i < 6; i++) + { + voices[voice].env_rate[i] = samples[sample].env_rate[i]; + voices[voice].env_offset[i] = samples[sample].env_offset[i]; + } + } + sample_map[voice] = sample; + + if (voices[voice].fixed_pitch) /* Fixed pitch */ + { + freq = samples[sample].base_freq; + } else + { + base_note = samples[sample].base_note / 100; + note_freq /= 100; + + freq = samples[sample].base_freq * note_freq / base_note; + } + + voices[voice].orig_freq = freq; + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ + + freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender, + voices[voice].bender_range, 0); + voices[voice].current_freq = freq; + + pan = (samples[sample].panning + voices[voice].panning) / 32; + pan += 7; + if (pan < 0) + pan = 0; + if (pan > 15) + pan = 15; + + if (samples[sample].mode & WAVE_16_BITS) + { + mode |= 0x04; /* 16 bits */ + if ((sample_ptrs[sample] / GUS_BANK_SIZE) != + ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) + printk("GUS: Sample address error\n"); + } /************************************************************************* * CAUTION! Interrupts disabled. Don't return before enabling *************************************************************************/ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_off (); - gus_rampoff (); - - restore_flags (flags); - - if (voices[voice].mode & WAVE_ENVELOPES) - { - compute_volume (voice, volume); - init_envelope (voice); - } - else - { - compute_and_set_volume (voice, volume, 0); - } - - save_flags (flags); - cli (); - gus_select_voice (voice); - - if (samples[sample].mode & WAVE_LOOP_BACK) - gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, 0, is16bits); /* start=end */ - else - gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - 0, is16bits); /* Sample start=begin */ - - if (samples[sample].mode & WAVE_LOOPING) - { - mode |= 0x08; - - if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; - - if (samples[sample].mode & WAVE_LOOP_BACK) - { - gus_write_addr (0x0a, - sample_ptrs[sample] + samples[sample].loop_end - - voices[voice].offset_pending, - (samples[sample].fractions >> 4) & 0x0f, is16bits); - mode |= 0x40; - } - - gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, - samples[sample].fractions & 0x0f, - is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } - else - { - mode |= 0x20; /* Loop IRQ at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ - voices[voice].loop_irq_parm = 1; - gus_write_addr (0x02, sample_ptrs[sample], - 0, is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } - gus_voice_freq (freq); - gus_voice_balance (pan); - gus_voice_on (mode); - restore_flags (flags); - - return 0; + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_off(); + gus_rampoff(); + + restore_flags(flags); + + if (voices[voice].mode & WAVE_ENVELOPES) + { + compute_volume(voice, volume); + init_envelope(voice); + } else + { + compute_and_set_volume(voice, volume, 0); + } + + save_flags(flags); + cli(); + gus_select_voice(voice); + + if (samples[sample].mode & WAVE_LOOP_BACK) + gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - + voices[voice].offset_pending, 0, is16bits); /* start=end */ + else + gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, + 0, is16bits); /* Sample start=begin */ + + if (samples[sample].mode & WAVE_LOOPING) + { + mode |= 0x08; + + if (samples[sample].mode & WAVE_BIDIR_LOOP) + mode |= 0x10; + + if (samples[sample].mode & WAVE_LOOP_BACK) + { + gus_write_addr(0x0a, + sample_ptrs[sample] + samples[sample].loop_end - + voices[voice].offset_pending, + (samples[sample].fractions >> 4) & 0x0f, is16bits); + mode |= 0x40; + } + gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, + samples[sample].fractions & 0x0f, + is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, + (samples[sample].fractions >> 4) & 0x0f, + is16bits); /* Loop end location */ + } else + { + mode |= 0x20; /* Loop IRQ at the end */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ + voices[voice].loop_irq_parm = 1; + gus_write_addr(0x02, sample_ptrs[sample], + 0, is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, + (samples[sample].fractions >> 4) & 0x0f, + is16bits); /* Loop end location */ + } + gus_voice_freq(freq); + gus_voice_balance(pan); + gus_voice_on(mode); + restore_flags(flags); + + return 0; } /* @@ -1637,1946 +1600,1925 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume) */ static int -guswave_start_note (int dev, int voice, int note_num, int volume) -{ - long int flags; - int mode; - int ret_val = 0; - - save_flags (flags); - cli (); - if (note_num == 255) - { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].volume_pending = volume; - } - else - { - ret_val = guswave_start_note2 (dev, voice, note_num, volume); - } - } - else - { - gus_select_voice (voice); - mode = gus_read8 (0x00); - if (mode & 0x20) - gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ - - voices[voice].offset_pending = 0; - voices[voice].kill_pending = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].loop_irq_mode = 0; - - if (voices[voice].sample_pending >= 0) - { - restore_flags (flags); /* Run temporarily with interrupts enabled */ - guswave_set_instr (voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - save_flags (flags); - cli (); - gus_select_voice (voice); /* Reselect the voice (just to be sure) */ - } - - if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < (unsigned) 2065)) - { - ret_val = guswave_start_note2 (dev, voice, note_num, volume); - } - else - { - voices[voice].dev_pending = dev; - voices[voice].note_pending = note_num; - voices[voice].volume_pending = volume; - voices[voice].volume_irq_mode = VMODE_START_NOTE; - - gus_rampoff (); - gus_ramp_range (2000, 4065); - gus_ramp_rate (0, 63); /* Fastest possible rate */ - gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ - } - } - restore_flags (flags); - return ret_val; +guswave_start_note(int dev, int voice, int note_num, int volume) +{ + long int flags; + int mode; + int ret_val = 0; + + save_flags(flags); + cli(); + if (note_num == 255) + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].volume_pending = volume; + } else + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } + } else + { + gus_select_voice(voice); + mode = gus_read8(0x00); + if (mode & 0x20) + gus_write8(0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + restore_flags(flags); /* Run temporarily with interrupts enabled */ + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + save_flags(flags); + cli(); + gus_select_voice(voice); /* Reselect the voice (just to be sure) */ + } + if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } else + { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff(); + gus_ramp_range(2000, 4065); + gus_ramp_rate(0, 63); /* Fastest possible rate */ + gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ + } + } + restore_flags(flags); + return ret_val; } static void -guswave_reset (int dev) +guswave_reset(int dev) { - int i; + int i; - for (i = 0; i < 32; i++) - { - gus_voice_init (i); - gus_voice_init2 (i); - } + for (i = 0; i < 32; i++) + { + gus_voice_init(i); + gus_voice_init2(i); + } } static int -guswave_open (int dev, int mode) +guswave_open(int dev, int mode) { - int err; + int err; - if (gus_busy) - return -EBUSY; + if (gus_busy) + return -EBUSY; - voice_alloc->timestamp = 0; + voice_alloc->timestamp = 0; - if ((err = DMAbuf_open_dma (gus_devnum)) < 0) - { - /* printk ("GUS: Loading samples without DMA\n"); */ - gus_no_dma = 1; /* Upload samples using PIO */ - } - else - gus_no_dma = 0; + if ((err = DMAbuf_open_dma(gus_devnum)) < 0) + { + /* printk( "GUS: Loading samples without DMA\n"); */ + gus_no_dma = 1; /* Upload samples using PIO */ + } else + gus_no_dma = 0; - dram_sleep_flag.opts = WK_NONE; - gus_busy = 1; - active_device = GUS_DEV_WAVE; + dram_sleep_flag.opts = WK_NONE; + gus_busy = 1; + active_device = GUS_DEV_WAVE; - gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ - gus_initialize (); - gus_reset (); - gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + gusintr(gus_irq, NULL, NULL); /* Serve pending interrupts */ + gus_initialize(); + gus_reset(); + gusintr(gus_irq, NULL, NULL); /* Serve pending interrupts */ - return 0; + return 0; } static void -guswave_close (int dev) +guswave_close(int dev) { - gus_busy = 0; - active_device = 0; - gus_reset (); + gus_busy = 0; + active_device = 0; + gus_reset(); - if (!gus_no_dma) - DMAbuf_close_dma (gus_devnum); + if (!gus_no_dma) + DMAbuf_close_dma(gus_devnum); } static int -guswave_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) -{ - struct patch_info patch; - int instr; - long sizeof_patch; - - unsigned long blk_sz, blk_end, left, src_offs, target; - - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ - - if (format != GUS_PATCH) - { - printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } - - if (count < sizeof_patch) - { - printk ("GUS Error: Patch header too short\n"); - return -EINVAL; - } - - count -= sizeof_patch; - - if (free_sample >= MAX_SAMPLE) - { - printk ("GUS: Sample table full\n"); - return -ENOSPC; - } - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - copy_from_user (&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs); - - if (patch.mode & WAVE_ROM) - return -EINVAL; - if (gus_mem_size == 0) - - return -ENOSPC; - - instr = patch.instr_no; - - if (instr < 0 || instr > MAX_PATCH) - { - printk ("GUS: Invalid patch number %d\n", instr); - return -EINVAL; - } - - if (count < patch.len) - { - printk ("GUS Warning: Patch record too short (%d<%d)\n", - count, (int) patch.len); - patch.len = count; - } - - if (patch.len <= 0 || patch.len > gus_mem_size) - { - printk ("GUS: Invalid sample length %d\n", (int) patch.len); - return -EINVAL; - } - - if (patch.mode & WAVE_LOOPING) - { - if (patch.loop_start < 0 || patch.loop_start >= patch.len) - { - printk ("GUS: Invalid loop start\n"); - return -EINVAL; - } - - if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) - { - printk ("GUS: Invalid loop end\n"); - return -EINVAL; - } - } - - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ - - if (patch.mode & WAVE_16_BITS) - { - /* - * 16 bit samples must fit one 256k bank. - */ - if (patch.len >= GUS_BANK_SIZE) - { - printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return -ENOSPC; - } - - if ((free_mem_ptr / GUS_BANK_SIZE) != - ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) - { - unsigned long tmp_mem = /* Align to 256K */ - ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - - if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; - - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ - } - } - - if ((free_mem_ptr + patch.len) > gus_mem_size) - return -ENOSPC; - - sample_ptrs[free_sample] = free_mem_ptr; - - /* - * Tremolo is not possible with envelopes - */ - - if (patch.mode & WAVE_ENVELOPES) - patch.mode &= ~WAVE_TREMOLO; - - if (!(patch.mode & WAVE_FRACTIONS)) - { - patch.fractions = 0; - } - - memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); - - /* - * Link this_one sample to the list of samples for patch 'instr'. - */ - - samples[free_sample].key = patch_table[instr]; - patch_table[instr] = free_sample; - - /* - * Use DMA to transfer the wave data to the DRAM - */ - - left = patch.len; - src_offs = 0; - target = free_mem_ptr; - - while (left) /* Not completely transferred yet */ - { - blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; - if (blk_sz > left) - blk_sz = left; - - /* - * DMA cannot cross bank (256k) boundaries. Check for that. - */ - blk_end = target + blk_sz; - - if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) - { /* Split the block */ - - blk_end &= ~(GUS_BANK_SIZE - 1); - blk_sz = blk_end - target; - } - - if (gus_no_dma) - { - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - long i; - unsigned char data; - - for (i = 0; i < blk_sz; i++) - { - get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); - if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke (target + i, data); - } - } - else - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; - - if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) - { - printk ("GUS: DMA buffer == NULL\n"); - return -ENOSPC; - } +guswave_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) +{ + struct patch_info patch; + int instr; + long sizeof_patch; - /* - * OK, move now. First in and then out. - */ + unsigned long blk_sz, blk_end, left, src_offs, target; - copy_from_user (audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ - save_flags (flags); - cli (); -/******** INTERRUPTS DISABLED NOW ********/ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (gus_devnum, - audio_devs[gus_devnum]->dmap_out->raw_buf_phys, - blk_sz, DMA_MODE_WRITE); + if (format != GUS_PATCH) + { + printk("GUS Error: Invalid patch format (key) 0x%x\n", format); + return -EINVAL; + } + if (count < sizeof_patch) + { + printk("GUS Error: Patch header too short\n"); + return -EINVAL; + } + count -= sizeof_patch; - /* - * Set the DRAM address for the wave data - */ + if (free_sample >= MAX_SAMPLE) + { + printk("GUS: Sample table full\n"); + return -ENOSPC; + } + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ - if (iw_mode) - { - /* Different address translation in enhanced mode */ + copy_from_user(&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs); - unsigned char hi; + if (patch.mode & WAVE_ROM) + return -EINVAL; + if (gus_mem_size == 0) - if (gus_dma > 4) - address = target >> 1; /* Convert to 16 bit word address */ - else - address = target; + return -ENOSPC; - hi = (unsigned char) ((address >> 16) & 0xf0); - hi += (unsigned char) (address & 0x0f); + instr = patch.instr_no; - gus_write16 (0x42, (address >> 4) & 0xffff); /* DMA address (low) */ - gus_write8 (0x50, hi); - } - else - { - address = target; + if (instr < 0 || instr > MAX_PATCH) + { + printk("GUS: Invalid patch number %d\n", instr); + return -EINVAL; + } + if (count < patch.len) + { + printk("GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len); + patch.len = count; + } + if (patch.len <= 0 || patch.len > gus_mem_size) + { + printk("GUS: Invalid sample length %d\n", (int) patch.len); + return -EINVAL; + } + if (patch.mode & WAVE_LOOPING) + { + if (patch.loop_start < 0 || patch.loop_start >= patch.len) + { + printk("GUS: Invalid loop start\n"); + return -EINVAL; + } + if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) + { + printk("GUS: Invalid loop end\n"); + return -EINVAL; + } + } + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + if (patch.mode & WAVE_16_BITS) + { + /* + * 16 bit samples must fit one 256k bank. + */ + if (patch.len >= GUS_BANK_SIZE) + { + printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len); + return -ENOSPC; + } + if ((free_mem_ptr / GUS_BANK_SIZE) != + ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) + { + unsigned long tmp_mem = /* Align to 256K */ + ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; + + if ((tmp_mem + patch.len) > gus_mem_size) + return -ENOSPC; + + free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + } + } + if ((free_mem_ptr + patch.len) > gus_mem_size) + return -ENOSPC; - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - } + sample_ptrs[free_sample] = free_mem_ptr; - /* - * Start the DMA transfer - */ + /* + * Tremolo is not possible with envelopes + */ - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ + if (patch.mode & WAVE_ENVELOPES) + patch.mode &= ~WAVE_TREMOLO; - gus_write8 (0x41, dma_command); /* Lets go luteet (=bugs) */ + if (!(patch.mode & WAVE_FRACTIONS)) + { + patch.fractions = 0; + } + memcpy((char *) &samples[free_sample], &patch, sizeof_patch); - /* - * Sleep here until the DRAM DMA done interrupt is served - */ - active_device = GUS_DEV_WAVE; + /* + * Link this_one sample to the list of samples for patch 'instr'. + */ + + samples[free_sample].key = patch_table[instr]; + patch_table[instr] = free_sample; + /* + * Use DMA to transfer the wave data to the DRAM + */ + left = patch.len; + src_offs = 0; + target = free_mem_ptr; + + while (left) /* Not completely transferred yet */ { - unsigned long tlimit; + blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; + if (blk_sz > left) + blk_sz = left; + + /* + * DMA cannot cross bank (256k) boundaries. Check for that. + */ + blk_end = target + blk_sz; + + if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) + { /* Split the block */ + + blk_end &= ~(GUS_BANK_SIZE - 1); + blk_sz = blk_end - target; + } + if (gus_no_dma) + { + /* + * For some reason the DMA is not possible. We have to use PIO. + */ + long i; + unsigned char data; + + for (i = 0; i < blk_sz; i++) + { + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); + if (patch.mode & WAVE_UNSIGNED) + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* Convert to signed */ + gus_poke(target + i, data); + } + } else + { + unsigned long address, hold_address; + unsigned char dma_command; + unsigned long flags; + + if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) + { + printk("GUS: DMA buffer == NULL\n"); + return -ENOSPC; + } + /* + * OK, move now. First in and then out. + */ + + copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); + + save_flags(flags); + cli(); +/******** INTERRUPTS DISABLED NOW ********/ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(gus_devnum, + audio_devs[gus_devnum]->dmap_out->raw_buf_phys, + blk_sz, DMA_MODE_WRITE); + + /* + * Set the DRAM address for the wave data + */ + + if (iw_mode) + { + /* Different address translation in enhanced mode */ + + unsigned char hi; + + if (gus_dma > 4) + address = target >> 1; /* Convert to 16 bit word address */ + else + address = target; + + hi = (unsigned char) ((address >> 16) & 0xf0); + hi += (unsigned char) (address & 0x0f); + + gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ + gus_write8(0x50, hi); + } else + { + address = target; + + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + } + + /* + * Start the DMA transfer + */ + + dma_command = 0x21; /* IRQ enable, DMA start */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* Invert MSB */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ + + gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ + + /* + * Sleep here until the DRAM DMA done interrupt is served + */ + active_device = GUS_DEV_WAVE; + + + { + unsigned long tlimit; + + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + dram_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&dram_sleeper); + if (!(dram_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + dram_sleep_flag.opts |= WK_TIMEOUT; + } + dram_sleep_flag.opts &= ~WK_SLEEP; + }; + if ((dram_sleep_flag.opts & WK_TIMEOUT)) + printk("GUS: DMA Transfer timed out\n"); + restore_flags(flags); + } + + /* + * Now the next part + */ + + left -= blk_sz; + src_offs += blk_sz; + target += blk_sz; + + gus_write8(0x41, 0); /* Stop DMA */ + } - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - dram_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&dram_sleeper); - if (!(dram_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - dram_sleep_flag.opts |= WK_TIMEOUT; - } - dram_sleep_flag.opts &= ~WK_SLEEP; - }; - if ((dram_sleep_flag.opts & WK_TIMEOUT)) - printk ("GUS: DMA Transfer timed out\n"); - restore_flags (flags); - } + free_mem_ptr += patch.len; - /* - * Now the next part - */ + free_sample++; + return 0; +} - left -= blk_sz; - src_offs += blk_sz; - target += blk_sz; +static void +guswave_hw_control(int dev, unsigned char *event_rec) +{ + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; + unsigned flags; - gus_write8 (0x41, 0); /* Stop DMA */ - } + cmd = event_rec[2]; + voice = event_rec[3]; + p1 = *(unsigned short *) &event_rec[4]; + p2 = *(unsigned short *) &event_rec[6]; + plong = *(unsigned int *) &event_rec[4]; - free_mem_ptr += patch.len; + if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + do_volume_irq(voice); - free_sample++; - return 0; -} + switch (cmd) + { -static void -guswave_hw_control (int dev, unsigned char *event_rec) -{ - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; - unsigned flags; - - cmd = event_rec[2]; - voice = event_rec[3]; - p1 = *(unsigned short *) &event_rec[4]; - p2 = *(unsigned short *) &event_rec[6]; - plong = *(unsigned int *) &event_rec[4]; - - if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && - (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) - do_volume_irq (voice); - - switch (cmd) - { - - case _GUS_NUMVOICES: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_select_max_voices (p1); - restore_flags (flags); - break; - - case _GUS_VOICESAMPLE: - guswave_set_instr (dev, voice, p1); - break; - - case _GUS_VOICEON: - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_on (p1); - restore_flags (flags); - break; - - case _GUS_VOICEOFF: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_off (); - restore_flags (flags); - break; - - case _GUS_VOICEFADE: - gus_voice_fade (voice); - break; - - case _GUS_VOICEMODE: - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_mode (p1); - restore_flags (flags); - break; - - case _GUS_VOICEBALA: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_balance (p1); - restore_flags (flags); - break; - - case _GUS_VOICEFREQ: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_freq (plong); - restore_flags (flags); - break; - - case _GUS_VOICEVOL: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_volume (p1); - restore_flags (flags); - break; - - case _GUS_VOICEVOL2: /* Just update the software voice level */ - voices[voice].initial_volume = - voices[voice].current_volume = p1; - break; - - case _GUS_RAMPRANGE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_ramp_range (p1, p2); - restore_flags (flags); - break; - - case _GUS_RAMPRATE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NJET-NJET */ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_ramp_rate (p1, p2); - restore_flags (flags); - break; - - case _GUS_RAMPMODE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_ramp_mode (p1); - restore_flags (flags); - break; - - case _GUS_RAMPON: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* EI-EI */ - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_rampon (p1); - restore_flags (flags); - break; - - case _GUS_RAMPOFF: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NEJ-NEJ */ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_rampoff (); - restore_flags (flags); - break; - - case _GUS_VOLUME_SCALE: - volume_base = p1; - volume_scale = p2; - break; - - case _GUS_VOICE_POS: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_set_voice_pos (voice, plong); - restore_flags (flags); - break; - - default:; - } + case _GUS_NUMVOICES: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_select_max_voices(p1); + restore_flags(flags); + break; + + case _GUS_VOICESAMPLE: + guswave_set_instr(dev, voice, p1); + break; + + case _GUS_VOICEON: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_on(p1); + restore_flags(flags); + break; + + case _GUS_VOICEOFF: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_off(); + restore_flags(flags); + break; + + case _GUS_VOICEFADE: + gus_voice_fade(voice); + break; + + case _GUS_VOICEMODE: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_mode(p1); + restore_flags(flags); + break; + + case _GUS_VOICEBALA: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_balance(p1); + restore_flags(flags); + break; + + case _GUS_VOICEFREQ: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(plong); + restore_flags(flags); + break; + + case _GUS_VOICEVOL: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(p1); + restore_flags(flags); + break; + + case _GUS_VOICEVOL2: /* Just update the software voice level */ + voices[voice].initial_volume = + voices[voice].current_volume = p1; + break; + + case _GUS_RAMPRANGE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_range(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPRATE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NJET-NJET */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_rate(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPMODE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_ramp_mode(p1); + restore_flags(flags); + break; + + case _GUS_RAMPON: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* EI-EI */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_rampon(p1); + restore_flags(flags); + break; + + case _GUS_RAMPOFF: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NEJ-NEJ */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + break; + + case _GUS_VOLUME_SCALE: + volume_base = p1; + volume_scale = p2; + break; + + case _GUS_VOICE_POS: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_set_voice_pos(voice, plong); + restore_flags(flags); + break; + + default:; + } } static int -gus_audio_set_speed (int speed) +gus_audio_set_speed(int speed) { - if (speed <= 0) - speed = gus_audio_speed; + if (speed <= 0) + speed = gus_audio_speed; - if (speed < 4000) - speed = 4000; + if (speed < 4000) + speed = 4000; - if (speed > 44100) - speed = 44100; + if (speed > 44100) + speed = 44100; - gus_audio_speed = speed; + gus_audio_speed = speed; - if (only_read_access) - { - /* Compute nearest valid recording speed and return it */ + if (only_read_access) + { + /* Compute nearest valid recording speed and return it */ - /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ - speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - speed = (9878400 / (speed * 16)) - 2; - } - return speed; + /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ + speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; + speed = (9878400 / (speed * 16)) - 2; + } + return speed; } static int -gus_audio_set_channels (int channels) +gus_audio_set_channels(int channels) { - if (!channels) - return gus_audio_channels; - if (channels > 2) - channels = 2; - if (channels < 1) - channels = 1; - gus_audio_channels = channels; - return channels; + if (!channels) + return gus_audio_channels; + if (channels > 2) + channels = 2; + if (channels < 1) + channels = 1; + gus_audio_channels = channels; + return channels; } static int -gus_audio_set_bits (int bits) +gus_audio_set_bits(int bits) { - if (!bits) - return gus_audio_bits; + if (!bits) + return gus_audio_bits; - if (bits != 8 && bits != 16) - bits = 8; + if (bits != 8 && bits != 16) + bits = 8; - if (only_8_bits) - bits = 8; + if (only_8_bits) + bits = 8; - gus_audio_bits = bits; - return bits; + gus_audio_bits = bits; + return bits; } static int -gus_audio_ioctl (int dev, unsigned int cmd, caddr_t arg) +gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int val; + int val; - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_speed (val)); - break; + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_speed(val)); + break; - case SOUND_PCM_READ_RATE: - return (*(int *) arg = gus_audio_speed); - break; + case SOUND_PCM_READ_RATE: + return (*(int *) arg = gus_audio_speed); + break; - case SNDCTL_DSP_STEREO: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_channels (val + 1) - 1); - break; + case SNDCTL_DSP_STEREO: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_channels(val + 1) - 1); + break; - case SOUND_PCM_WRITE_CHANNELS: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_channels (val)); - break; + case SOUND_PCM_WRITE_CHANNELS: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_channels(val)); + break; - case SOUND_PCM_READ_CHANNELS: - return (*(int *) arg = gus_audio_channels); - break; + case SOUND_PCM_READ_CHANNELS: + return (*(int *) arg = gus_audio_channels); + break; - case SNDCTL_DSP_SETFMT: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_bits (val)); - break; + case SNDCTL_DSP_SETFMT: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_bits(val)); + break; - case SOUND_PCM_READ_BITS: - return (*(int *) arg = gus_audio_bits); + case SOUND_PCM_READ_BITS: + return (*(int *) arg = gus_audio_bits); - case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - return (*(int *) arg = -EINVAL); - break; + case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ + return (*(int *) arg = -EINVAL); + break; - case SOUND_PCM_READ_FILTER: - return (*(int *) arg = -EINVAL); - break; + case SOUND_PCM_READ_FILTER: + return (*(int *) arg = -EINVAL); + break; - } - return -EINVAL; + } + return -EINVAL; } static void -gus_audio_reset (int dev) +gus_audio_reset(int dev) { - if (recording_active) - { - gus_write8 (0x49, 0x00); /* Halt recording */ - set_input_volumes (); - } + if (recording_active) + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } } static int saved_iw_mode; /* A hack hack hack */ static int -gus_audio_open (int dev, int mode) -{ - if (gus_busy) - return -EBUSY; - - if (gus_pnp_flag && mode & OPEN_READ) - { - printk ("Sound: This audio device doesn't have recording capability\n"); - return -EIO; - } - gus_initialize (); - - gus_busy = 1; - active_device = 0; - - gus_reset (); - reset_sample_memory (); - gus_select_max_voices (14); - saved_iw_mode = iw_mode; - if (iw_mode) - { - /* There are some problems with audio in enhanced mode so disable it */ - gus_write8 (0x19, gus_read8 (0x19) & ~0x01); /* Disable enhanced mode */ - iw_mode = 0; - } - - pcm_active = 0; - dma_active = 0; - pcm_opened = 1; - if (mode & OPEN_READ) - { - recording_active = 1; - set_input_volumes (); - } - only_read_access = !(mode & OPEN_WRITE); - only_8_bits = mode & OPEN_READ; - if (only_8_bits) - audio_devs[dev]->format_mask = AFMT_U8; - else - audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; - - return 0; +gus_audio_open(int dev, int mode) +{ + if (gus_busy) + return -EBUSY; + + if (gus_pnp_flag && mode & OPEN_READ) + { + printk("GUS: Audio device #%d is playback only.\n", dev); + return -EIO; + } + gus_initialize(); + + gus_busy = 1; + active_device = 0; + + gus_reset(); + reset_sample_memory(); + gus_select_max_voices(14); + saved_iw_mode = iw_mode; + if (iw_mode) + { + /* There are some problems with audio in enhanced mode so disable it */ + gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ + iw_mode = 0; + } + pcm_active = 0; + dma_active = 0; + pcm_opened = 1; + if (mode & OPEN_READ) + { + recording_active = 1; + set_input_volumes(); + } + only_read_access = !(mode & OPEN_WRITE); + only_8_bits = mode & OPEN_READ; + if (only_8_bits) + audio_devs[dev]->format_mask = AFMT_U8; + else + audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; + + return 0; } static void -gus_audio_close (int dev) +gus_audio_close(int dev) { - iw_mode = saved_iw_mode; - gus_reset (); - gus_busy = 0; - pcm_opened = 0; - active_device = 0; + iw_mode = saved_iw_mode; + gus_reset(); + gus_busy = 0; + pcm_opened = 0; + active_device = 0; - if (recording_active) - { - gus_write8 (0x49, 0x00); /* Halt recording */ - set_input_volumes (); - } + if (recording_active) + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } + recording_active = 0; +} + +static void +gus_audio_update_volume(void) +{ + unsigned long flags; + int voice; - recording_active = 0; + if (pcm_active && pcm_opened) + for (voice = 0; voice < gus_audio_channels; voice++) + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + restore_flags(flags); + } } static void -gus_audio_update_volume (void) +play_next_pcm_block(void) { - unsigned long flags; - int voice; + unsigned long flags; + int speed = gus_audio_speed; + int this_one, is16bits, chn; + unsigned long dram_loc; + unsigned char mode[2], ramp_mode[2]; + + if (!pcm_qlen) + return; - if (pcm_active && pcm_opened) - for (voice = 0; voice < gus_audio_channels; voice++) - { - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_rampoff (); - gus_voice_volume (1530 + (25 * gus_pcm_volume)); - gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - restore_flags (flags); - } + this_one = pcm_head; + + for (chn = 0; chn < gus_audio_channels; chn++) + { + mode[chn] = 0x00; + ramp_mode[chn] = 0x03; /* Ramping and rollover off */ + + if (chn == 0) + { + mode[chn] |= 0x20; /* Loop IRQ */ + voices[chn].loop_irq_mode = LMODE_PCM; + } + if (gus_audio_bits != 8) + { + is16bits = 1; + mode[chn] |= 0x04; /* 16 bit data */ + } else + is16bits = 0; + + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; + + if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ + { + mode[chn] |= 0x08; /* Enable loop */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ + } else + { + if (chn == 0) + ramp_mode[chn] = 0x04; /* Enable rollover bit */ + } + + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_voice_freq(speed); + + if (gus_audio_channels == 1) + gus_voice_balance(7); /* mono */ + else if (chn == 0) + gus_voice_balance(0); /* left */ + else + gus_voice_balance(15); /* right */ + + if (!pcm_active) /* Playback not already active */ + { + /* + * The playback was not started yet (or there has been a pause). + * Start the voice (again) and ask for a rollover irq at the end of + * this_one block. If this_one one is last of the buffers, use just + * the normal loop with irq. + */ + + gus_voice_off(); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + + gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ + gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + + if (chn != 0) + gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, + 0, is16bits); /* Loop end location */ + } + if (chn == 0) + gus_write_addr(0x04, dram_loc + pcm_bsize - 1, + 0, is16bits); /* Loop end location */ + else + mode[chn] |= 0x08; /* Enable looping */ + + + restore_flags(flags); + } + + for (chn = 0; chn < gus_audio_channels; chn++) + { + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_write8(0x0d, ramp_mode[chn]); + if (iw_mode) + gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ + gus_voice_on(mode[chn]); + restore_flags(flags); + } + + pcm_active = 1; } static void -play_next_pcm_block (void) -{ - unsigned long flags; - int speed = gus_audio_speed; - int this_one, is16bits, chn; - unsigned long dram_loc; - unsigned char mode[2], ramp_mode[2]; - - if (!pcm_qlen) - return; - - this_one = pcm_head; - - for (chn = 0; chn < gus_audio_channels; chn++) - { - mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - - if (chn == 0) - { - mode[chn] |= 0x20; /* Loop IRQ */ - voices[chn].loop_irq_mode = LMODE_PCM; - } - - if (gus_audio_bits != 8) - { - is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ - } - else - is16bits = 0; - - dram_loc = this_one * pcm_bsize; - dram_loc += chn * pcm_banksize; - - if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ - { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03; /* Disable rollover bit */ - } - else - { - if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ - } - - save_flags (flags); - cli (); - gus_select_voice (chn); - gus_voice_freq (speed); - - if (gus_audio_channels == 1) - gus_voice_balance (7); /* mono */ - else if (chn == 0) - gus_voice_balance (0); /* left */ - else - gus_voice_balance (15); /* right */ - - if (!pcm_active) /* Playback not already active */ - { - /* - * The playback was not started yet (or there has been a pause). - * Start the voice (again) and ask for a rollover irq at the end of - * this_one block. If this_one one is last of the buffers, use just - * the normal loop with irq. - */ +gus_transfer_output_block(int dev, unsigned long buf, + int total_count, int intrflag, int chn) +{ + /* + * This routine transfers one block of audio data to the DRAM. In mono mode + * it's called just once. When in stereo mode, this_one routine is called + * once for both channels. + * + * The left/mono channel data is transferred to the beginning of dram and the + * right data to the area pointed by gus_page_size. + */ - gus_voice_off (); - gus_rampoff (); - gus_voice_volume (1530 + (25 * gus_pcm_volume)); - gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); + int this_one, count; + unsigned long flags; + unsigned char dma_command; + unsigned long address, hold_address; - gus_write_addr (0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ - gus_write_addr (0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + save_flags(flags); + cli(); - if (chn != 0) - gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - 0, is16bits); /* Loop end location */ - } + count = total_count / gus_audio_channels; - if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_bsize - 1, - 0, is16bits); /* Loop end location */ - else - mode[chn] |= 0x08; /* Enable looping */ + if (chn == 0) + { + if (pcm_qlen >= pcm_nblk) + printk("GUS Warning: PCM buffers out of sync\n"); + this_one = pcm_current_block = pcm_tail; + pcm_qlen++; + pcm_tail = (pcm_tail + 1) % pcm_nblk; + pcm_datasize[this_one] = count; + } else + this_one = pcm_current_block; - restore_flags (flags); - } + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE); - for (chn = 0; chn < gus_audio_channels; chn++) - { - save_flags (flags); - cli (); - gus_select_voice (chn); - gus_write8 (0x0d, ramp_mode[chn]); - if (iw_mode) - gus_write8 (0x15, 0x00); /* Reset voice deactivate bit of SMSI */ - gus_voice_on (mode[chn]); - restore_flags (flags); - } + address = this_one * pcm_bsize; + address += chn * pcm_banksize; - pcm_active = 1; -} + if (audio_devs[dev]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ -static void -gus_transfer_output_block (int dev, unsigned long buf, - int total_count, int intrflag, int chn) -{ - /* - * This routine transfers one block of audio data to the DRAM. In mono mode - * it's called just once. When in stereo mode, this_one routine is called - * once for both channels. - * - * The left/mono channel data is transferred to the beginning of dram and the - * right data to the area pointed by gus_page_size. - */ - - int this_one, count; - unsigned long flags; - unsigned char dma_command; - unsigned long address, hold_address; - - save_flags (flags); - cli (); - - count = total_count / gus_audio_channels; - - if (chn == 0) - { - if (pcm_qlen >= pcm_nblk) - printk ("GUS Warning: PCM buffers out of sync\n"); - - this_one = pcm_current_block = pcm_tail; - pcm_qlen++; - pcm_tail = (pcm_tail + 1) % pcm_nblk; - pcm_datasize[this_one] = count; - } - else - this_one = pcm_current_block; - - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); - - address = this_one * pcm_bsize; - address += chn * pcm_banksize; - - if (audio_devs[dev]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - - dma_command = 0x21; /* IRQ enable, DMA start */ - - if (gus_audio_bits != 8) - dma_command |= 0x40; /* 16 bit _DATA_ */ - else - dma_command |= 0x80; /* Invert MSB */ - - if (audio_devs[dev]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ - - gus_write8 (0x41, dma_command); /* Kick start */ - - if (chn == (gus_audio_channels - 1)) /* Last channel */ - { - /* - * Last (right or mono) channel data - */ - dma_active = 1; /* DMA started. There is a unacknowledged buffer */ - active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) - { - play_next_pcm_block (); - } - } - else - { - /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ - active_device = GUS_DEV_PCM_CONTINUE; - } - - restore_flags (flags); + dma_command = 0x21; /* IRQ enable, DMA start */ + + if (gus_audio_bits != 8) + dma_command |= 0x40; /* 16 bit _DATA_ */ + else + dma_command |= 0x80; /* Invert MSB */ + + if (audio_devs[dev]->dmap_out->dma > 3) + dma_command |= 0x04; /* 16 bit DMA channel */ + + gus_write8(0x41, dma_command); /* Kick start */ + + if (chn == (gus_audio_channels - 1)) /* Last channel */ + { + /* + * Last (right or mono) channel data + */ + dma_active = 1; /* DMA started. There is a unacknowledged buffer */ + active_device = GUS_DEV_PCM_DONE; + if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) + { + play_next_pcm_block(); + } + } else + { + /* + * Left channel data. The right channel + * is transferred after DMA interrupt + */ + active_device = GUS_DEV_PCM_CONTINUE; + } + + restore_flags(flags); } static void -gus_uninterleave8 (char *buf, int l) +gus_uninterleave8(char *buf, int l) { /* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - char *buf2 = buf + halfsize, *src = bounce_buf; + int i, p = 0, halfsize = l / 2; + char *buf2 = buf + halfsize, *src = bounce_buf; - memcpy (bounce_buf, buf, l); + memcpy(bounce_buf, buf, l); - for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + for (i = 0; i < halfsize; i++) + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } static void -gus_uninterleave16 (short *buf, int l) +gus_uninterleave16(short *buf, int l) { /* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - short *buf2 = buf + halfsize, *src = (short *) bounce_buf; + int i, p = 0, halfsize = l / 2; + short *buf2 = buf + halfsize, *src = (short *) bounce_buf; - memcpy (bounce_buf, (char *) buf, l * 2); + memcpy(bounce_buf, (char *) buf, l * 2); - for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + for (i = 0; i < halfsize; i++) + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } static void -gus_audio_output_block (int dev, unsigned long buf, int total_count, - int intrflag) +gus_audio_output_block(int dev, unsigned long buf, int total_count, + int intrflag) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; + dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; - pcm_current_buf = buf; - pcm_current_count = total_count; - pcm_current_intrflag = intrflag; - pcm_current_dev = dev; - if (gus_audio_channels == 2) - { - char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); + pcm_current_buf = buf; + pcm_current_count = total_count; + pcm_current_intrflag = intrflag; + pcm_current_dev = dev; + if (gus_audio_channels == 2) + { + char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); - if (gus_audio_bits == 8) - gus_uninterleave8 (b, total_count); - else - gus_uninterleave16 ((short *) b, total_count / 2); - } - gus_transfer_output_block (dev, buf, total_count, intrflag, 0); + if (gus_audio_bits == 8) + gus_uninterleave8(b, total_count); + else + gus_uninterleave16((short *) b, total_count / 2); + } + gus_transfer_output_block(dev, buf, total_count, intrflag, 0); } static void -gus_audio_start_input (int dev, unsigned long buf, int count, - int intrflag) +gus_audio_start_input(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags; - unsigned char mode; + unsigned long flags; + unsigned char mode; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enabled, invert MSB */ + mode = 0xa0; /* DMA IRQ enabled, invert MSB */ - if (audio_devs[dev]->dmap_in->dma > 3) - mode |= 0x04; /* 16 bit DMA channel */ - if (gus_audio_channels > 1) - mode |= 0x02; /* Stereo */ - mode |= 0x01; /* DMA enable */ + if (audio_devs[dev]->dmap_in->dma > 3) + mode |= 0x04; /* 16 bit DMA channel */ + if (gus_audio_channels > 1) + mode |= 0x02; /* Stereo */ + mode |= 0x01; /* DMA enable */ - gus_write8 (0x49, mode); + gus_write8(0x49, mode); - restore_flags (flags); + restore_flags(flags); } static int -gus_audio_prepare_for_input (int dev, int bsize, int bcount) +gus_audio_prepare_for_input(int dev, int bsize, int bcount) { - unsigned int rate; - - gus_audio_bsize = bsize; - audio_devs[dev]->dmap_in->flags |= DMA_NODMA; - rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; + unsigned int rate; - gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ + gus_audio_bsize = bsize; + audio_devs[dev]->dmap_in->flags |= DMA_NODMA; + rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - if (gus_audio_bits != 8) - { - printk ("GUS Error: 16 bit recording not supported\n"); - return -EINVAL; - } + gus_write8(0x48, rate & 0xff); /* Set sampling rate */ - return 0; + if (gus_audio_bits != 8) + { + printk("GUS Error: 16 bit recording not supported\n"); + return -EINVAL; + } + return 0; } static int -gus_audio_prepare_for_output (int dev, int bsize, int bcount) +gus_audio_prepare_for_output(int dev, int bsize, int bcount) { - int i; + int i; - long mem_ptr, mem_size; + long mem_ptr, mem_size; - audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; - mem_ptr = 0; - mem_size = gus_mem_size / gus_audio_channels; + audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; + mem_ptr = 0; + mem_size = gus_mem_size / gus_audio_channels; - if (mem_size > (256 * 1024)) - mem_size = 256 * 1024; + if (mem_size > (256 * 1024)) + mem_size = 256 * 1024; - pcm_bsize = bsize / gus_audio_channels; - pcm_head = pcm_tail = pcm_qlen = 0; + pcm_bsize = bsize / gus_audio_channels; + pcm_head = pcm_tail = pcm_qlen = 0; - pcm_nblk = 2; /* MAX_PCM_BUFFERS; */ - if ((pcm_bsize * pcm_nblk) > mem_size) - pcm_nblk = mem_size / pcm_bsize; + pcm_nblk = 2; /* MAX_PCM_BUFFERS; */ + if ((pcm_bsize * pcm_nblk) > mem_size) + pcm_nblk = mem_size / pcm_bsize; - for (i = 0; i < pcm_nblk; i++) - pcm_datasize[i] = 0; + for (i = 0; i < pcm_nblk; i++) + pcm_datasize[i] = 0; - pcm_banksize = pcm_nblk * pcm_bsize; + pcm_banksize = pcm_nblk * pcm_bsize; - if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) - pcm_nblk--; - gus_write8 (0x41, 0); /* Disable GF1 DMA */ + if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) + pcm_nblk--; + gus_write8(0x41, 0); /* Disable GF1 DMA */ - return 0; + return 0; } static int -gus_local_qlen (int dev) +gus_local_qlen(int dev) { - return pcm_qlen; + return pcm_qlen; } static struct audio_driver gus_audio_driver = { - gus_audio_open, - gus_audio_close, - gus_audio_output_block, - gus_audio_start_input, - gus_audio_ioctl, - gus_audio_prepare_for_input, - gus_audio_prepare_for_output, - gus_audio_reset, - gus_local_qlen, - NULL + gus_audio_open, + gus_audio_close, + gus_audio_output_block, + gus_audio_start_input, + gus_audio_ioctl, + gus_audio_prepare_for_input, + gus_audio_prepare_for_output, + gus_audio_reset, + gus_local_qlen, + NULL }; static void -guswave_setup_voice (int dev, int voice, int chn) +guswave_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; - guswave_set_instr (dev, voice, info->pgm_num); + guswave_set_instr(dev, voice, info->pgm_num); - voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just MSB */ - voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - voices[voice].panning = - (info->controllers[CTL_PAN] * 2) - 128; - voices[voice].bender = 0; - voices[voice].bender_range = info->bender_range; + voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just MSB */ + voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + voices[voice].panning = + (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].bender = 0; + voices[voice].bender_range = info->bender_range; - if (chn == 9) - voices[voice].fixed_pitch = 1; + if (chn == 9) + voices[voice].fixed_pitch = 1; } static void -guswave_bender (int dev, int voice, int value) +guswave_bender(int dev, int voice, int value) { - int freq; - unsigned long flags; + int freq; + unsigned long flags; - voices[voice].bender = value - 8192; - freq = compute_finetune (voices[voice].orig_freq, value - 8192, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; + voices[voice].bender = value - 8192; + freq = compute_finetune(voices[voice].orig_freq, value - 8192, + voices[voice].bender_range, 0); + voices[voice].current_freq = freq; - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_freq (freq); - restore_flags (flags); + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(freq); + restore_flags(flags); } static int -guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) -{ - int i, p, best = -1, best_time = 0x7fffffff; - - p = alloc->ptr; - /* - * First look for a completely stopped voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } - - /* - * Then look for a releasing voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - return p; - } - p = (p + 1) % alloc->max_voice; - } - - if (best >= 0) - p = best; - - alloc->ptr = p; - return p; +guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) +{ + int i, p, best = -1, best_time = 0x7fffffff; + + p = alloc->ptr; + /* + * First look for a completely stopped voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } + + /* + * Then look for a releasing voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; + } + + if (best >= 0) + p = best; + + alloc->ptr = p; + return p; } static struct synth_operations guswave_operations = { - "GUS", - &gus_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_GUS, - guswave_open, - guswave_close, - guswave_ioctl, - guswave_kill_note, - guswave_start_note, - guswave_set_instr, - guswave_reset, - guswave_hw_control, - guswave_load_patch, - guswave_aftertouch, - guswave_controller, - guswave_panning, - guswave_volume_method, - guswave_bender, - guswave_alloc, - guswave_setup_voice + "GUS", + &gus_info, + 0, + SYNTH_TYPE_SAMPLE, + SAMPLE_TYPE_GUS, + guswave_open, + guswave_close, + guswave_ioctl, + guswave_kill_note, + guswave_start_note, + guswave_set_instr, + guswave_reset, + guswave_hw_control, + guswave_load_patch, + guswave_aftertouch, + guswave_controller, + guswave_panning, + guswave_volume_method, + guswave_bender, + guswave_alloc, + guswave_setup_voice }; static void -set_input_volumes (void) +set_input_volumes(void) { - unsigned long flags; - unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ - - if (have_gus_max) /* Don't disturb GUS MAX */ - return; + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ - save_flags (flags); - cli (); + if (have_gus_max) /* Don't disturb GUS MAX */ + return; - /* - * Enable channels having vol > 10% - * Note! bit 0x01 means the line in DISABLED while 0x04 means - * the mic in ENABLED. - */ - if (gus_line_vol > 10) - mask &= ~0x01; - if (gus_mic_vol > 10) - mask |= 0x04; + save_flags(flags); + cli(); - if (recording_active) - { - /* - * Disable channel, if not selected for recording - */ - if (!(gus_recmask & SOUND_MASK_LINE)) - mask |= 0x01; - if (!(gus_recmask & SOUND_MASK_MIC)) - mask &= ~0x04; - } + /* + * Enable channels having vol > 10% + * Note! bit 0x01 means the line in DISABLED while 0x04 means + * the mic in ENABLED. + */ + if (gus_line_vol > 10) + mask &= ~0x01; + if (gus_mic_vol > 10) + mask |= 0x04; - mix_image &= ~0x07; - mix_image |= mask & 0x07; - outb ((mix_image), u_Mixer); + if (recording_active) + { + /* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) + mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) + mask &= ~0x04; + } + mix_image &= ~0x07; + mix_image |= mask & 0x07; + outb((mix_image), u_Mixer); - restore_flags (flags); + restore_flags(flags); } int -gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ SOUND_MASK_SYNTH|SOUND_MASK_PCM) - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - gus_recmask = *(int *) arg; - gus_recmask &= MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - return (*(int *) arg = gus_recmask); - break; - - case SOUND_MIXER_MIC: - { - int vol; - - vol = *(int *) arg; - vol &= 0xff; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes (); - return (*(int *) arg = vol | (vol << 8)); - } - break; - - case SOUND_MIXER_LINE: - { - int vol; - - vol = *(int *) arg; - vol &= 0xff; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes (); - return (*(int *) arg = vol | (vol << 8)); - } - break; - - case SOUND_MIXER_PCM: - gus_pcm_volume = *(int *) arg; - gus_pcm_volume &= 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_audio_update_volume (); - return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); - break; - - case SOUND_MIXER_SYNTH: - { - int voice; - - gus_wave_volume = *(int *) arg; - gus_wave_volume &= 0xff; - - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; - - if (active_device == GUS_DEV_WAVE) - for (voice = 0; voice < nr_voices; voice++) - dynamic_volume_change (voice); /* Apply the new vol */ - - return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); - } - break; - - default: - return -EINVAL; - } - else - switch (cmd & 0xff) /* - * Return parameters - */ + if (((cmd >> 8) & 0xff) == 'M') { - - case SOUND_MIXER_RECSRC: - return (*(int *) arg = gus_recmask); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = MIX_DEVS); - break; - - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = 0); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); - break; - - case SOUND_MIXER_MIC: - return (*(int *) arg = gus_mic_vol | (gus_mic_vol << 8)); - break; - - case SOUND_MIXER_LINE: - return (*(int *) arg = gus_line_vol | (gus_line_vol << 8)); - break; - - case SOUND_MIXER_PCM: - return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); - break; - - case SOUND_MIXER_SYNTH: - return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); - break; - - default: - return -EINVAL; - } - } - else - return -EINVAL; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = *(int *) arg; + gus_recmask &= MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + return (*(int *) arg = gus_recmask); + break; + + case SOUND_MIXER_MIC: + { + int vol; + + vol = *(int *) arg; + vol &= 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + return (*(int *) arg = vol | (vol << 8)); + } + break; + + case SOUND_MIXER_LINE: + { + int vol; + + vol = *(int *) arg; + vol &= 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes(); + return (*(int *) arg = vol | (vol << 8)); + } + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = *(int *) arg; + gus_pcm_volume &= 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_audio_update_volume(); + return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + { + int voice; + + gus_wave_volume = *(int *) arg; + gus_wave_volume &= 0xff; + + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + + if (active_device == GUS_DEV_WAVE) + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change(voice); /* Apply the new vol */ + + return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); + } + break; + + default: + return -EINVAL; + } else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = gus_recmask); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = MIX_DEVS); + break; + + case SOUND_MIXER_STEREODEVS: + return (*(int *) arg = 0); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = 0); + break; + + case SOUND_MIXER_MIC: + return (*(int *) arg = gus_mic_vol | (gus_mic_vol << 8)); + break; + + case SOUND_MIXER_LINE: + return (*(int *) arg = gus_line_vol | (gus_line_vol << 8)); + break; + + case SOUND_MIXER_PCM: + return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); + break; + + default: + return -EINVAL; + } + } else + return -EINVAL; } static struct mixer_operations gus_mixer_operations = { - "GUS", - "Gravis Ultrasound", - gus_default_mixer_ioctl + "GUS", + "Gravis Ultrasound", + gus_default_mixer_ioctl }; -static void -gus_default_mixer_init (void) +static int +gus_default_mixer_init(void) { - if (num_mixers < MAX_MIXER_DEV) /* - * Don't install if there is another - * mixer - */ - mixer_devs[num_mixers++] = &gus_mixer_operations; + int n; - if (have_gus_max) - { + if ((n = sound_alloc_mixerdev()) != -1) + { /* + * Don't install if there is another + * mixer + */ + mixer_devs[n] = &gus_mixer_operations; + } + if (have_gus_max) + { /* * Enable all mixer channels on the GF1 side. Otherwise recording will * not be possible using GUS MAX. */ - mix_image &= ~0x07; - mix_image |= 0x04; /* All channels enabled */ - outb ((mix_image), u_Mixer); - } + mix_image &= ~0x07; + mix_image |= 0x04; /* All channels enabled */ + outb((mix_image), u_Mixer); + } + return n; } void -gus_wave_init (struct address_info *hw_config) -{ - unsigned long flags; - unsigned char val; - char *model_num = "2.4"; - char tmp[64], tmp2[64]; - int gus_type = 0x24; /* 2.4 */ - - int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; - - if (!gus_pnp_flag) - if (irq < 0 || irq > 15) - { - printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return; - } - - if (dma < 0 || dma > 7 || dma == 4) - { - printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return; - } - - gus_irq = irq; - gus_dma = dma; - gus_dma2 = dma2; - - if (gus_dma2 == -1) - gus_dma2 = dma; - - /* - * Try to identify the GUS model. - * - * Versions < 3.6 don't have the digital ASIC. Try to probe it first. - */ - - save_flags (flags); - cli (); - outb ((0x20), gus_base + 0x0f); - val = inb (gus_base + 0x0f); - restore_flags (flags); - - if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ - { - int ad_flags = 0; - - if (gus_pnp_flag) - ad_flags = 0x12345678; /* Interwave "magic" */ - /* - * It has the digital ASIC so the card is at least v3.4. - * Next try to detect the true model. - */ - - if (gus_pnp_flag) /* Hack hack hack */ - val = 10; - else - val = inb (u_MixSelect); - - /* - * Value 255 means pre-3.7 which don't have mixer. - * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. - * 10 and above is GUS MAX which has the CS4231 codec/mixer. - * - */ - - if (val == 255 || val < 5) - { - model_num = "3.4"; - gus_type = 0x34; - } - else if (val < 10) - { - model_num = "3.7"; - gus_type = 0x37; - mixer_type = ICS2101; - request_region (u_MixSelect, 1, "GUS mixer"); - } - else - { - model_num = "MAX"; - gus_type = 0x40; - mixer_type = CS4231; -#ifdef CONFIG_GUSMAX +gus_wave_init(struct address_info *hw_config) +{ + unsigned long flags; + unsigned char val; + char *model_num = "2.4"; + char tmp[64], tmp2[64]; + int gus_type = 0x24; /* 2.4 */ + + int irq = hw_config->irq, dma = hw_config->dma, + dma2 = hw_config->dma2; + int dev; + int sdev; + + hw_config->slots[0] = -1; /* No wave */ + hw_config->slots[1] = -1; /* No ad1848 */ + hw_config->slots[4] = -1; /* No audio */ + hw_config->slots[5] = -1; /* No mixer */ + + if (!gus_pnp_flag) + if (irq < 0 || irq > 15) + { + printk("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + return; + } + if (dma < 0 || dma > 7 || dma == 4) { - unsigned char max_config = 0x40; /* Codec enable */ - - if (gus_dma2 == -1) - gus_dma2 = gus_dma; + printk("ERROR! Invalid DMA#%d. GUS Disabled", dma); + return; + } + gus_irq = irq; + gus_dma = dma; + gus_dma2 = dma2; - if (gus_dma > 3) - max_config |= 0x10; /* 16 bit capture DMA */ + if (gus_dma2 == -1) + gus_dma2 = dma; - if (gus_dma2 > 3) - max_config |= 0x20; /* 16 bit playback DMA */ + /* + * Try to identify the GUS model. + * + * Versions < 3.6 don't have the digital ASIC. Try to probe it first. + */ - max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ + save_flags(flags); + cli(); + outb((0x20), gus_base + 0x0f); + val = inb(gus_base + 0x0f); + restore_flags(flags); - outb ((max_config), gus_base + 0x106); /* UltraMax control */ + if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ + { + int ad_flags = 0; + + if (gus_pnp_flag) + ad_flags = 0x12345678; /* Interwave "magic" */ + /* + * It has the digital ASIC so the card is at least v3.4. + * Next try to detect the true model. + */ + + if (gus_pnp_flag) /* Hack hack hack */ + val = 10; + else + val = inb(u_MixSelect); + + /* + * Value 255 means pre-3.7 which don't have mixer. + * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. + * 10 and above is GUS MAX which has the CS4231 codec/mixer. + * + */ + + if (val == 255 || val < 5) + { + model_num = "3.4"; + gus_type = 0x34; + } else if (val < 10) + { + model_num = "3.7"; + gus_type = 0x37; + mixer_type = ICS2101; + request_region(u_MixSelect, 1, "GUS mixer"); + } else + { + model_num = "MAX"; + gus_type = 0x40; + mixer_type = CS4231; +#ifdef CONFIG_GUSMAX + { + unsigned char max_config = 0x40; /* Codec enable */ + + if (gus_dma2 == -1) + gus_dma2 = gus_dma; + + if (gus_dma > 3) + max_config |= 0x10; /* 16 bit capture DMA */ + + if (gus_dma2 > 3) + max_config |= 0x20; /* 16 bit playback DMA */ + + max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ + + outb((max_config), gus_base + 0x106); /* UltraMax control */ + } + + if (ad1848_detect(gus_base + 0x10c, &ad_flags, hw_config->osp)) + { + char *name = "GUS MAX"; + int old_num_mixers = num_mixers; + + if (gus_pnp_flag) + name = "GUS PnP"; + + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + have_gus_max = 1; + if (hw_config->name) + name = hw_config->name; + + hw_config->slots[1] = ad1848_init(name, gus_base + 0x10c, + -irq, + gus_dma2, /* Playback DMA */ + gus_dma, /* Capture DMA */ + 1, /* Share DMA channels with GF1 */ + hw_config->osp); + + if (num_mixers > old_num_mixers) + { /* GUS has it's own mixer map */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } + } else + printk("[Where's the CS4231?]"); +#else + printk("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); +#endif + } + } else + { + /* + * ASIC not detected so the card must be 2.2 or 2.4. + * There could still be the 16-bit/mixer daughter card. + */ } - if (ad1848_detect (gus_base + 0x10c, &ad_flags, hw_config->osp)) - { - char *name = "GUS MAX"; - int old_num_mixers = num_mixers; + if (hw_config->name) + { - if (gus_pnp_flag) - name = "GUS PnP"; + strncpy(tmp, hw_config->name, 45); + tmp[45] = 0; + sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024); + tmp2[sizeof(tmp2) - 1] = 0; + } else if (gus_pnp_flag) + { + sprintf(tmp2, "Gravis UltraSound PnP (%dk)", + (int) gus_mem_size / 1024); + } else + sprintf(tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - have_gus_max = 1; - if (hw_config->name) - name = hw_config->name; - ad1848_init (name, gus_base + 0x10c, - -irq, - gus_dma2, /* Playback DMA */ - gus_dma, /* Capture DMA */ - 1, /* Share DMA channels with GF1 */ - hw_config->osp); + samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc((MAX_SAMPLE + 1) * sizeof(*samples))); + sound_mem_sizes[sound_nblocks] = (MAX_SAMPLE + 1) * sizeof(*samples); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (samples == NULL) + { + printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n"); + return; + } + conf_printf(tmp2, hw_config); + tmp2[sizeof(gus_info.name) - 1] = 0; + strcpy(gus_info.name, tmp2); - if (num_mixers > old_num_mixers) - { /* GUS has it's own mixer map */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE); - } - } - else - printk ("[Where's the CS4231?]"); -#else - printk ("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); -#endif - } - } - else - { - /* - * ASIC not detected so the card must be 2.2 or 2.4. - * There could still be the 16-bit/mixer daughter card. - */ - } - - if (hw_config->name) - { - - strncpy (tmp, hw_config->name, 45); - tmp[45] = 0; - sprintf (tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024); - tmp2[sizeof (tmp2) - 1] = 0; - } - else if (gus_pnp_flag) - { - sprintf (tmp2, "Gravis UltraSound PnP (%dk)", - (int) gus_mem_size / 1024); - } - else - sprintf (tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); - - - samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc ((MAX_SAMPLE + 1) * sizeof (*samples))); - sound_mem_sizes[sound_nblocks] = (MAX_SAMPLE + 1) * sizeof (*samples); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (samples == NULL) - { - printk ("GUS Error: Cant allocate memory for instrument tables\n"); - return; - } - - conf_printf (tmp2, hw_config); - tmp2[sizeof (gus_info.name) - 1] = 0; - strcpy (gus_info.name, tmp2); - - if (num_synths >= MAX_SYNTH_DEV) - printk ("GUS Error: Too many synthesizers\n"); - else - { - voice_alloc = &guswave_operations.alloc; - if (iw_mode) - guswave_operations.id = "IWAVE"; - synth_devs[num_synths++] = &guswave_operations; - sequencer_init (); -#ifdef CONFIG_SEQUENCER - gus_tmr_install (gus_base + 8); + if ((sdev = sound_alloc_synthdev()) == -1) + printk(KERN_WARNING "gus_init: Too many synthesizers\n"); + else + { + voice_alloc = &guswave_operations.alloc; + if (iw_mode) + guswave_operations.id = "IWAVE"; + hw_config->slots[0] = sdev; + synth_devs[sdev] = &guswave_operations; + sequencer_init(); +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + gus_tmr_install(gus_base + 8); #endif - } - - reset_sample_memory (); - - gus_initialize (); - - if (gus_mem_size > 0) - if (num_audiodevs < MAX_AUDIO_DEV) - { - - if ((gus_devnum = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - "Ultrasound", - &gus_audio_driver, - sizeof (struct audio_driver), - NEEDS_RESTART | - ((!iw_mode && dma2 != dma && dma2 != -1) ? - DMA_DUPLEX : 0), - AFMT_U8 | AFMT_S16_LE, - NULL, - dma, - dma2)) < 0) - return; - - audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ - audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ - audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */ - audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; - } - else - printk ("GUS: Too many audio devices available\n"); - - /* - * Mixer dependent initialization. - */ - - switch (mixer_type) - { - case ICS2101: - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - request_region (u_MixSelect, 1, "GUS mixer"); - ics2101_mixer_init (); - return; - - case CS4231: - /* Initialized elsewhere (ad1848.c) */ - default: - gus_default_mixer_init (); - return; - } + } + + reset_sample_memory(); + + gus_initialize(); + + if (gus_mem_size > 0) + if ((dev = sound_alloc_audiodev()) != -1) + { + hw_config->slots[4] = dev; + if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + "Ultrasound", + &gus_audio_driver, + sizeof(struct audio_driver), + NEEDS_RESTART | + ((!iw_mode && dma2 != dma && dma2 != -1) ? + DMA_DUPLEX : 0), + AFMT_U8 | AFMT_S16_LE, + NULL, + dma, + dma2)) < 0) + return; + + audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ + audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ + audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */ + audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; + } else + printk("GUS: Too many audio devices available\n"); + + /* + * Mixer dependent initialization. + */ + + switch (mixer_type) + { + case ICS2101: + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + request_region(u_MixSelect, 1, "GUS mixer"); + hw_config->slots[5] = ics2101_mixer_init(); + audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ + return; + + case CS4231: + /* Initialized elsewhere (ad1848.c) */ + default: + hw_config->slots[5] = gus_default_mixer_init(); + audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ + return; + } } void -gus_wave_unload (void) +gus_wave_unload(struct address_info *hw_config) { #ifdef CONFIG_GUSMAX - if (have_gus_max) - { - ad1848_unload (gus_base + 0x10c, - -gus_irq, - gus_dma2, /* Playback DMA */ - gus_dma, /* Capture DMA */ - 1); /* Share DMA channels with GF1 */ - } + if (have_gus_max) + { + ad1848_unload(gus_base + 0x10c, + -gus_irq, + gus_dma2, /* Playback DMA */ + gus_dma, /* Capture DMA */ + 1); /* Share DMA channels with GF1 */ + } #endif - if (mixer_type == ICS2101) - { - release_region (u_MixSelect, 1); - } + if (mixer_type == ICS2101) + { + release_region(u_MixSelect, 1); + } + if (hw_config->slots[0] != -1) + sound_unload_synthdev(hw_config->slots[0]); + if (hw_config->slots[1] != -1) + sound_unload_audiodev(hw_config->slots[1]); + if (hw_config->slots[2] != -1) + sound_unload_mididev(hw_config->slots[2]); + if (hw_config->slots[4] != -1) + sound_unload_audiodev(hw_config->slots[4]); + if (hw_config->slots[5] != -1) + sound_unload_mixerdev(hw_config->slots[4]); } static void -do_loop_irq (int voice) +do_loop_irq(int voice) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + unsigned char tmp; + int mode, parm; + unsigned long flags; - save_flags (flags); - cli (); - gus_select_voice (voice); + save_flags(flags); + cli(); + gus_select_voice(voice); - tmp = gus_read8 (0x00); - tmp &= ~0x20; /* + tmp = gus_read8(0x00); + tmp &= ~0x20; /* * Disable wave IRQ for this_one voice */ - gus_write8 (0x00, tmp); + gus_write8(0x00, tmp); - if (tmp & 0x03) /* Voice stopped */ - voice_alloc->map[voice] = 0; + if (tmp & 0x03) /* Voice stopped */ + voice_alloc->map[voice] = 0; - mode = voices[voice].loop_irq_mode; - voices[voice].loop_irq_mode = 0; - parm = voices[voice].loop_irq_parm; + mode = voices[voice].loop_irq_mode; + voices[voice].loop_irq_mode = 0; + parm = voices[voice].loop_irq_parm; - switch (mode) - { + switch (mode) + { - case LMODE_FINISH: /* + case LMODE_FINISH: /* * Final loop finished, shoot volume down */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* - * Get current volume - */ - { - gus_voice_off (); - gus_rampoff (); - gus_voice_init (voice); - break; - } - gus_ramp_range (65, 4065); - gus_ramp_rate (0, 63); /* - * Fastest possible rate - */ - gus_rampon (0x20 | 0x40); /* - * Ramp down, once, irq - */ - voices[voice].volume_irq_mode = VMODE_HALT; - break; - - case LMODE_PCM_STOP: - pcm_active = 0; /* Signal to the play_next_pcm_block routine */ - case LMODE_PCM: - { - - pcm_qlen--; - pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen && pcm_active) - { - play_next_pcm_block (); - } - else - { /* Underrun. Just stop the voice */ - gus_select_voice (0); /* Left channel */ - gus_voice_off (); - gus_rampoff (); - gus_select_voice (1); /* Right channel */ - gus_voice_off (); - gus_rampoff (); - pcm_active = 0; + if ((int) (gus_read16(0x09) >> 4) < 100) /* + * Get current volume + */ + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + break; + } + gus_ramp_range(65, 4065); + gus_ramp_rate(0, 63); /* + * Fastest possible rate + */ + gus_rampon(0x20 | 0x40); /* + * Ramp down, once, irq + */ + voices[voice].volume_irq_mode = VMODE_HALT; + break; + + case LMODE_PCM_STOP: + pcm_active = 0; /* Signal to the play_next_pcm_block routine */ + case LMODE_PCM: + { + + pcm_qlen--; + pcm_head = (pcm_head + 1) % pcm_nblk; + if (pcm_qlen && pcm_active) + { + play_next_pcm_block(); + } else + { /* Underrun. Just stop the voice */ + gus_select_voice(0); /* Left channel */ + gus_voice_off(); + gus_rampoff(); + gus_select_voice(1); /* Right channel */ + gus_voice_off(); + gus_rampoff(); + pcm_active = 0; + } + + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + break; + + default:; } - - /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr (gus_devnum, 0); - } - break; - - default:; - } - restore_flags (flags); + restore_flags(flags); } static void -do_volume_irq (int voice) +do_volume_irq(int voice) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + unsigned char tmp; + int mode, parm; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - gus_select_voice (voice); + gus_select_voice(voice); - tmp = gus_read8 (0x0d); - tmp &= ~0x20; /* + tmp = gus_read8(0x0d); + tmp &= ~0x20; /* * Disable volume ramp IRQ */ - gus_write8 (0x0d, tmp); - - mode = voices[voice].volume_irq_mode; - voices[voice].volume_irq_mode = 0; - parm = voices[voice].volume_irq_parm; - - switch (mode) - { - case VMODE_HALT: /* Decay phase finished */ - if (iw_mode) - gus_write8 (0x15, 0x02); /* Set voice deactivate bit of SMSI */ - restore_flags (flags); - gus_voice_init (voice); - break; - - case VMODE_ENVELOPE: - gus_rampoff (); - restore_flags (flags); - step_envelope (voice); - break; - - case VMODE_START_NOTE: - restore_flags (flags); - guswave_start_note2 (voices[voice].dev_pending, voice, - voices[voice].note_pending, voices[voice].volume_pending); - if (voices[voice].kill_pending) - guswave_kill_note (voices[voice].dev_pending, voice, - voices[voice].note_pending, 0); - - if (voices[voice].sample_pending >= 0) - { - guswave_set_instr (voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - } - break; - - default:; - } -} + gus_write8(0x0d, tmp); -void -gus_voice_irq (void) -{ - unsigned long wave_ignore = 0, volume_ignore = 0; - unsigned long voice_bit; + mode = voices[voice].volume_irq_mode; + voices[voice].volume_irq_mode = 0; + parm = voices[voice].volume_irq_parm; - unsigned char src, voice; + switch (mode) + { + case VMODE_HALT: /* Decay phase finished */ + if (iw_mode) + gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */ + restore_flags(flags); + gus_voice_init(voice); + break; + + case VMODE_ENVELOPE: + gus_rampoff(); + restore_flags(flags); + step_envelope(voice); + break; + + case VMODE_START_NOTE: + restore_flags(flags); + guswave_start_note2(voices[voice].dev_pending, voice, + voices[voice].note_pending, voices[voice].volume_pending); + if (voices[voice].kill_pending) + guswave_kill_note(voices[voice].dev_pending, voice, + voices[voice].note_pending, 0); + + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; - while (1) - { - src = gus_read8 (0x0f); /* - * Get source info - */ - voice = src & 0x1f; - src &= 0xc0; + default: + restore_flags(flags); + } + restore_flags(flags); +} - if (src == (0x80 | 0x40)) - return; /* - * No interrupt - */ +void +gus_voice_irq(void) +{ + unsigned long wave_ignore = 0, volume_ignore = 0; + unsigned long voice_bit; - voice_bit = 1 << voice; + unsigned char src, voice; - if (!(src & 0x80)) /* - * Wave IRQ pending - */ - if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ + while (1) { - wave_ignore |= voice_bit; - do_loop_irq (voice); - } + src = gus_read8(0x0f); /* + * Get source info + */ + voice = src & 0x1f; + src &= 0xc0; + + if (src == (0x80 | 0x40)) + return; /* + * No interrupt + */ - if (!(src & 0x40)) /* - * Volume IRQ pending - */ - if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ - { - volume_ignore |= voice_bit; - do_volume_irq (voice); + voice_bit = 1 << voice; + + if (!(src & 0x80)) /* + * Wave IRQ pending + */ + if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* + * Not done + * yet + */ + { + wave_ignore |= voice_bit; + do_loop_irq(voice); + } + if (!(src & 0x40)) /* + * Volume IRQ pending + */ + if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* + * Not done + * yet + */ + { + volume_ignore |= voice_bit; + do_volume_irq(voice); + } } - } } void -guswave_dma_irq (void) -{ - unsigned char status; - - status = gus_look8 (0x41); /* Get DMA IRQ Status */ - if (status & 0x40) /* DMA interrupt pending */ - switch (active_device) - { - case GUS_DEV_WAVE: - if ((dram_sleep_flag.opts & WK_SLEEP)) - { - dram_sleep_flag.opts = WK_WAKEUP; - wake_up (&dram_sleeper); - }; - break; - - case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - gus_transfer_output_block (pcm_current_dev, pcm_current_buf, - pcm_current_count, - pcm_current_intrflag, 1); - break; - - case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - if (pcm_qlen < pcm_nblk) - { - dma_active = 0; - if (gus_busy) - { - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr (gus_devnum, 0); - } - } - break; - - default:; - } - - status = gus_look8 (0x49); /* - * Get Sampling IRQ Status - */ - if (status & 0x40) /* +guswave_dma_irq(void) +{ + unsigned char status; + + status = gus_look8(0x41); /* Get DMA IRQ Status */ + if (status & 0x40) /* DMA interrupt pending */ + switch (active_device) + { + case GUS_DEV_WAVE: + if ((dram_sleep_flag.opts & WK_SLEEP)) + { + dram_sleep_flag.opts = WK_WAKEUP; + wake_up(&dram_sleeper); + }; + break; + + case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + gus_transfer_output_block(pcm_current_dev, pcm_current_buf, + pcm_current_count, + pcm_current_intrflag, 1); + break; + + case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + if (pcm_qlen < pcm_nblk) + { + dma_active = 0; + if (gus_busy) + { + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + } + break; + + default:; + } + status = gus_look8(0x49); /* + * Get Sampling IRQ Status + */ + if (status & 0x40) /* * Sampling Irq pending */ - { - DMAbuf_inputintr (gus_devnum); - } - + { + DMAbuf_inputintr(gus_devnum); + } } -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + /* * Timer stuff */ @@ -3585,105 +3527,103 @@ static volatile int select_addr, data_addr; static volatile int curr_timer = 0; void -gus_timer_command (unsigned int addr, unsigned int val) +gus_timer_command(unsigned int addr, unsigned int val) { - int i; + int i; - outb (((unsigned char) (addr & 0xff)), select_addr); + outb(((unsigned char) (addr & 0xff)), select_addr); - for (i = 0; i < 2; i++) - inb (select_addr); + for (i = 0; i < 2; i++) + inb(select_addr); - outb (((unsigned char) (val & 0xff)), data_addr); + outb(((unsigned char) (val & 0xff)), data_addr); - for (i = 0; i < 2; i++) - inb (select_addr); + for (i = 0; i < 2; i++) + inb(select_addr); } static void -arm_timer (int timer, unsigned int interval) +arm_timer(int timer, unsigned int interval) { - curr_timer = timer; + curr_timer = timer; - if (timer == 1) - { - gus_write8 (0x46, 256 - interval); /* Set counter for timer 1 */ - gus_write8 (0x45, 0x04); /* Enable timer 1 IRQ */ - gus_timer_command (0x04, 0x01); /* Start timer 1 */ - } - else - { - gus_write8 (0x47, 256 - interval); /* Set counter for timer 2 */ - gus_write8 (0x45, 0x08); /* Enable timer 2 IRQ */ - gus_timer_command (0x04, 0x02); /* Start timer 2 */ - } + if (timer == 1) + { + gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ + gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ + gus_timer_command(0x04, 0x01); /* Start timer 1 */ + } else + { + gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ + gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ + gus_timer_command(0x04, 0x02); /* Start timer 2 */ + } - gus_timer_enabled = 1; + gus_timer_enabled = 1; } static unsigned int -gus_tmr_start (int dev, unsigned int usecs_per_tick) +gus_tmr_start(int dev, unsigned int usecs_per_tick) { - int timer_no, resolution; - int divisor; + int timer_no, resolution; + int divisor; - if (usecs_per_tick > (256 * 80)) - { - timer_no = 2; - resolution = 320; /* usec */ - } - else - { - timer_no = 1; - resolution = 80; /* usec */ - } + if (usecs_per_tick > (256 * 80)) + { + timer_no = 2; + resolution = 320; /* usec */ + } else + { + timer_no = 1; + resolution = 80; /* usec */ + } - divisor = (usecs_per_tick + (resolution / 2)) / resolution; + divisor = (usecs_per_tick + (resolution / 2)) / resolution; - arm_timer (timer_no, divisor); + arm_timer(timer_no, divisor); - return divisor * resolution; + return divisor * resolution; } static void -gus_tmr_disable (int dev) +gus_tmr_disable(int dev) { - gus_write8 (0x45, 0); /* Disable both timers */ - gus_timer_enabled = 0; + gus_write8(0x45, 0); /* Disable both timers */ + gus_timer_enabled = 0; } static void -gus_tmr_restart (int dev) +gus_tmr_restart(int dev) { - if (curr_timer == 1) - gus_write8 (0x45, 0x04); /* Start timer 1 again */ - else - gus_write8 (0x45, 0x08); /* Start timer 2 again */ - gus_timer_enabled = 1; + if (curr_timer == 1) + gus_write8(0x45, 0x04); /* Start timer 1 again */ + else + gus_write8(0x45, 0x08); /* Start timer 2 again */ + gus_timer_enabled = 1; } static struct sound_lowlev_timer gus_tmr = { - 0, - 1, - gus_tmr_start, - gus_tmr_disable, - gus_tmr_restart + 0, + 1, + gus_tmr_start, + gus_tmr_disable, + gus_tmr_restart }; static void -gus_tmr_install (int io_base) +gus_tmr_install(int io_base) { - struct sound_lowlev_timer *tmr; + struct sound_lowlev_timer *tmr; - select_addr = io_base; - data_addr = io_base + 1; + select_addr = io_base; + data_addr = io_base + 1; - tmr = &gus_tmr; + tmr = &gus_tmr; #ifdef THIS_GETS_FIXED - sound_timer_init (&gus_tmr, "GUS"); + sound_timer_init(&gus_tmr, "GUS"); #endif } #endif diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c index 07666ec29..3c47f5a50 100644 --- a/drivers/sound/ics2101.c +++ b/drivers/sound/ics2101.c @@ -14,7 +14,7 @@ #include "sound_config.h" -#if defined(CONFIG_GUSHW) +#if defined(CONFIG_GUSHW) || defined(MODULE) #include <linux/ultrasound.h> #include "gus_hw.h" @@ -31,222 +31,206 @@ static int left_fix[ICS_MIXDEVS] = static int right_fix[ICS_MIXDEVS] = {2, 2, 2, 1, 2, 1}; -static int -scale_vol (int vol) +static int scale_vol(int vol) { - /* - * Experimental volume scaling by Risto Kankkunen. - * This should give smoother volume response than just - * a plain multiplication. - */ - int e; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - vol = (31 * vol + 50) / 100; - e = 0; - if (vol) - { - while (vol < 16) + /* + * Experimental volume scaling by Risto Kankkunen. + * This should give smoother volume response than just + * a plain multiplication. + */ + + int e; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + vol = (31 * vol + 50) / 100; + e = 0; + if (vol) { - vol <<= 1; - e--; + while (vol < 16) + { + vol <<= 1; + e--; + } + vol -= 16; + e += 7; } - vol -= 16; - e += 7; - } - return ((e << 4) + vol); + return ((e << 4) + vol); } -static void -write_mix (int dev, int chn, int vol) +static void write_mix(int dev, int chn, int vol) { - int *selector; - unsigned long flags; - int ctrl_addr = dev << 3; - int attn_addr = dev << 3; - - vol = scale_vol (vol); - - if (chn == CHN_LEFT) - { - selector = left_fix; - ctrl_addr |= 0x00; - attn_addr |= 0x02; - } - else - { - selector = right_fix; - ctrl_addr |= 0x01; - attn_addr |= 0x03; - } - - save_flags (flags); - cli (); - outb ((ctrl_addr), u_MixSelect); - outb ((selector[dev]), u_MixData); - outb ((attn_addr), u_MixSelect); - outb (((unsigned char) vol), u_MixData); - restore_flags (flags); + int *selector; + unsigned long flags; + int ctrl_addr = dev << 3; + int attn_addr = dev << 3; + + vol = scale_vol(vol); + + if (chn == CHN_LEFT) + { + selector = left_fix; + ctrl_addr |= 0x00; + attn_addr |= 0x02; + } + else + { + selector = right_fix; + ctrl_addr |= 0x01; + attn_addr |= 0x03; + } + + save_flags(flags); + cli(); + outb((ctrl_addr), u_MixSelect); + outb((selector[dev]), u_MixData); + outb((attn_addr), u_MixSelect); + outb(((unsigned char) vol), u_MixData); + restore_flags(flags); } -static int -set_volumes (int dev, int vol) +static int set_volumes(int dev, int vol) { - int left = vol & 0x00ff; - int right = (vol >> 8) & 0x00ff; - - if (left < 0) - left = 0; - if (left > 100) - left = 100; - if (right < 0) - right = 0; - if (right > 100) - right = 100; - - write_mix (dev, CHN_LEFT, left); - write_mix (dev, CHN_RIGHT, right); - - vol = left + (right << 8); - volumes[dev] = vol; - return vol; + int left = vol & 0x00ff; + int right = (vol >> 8) & 0x00ff; + + if (left < 0) + left = 0; + if (left > 100) + left = 100; + if (right < 0) + right = 0; + if (right > 100) + right = 100; + + write_mix(dev, CHN_LEFT, left); + write_mix(dev, CHN_RIGHT, right); + + vol = left + (right << 8); + volumes[dev] = vol; + return vol; } -static int -ics2101_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR (cmd) & _SIOC_WRITE) + if (((cmd >> 8) & 0xff) == 'M') { - int val; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { + int val; + + val = *(int *) arg; + + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + return gus_default_mixer_ioctl(dev, cmd, arg); + + case SOUND_MIXER_MIC: + return (*(int *) arg = set_volumes(DEV_MIC, val)); + + case SOUND_MIXER_CD: + return (*(int *) arg = set_volumes(DEV_CD, val)); - val = *(int *) arg; + case SOUND_MIXER_LINE: + return (*(int *) arg = set_volumes(DEV_LINE, val)); - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - return gus_default_mixer_ioctl (dev, cmd, arg); - break; + case SOUND_MIXER_SYNTH: + return (*(int *) arg = set_volumes(DEV_GF1, val)); - case SOUND_MIXER_MIC: - return (*(int *) arg = set_volumes (DEV_MIC, val)); - break; + case SOUND_MIXER_VOLUME: + return (*(int *) arg = set_volumes(DEV_VOL, val)); - case SOUND_MIXER_CD: - return (*(int *) arg = set_volumes (DEV_CD, val)); - break; + default: + return -EINVAL; + } + } + else + { + switch (cmd & 0xff) /* + * Return parameters + */ + { - case SOUND_MIXER_LINE: - return (*(int *) arg = set_volumes (DEV_LINE, val)); - break; + case SOUND_MIXER_RECSRC: + return gus_default_mixer_ioctl(dev, cmd, arg); - case SOUND_MIXER_SYNTH: - return (*(int *) arg = set_volumes (DEV_GF1, val)); - break; + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = MIX_DEVS); - case SOUND_MIXER_VOLUME: - return (*(int *) arg = set_volumes (DEV_VOL, val)); - break; + case SOUND_MIXER_STEREODEVS: + return (*(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC); - default: - return -EINVAL; - } + case SOUND_MIXER_RECMASK: + return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); + + case SOUND_MIXER_CAPS: + return (*(int *) arg = 0); + break; + + case SOUND_MIXER_MIC: + return (*(int *) arg = volumes[DEV_MIC]); + + case SOUND_MIXER_LINE: + return (*(int *) arg = volumes[DEV_LINE]); + + case SOUND_MIXER_CD: + return (*(int *) arg = volumes[DEV_CD]); + + case SOUND_MIXER_VOLUME: + return (*(int *) arg = volumes[DEV_VOL]); + + case SOUND_MIXER_SYNTH: + return (*(int *) arg = volumes[DEV_GF1]); + + default: + return -EINVAL; + } + } } - else - switch (cmd & 0xff) /* - * Return parameters - */ - { - - case SOUND_MIXER_RECSRC: - return gus_default_mixer_ioctl (dev, cmd, arg); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = MIX_DEVS); - break; - - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); - break; - - case SOUND_MIXER_MIC: - return (*(int *) arg = volumes[DEV_MIC]); - break; - - case SOUND_MIXER_LINE: - return (*(int *) arg = volumes[DEV_LINE]); - break; - - case SOUND_MIXER_CD: - return (*(int *) arg = volumes[DEV_CD]); - break; - - case SOUND_MIXER_VOLUME: - return (*(int *) arg = volumes[DEV_VOL]); - break; - - case SOUND_MIXER_SYNTH: - return (*(int *) arg = volumes[DEV_GF1]); - break; - - default: - return -EINVAL; - } - } - - return -EINVAL; + return -EINVAL; } static struct mixer_operations ics2101_mixer_operations = { - "ICS2101", - "ICS2101 Multimedia Mixer", - ics2101_mixer_ioctl + "ICS2101", + "ICS2101 Multimedia Mixer", + ics2101_mixer_ioctl }; -void -ics2101_mixer_init (void) +int +ics2101_mixer_init(void) { - int i; - - if (num_mixers < MAX_MIXER_DEV) - { - mixer_devs[num_mixers++] = &ics2101_mixer_operations; - - /* - * Some GUS v3.7 cards had some channels flipped. Disable - * the flipping feature if the model id is other than 5. - */ + int i; + int n; - if (inb (u_MixSelect) != 5) + if ((n = sound_alloc_mixerdev()) != -1) { - for (i = 0; i < ICS_MIXDEVS; i++) - left_fix[i] = 1; - for (i = 0; i < ICS_MIXDEVS; i++) - right_fix[i] = 2; + n = num_mixers; + mixer_devs[n] = &ics2101_mixer_operations; + + /* + * Some GUS v3.7 cards had some channels flipped. Disable + * the flipping feature if the model id is other than 5. + */ + + if (inb(u_MixSelect) != 5) + { + for (i = 0; i < ICS_MIXDEVS; i++) + left_fix[i] = 1; + for (i = 0; i < ICS_MIXDEVS; i++) + right_fix[i] = 2; + } + set_volumes(DEV_GF1, 0x5a5a); + set_volumes(DEV_CD, 0x5a5a); + set_volumes(DEV_MIC, 0x0000); + set_volumes(DEV_LINE, 0x5a5a); + set_volumes(DEV_VOL, 0x5a5a); + set_volumes(DEV_UNUSED, 0x0000); } - - set_volumes (DEV_GF1, 0x5a5a); - set_volumes (DEV_CD, 0x5a5a); - set_volumes (DEV_MIC, 0x0000); - set_volumes (DEV_LINE, 0x5a5a); - set_volumes (DEV_VOL, 0x5a5a); - set_volumes (DEV_UNUSED, 0x0000); - } - + return n; } #endif diff --git a/drivers/sound/local.h.master b/drivers/sound/local.h.master new file mode 100644 index 000000000..91ad38d1d --- /dev/null +++ b/drivers/sound/local.h.master @@ -0,0 +1,228 @@ +/* Computer generated file. Please don't edit! */ + +#define KERNEL_COMPATIBLE_CONFIG + +#define SELECTED_SOUND_OPTIONS 0x00000000 + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) +# define CONFIG_MPU_EMU +#endif + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_MSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_MSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) +# define CONFIG_AD1848 +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_PSS) || \ + defined(CONFIG_GUS16) || defined(CONFIG_GUSMAX) || \ + defined(CONFIG_MSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_OPL3SA1) || \ + defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_GUS16_MODULE) || defined(CONFIG_GUSMAX_MODULE) || \ + defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \ + defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_AUDIO +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_MPU401) || \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_OPL3SA1) || defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_MPU401_MODULE) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) || \ + defined(CONFIG_OPL3SA1_MODULE) || defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_MIDI +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP +#endif +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP_MODULE +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) +# define CONFIG_UART401 +#endif + +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +#ifndef CONFIG_UART401_MODULE +#define CONFIG_UART401_MODULE +#endif +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_ADLIB) || defined(CONFIG_GUS) || \ + defined(CONFIG_MPU401) || defined(CONFIG_PSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_MAUI) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_ADLIB_MODULE) || defined(CONFIG_GUS_MODULE) || \ + defined(CONFIG_MPU401_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \ + defined(CONFIG_MAUI_MODULE) +# define CONFIG_SEQUENCER +#endif + +/* + * Force on additional support + */ + +#define SM_WAVE +#define __SGNXPRO__ +#define SM_GAMES +#define DESKPROXL +/* Computer generated file. Please don't edit! */ + +#define KERNEL_COMPATIBLE_CONFIG + +#define SELECTED_SOUND_OPTIONS 0x00000000 + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) +# define CONFIG_MPU_EMU +#endif + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_MSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_MSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) +# define CONFIG_AD1848 +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_PSS) || \ + defined(CONFIG_GUS16) || defined(CONFIG_GUSMAX) || \ + defined(CONFIG_MSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_OPL3SA1) || \ + defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_GUS16_MODULE) || defined(CONFIG_GUSMAX_MODULE) || \ + defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \ + defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_AUDIO +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_MPU401) || \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_OPL3SA1) || defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_MPU401_MODULE) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) || \ + defined(CONFIG_OPL3SA1_MODULE) || defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_MIDI +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP +#endif +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP_MODULE +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) +# define CONFIG_UART401 +#endif + +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +#ifndef CONFIG_UART401_MODULE +#define CONFIG_UART401_MODULE +#endif +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_ADLIB) || defined(CONFIG_GUS) || \ + defined(CONFIG_MPU401) || defined(CONFIG_PSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_MAUI) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_ADLIB_MODULE) || defined(CONFIG_GUS_MODULE) || \ + defined(CONFIG_MPU401_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \ + defined(CONFIG_MAUI_MODULE) +# define CONFIG_SEQUENCER +#endif + +/* + * Force on additional support + */ + +#define SM_WAVE +#define __SGNXPRO__ +#define SM_GAMES +#define DESKPROXL diff --git a/drivers/sound/lowlevel/ChangeLog.awe b/drivers/sound/lowlevel/ChangeLog.awe index 9ee76e4b6..196da64d4 100644 --- a/drivers/sound/lowlevel/ChangeLog.awe +++ b/drivers/sound/lowlevel/ChangeLog.awe @@ -1,3 +1,85 @@ +ver.0.4.2c + - Add a mode to enable drum channel toggle via bank number + change. + +ver.0.4.2b + - Clear voice position after note on + - Change nrvoices according to the current playing mode + +ver.0.4.2a + - Fix a bug in pitch calculation with scale parameter + - Change default chorus & reverb modes + +ver.0.4.2 + - Use indirect voice allocation mode; used as default mode + - Add preset mapping + - Free buffers when resetting samples + - Set default preset/bank/drumset as variable + - Fix a bug in exclusive note-off + - Add channel reset control macro + - Change modwheel sensitivity as variable + - Add lock option in open_patch + - Add channel priority mode macro, and disable it as default + - Add unset effect macro + - Add user defined chorus/reverb modes + - Do not initialize effect parameters when allocating voices + - Accept realtime filter-Q parameter change + - Check value range of set/add effects + - Change drum flags automatically when receiving bank #128 + +ver.0.4.1 development versions + +ver.0.4.0c + - Fix kernel oops when setting AWE_FX_ATTEN + +ver.0.4.0b + - Do not kill_note in start_note when velocity is zero + +ver.0.4.0a + - Fix a bug in channel pressure effects + +ver.0.4.0 + - Support dynamic buffer allocation + - Add functions to open/close/unload a patch + - Change from pointer to integer index in voice/sample lists + - Support for Linux/Alpha-AXP + - Fix for FreeBSD + - Add sostenuto control + - Add midi channel priority + - Fix a bug in all notes off control + - Use AWE_DEFAULT_MEMSIZE always if defined + - Fix a bug in awe_reset causes seg fault when no DRAM onboard + - Use awe_mem_start variable instead of constant + +ver.0.3.3c + - Fix IOCTL_TO_USER for OSS-3.8 (on Linux-2.1.25) + - Fix i/o macros for mixer controls + +ver.0.3.3b + - Fix version number in awe_version.h + - Fix a small bug in noteoff/relese all + +ver.0.3.3a + - Fix all notes/sounds off + - Add layer effect control + - Add misc mode controls; realtime pan, version number, etc. + - Move gus bank control in misc mode control + - Modify awe_operations for OSS3.8b5 + - Fix installation script + +ver.0.3.3 + - Add bass/treble control in Emu8000 chip + - Add mixer device + - Fix sustain on to value 127 + +ver.0.3.2 + - Refuse linux-2.0.0 at installation + - Move awe_voice.h to /usr/include/linux + +ver.0.3.1b (not released) + - Rewrite chorus/reverb mode change functions + - Rewrite awe_detect & awe_check_dram routines + ver.0.3.1a - Fix a bug to reset voice counter in awe_reset - Fix voice balance on GUS mode diff --git a/drivers/sound/lowlevel/Makefile b/drivers/sound/lowlevel/Makefile index d4687017f..1a4c6a396 100644 --- a/drivers/sound/lowlevel/Makefile +++ b/drivers/sound/lowlevel/Makefile @@ -3,18 +3,29 @@ all: lowlevel.o ALLOBJS = init.o aci.o awe_wave.o aedsp16.o OBJS = init.o -ifdef CONFIG_LOWLEVEL_SOUND -ifdef CONFIG_ACI_MIXER -OBJS := $(OBJS) aci.o +ifeq ($(CONFIG_LOWLEVEL_SOUND),y) +ifeq ($(CONFIG_ACI_MIXER),y) + OBJS := $(OBJS) aci.o endif -ifdef CONFIG_AWE32_SYNTH +ifeq ($(CONFIG_AWE32_SYNTH),y) OBJS := $(OBJS) awe_wave.o +else + ifeq ($(CONFIG_AWE32_SYNTH),m) + MX_OBJS := $(MX_OBJS) awe_wave.o + endif endif -ifdef CONFIG_AEDSP16 -OBJS := $(OBJS) aedsp16.o +ifeq ($(CONFIG_AEDSP16),y) + OBJS := $(OBJS) aedsp16.o endif endif +ifndef TOPDIR +TOPDIR=/usr/src/linux +endif + +.c.o: + $(CC) $(CFLAGS) -c $< + lowlevel.o: $(OBJS) $(LD) -r -o lowlevel.o $(OBJS) @@ -35,10 +46,16 @@ clean: dep: $(CPP) -M $(CFLAGS) -I. *.c > .depend -ifdef HOSTCC -include $(TOPDIR)/Rules.make -else +ifndef HOSTCC +# +# Running outside the kernel build. +# +CC = gcc +HOSTCC = gcc +CFLAGS = -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -pipe -m486 USE_DEPEND=y +else +include $(TOPDIR)/Rules.make endif ifdef USE_DEPEND diff --git a/drivers/sound/lowlevel/README.awe b/drivers/sound/lowlevel/README.awe index db082bf52..a0281710a 100644 --- a/drivers/sound/lowlevel/README.awe +++ b/drivers/sound/lowlevel/README.awe @@ -1,6 +1,6 @@ ================================================================ AWE32 Sound Driver for Linux / FreeBSD - version 0.3.1; Jan. 11, 1997 + version 0.4.2c; Oct. 7, 1997 ================================================================ * GENERAL NOTES @@ -8,9 +8,9 @@ This is a sound driver extension for SoundBlaster AWE32 and other compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable the wave synth operations. The driver is provided for both Linux -1.2.x and 2.[01].x kernels, and also FreeBSD. Consult the -installation document for installation on the original sound driver -package. +1.2.x and 2.[01].x kernels, and also FreeBSD on Intel x86 and DEC +Alpha systems. See INSTALL.awe (or INSTALL.fbsd) document for +installation of the driver package. This driver was written by Takashi Iwai (iwai@dragon.mm.t.u-tokyo.ac.jp) who also maintains the code. Please forward any questions, bug fixes @@ -18,47 +18,80 @@ and suggestions directly to Iwai (_NOT_ to Linus Torvalds or Hannu Savolainen). -* CAUTION - -- On ver.0.3.1, some zero size array entries are removed from -awe_voice.h to avoid compile error in some non-ANSI compilers. -Due to this fix, the size of awe_voice_rec structure is changed from -older versions. Use a constant AWE_VOICE_REC_SIZE instead of -sizeof(awe_voice_rec). -You can still have a compatibility by defining AWE_COMPAT_030=1, but -this feature will be omitted in the future release. - - * NOTE TO LINUX USERS To enable this driver on linux-2.[01].x kernels, you need turn on both "lowlevel drivers support" and "AWE32 synth support" options in sound menu when configure your linux kernel and modules. For more details, see the installation document in the original driver package -(awedrv-0.x.x.tar.gz) available at the web page: +(awedrv-0.4.2.tar.gz) available at the web page: http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/ If you're using PnP cards, the card must be initialized before loading the sound driver. There're several options to do this: - Initialize the card via ISA PnP tools, and load the sound module. - Initialize the card on DOS, and load linux by loadlin.exe - - Use PnP driver (for Linux-2.0.x) + - Use PnP driver (for Linux-2.x.x) See the FAQ list on the URL above. +* USING THE DRIVER + +The GM and GS sounds include multiple instrument layers. +The current version supports this type of sounds with a special +extension, but it uses a non-standard way of sequencer calls. Then, +so far, only drvmidi and playmidi can play the multiple instruments +and stereo sounds properly as MIDI sequencers. + +To load SoundFont files, sfxload utility is required. +All AWE32 driver and utilities can be downloaded from: + http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/ + +The sfxload is included in the package awesfx-0.4.2.tgz. Binary +packages are available there, too. See the instruction in each +package for installation. + +Sfxload reads a SoundFont file and transfers it to the sound driver. +Note that new sfxload no longer requires -i option. + + % sfxload synthgm.sbk + +You can tune up the sound via some new options, -A, -a and -d. + + % sfxload -A2 synthgm.sbk + +See the manual of sfxload for more details. + +Now you can hear midi musics by supported midi players (drvmidi or +playmidi-2.5). + + % drvmidi foo.mid + +If you have only 512kb on the sound card, I recommend to use dynamic +sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is +available in most midi files. + + % sfxload synthgm + % drvmidi -L 2mbgmgs foo.mid + +Enjoy. + + * COMPILE FLAGS Compile conditions are defined in awe_config.h. +[Compatibility Conditions] +The following flags are defined automatically when using installation +shell script. + - AWE_OBSOLETE_VOXWARE (default: not defined) indicates the system is VoxWare-3.0.x (with linux 1.2.x or - FreeBSD) if defined. This option will be set automatically when - you use installation script. + FreeBSD) if defined. - AWE_NEW_KERNEL_INTERFACE (default: not defined) indicates the system is OSSLite on Linux 2.1.6 or later if - defined. This option will be set automatically when you use - installation script. + defined. - HAS_LOWLEVEL_H (default: not defined) indicates the system has "lowlevel.h" in the sound/lowlevel @@ -68,27 +101,32 @@ Compile conditions are defined in awe_config.h. indicates the sound driver has no patch manager function (for OSS-3.707 (in Linux-2.1.13) or newer). +- AWE_OSS38 (default: not defined) + indicates the sound driver has an additional parameter in + operation table (for OSS-3.8b5 in Linux-2.1.25 or newer). + + +[Hardware Conditions] +You don't have to define the following two values. +Define them only when the driver couldn't detect the card properly. + - AWE_DEFAULT_BASE_ADDR (default: not defined) specifies the base port address of your AWE32 card. - Define this only when the driver couldn't detect your card - properly. - AWE_DEFAULT_MEM_SIZE (default: not defined) - specifies the memory size of your AWE32 card by kilo bytes. - Define this only when the driver couldn't detect memory size - properly. + specifies the memory size of your AWE32 card in kilo bytes. -- AWE_MAX_SAMPLES (default: 400) - specifies the maximum number of wave samples. - The default size is set for the original GM and GS presets from - CreativeLab. If you have a large set of samples (eg 2MB & 8MB GM - presets), increase this value to appropriate size. - -- AWE_MAX_INFOS (default: 900) - specifies the maximum number of instruments. - The default size is set for the original GM and GS presets from - CreativeLab. If you have a large set of samples (eg 2MB & 8MB GM - presets), increase this value to appropriate size. + +[Sample Table Size] +From ver.0.4.0, sample tables are allocated dynamically (except +Linux-1.2.x system), so you need NOT to touch these parameters. +Linux-1.2.x users may need to increase these values to apropriate size +if larger DRAM is equipped with the soundcard. + +- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS + + +[Other Conditions] - AWE_ALWAYS_INIT_FM (default: not defined) indicates the AWE driver always initialize FM passthrough even @@ -99,22 +137,24 @@ Compile conditions are defined in awe_config.h. - AWE_DEBUG_ON (default: defined) turns on debuggin messages if defined. -- AWE_CHECKSUM_DATA (default: defined) - verifies check sum of sample data with the transferred data if - defined. - -- AWE_CHECKSUM_MEMORY (default: defined) - Verifies check sum of sample data with the written data on DRAM. - - AWE_HAS_GUS_COMPATIBILITY (default: defined) Enables GUS compatibility mode if defined, reading GUS patches and GUS control commands. Define this option to use GMOD or other GUS module players. -- AWE_ACCEPT_ALL_SOUNDS_CONTROL (default: not defined) +- AWE_ACCEPT_ALL_SOUNDS_CONTROL (default: defined) Enables MIDI control #120 and #123 as "all notes off" and "all sounds off" events, respectively. +- CONFIG_AWE32_MIXER (default: defined) + Adds a mixer device for AWE32 bass/treble equalizer control. + You can access this device using /dev/mixer?? (usually mixer01). + +- AWE_LOOKUP_MIDI_PRIORIITY (default: defined) + Allocates voices according to MIDI channel priority. + Drum channels have the highest priorit, followed by #1, #2, and + so on. + - DEF_FM_CHORUS_DEPTH (default: 0x10) The default strength to be sent to the chorus effect engine. From 0 to 0xff. Larger numbers may often cause weird sounds. @@ -124,43 +164,12 @@ Compile conditions are defined in awe_config.h. From 0 to 0xff. Larger numbers may often cause weird sounds. -* USING THE DRIVER - -To load SoundFont files, sfxload utility is required. -All AWE32 driver and utilities can be downloaded from: - http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/ - -The GM and GS sounds include multiple instrument layers. The older -driver couldn't handle multiple instruments. The current version -supports this type of sounds with a special extension, but so far only -drvmidi and playmidi can play the multiple instruments and stereo -sounds. - -To play drvmidi, load the SoundFont file directly uing sfxload utility. - - % sfxload -i synthgm.sf2 - -To use other sequencers like musserver, some sounds may become -inaudible unless converting to SFX file. Follow the instruction in -awesfx package to make patched GM and GS presets. Then, load the SFX -file on driver by sfxload utility. - - % sfxload -i gm.sfx - -Now you can hear midi musics by supported midi players -(awemidi-0.1.x.tar.gz or patch file to playmidi-2.3). - - % drvmidi foo.mid - -Enjoy. - - * ACKNOWLEDGMENTS Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for many advices to programming of AWE32. Many codes are brought from his AWE32-native MOD player, ALMP. -The port of awedrv0.1.6 to FreeBSD is done by Randall Hopper +The port of awedrv to FreeBSD is done by Randall Hopper (rhh@ct.picker.com). I also thank linux-awe-ml members for their efforts to reboot their system many times :-) @@ -168,9 +177,9 @@ to reboot their system many times :-) * BUGS & TODO'S +- Can't detect DRAM size on some card - More smart patch management - More smart DRAM memory control -- Dynamic buffer allocation - etc, etc, etc. diff --git a/drivers/sound/lowlevel/aedsp16.c b/drivers/sound/lowlevel/aedsp16.c index beb1695a6..93db242a1 100644 --- a/drivers/sound/lowlevel/aedsp16.c +++ b/drivers/sound/lowlevel/aedsp16.c @@ -250,7 +250,7 @@ #undef AEDSP16_INFO 1 /* Define this to enable info code */ #if defined(AEDSP16_DEBUG) -# define DBG(x) printk x +# define DBG(x) printk x # if defined(AEDSP16_DEBUG_MORE) # define DBG1(x) printk x # else diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h new file mode 100644 index 000000000..d0c34a1fa --- /dev/null +++ b/drivers/sound/lowlevel/awe_compat.h @@ -0,0 +1,190 @@ +/*---------------------------------------------------------------- + * compatibility macros for AWE32 driver + *----------------------------------------------------------------*/ + +/* redefine following macros */ +#undef IOCTL_IN +#undef IOCTL_OUT +#undef OUTW +#undef COPY_FROM_USER +#undef COPY_TO_USER +#undef GET_BYTE_FROM_USER +#undef GET_SHORT_FROM_USER +#undef IOCTL_TO_USER + +#ifdef linux + +/*================================================================ + * Linux macros + *================================================================*/ + +/* use inline prefix */ +#define INLINE inline + +/*---------------------------------------------------------------- + * memory management for linux + *----------------------------------------------------------------*/ + +#ifdef AWE_OBSOLETE_VOXWARE +/* old type linux system */ + +/* i/o requests; nothing */ +#define awe_check_port() 0 /* always false */ +#define awe_request_region() /* nothing */ +#define awe_release_region() /* nothing */ + +static int _mem_start; /* memory pointer for permanent buffers */ + +#define my_malloc_init(memptr) _mem_start = (memptr) +#define my_malloc_memptr() _mem_start +#define my_free(ptr) /* do nothing */ +#define my_realloc(buf,oldsize,size) NULL /* no realloc */ + +static void *my_malloc(int size) +{ + char *ptr; + PERMANENT_MALLOC(ptr, char*, size, _mem_start); + return (void*)ptr; +} + +/* allocate buffer only once */ +#define INIT_TABLE(buffer,index,nums,type) {\ +buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ +} + +#else + +#define AWE_DYNAMIC_BUFFER + +#define my_malloc_init(ptr) /* nothing */ +#define my_malloc_memptr() 0 +#define my_malloc(size) vmalloc(size) +#define my_free(ptr) if (ptr) {vfree(ptr);} + +static void *my_realloc(void *buf, int oldsize, int size) +{ + void *ptr; + if ((ptr = vmalloc(size)) == NULL) + return NULL; + memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) ); + vfree(buf); + return ptr; +} + +/* do not allocate buffer at beginning */ +#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} + +/* old type macro */ +#define RET_ERROR(err) -err + +#endif + +/*---------------------------------------------------------------- + * i/o interfaces for linux + *----------------------------------------------------------------*/ + +#define OUTW(data,addr) outw(data, addr) + +#ifdef AWE_NEW_KERNEL_INTERFACE +#define COPY_FROM_USER(target,source,offs,count) \ + copy_from_user(target, (source)+(offs), count) +#define GET_BYTE_FROM_USER(target,addr,offs) \ + get_user(target, (unsigned char*)&((addr)[offs])) +#define GET_SHORT_FROM_USER(target,addr,offs) \ + get_user(target, (unsigned short*)&((addr)[offs])) +#ifdef AWE_OSS38 +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy(target, (source)+(offs), count) +#define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE) +#else +#define IOCTL_TO_USER(target,offs,source,count) \ + copy_to_user(target, (source)+(offs), count) +#define IO_WRITE_CHECK(cmd) (_IOC_DIR(cmd) & _IOC_WRITE) +#endif /* AWE_OSS38 */ +#define COPY_TO_USER IOCTL_TO_USER +#define IOCTL_IN(arg) (*(int*)(arg)) +#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) + +#else /* old type i/o */ +#define COPY_FROM_USER(target,source,offs,count) \ + memcpy_fromfs(target, (source)+(offs), (count)) +#define GET_BYTE_FROM_USER(target,addr,offs) \ + *((char *)&(target)) = get_fs_byte((addr)+(offs)) +#define GET_SHORT_FROM_USER(target,addr,offs) \ + *((short *)&(target)) = get_fs_word((addr)+(offs)) +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy_tofs(target, (source)+(offs), (count)) +#define COPY_TO_USER IOCTL_TO_USER +#define IO_WRITE_CHECK(cmd) (cmd & IOC_IN) +#define IOCTL_IN(arg) get_fs_long((long *)(arg)) +#define IOCTL_OUT(arg,ret) snd_ioctl_return((int *)arg, ret) + +#endif /* AWE_NEW_KERNEL_INTERFACE */ + +#define BZERO(target,len) memset(target, 0, len) +#define MEMCPY(dst,src,len) memcpy(dst, src, len) + + +#elif defined(__FreeBSD__) + +/*================================================================ + * FreeBSD macros + *================================================================*/ + +/* inline is not checked yet.. maybe it'll work */ +#define INLINE /*inline*/ + +/*---------------------------------------------------------------- + * memory management for freebsd + *----------------------------------------------------------------*/ + +/* i/o requests; nothing */ +#define awe_check_port() 0 /* always false */ +#define awe_request_region() /* nothing */ +#define awe_release_region() /* nothing */ + +#define AWE_DYNAMIC_BUFFER + +#define my_malloc_init(ptr) /* nothing */ +#define my_malloc_memptr() 0 +#define my_malloc(size) malloc(size, M_TEMP, M_WAITOK) +#define my_free(ptr) if (ptr) {free(ptr, M_TEMP);} + +#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} + +/* it should be realloc? */ +static void *my_realloc(void *buf, int oldsize, int size) +{ + void *ptr; + if ((ptr = my_malloc(size)) == NULL) + return NULL; + memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) ); + my_free(buf); + return ptr; +} + +/*---------------------------------------------------------------- + * i/o interfaces for freebsd + *----------------------------------------------------------------*/ + +/* according to linux rule; the arguments are swapped */ +#define OUTW(data,addr) outw(addr, data) + +#define COPY_FROM_USER(target,source,offs,count) \ + uiomove(((caddr_t)(target)),(count),((struct uio *)(source))) +#define COPY_TO_USER(target,source,offs,count) \ + uiomove(((caddr_t)(source)),(count),((struct uio *)(target))) +#define GET_BYTE_FROM_USER(target,addr,offs) \ + uiomove(((char*)&(target)), 1, ((struct uio *)(addr))) +#define GET_SHORT_FROM_USER(target,addr,offs) \ + uiomove(((char*)&(target)), 2, ((struct uio *)(addr))) +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy(&((target)[offs]), (source), (count)) +#define IO_WRITE_CHECK(cmd) (cmd & IOC_IN) +#define IOCTL_IN(arg) (*(int*)(arg)) +#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) +#define BZERO(target,len) bzero((caddr_t)target, len) +#define MEMCPY(dst,src,len) bcopy((caddr_t)src, (caddr_t)dst, len) + +#endif + diff --git a/drivers/sound/lowlevel/awe_config.h b/drivers/sound/lowlevel/awe_config.h index c80eb3f35..c6b0dae6d 100644 --- a/drivers/sound/lowlevel/awe_config.h +++ b/drivers/sound/lowlevel/awe_config.h @@ -2,9 +2,9 @@ * sound/awe_config.h * * Configuration of AWE32 sound driver - * version 0.2.99e; Dec. 10, 1997 + * version 0.4.2; Sep. 15, 1997 * - * Copyright (C) 1996,1997 Takashi Iwai + * Copyright (C) 1996 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,6 +52,10 @@ */ #define AWE_NO_PATCHMGR +/* if your system has an additional parameter (OSS 3.8b5 or newer), + * define this. + */ +#define AWE_OSS38 /*---------------------------------------------------------------- * AWE32 card configuration: @@ -64,13 +68,20 @@ /*---------------------------------------------------------------- - * maximum size of sample table: - * the followings are for ROM GM and 512k GS samples. if your have - * additional DRAM and SoundFonts, increase these values. + * maximum size of soundfont list table: + * you usually don't need to touch this value. + *----------------------------------------------------------------*/ + +#define AWE_MAX_SF_LISTS 16 + + +/*---------------------------------------------------------------- + * chunk size of sample and voice tables: + * you usually don't need to touch these values. *----------------------------------------------------------------*/ #define AWE_MAX_SAMPLES 400 -#define AWE_MAX_INFOS 1500 +#define AWE_MAX_INFOS 800 /*---------------------------------------------------------------- @@ -92,24 +103,17 @@ /* debug on */ #define AWE_DEBUG_ON -/* verify checksum for uploading samples */ -#define AWE_CHECKSUM_DATA -#define AWE_CHECKSUM_MEMORY - /* GUS compatible mode */ #define AWE_HAS_GUS_COMPATIBILITY /* accept all notes/sounds off controls */ -#undef AWE_ACCEPT_ALL_SOUNDS_CONTROL - +#define AWE_ACCEPT_ALL_SOUNDS_CONTROL -#ifdef linux -/* i tested this only on my linux */ -#define INLINE __inline__ -#else -#define INLINE /**/ -#endif +/* add mixer control of emu8000 equalizer */ +#define CONFIG_AWE32_MIXER +/* look up voices according to MIDI channel priority */ +#define AWE_LOOKUP_MIDI_PRIORITY /*----------------------------------------------------------------*/ diff --git a/drivers/sound/lowlevel/awe_hw.h b/drivers/sound/lowlevel/awe_hw.h index 6aa151fc1..7d0d88e77 100644 --- a/drivers/sound/lowlevel/awe_hw.h +++ b/drivers/sound/lowlevel/awe_hw.h @@ -3,7 +3,7 @@ * * Access routines and definitions for the low level driver for the * AWE32/Sound Blaster 32 wave table synth. - * version 0.3.1; Jan. 21, 1997 + * version 0.4.2; Sep. 15, 1997 * * Copyright (C) 1996,1997 Takashi Iwai * @@ -89,10 +89,12 @@ #define AWE_NORMAL_VOICES 30 /*30&31 are reserved for DRAM refresh*/ #define AWE_MAX_CHANNELS 32 /* max midi channels (must >= voices) */ +#define AWE_MAX_LAYERS AWE_MAX_VOICES /* maximum number of multiple layers */ #define AWE_DRAM_OFFSET 0x200000 #define AWE_MAX_DRAM_SIZE (28 * 1024) /* 28 MB is max onboard memory */ #define AWE_DEFAULT_ATTENUATION 32 /* 12dB below */ +#define AWE_DEFAULT_MOD_SENSE 18 #endif diff --git a/drivers/sound/lowlevel/awe_version.h b/drivers/sound/lowlevel/awe_version.h new file mode 100644 index 000000000..a579b09ef --- /dev/null +++ b/drivers/sound/lowlevel/awe_version.h @@ -0,0 +1,24 @@ +/* AWE32 driver version number */ + +#ifndef AWE_VERSION_H_DEF +#define AWE_VERSION_H_DEF + +#define AWE_VERSION_NUMBER 0x00040203 +#define AWEDRV_VERSION "0.4.2c" +#define AWE_MAJOR_VERSION(id) (((id) >> 16) & 0xff) +#define AWE_MINOR_VERSION(id) (((id) >> 8) & 0xff) +#define AWE_TINY_VERSION(id) ((id) & 0xff) + +#endif +/* AWE32 driver version number */ + +#ifndef AWE_VERSION_H_DEF +#define AWE_VERSION_H_DEF + +#define AWE_VERSION_NUMBER 0x00040202 +#define AWEDRV_VERSION "0.4.2b" +#define AWE_MAJOR_VERSION(id) (((id) >> 16) & 0xff) +#define AWE_MINOR_VERSION(id) (((id) >> 8) & 0xff) +#define AWE_TINY_VERSION(id) ((id) & 0xff) + +#endif diff --git a/drivers/sound/lowlevel/awe_voice.h b/drivers/sound/lowlevel/awe_voice.h new file mode 100644 index 000000000..aa1313131 --- /dev/null +++ b/drivers/sound/lowlevel/awe_voice.h @@ -0,0 +1,490 @@ +/* + * sound/awe_voice.h + * + * Voice information definitions for the low level driver for the + * AWE32/Sound Blaster 32 wave table synth. + * version 0.4.2c; Oct. 7, 1997 + * + * Copyright (C) 1996,1997 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AWE_VOICE_H +#define AWE_VOICE_H + +#ifndef SAMPLE_TYPE_AWE32 +#define SAMPLE_TYPE_AWE32 0x20 +#endif + +#ifndef _PATCHKEY +#define _PATCHKEY(id) ((id<<8)|0xfd) +#endif + +/*---------------------------------------------------------------- + * patch information record + *----------------------------------------------------------------*/ + +/* patch interface header: 16 bytes */ +typedef struct awe_patch_info { + short key; /* use AWE_PATCH here */ +#define AWE_PATCH _PATCHKEY(0x07) + + short device_no; /* synthesizer number */ + unsigned short sf_id; /* file id (should be zero) */ + short optarg; /* optional argument */ + int len; /* data length (without this header) */ + + short type; /* patch operation type */ +#define AWE_LOAD_INFO 0 /* awe_voice_rec */ +#define AWE_LOAD_DATA 1 /* awe_sample_info */ +#define AWE_OPEN_PATCH 2 /* awe_open_parm */ +#define AWE_CLOSE_PATCH 3 /* none */ +#define AWE_UNLOAD_PATCH 4 /* none */ +#define AWE_REPLACE_DATA 5 /* awe_sample_info (optarg=#channels)*/ +#define AWE_MAP_PRESET 6 /* awe_voice_map */ +#define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */ +#define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */ + + short reserved; /* word alignment data */ + + /* the actual patch data begins after this */ +#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 + char data[0]; +#endif +} awe_patch_info; + +/*#define AWE_PATCH_INFO_SIZE 16*/ +#define AWE_PATCH_INFO_SIZE sizeof(awe_patch_info) + + +/*---------------------------------------------------------------- + * open patch + *----------------------------------------------------------------*/ + +#define AWE_PATCH_NAME_LEN 32 + +typedef struct _awe_open_parm { + unsigned short type; /* sample type */ +#define AWE_PAT_TYPE_MISC 0 +#define AWE_PAT_TYPE_GM 1 +#define AWE_PAT_TYPE_GS 2 +#define AWE_PAT_TYPE_MT32 3 +#define AWE_PAT_TYPE_XG 4 +#define AWE_PAT_TYPE_SFX 5 +#define AWE_PAT_TYPE_GUS 6 +#define AWE_PAT_TYPE_MAP 7 + +#define AWE_PAT_LOCKED 0x100 /* lock the samples */ + + short reserved; + char name[AWE_PATCH_NAME_LEN]; +} awe_open_parm; + +/*#define AWE_OPEN_PARM_SIZE 28*/ +#define AWE_OPEN_PARM_SIZE sizeof(awe_open_parm) + + +/*---------------------------------------------------------------- + * raw voice information record + *----------------------------------------------------------------*/ + +/* wave table envelope & effect parameters to control EMU8000 */ +typedef struct _awe_voice_parm { + unsigned short moddelay; /* modulation delay (0x8000) */ + unsigned short modatkhld; /* modulation attack & hold time (0x7f7f) */ + unsigned short moddcysus; /* modulation decay & sustain (0x7f7f) */ + unsigned short modrelease; /* modulation release time (0x807f) */ + short modkeyhold, modkeydecay; /* envelope change per key (not used) */ + unsigned short voldelay; /* volume delay (0x8000) */ + unsigned short volatkhld; /* volume attack & hold time (0x7f7f) */ + unsigned short voldcysus; /* volume decay & sustain (0x7f7f) */ + unsigned short volrelease; /* volume release time (0x807f) */ + short volkeyhold, volkeydecay; /* envelope change per key (not used) */ + unsigned short lfo1delay; /* LFO1 delay (0x8000) */ + unsigned short lfo2delay; /* LFO2 delay (0x8000) */ + unsigned short pefe; /* modulation pitch & cutoff (0x0000) */ + unsigned short fmmod; /* LFO1 pitch & cutoff (0x0000) */ + unsigned short tremfrq; /* LFO1 volume & freq (0x0000) */ + unsigned short fm2frq2; /* LFO2 pitch & freq (0x0000) */ + unsigned char cutoff; /* initial cutoff (0xff) */ + unsigned char filterQ; /* initial filter Q [0-15] (0x0) */ + unsigned char chorus; /* chorus send (0x00) */ + unsigned char reverb; /* reverb send (0x00) */ + unsigned short reserved[4]; /* not used */ +} awe_voice_parm; + +#define AWE_VOICE_PARM_SIZE 48 + + +/* wave table parameters: 92 bytes */ +typedef struct _awe_voice_info { + unsigned short sf_id; /* file id (should be zero) */ + unsigned short sample; /* sample id */ + int start, end; /* sample offset correction */ + int loopstart, loopend; /* loop offset correction */ + short rate_offset; /* sample rate pitch offset */ + unsigned short mode; /* sample mode */ +#define AWE_MODE_ROMSOUND 0x8000 +#define AWE_MODE_STEREO 1 +#define AWE_MODE_LOOPING 2 +#define AWE_MODE_NORELEASE 4 /* obsolete */ +#define AWE_MODE_INIT_PARM 8 + + short root; /* midi root key */ + short tune; /* pitch tuning (in cents) */ + char low, high; /* key note range */ + char vellow, velhigh; /* velocity range */ + char fixkey, fixvel; /* fixed key, velocity */ + char pan, fixpan; /* panning, fixed panning */ + short exclusiveClass; /* exclusive class (0 = none) */ + unsigned char amplitude; /* sample volume (127 max) */ + unsigned char attenuation; /* attenuation (0.375dB) */ + short scaleTuning; /* pitch scale tuning(%), normally 100 */ + awe_voice_parm parm; /* voice envelope parameters */ + short index; /* internal index (set by driver) */ +} awe_voice_info; + +/*#define AWE_VOICE_INFO_SIZE 92*/ +#define AWE_VOICE_INFO_SIZE sizeof(awe_voice_info) + +/*----------------------------------------------------------------*/ + +/* The info entry of awe_voice_rec is changed from 0 to 1 + * for some compilers refusing zero size array. + * Due to this change, sizeof(awe_voice_rec) becomes different + * from older versions. + * Use AWE_VOICE_REC_SIZE instead. + */ + +/* instrument info header: 4 bytes */ +typedef struct _awe_voice_rec_hdr { + unsigned char bank; /* midi bank number */ + unsigned char instr; /* midi preset number */ + char nvoices; /* number of voices */ + char write_mode; /* write mode; normally 0 */ +#define AWE_WR_APPEND 0 /* append anyway */ +#define AWE_WR_EXCLUSIVE 1 /* skip if already exists */ +#define AWE_WR_REPLACE 2 /* replace if already exists */ +} awe_voice_rec_hdr; + +/*#define AWE_VOICE_REC_SIZE 4*/ +#define AWE_VOICE_REC_SIZE sizeof(awe_voice_rec_hdr) + +/* the standard patch structure for one sample */ +typedef struct _awe_voice_rec_patch { + awe_patch_info patch; + awe_voice_rec_hdr hdr; + awe_voice_info info; +} awe_voice_rec_patch; + + +/* obsolete data type */ +#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 +#define AWE_INFOARRAY_SIZE 0 +#else +#define AWE_INFOARRAY_SIZE 1 +#endif + +typedef struct _awe_voice_rec { + unsigned char bank; /* midi bank number */ + unsigned char instr; /* midi preset number */ + short nvoices; /* number of voices */ + /* voice information follows here */ + awe_voice_info info[AWE_INFOARRAY_SIZE]; +} awe_voice_rec; + + +/*---------------------------------------------------------------- + * sample wave information + *----------------------------------------------------------------*/ + +/* wave table sample header: 32 bytes */ +typedef struct awe_sample_info { + unsigned short sf_id; /* file id (should be zero) */ + unsigned short sample; /* sample id */ + int start, end; /* start & end offset */ + int loopstart, loopend; /* loop start & end offset */ + int size; /* size (0 = ROM) */ + short checksum_flag; /* use check sum = 1 */ + unsigned short mode_flags; /* mode flags */ +#define AWE_SAMPLE_8BITS 1 /* wave data is 8bits */ +#define AWE_SAMPLE_UNSIGNED 2 /* wave data is unsigned */ +#define AWE_SAMPLE_NO_BLANK 4 /* no blank loop is attached */ +#define AWE_SAMPLE_SINGLESHOT 8 /* single-shot w/o loop */ +#define AWE_SAMPLE_BIDIR_LOOP 16 /* bidirectional looping */ +#define AWE_SAMPLE_STEREO_LEFT 32 /* stereo left sound */ +#define AWE_SAMPLE_STEREO_RIGHT 64 /* stereo right sound */ +#define AWE_SAMPLE_REVERSE_LOOP 128 /* reverse looping */ + unsigned int checksum; /* check sum */ +#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 + unsigned short data[0]; /* sample data follows here */ +#endif +} awe_sample_info; + +/*#define AWE_SAMPLE_INFO_SIZE 32*/ +#define AWE_SAMPLE_INFO_SIZE sizeof(awe_sample_info) + + +/*---------------------------------------------------------------- + * voice preset mapping + *----------------------------------------------------------------*/ + +typedef struct awe_voice_map { + int map_bank, map_instr, map_key; /* key = -1 means all keys */ + int src_bank, src_instr, src_key; +} awe_voice_map; + +#define AWE_VOICE_MAP_SIZE sizeof(awe_voice_map) + + +/*---------------------------------------------------------------- + * awe hardware controls + *----------------------------------------------------------------*/ + +#define _AWE_DEBUG_MODE 0x00 +#define _AWE_REVERB_MODE 0x01 +#define _AWE_CHORUS_MODE 0x02 +#define _AWE_REMOVE_LAST_SAMPLES 0x03 +#define _AWE_INITIALIZE_CHIP 0x04 +#define _AWE_SEND_EFFECT 0x05 +#define _AWE_TERMINATE_CHANNEL 0x06 +#define _AWE_TERMINATE_ALL 0x07 +#define _AWE_INITIAL_VOLUME 0x08 +#define _AWE_INITIAL_ATTEN _AWE_INITIAL_VOLUME +#define _AWE_RESET_CHANNEL 0x09 +#define _AWE_CHANNEL_MODE 0x0a +#define _AWE_DRUM_CHANNELS 0x0b +#define _AWE_MISC_MODE 0x0c +#define _AWE_RELEASE_ALL 0x0d +#define _AWE_NOTEOFF_ALL 0x0e +#define _AWE_CHN_PRESSURE 0x0f +/*#define _AWE_GET_CURRENT_MODE 0x10*/ +#define _AWE_EQUALIZER 0x11 +/*#define _AWE_GET_MISC_MODE 0x12*/ +/*#define _AWE_GET_FONTINFO 0x13*/ + +#define _AWE_MODE_FLAG 0x80 +#define _AWE_COOKED_FLAG 0x40 /* not supported */ +#define _AWE_MODE_VALUE_MASK 0x3F + +/*----------------------------------------------------------------*/ + +#define _AWE_SET_CMD(p,dev,voice,cmd,p1,p2) \ +{((char*)(p))[0] = SEQ_PRIVATE;\ + ((char*)(p))[1] = dev;\ + ((char*)(p))[2] = _AWE_MODE_FLAG|(cmd);\ + ((char*)(p))[3] = voice;\ + ((unsigned short*)(p))[2] = p1;\ + ((unsigned short*)(p))[3] = p2;} + +/* buffered access */ +#define _AWE_CMD(dev, voice, cmd, p1, p2) \ +{_SEQ_NEEDBUF(8);\ + _AWE_SET_CMD(_seqbuf + _seqbufptr, dev, voice, cmd, p1, p2);\ + _SEQ_ADVBUF(8);} + +/* direct access */ +#define _AWE_CMD_NOW(seqfd,dev,voice,cmd,p1,p2) \ +{struct seq_event_rec tmp;\ + _AWE_SET_CMD(&tmp, dev, voice, cmd, p1, p2);\ + ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, &tmp);} + +/*----------------------------------------------------------------*/ + +/* set debugging mode */ +#define AWE_DEBUG_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0) +/* set reverb mode; from 0 to 7 */ +#define AWE_REVERB_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0) +/* set chorus mode; from 0 to 7 */ +#define AWE_CHORUS_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0) + +/* reset channel */ +#define AWE_RESET_CHANNEL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 0, 0) +#define AWE_RESET_CONTROL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 1, 0) + +/* send an effect to all layers */ +#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value) +#define AWE_ADD_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x80),value) +#define AWE_UNSET_EFFECT(dev,voice,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x40),0) +/* send an effect to a layer */ +#define AWE_SEND_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)),value) +#define AWE_ADD_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x80),value) +#define AWE_UNSET_LAYER_EFFECT(dev,voice,layer,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x40),0) + +/* terminate sound on the channel/voice */ +#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0) +/* terminate all sounds */ +#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0) +/* release all sounds (w/o sustain effect) */ +#define AWE_RELEASE_ALL(dev) _AWE_CMD(dev, 0, _AWE_RELEASE_ALL, 0, 0) +/* note off all sounds (w sustain effect) */ +#define AWE_NOTEOFF_ALL(dev) _AWE_CMD(dev, 0, _AWE_NOTEOFF_ALL, 0, 0) + +/* set initial attenuation */ +#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0) +#define AWE_INITIAL_ATTEN AWE_INITIAL_VOLUME +/* relative attenuation */ +#define AWE_SET_ATTEN(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 1) + +/* set channel playing mode; mode=0/1/2 */ +#define AWE_SET_CHANNEL_MODE(dev,mode) _AWE_CMD(dev, 0, _AWE_CHANNEL_MODE, mode, 0) +#define AWE_PLAY_INDIRECT 0 /* indirect voice mode (default) */ +#define AWE_PLAY_MULTI 1 /* multi note voice mode */ +#define AWE_PLAY_DIRECT 2 /* direct single voice mode */ +#define AWE_PLAY_MULTI2 3 /* sequencer2 mode; used internally */ + +/* set drum channel mask; channels is 32bit long value */ +#define AWE_DRUM_CHANNELS(dev,channels) _AWE_CMD(dev, 0, _AWE_DRUM_CHANNELS, ((channels) & 0xffff), ((channels) >> 16)) + +/* set bass and treble control; values are from 0 to 11 */ +#define AWE_EQUALIZER(dev,bass,treble) _AWE_CMD(dev, 0, _AWE_EQUALIZER, bass, treble) + +/* remove last loaded samples */ +#define AWE_REMOVE_LAST_SAMPLES(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0) +/* initialize emu8000 chip */ +#define AWE_INITIALIZE_CHIP(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_INITIALIZE_CHIP, 0, 0) + +/* set miscellaneous modes; meta command */ +#define AWE_MISC_MODE(dev,mode,value) _AWE_CMD(dev, 0, _AWE_MISC_MODE, mode, value) +/* exclusive sound off; 1=off */ +#define AWE_EXCLUSIVE_SOUND(dev,mode) AWE_MISC_MODE(dev,AWE_MD_EXCLUSIVE_SOUND,mode) +/* default GUS bank number */ +#define AWE_SET_GUS_BANK(dev,bank) AWE_MISC_MODE(dev,AWE_MD_GUS_BANK,bank) +/* change panning position in realtime; 0=don't 1=do */ +#define AWE_REALTIME_PAN(dev,mode) AWE_MISC_MODE(dev,AWE_MD_REALTIME_PAN,mode) + +/* extended pressure controls; not portable with other sound drivers */ +#define AWE_KEY_PRESSURE(dev,ch,note,vel) SEQ_START_NOTE(dev,ch,(note)+128,vel) +#define AWE_CHN_PRESSURE(dev,ch,vel) _AWE_CMD(dev,ch,_AWE_CHN_PRESSURE,vel,0) + +/*----------------------------------------------------------------*/ + +/* reverb mode parameters */ +#define AWE_REVERB_ROOM1 0 +#define AWE_REVERB_ROOM2 1 +#define AWE_REVERB_ROOM3 2 +#define AWE_REVERB_HALL1 3 +#define AWE_REVERB_HALL2 4 +#define AWE_REVERB_PLATE 5 +#define AWE_REVERB_DELAY 6 +#define AWE_REVERB_PANNINGDELAY 7 +#define AWE_REVERB_PREDEFINED 8 +/* user can define reverb modes up to 32 */ +#define AWE_REVERB_NUMBERS 32 + +typedef struct awe_reverb_fx_rec { + unsigned short parms[28]; +} awe_reverb_fx_rec; + +/*----------------------------------------------------------------*/ + +/* chorus mode parameters */ +#define AWE_CHORUS_1 0 +#define AWE_CHORUS_2 1 +#define AWE_CHORUS_3 2 +#define AWE_CHORUS_4 3 +#define AWE_CHORUS_FEEDBACK 4 +#define AWE_CHORUS_FLANGER 5 +#define AWE_CHORUS_SHORTDELAY 6 +#define AWE_CHORUS_SHORTDELAY2 7 +#define AWE_CHORUS_PREDEFINED 8 +/* user can define chorus modes up to 32 */ +#define AWE_CHORUS_NUMBERS 32 + +typedef struct awe_chorus_fx_rec { + unsigned short feedback; /* feedback level (0xE600-0xE6FF) */ + unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */ + unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */ + unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */ + unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */ +} awe_chorus_fx_rec; + +/*----------------------------------------------------------------*/ + +/* misc mode types */ +enum { +/* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */ +/* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */ +/* 2*/ AWE_MD_VERSION, /* read only */ +/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* ignored */ +/* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */ +/* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */ +/* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */ +/* 7*/ AWE_MD_ZERO_ATTEN, /* attenuation of max volume (default=32) */ +/* 8*/ AWE_MD_CHN_PRIOR, /* 0/1: set MIDI channel priority mode (default=1) */ +/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity (def=18) */ +/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number (def=0) */ +/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */ +/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */ +/*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */ + AWE_MD_END, +}; + +/*----------------------------------------------------------------*/ + +/* effect parameters */ +enum { + +/* modulation envelope parameters */ +/* 0*/ AWE_FX_ENV1_DELAY, /* WORD: ENVVAL */ +/* 1*/ AWE_FX_ENV1_ATTACK, /* BYTE: up ATKHLD */ +/* 2*/ AWE_FX_ENV1_HOLD, /* BYTE: lw ATKHLD */ +/* 3*/ AWE_FX_ENV1_DECAY, /* BYTE: lw DCYSUS */ +/* 4*/ AWE_FX_ENV1_RELEASE, /* BYTE: lw DCYSUS */ +/* 5*/ AWE_FX_ENV1_SUSTAIN, /* BYTE: up DCYSUS */ +/* 6*/ AWE_FX_ENV1_PITCH, /* BYTE: up PEFE */ +/* 7*/ AWE_FX_ENV1_CUTOFF, /* BYTE: lw PEFE */ + +/* volume envelope parameters */ +/* 8*/ AWE_FX_ENV2_DELAY, /* WORD: ENVVOL */ +/* 9*/ AWE_FX_ENV2_ATTACK, /* BYTE: up ATKHLDV */ +/*10*/ AWE_FX_ENV2_HOLD, /* BYTE: lw ATKHLDV */ +/*11*/ AWE_FX_ENV2_DECAY, /* BYTE: lw DCYSUSV */ +/*12*/ AWE_FX_ENV2_RELEASE, /* BYTE: lw DCYSUSV */ +/*13*/ AWE_FX_ENV2_SUSTAIN, /* BYTE: up DCYSUSV */ + +/* LFO1 (tremolo & vibrato) parameters */ +/*14*/ AWE_FX_LFO1_DELAY, /* WORD: LFO1VAL */ +/*15*/ AWE_FX_LFO1_FREQ, /* BYTE: lo TREMFRQ */ +/*16*/ AWE_FX_LFO1_VOLUME, /* BYTE: up TREMFRQ */ +/*17*/ AWE_FX_LFO1_PITCH, /* BYTE: up FMMOD */ +/*18*/ AWE_FX_LFO1_CUTOFF, /* BYTE: lo FMMOD */ + +/* LFO2 (vibrato) parameters */ +/*19*/ AWE_FX_LFO2_DELAY, /* WORD: LFO2VAL */ +/*20*/ AWE_FX_LFO2_FREQ, /* BYTE: lo FM2FRQ2 */ +/*21*/ AWE_FX_LFO2_PITCH, /* BYTE: up FM2FRQ2 */ + +/* Other overall effect parameters */ +/*22*/ AWE_FX_INIT_PITCH, /* SHORT: pitch offset */ +/*23*/ AWE_FX_CHORUS, /* BYTE: chorus effects send (0-255) */ +/*24*/ AWE_FX_REVERB, /* BYTE: reverb effects send (0-255) */ +/*25*/ AWE_FX_CUTOFF, /* BYTE: up IFATN */ +/*26*/ AWE_FX_FILTERQ, /* BYTE: up CCCA */ + +/* Sample / loop offset changes */ +/*27*/ AWE_FX_SAMPLE_START, /* SHORT: offset */ +/*28*/ AWE_FX_LOOP_START, /* SHORT: offset */ +/*29*/ AWE_FX_LOOP_END, /* SHORT: offset */ +/*30*/ AWE_FX_COARSE_SAMPLE_START, /* SHORT: upper word offset */ +/*31*/ AWE_FX_COARSE_LOOP_START, /* SHORT: upper word offset */ +/*32*/ AWE_FX_COARSE_LOOP_END, /* SHORT: upper word offset */ +/*33*/ AWE_FX_ATTEN, /* BYTE: lo IFATN */ + + AWE_FX_END, +}; + +#endif /* AWE_VOICE_H */ diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/lowlevel/awe_wave.c index 740ecb94b..196882423 100644 --- a/drivers/sound/lowlevel/awe_wave.c +++ b/drivers/sound/lowlevel/awe_wave.c @@ -2,7 +2,7 @@ * sound/awe_wave.c * * The low level driver for the AWE32/Sound Blaster 32 wave table synth. - * version 0.3.1b; Jan. 21, 1997 + * version 0.4.2c; Oct. 7, 1997 * * Copyright (C) 1996,1997 Takashi Iwai * @@ -21,25 +21,34 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define AWEDRV_VERSION "0.3.1b" #ifdef __FreeBSD__ # include <i386/isa/sound/awe_config.h> #else +#ifdef MODULE +#include <linux/config.h> +#include <linux/string.h> +#include <linux/module.h> +# include "../soundmodule.h" +#endif # include "awe_config.h" #endif /*----------------------------------------------------------------*/ -#ifdef CONFIG_AWE32_SYNTH +#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE) #ifdef __FreeBSD__ # include <i386/isa/sound/awe_hw.h> +# include <i386/isa/sound/awe_version.h> # include <i386/isa/sound/awe_voice.h> #else # include "awe_hw.h" +# include "awe_version.h" # include <linux/awe_voice.h> #endif +#ifdef AWE_HAS_GUS_COMPATIBILITY +/* include finetune table */ #ifdef AWE_OBSOLETE_VOXWARE # ifdef __FreeBSD__ # define SEQUENCER_C @@ -57,6 +66,8 @@ # include <machine/ultrasound.h> #endif +#endif /* AWE_HAS_GUS_COMPATIBILITY */ + /*---------------------------------------------------------------- * debug message @@ -77,39 +88,79 @@ static int debug_mode = 0; * bank and voice record *----------------------------------------------------------------*/ +/* soundfont record */ +typedef struct _sf_list { + unsigned short sf_id; + unsigned short type; + int num_info; /* current info table index */ + int num_sample; /* current sample table index */ + int mem_ptr; /* current word byte pointer */ + int infos; + int samples; + /*char name[AWE_PATCH_NAME_LEN];*/ +} sf_list; + /* bank record */ typedef struct _awe_voice_list { - unsigned char bank, instr; - awe_voice_info v; - struct _awe_voice_list *next_instr; - struct _awe_voice_list *next_bank; + int next; /* linked list with same sf_id */ + unsigned char bank, instr; /* preset number information */ + char type, disabled; /* type=normal/mapped, disabled=boolean */ + awe_voice_info v; /* voice information */ + int next_instr; /* preset table list */ + int next_bank; /* preset table list */ } awe_voice_list; +/* voice list type */ +#define V_ST_NORMAL 0 +#define V_ST_MAPPED 1 + +typedef struct _awe_sample_list { + int next; /* linked list with same sf_id */ + awe_sample_info v; /* sample information */ +} awe_sample_list; + /* sample and information table */ -static awe_sample_info *samples; -static awe_voice_list *infos; +static int current_sf_id = 0; +static int locked_sf_id = 0; +static int max_sfs; +static sf_list *sflists = NULL; + +#define awe_free_mem_ptr() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].mem_ptr) +#define awe_free_info() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_info) +#define awe_free_sample() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_sample) + +static int max_samples; +static awe_sample_list *samples = NULL; + +static int max_infos; +static awe_voice_list *infos = NULL; + #define AWE_MAX_PRESETS 256 +#define AWE_DEFAULT_PRESET 0 #define AWE_DEFAULT_BANK 0 +#define AWE_DEFAULT_DRUM 0 #define AWE_DRUM_BANK 128 +#define MAX_LAYERS AWE_MAX_VOICES + /* preset table index */ -static awe_voice_list *preset_table[AWE_MAX_PRESETS]; +static int preset_table[AWE_MAX_PRESETS]; /*---------------------------------------------------------------- * voice table *----------------------------------------------------------------*/ /* effects table */ -#define AWE_FX_NBYTES ((AWE_FX_END+7)/8) typedef struct FX_Rec { /* channel effects */ - unsigned char flags[AWE_FX_NBYTES]; + unsigned char flags[AWE_FX_END]; short val[AWE_FX_END]; } FX_Rec; /* channel parameters */ typedef struct _awe_chan_info { + int channel; /* channel number */ int bank; /* current tone bank */ int instr; /* current program */ int bender; /* midi pitchbend (-8192 - 8192) */ @@ -117,28 +168,35 @@ typedef struct _awe_chan_info { int panning; /* panning (0-127) */ int main_vol; /* channel volume (0-127) */ int expression_vol; /* midi expression (0-127) */ - awe_voice_list *vrec; /* instrument list */ - awe_voice_list *def_vrec; /* default instrument list */ - FX_Rec fx; /* effects */ + int chan_press; /* channel pressure */ + int vrec; /* instrument list */ + int def_vrec; /* default instrument list */ int sustained; /* sustain status in MIDI */ + FX_Rec fx; /* effects */ + FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */ } awe_chan_info; /* voice parameters */ typedef struct _voice_info { int state; -#define AWE_ST_OFF 0 /* no sound */ -#define AWE_ST_ON 1 /* playing */ -#define AWE_ST_STANDBY 2 /* stand by for playing */ -#define AWE_ST_SUSTAINED 3 /* sustained */ -#define AWE_ST_MARK 4 /* marked for allocation */ +#define AWE_ST_OFF (1<<0) /* no sound */ +#define AWE_ST_ON (1<<1) /* playing */ +#define AWE_ST_STANDBY (1<<2) /* stand by for playing */ +#define AWE_ST_SUSTAINED (1<<3) /* sustained */ +#define AWE_ST_MARK (1<<4) /* marked for allocation */ +#define AWE_ST_DRAM (1<<5) /* DRAM read/write */ +#define AWE_ST_FM (1<<6) /* reserved for FM */ +#define AWE_ST_RELEASED (1<<7) /* released */ int ch; /* midi channel */ int key; /* internal key for search */ + int layer; /* layer number (for channel mode only) */ int time; /* allocated time */ awe_chan_info *cinfo; /* channel info */ int note; /* midi key (0-127) */ int velocity; /* midi velocity (0-127) */ + int sostenuto; /* sostenuto on/off */ awe_voice_info *sample; /* assigned voice */ /* EMU8000 parameters */ @@ -148,58 +206,87 @@ typedef struct _voice_info { } voice_info; /* voice information */ -static voice_info voices[AWE_MAX_VOICES]; +static voice_info *voices; -#define IS_NO_SOUND(v) (voices[v].state == AWE_ST_OFF || voices[v].state == AWE_ST_STANDBY) +#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED)) #define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON) -#define IS_PLAYING(v) (!IS_NO_SOUND(v)) +#define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED)) +#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM)) /* MIDI channel effects information (for hw control) */ -#if AWE_MAX_CHANNELS < AWE_MAX_VOICES -static awe_chan_info channels[AWE_MAX_VOICES]; -#else -static awe_chan_info channels[AWE_MAX_CHANNELS]; -#endif +static awe_chan_info *channels; /*---------------------------------------------------------------- * global variables *----------------------------------------------------------------*/ +#ifndef AWE_DEFAULT_BASE_ADDR +#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */ +#endif + +#ifndef AWE_DEFAULT_MEM_SIZE +#define AWE_DEFAULT_MEM_SIZE 0 /* autodetect */ +#endif + /* awe32 base address (overwritten at initialization) */ -static int awe_base = 0; -/* memory byte size (overwritten at initialization) */ -static long awe_mem_size = 0; +static int awe_base = AWE_DEFAULT_BASE_ADDR; +/* memory byte size */ +static int awe_mem_size = AWE_DEFAULT_MEM_SIZE; +/* DRAM start offset */ +static int awe_mem_start = AWE_DRAM_OFFSET; /* maximum channels for playing */ static int awe_max_voices = AWE_MAX_VOICES; -static long free_mem_ptr = 0; /* free word byte size */ -static int free_info = 0; /* free info tables */ -static int last_info = 0; /* last loaded info index */ -static int free_sample = 0; /* free sample tables */ -static int last_sample = 0; /* last loaded sample index */ -static int loaded_once = 0; /* samples are loaded after init? */ -static unsigned short current_sf_id = 0; /* internal id */ +static int patch_opened = 0; /* sample already loaded? */ -static int reverb_mode = 0; /* reverb mode */ -static int chorus_mode = 0; /* chorus mode */ -static unsigned short init_atten = AWE_DEFAULT_ATTENUATION; /* 12dB below */ +static int reverb_mode = 4; /* reverb mode */ +static int chorus_mode = 2; /* chorus mode */ +static short init_atten = AWE_DEFAULT_ATTENUATION; /* 12dB below */ static int awe_present = FALSE; /* awe device present? */ static int awe_busy = FALSE; /* awe device opened? */ -#define DEFAULT_DRUM_FLAGS (1 << 9) -#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c))) -static unsigned long drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */ +static int my_dev = -1; +static int my_mixerdev = -1 ; -static int awe_channel_mode = 0; /* channel control mode */ +#define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25)) +#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c))) +#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c))) +#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c))) +static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */ + +static int playing_mode = AWE_PLAY_INDIRECT; +#define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT) +#define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2) + +static int current_alloc_time = 0; /* voice allocation index for channel mode */ + +static struct MiscModeDef { + int value; + int init_each_time; +} misc_modes_default[AWE_MD_END] = { + {0,0}, {0,0}, /* <-- not used */ + {AWE_VERSION_NUMBER, FALSE}, + {TRUE, TRUE}, /* exclusive */ + {TRUE, TRUE}, /* realpan */ + {AWE_DEFAULT_BANK, TRUE}, /* gusbank */ + {FALSE, TRUE}, /* keep effect */ + {AWE_DEFAULT_ATTENUATION, FALSE}, /* zero_atten */ + {FALSE, TRUE}, /* chn_prior */ + {AWE_DEFAULT_MOD_SENSE, TRUE}, /* modwheel sense */ + {AWE_DEFAULT_PRESET, TRUE}, /* def_preset */ + {AWE_DEFAULT_BANK, TRUE}, /* def_bank */ + {AWE_DEFAULT_DRUM, TRUE}, /* def_drum */ + {FALSE, TRUE}, /* toggle_drum_bank */ +}; -static int current_alloc_time = 0; /* voice allocation time */ +static int misc_modes[AWE_MD_END]; -static int awe_gus_bank = AWE_DEFAULT_BANK; /* GUS default bank number */ -static int awe_exclusive_sound = TRUE; /* exclusive sound on */ +static int awe_bass_level = 5; +static int awe_treble_level = 9; static struct synth_info awe_info = { @@ -230,15 +317,16 @@ static void awe_release_region(void); static void awe_reset_samples(void); /* emu8000 chip i/o access */ static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data); -static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned long data); +static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data); static unsigned short awe_peek(unsigned short cmd, unsigned short port); -static unsigned long awe_peek_dw(unsigned short cmd, unsigned short port); +static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port); static void awe_wait(unsigned short delay); /* initialize emu8000 chip */ static void awe_initialize(void); /* set voice parameters */ +static void awe_init_misc_modes(int init_all); static void awe_init_voice_info(awe_voice_info *vp); static void awe_init_voice_parm(awe_voice_parm *pp); #ifdef AWE_HAS_GUS_COMPATIBILITY @@ -255,7 +343,8 @@ static int calc_parm_search(int msec, short *table); static void awe_note_on(int voice); static void awe_note_off(int voice); static void awe_terminate(int voice); -static void awe_exclusive_off(int voice, int exclass); +static void awe_exclusive_off(int voice); +static void awe_note_off_all(int do_sustain); /* calculate voice parameters */ typedef void (*fx_affect_func)(int voice, int forced); @@ -267,13 +356,15 @@ static void awe_set_pan(int voice, int forced); static void awe_fx_fmmod(int voice, int forced); static void awe_fx_tremfrq(int voice, int forced); static void awe_fx_fm2frq2(int voice, int forced); -static void awe_fx_cutoff(int voice, int forced); +static void awe_fx_filterQ(int voice, int forced); static void awe_calc_pitch(int voice); #ifdef AWE_HAS_GUS_COMPATIBILITY static void awe_calc_pitch_from_freq(int voice, int freq); #endif static void awe_calc_volume(int voice); -static void awe_voice_init(int voice); +static void awe_voice_init(int voice, int init_all); +static void awe_channel_init(int ch, int init_all); +static void awe_fx_init(int ch); /* sequencer interface */ static int awe_open(int dev, int mode); @@ -304,25 +395,36 @@ static void awe_hw_gus_control(int dev, int cmd, unsigned char *event); #endif static void awe_hw_awe_control(int dev, int cmd, unsigned char *event); static void awe_voice_change(int voice, fx_affect_func func); +static void awe_sostenuto_on(int voice, int forced); static void awe_sustain_off(int voice, int forced); +static void awe_terminate_and_init(int voice, int forced); /* voice search */ -static awe_voice_list *awe_search_instr(int bank, int preset); -static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist); -static void awe_alloc_multi_voices(int ch, int note, int velocity); +static int awe_search_instr(int bank, int preset); +static int awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist); +static void awe_alloc_multi_voices(int ch, int note, int velocity, int key); static void awe_alloc_one_voice(int voice, int note, int velocity); static int awe_clear_voice(void); /* load / remove patches */ -static void awe_check_loaded(void); -static int awe_load_info(awe_patch_info *patch, const char *addr); -static int awe_load_data(awe_patch_info *patch, const char *addr); +static int awe_open_patch(awe_patch_info *patch, const char *addr, int count); +static int awe_close_patch(awe_patch_info *patch, const char *addr, int count); +static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count); +static int awe_load_info(awe_patch_info *patch, const char *addr, int count); +static int awe_load_data(awe_patch_info *patch, const char *addr, int count); +static int awe_replace_data(awe_patch_info *patch, const char *addr, int count); +static int awe_load_map(awe_patch_info *patch, const char *addr, int count); #ifdef AWE_HAS_GUS_COMPATIBILITY static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag); #endif -static int awe_write_wave_data(const char *addr, long offset, int size); -static awe_voice_list *awe_get_removed_list(awe_voice_list *curp); -static void awe_remove_samples(void); +static int check_patch_opened(int type, char *name); +static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels); +static void add_sf_info(int rec); +static void add_sf_sample(int rec); +static void purge_old_list(int rec, int next); +static void add_info_list(int rec); +static void awe_remove_samples(int sf_id); +static void rebuild_preset_list(void); static short awe_set_sample(awe_voice_info *vp); /* lowlevel functions */ @@ -333,89 +435,28 @@ static void awe_send_array(unsigned short *data); static void awe_tweak_voice(int voice); static void awe_tweak(void); static void awe_init_fm(void); -static int awe_open_dram_for_write(int offset); -static int awe_open_dram_for_read(int offset); +static int awe_open_dram_for_write(int offset, int channels); static void awe_open_dram_for_check(void); static void awe_close_dram(void); -static void awe_close_dram_for_read(void); static void awe_write_dram(unsigned short c); static int awe_detect_base(int addr); static int awe_detect(void); static int awe_check_dram(void); +static int awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count); static void awe_set_chorus_mode(int mode); +static int awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count); static void awe_set_reverb_mode(int mode); - -#ifdef AWE_OBSOLETE_VOXWARE - -#define awe_check_port() 0 /* always false */ -#define awe_request_region() /* nothing */ -#define awe_release_region() /* nothing */ - -#else /* AWE_OBSOLETE_VOXWARE */ - -/* the following macros are osbolete */ - -#define PERMANENT_MALLOC(type,var,size,memptr) \ - var = (type)(sound_mem_blocks[sound_nblocks++] = vmalloc(size)) -#define RET_ERROR(err) -err - -#endif /* AWE_OBSOLETE_VOXWARE */ - - -/* macros for Linux and FreeBSD compatibility */ - -#undef OUTW -#undef COPY_FROM_USER -#undef GET_BYTE_FROM_USER -#undef GET_SHORT_FROM_USER -#undef IOCTL_TO_USER - -#ifdef linux -# define NO_DATA_ERR ENODATA -# define OUTW(data, addr) outw(data, addr) - -#ifdef AWE_NEW_KERNEL_INTERFACE -# define COPY_FROM_USER(target, source, offs, count) \ - copy_from_user( ((caddr_t)(target)),(source)+(offs),(count) ) -# define GET_BYTE_FROM_USER(target, addr, offs) \ - get_user(target, (unsigned char*)&((addr)[offs])) -# define GET_SHORT_FROM_USER(target, addr, offs) \ - get_user(target, (unsigned short*)&((addr)[offs])) -# define IOCTL_TO_USER(target, offs, source, count) \ - copy_to_user ( ((caddr_t)(target)),(source)+(offs),(count) ) -#else /* AWE_NEW_KERNEL_INTERFACE */ -# define COPY_FROM_USER(target, source, offs, count) \ - memcpy_fromfs( ((caddr_t)(target)),(source)+(offs),(count) ) -# define GET_BYTE_FROM_USER(target, addr, offs) \ - *((char *)&(target)) = get_fs_byte( (addr)+(offs) ) -# define GET_SHORT_FROM_USER(target, addr, offs) \ - *((short *)&(target)) = get_fs_word( (addr)+(offs) ) -# define IOCTL_TO_USER(target, offs, source, count) \ - memcpy_tofs ( ((caddr_t)(target)),(source)+(offs),(count) ) -#endif /* AWE_NEW_KERNEL_INTERFACE */ - -# define BZERO(target,len) \ - memset( (caddr_t)target, '\0', len ) -# define MEMCPY(dst,src,len) \ - memcpy((caddr_t)dst, (caddr_t)src, len) - -#elif defined(__FreeBSD__) -# define NO_DATA_ERR EINVAL -# define OUTW(data, addr) outw(addr, data) -# define COPY_FROM_USER(target, source, offs, count) \ - uiomove( ((caddr_t)(target)),(count),((struct uio *)(source)) ) -# define GET_BYTE_FROM_USER(target, addr, offs) \ - uiomove( ((char*)&(target)), 1, ((struct uio *)(addr)) ) -# define GET_SHORT_FROM_USER(target, addr, offs) \ - uiomove( ((char*)&(target)), 2, ((struct uio *)(addr)) ) -# define IOCTL_TO_USER(target, offs, source, count) \ - memcpy( &((target)[offs]), (source), (count) ) -# define BZERO(target,len) \ - bzero( (caddr_t)target, len ) -# define MEMCPY(dst,src,len) \ - bcopy((caddr_t)src, (caddr_t)dst, len) +static void awe_equalizer(int bass, int treble); +#ifdef CONFIG_AWE32_MIXER +static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg); #endif +/* define macros for compatibility */ +#ifdef __FreeBSD__ +# include <i386/isa/sound/awe_compat.h> +#else +# include "awe_compat.h" +#endif /*---------------------------------------------------------------- * synth operation table @@ -423,7 +464,9 @@ static void awe_set_reverb_mode(int mode); static struct synth_operations awe_operations = { +#ifdef AWE_OSS38 "EMU8K", +#endif &awe_info, 0, SYNTH_TYPE_SAMPLE, @@ -449,6 +492,15 @@ static struct synth_operations awe_operations = awe_setup_voice }; +#ifdef CONFIG_AWE32_MIXER +static struct mixer_operations awe_mixer_operations = { +#ifndef __FreeBSD__ + "AWE32", +#endif + "AWE32 Equalizer", + awe_mixer_ioctl, +}; +#endif /*================================================================ @@ -456,10 +508,13 @@ static struct synth_operations awe_operations = *================================================================*/ #ifdef AWE_OBSOLETE_VOXWARE -long attach_awe_obsolete(long mem_start, struct address_info *hw_config) +#define ATTACH_DECL static #else -int attach_awe(void) +#define ATTACH_DECL /**/ #endif + +ATTACH_DECL +int attach_awe(void) { /* check presence of AWE32 card */ if (! awe_detect()) { @@ -473,24 +528,43 @@ int attach_awe(void) return 0; } - /* allocate sample tables */ - PERMANENT_MALLOC(awe_sample_info *, samples, - AWE_MAX_SAMPLES * AWE_SAMPLE_INFO_SIZE, mem_start); - PERMANENT_MALLOC(awe_voice_list *, infos, - AWE_MAX_INFOS * sizeof(awe_voice_list), mem_start); - if (samples == NULL || infos == NULL) { + /* set buffers to NULL */ + voices = NULL; + channels = NULL; + sflists = NULL; + samples = NULL; + infos = NULL; + + /* voice & channel info */ + voices = (voice_info*)my_malloc(AWE_MAX_VOICES * sizeof(voice_info)); + channels = (awe_chan_info*)my_malloc(AWE_MAX_CHANNELS * sizeof(awe_chan_info)); + + if (voices == NULL || channels == NULL) { + my_free(voices); + my_free(channels); printk("AWE32: can't allocate sample tables\n"); return 0; } - if (num_synths >= MAX_SYNTH_DEV) - printk("AWE32 Error: too many synthesizers\n"); + /* allocate sample tables */ + INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list); + INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list); + INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list); + + if (my_dev=sound_alloc_synthdev()) + printk(KERN_WARNING "AWE32 Error: too many synthesizers\n"); else { voice_alloc = &awe_operations.alloc; voice_alloc->max_voice = awe_max_voices; - synth_devs[num_synths++] = &awe_operations; + synth_devs[my_dev] = &awe_operations; } +#ifdef CONFIG_AWE32_MIXER + if (my_mixerdev=sound_alloc_mixerdev()) { + mixer_devs[my_mixerdev] = &awe_mixer_operations; + } +#endif + /* reserve I/O ports for awedrv */ awe_request_region(); @@ -500,15 +574,16 @@ int attach_awe(void) /* intialize AWE32 hardware */ awe_initialize(); -#ifndef __FreeBSD__ - printk("AWE32 Sound Driver v%s (DRAM %dk)\n", - AWEDRV_VERSION, (int)awe_mem_size/1024); -#else - DEBUG(0,printk("AWE32 Sound Driver v%s (DRAM %dk)\n", - AWEDRV_VERSION, (int)awe_mem_size/1024)); + sprintf(awe_info.name, "AWE32-%s (RAM%dk)", + AWEDRV_VERSION, awe_mem_size/1024); +#ifdef __FreeBSD__ + printk("awe0: <SoundBlaster EMU8000 MIDI (RAM%dk)>", awe_mem_size/1024); +#elif defined(AWE_DEBUG_ON) + printk("%s\n", awe_info.name); #endif - sprintf(awe_info.name, "AWE32 Driver v%s (DRAM %dk)", - AWEDRV_VERSION, (int)awe_mem_size/1024); + + /* set default values */ + awe_init_misc_modes(TRUE); /* set reverb & chorus modes */ awe_set_reverb_mode(reverb_mode); @@ -516,24 +591,59 @@ int attach_awe(void) awe_present = TRUE; -#ifdef AWE_OBSOLETE_VOXWARE - return mem_start; -#else return 1; -#endif } +#ifdef AWE_DYNAMIC_BUFFER +static void free_tables(void) +{ + my_free(sflists); + sflists = NULL; max_sfs = 0; + my_free(samples); + samples = NULL; max_samples = 0; + my_free(infos); + infos = NULL; max_infos = 0; +} +#else +#define free_buffers() /**/ +#endif + + +ATTACH_DECL void unload_awe(void) { if (awe_present) { awe_reset_samples(); awe_release_region(); + my_free(voices); + my_free(channels); + free_tables(); + sound_unload_mixerdev(my_mixerdev); + sound_unload_synthdev(my_dev); + awe_present = FALSE; } } +/*---------------------------------------------------------------- + * old type interface + *----------------------------------------------------------------*/ + #ifdef AWE_OBSOLETE_VOXWARE + +#ifdef __FreeBSD__ +long attach_awe_obsolete(long mem_start, struct address_info *hw_config) +#else +int attach_awe_obsolete(int mem_start, struct address_info *hw_config) +#endif +{ + my_malloc_init(mem_start); + if (! attach_awe()) + return 0; + return my_malloc_memptr(); +} + int probe_awe_obsolete(struct address_info *hw_config) { return 1; @@ -542,6 +652,7 @@ int probe_awe_obsolete(struct address_info *hw_config) #endif + /*================================================================ * clear sample tables *================================================================*/ @@ -552,15 +663,14 @@ awe_reset_samples(void) int i; /* free all bank tables */ - for (i = 0; i < AWE_MAX_PRESETS; i++) { - preset_table[i] = NULL; - } + for (i = 0; i < AWE_MAX_PRESETS; i++) + preset_table[i] = -1; + + free_tables(); - free_mem_ptr = 0; - last_sample = free_sample = 0; - last_info = free_info = 0; current_sf_id = 0; - loaded_once = 0; + locked_sf_id = 0; + patch_opened = 0; } @@ -584,7 +694,7 @@ awe_poke(unsigned short cmd, unsigned short port, unsigned short data) /* write 32bit data */ INLINE static void -awe_poke_dw(unsigned short cmd, unsigned short port, unsigned long data) +awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data) { awe_set_cmd(cmd); OUTW(data, awe_port(port)); /* write lower 16 bits */ @@ -602,10 +712,10 @@ awe_peek(unsigned short cmd, unsigned short port) } /* read 32bit data */ -INLINE static unsigned long +INLINE static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port) { - unsigned long k1, k2; + unsigned int k1, k2; awe_set_cmd(cmd); k1 = inw(awe_port(port)); k2 = inw(awe_port(port)+2); @@ -636,6 +746,13 @@ awe_wait(unsigned short delay) break; } +/* write a word data */ +INLINE static void +awe_write_dram(unsigned short c) +{ + awe_poke(AWE_SMLD, c); +} + #ifndef AWE_OBSOLETE_VOXWARE @@ -706,6 +823,9 @@ awe_initialize(void) /* enable audio */ awe_poke(AWE_HWCF3, 0x0004); + + /* set equalizer */ + awe_equalizer(5, 9); } @@ -717,7 +837,7 @@ awe_initialize(void) static void awe_init_voice_info(awe_voice_info *vp) { - vp->sf_id = 0; + vp->sf_id = 0; /* normal mode */ vp->sample = 0; vp->rate_offset = 0; @@ -792,10 +912,10 @@ static int freq_to_note(int mHz) { /* abscents = log(mHz/8176) / log(2) * 1200 */ - unsigned long max_val = (unsigned long)0xffffffff / 10000; + unsigned int max_val = (unsigned int)0xffffffff / 10000; int i, times; - unsigned long base; - unsigned long freq; + unsigned int base; + unsigned int freq; int note, tune; if (mHz == 0) @@ -913,7 +1033,7 @@ calc_parm_delay(int msec) static int calc_parm_hold(int msec) { - int val = 0x7f - (unsigned char)(msec / 92); + int val = (0x7f * 92 - msec) / 92; if (val < 1) val = 1; if (val > 127) val = 127; return val; @@ -955,46 +1075,137 @@ calc_parm_search(int msec, short *table) *================================================================*/ /* set an effect value */ +#define FX_FLAG_OFF 0 +#define FX_FLAG_SET 1 +#define FX_FLAG_ADD 2 + #define FX_SET(rec,type,value) \ - ((rec)->flags[(type)/8] |= (1 << ((type) % 8)), \ - (rec)->val[type] = (value)) + ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value)) +#define FX_ADD(rec,type,value) \ + ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value)) +#define FX_UNSET(rec,type) \ + ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0) /* check the effect value is set */ -#define FX_ON(rec,type) ((rec)->flags[(type)/8] & (1<<((type)%8))) +#define FX_ON(rec,type) ((rec)->flags[type]) + +#define PARM_BYTE 0 +#define PARM_WORD 1 + +static struct PARM_DEFS { + int type; /* byte or word */ + int low, high; /* value range */ + fx_affect_func realtime; /* realtime paramater change */ +} parm_defs[] = { + {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */ + {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */ + {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */ + {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */ + {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */ + + {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */ + {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */ + {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */ + + {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */ + {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */ + {PARM_BYTE, 0, 0x7f, awe_fx_tremfrq}, /* lfo1 volume (positive only)*/ + {PARM_BYTE, 0, 0x7f, awe_fx_fmmod}, /* lfo1 pitch (positive only)*/ + {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff (positive only)*/ + + {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */ + {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */ + {PARM_BYTE, 0, 0x7f, awe_fx_fm2frq2}, /* lfo2 pitch (positive only)*/ + + {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */ + {PARM_BYTE, 0, 0xff, NULL}, /* chorus */ + {PARM_BYTE, 0, 0xff, NULL}, /* reverb */ + {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */ + {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */ + + {PARM_WORD, 0, 0xffff, NULL}, /* sample start */ + {PARM_WORD, 0, 0xffff, NULL}, /* loop start */ + {PARM_WORD, 0, 0xffff, NULL}, /* loop end */ + {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */ + {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */ + {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */ + {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */ +}; + + +static unsigned char +FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value) +{ + int effect = 0; + int on = 0; + if (lay && (on = FX_ON(lay, type)) != 0) + effect = lay->val[type]; + if (!on && (on = FX_ON(rec, type)) != 0) + effect = rec->val[type]; + if (on == FX_FLAG_ADD) + effect += (int)value; + if (on) { + if (effect < parm_defs[type].low) + effect = parm_defs[type].low; + else if (effect > parm_defs[type].high) + effect = parm_defs[type].high; + return (unsigned char)effect; + } + return value; +} -/* get byte effect value */ -#define FX_BYTE(rec,type,value) \ - (unsigned char)(FX_ON(rec,type) ? (rec)->val[type] : (value)) /* get word effect value */ -#define FX_WORD(rec,type,value) \ - (unsigned short)(FX_ON(rec,type) ? (rec)->val[type] : (value)) +static unsigned short +FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value) +{ + int effect = 0; + int on = 0; + if (lay && (on = FX_ON(lay, type)) != 0) + effect = lay->val[type]; + if (!on && (on = FX_ON(rec, type)) != 0) + effect = rec->val[type]; + if (on == FX_FLAG_ADD) + effect += (int)value; + if (on) { + if (effect < parm_defs[type].low) + effect = parm_defs[type].low; + else if (effect > parm_defs[type].high) + effect = parm_defs[type].high; + return (unsigned short)effect; + } + return value; +} /* get word (upper=type1/lower=type2) effect value */ static unsigned short -FX_COMB(FX_Rec *rec, int type1, int type2, unsigned short value) +FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value) { unsigned short tmp; - if (FX_ON(rec, type1)) - tmp = (unsigned short)(rec->val[type1]) << 8; - else - tmp = value & 0xff00; - if (FX_ON(rec, type2)) - tmp |= (unsigned short)(rec->val[type2]) & 0xff; - else - tmp |= value & 0xff; + tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8)); + tmp <<= 8; + tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff)); return tmp; } /* address offset */ -static long -FX_OFFSET(FX_Rec *rec, int lo, int hi, int mode) +static int +FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode) { - long addr = 0; - if (FX_ON(rec, hi)) { + int addr = 0; + if (lay && FX_ON(lay, hi)) + addr = (short)lay->val[hi]; + else if (FX_ON(rec, hi)) addr = (short)rec->val[hi]; - addr = addr << 15; - } - if (FX_ON(rec, lo)) + addr = addr << 15; + if (lay && FX_ON(lay, lo)) + addr += (short)lay->val[lo]; + else if (FX_ON(rec, lo)) addr += (short)rec->val[lo]; if (!(mode & AWE_SAMPLE_8BITS)) addr /= 2; @@ -1009,10 +1220,13 @@ FX_OFFSET(FX_Rec *rec, int lo, int hi, int mode) static void awe_note_on(int voice) { - unsigned long temp; - long addr; + unsigned int temp; + int addr; awe_voice_info *vp; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; /* A voice sample must assigned before calling */ if ((vp = voices[voice].sample) == NULL || vp->index < 0) @@ -1027,17 +1241,17 @@ awe_note_on(int voice) /* modulation & volume envelope */ awe_poke(AWE_ENVVAL(voice), - FX_WORD(fx, AWE_FX_ENV1_DELAY, vp->parm.moddelay)); + FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, vp->parm.moddelay)); awe_poke(AWE_ATKHLD(voice), - FX_COMB(fx, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK, + FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK, vp->parm.modatkhld)); awe_poke(AWE_DCYSUS(voice), - FX_COMB(fx, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY, + FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY, vp->parm.moddcysus)); awe_poke(AWE_ENVVOL(voice), - FX_WORD(fx, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); + FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); awe_poke(AWE_ATKHLDV(voice), - FX_COMB(fx, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK, + FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK, vp->parm.volatkhld)); /* decay/sustain parameter for volume envelope must be set at last */ @@ -1049,14 +1263,14 @@ awe_note_on(int voice) /* modulation envelope heights */ awe_poke(AWE_PEFE(voice), - FX_COMB(fx, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF, + FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF, vp->parm.pefe)); /* lfo1/2 delay */ awe_poke(AWE_LFO1VAL(voice), - FX_WORD(fx, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay)); + FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay)); awe_poke(AWE_LFO2VAL(voice), - FX_WORD(fx, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay)); + FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay)); /* lfo1 pitch & cutoff shift */ awe_fx_fmmod(voice, TRUE); @@ -1065,27 +1279,25 @@ awe_note_on(int voice) /* lfo2 pitch & freq */ awe_fx_fm2frq2(voice, TRUE); /* pan & loop start */ - awe_set_pan(voice, 1); + awe_set_pan(voice, TRUE); /* chorus & loop end (chorus 8bit, MSB) */ addr = vp->loopend - 1; - addr += FX_OFFSET(fx, AWE_FX_LOOP_END, + addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END, AWE_FX_COARSE_LOOP_END, vp->mode); - temp = FX_BYTE(fx, AWE_FX_CHORUS, vp->parm.chorus); - temp = (temp <<24) | (unsigned long)addr; + temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus); + temp = (temp <<24) | (unsigned int)addr; awe_poke_dw(AWE_CSL(voice), temp); - DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", - (int)vp->loopend, (int)addr)); + DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr)); /* Q & current address (Q 4bit value, MSB) */ addr = vp->start - 1; - addr += FX_OFFSET(fx, AWE_FX_SAMPLE_START, + addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START, AWE_FX_COARSE_SAMPLE_START, vp->mode); - temp = FX_BYTE(fx, AWE_FX_FILTERQ, vp->parm.filterQ); - temp = (temp<<28) | (unsigned long)addr; + temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ); + temp = (temp<<28) | (unsigned int)addr; awe_poke_dw(AWE_CCCA(voice), temp); - DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", - (int)vp->start, (int)addr)); + DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr)); /* reset volume */ awe_poke_dw(AWE_VTFT(voice), 0x0000FFFF); @@ -1093,13 +1305,21 @@ awe_note_on(int voice) /* turn on envelope */ awe_poke(AWE_DCYSUSV(voice), - FX_COMB(fx, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, + FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, vp->parm.voldcysus)); - /* set chorus */ - temp = FX_BYTE(fx, AWE_FX_REVERB, vp->parm.reverb); + /* set reverb */ + temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb); temp = (awe_peek_dw(AWE_PTRX(voice)) & 0xffff0000) | (temp<<8); awe_poke_dw(AWE_PTRX(voice), temp); awe_poke_dw(AWE_CPF(voice), 0x40000000); + + voices[voice].state = AWE_ST_ON; + + /* clear voice position for the next note on this channel */ + if (SINGLE_LAYER_MODE()) { + FX_UNSET(fx, AWE_FX_SAMPLE_START); + FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START); + } } @@ -1110,24 +1330,22 @@ awe_note_off(int voice) awe_voice_info *vp; unsigned short tmp; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + if ((vp = voices[voice].sample) == NULL) { - awe_voice_init(voice); + voices[voice].state = AWE_ST_OFF; return; } - if (FX_ON(fx, AWE_FX_ENV1_RELEASE)) - tmp = 0x8000 | fx->val[AWE_FX_ENV1_RELEASE]; - else - tmp = vp->parm.modrelease; + tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE, + (unsigned char)vp->parm.modrelease); awe_poke(AWE_DCYSUS(voice), tmp); - if (FX_ON(fx, AWE_FX_ENV2_RELEASE)) - tmp = 0x8000 | fx->val[AWE_FX_ENV2_RELEASE]; - else - tmp = vp->parm.volrelease; + tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE, + (unsigned char)vp->parm.volrelease); awe_poke(AWE_DCYSUSV(voice), tmp); - voices[voice].state = AWE_ST_OFF; - - awe_voice_init(voice); + voices[voice].state = AWE_ST_RELEASED; } /* force to terminate the voice (no releasing echo) */ @@ -1136,26 +1354,28 @@ awe_terminate(int voice) { awe_poke(AWE_DCYSUSV(voice), 0x807F); awe_tweak_voice(voice); - awe_voice_init(voice); + voices[voice].state = AWE_ST_OFF; } - /* turn off other voices with the same exclusive class (for drums) */ static void -awe_exclusive_off(int voice, int exclass) +awe_exclusive_off(int voice) { - int i; + int i, exclass; - if (exclass == 0) /* not exclusive */ + if (voices[voice].sample == NULL) return; + if ((exclass = voices[voice].sample->exclusiveClass) == 0) + return; /* not exclusive */ /* turn off voices with the same class */ for (i = 0; i < awe_max_voices; i++) { - if (i != voice && IS_PLAYING(voice) && - voices[i].sample && + if (i != voice && IS_PLAYING(i) && + voices[i].sample && voices[i].ch == voices[voice].ch && voices[i].sample->exclusiveClass == exclass) { DEBUG(4,printk("AWE32: [exoff(%d)]\n", i)); - awe_note_off(i); + awe_terminate(i); + awe_voice_init(i, TRUE); } } } @@ -1182,20 +1402,25 @@ awe_set_voice_pitch(int voice, int forced) awe_set_pitch(voice, forced); } -/* change volume */ +/* change volume & cutoff */ static void awe_set_volume(int voice, int forced) { awe_voice_info *vp; unsigned short tmp2; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - if (IS_NO_EFFECT(voice) && !forced) return; + if (!IS_PLAYING(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; - tmp2 = FX_BYTE(fx, AWE_FX_CUTOFF, vp->parm.cutoff); - tmp2 = (tmp2 << 8) | voices[voice].avol; + tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF, vp->parm.cutoff); + tmp2 = (tmp2 << 8); + tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN, + (unsigned char)voices[voice].avol); awe_poke(AWE_IFATN(voice), tmp2); } @@ -1203,6 +1428,8 @@ awe_set_volume(int voice, int forced) static void awe_set_voice_vol(int voice, int forced) { + if (IS_EMPTY(voice)) + return; awe_calc_volume(voice); awe_set_volume(voice, forced); } @@ -1212,10 +1439,13 @@ awe_set_voice_vol(int voice, int forced) static void awe_set_pan(int voice, int forced) { - unsigned long temp; - long addr; + unsigned int temp; + int addr; awe_voice_info *vp; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (IS_NO_EFFECT(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) @@ -1239,13 +1469,12 @@ awe_set_pan(int voice, int forced) } if (forced || temp != voices[voice].apan) { addr = vp->loopstart - 1; - addr += FX_OFFSET(fx, AWE_FX_LOOP_START, + addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START, AWE_FX_COARSE_LOOP_START, vp->mode); - temp = (temp<<24) | (unsigned long)addr; + temp = (temp<<24) | (unsigned int)addr; awe_poke_dw(AWE_PSST(voice), temp); voices[voice].apan = temp; - DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", - (int)vp->loopstart, (int)addr)); + DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr)); } } @@ -1255,11 +1484,15 @@ awe_fx_fmmod(int voice, int forced) { awe_voice_info *vp; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + if (IS_NO_EFFECT(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; awe_poke(AWE_FMMOD(voice), - FX_COMB(fx, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, + FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, vp->parm.fmmod)); } @@ -1269,11 +1502,15 @@ awe_fx_tremfrq(int voice, int forced) { awe_voice_info *vp; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + if (IS_NO_EFFECT(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; awe_poke(AWE_TREMFRQ(voice), - FX_COMB(fx, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, + FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, vp->parm.tremfrq)); } @@ -1283,29 +1520,38 @@ awe_fx_fm2frq2(int voice, int forced) { awe_voice_info *vp; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + if (IS_NO_EFFECT(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; awe_poke(AWE_FM2FRQ2(voice), - FX_COMB(fx, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, + FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, vp->parm.fm2frq2)); } -/* set total cutoff & current pitch */ + +/* Q & current address (Q 4bit value, MSB) */ static void -awe_fx_cutoff(int voice, int forced) +awe_fx_filterQ(int voice, int forced) { - unsigned short tmp2; + unsigned int addr; awe_voice_info *vp; FX_Rec *fx = &voices[voice].cinfo->fx; - if (IS_NO_EFFECT(voice)) return; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + + if (IS_NO_EFFECT(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; - tmp2 = FX_BYTE(fx, AWE_FX_CUTOFF, vp->parm.cutoff); - tmp2 = (tmp2 << 8) | voices[voice].avol; - awe_poke(AWE_IFATN(voice), tmp2); -} + addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff; + addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28); + awe_poke_dw(AWE_CCCA(voice), addr); +} /*================================================================ * calculate pitch offset @@ -1326,6 +1572,7 @@ awe_calc_pitch(int voice) if ((ap = vp->sample) == NULL) return; if (ap->index < 0) { + DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); if (awe_set_sample(ap) < 0) return; } @@ -1339,6 +1586,8 @@ awe_calc_pitch(int voice) offset = (vp->note - ap->root) * 4096 / 12; DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset)); } + offset = (offset * ap->scaleTuning) / 100; + DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); offset += ap->tune * 4096 / 1200; DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset)); if (cp->bender != 0) { @@ -1346,14 +1595,12 @@ awe_calc_pitch(int voice) /* (819200: 1 semitone) ==> (4096: 12 semitones) */ offset += cp->bender * cp->bender_range / 2400; } - offset = (offset * ap->scaleTuning) / 100; - DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); /* add initial pitch correction */ - if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH)) { - DEBUG(3,printk("AWE32: fx_pitch(%d) %d\n", voice, cp->fx.val[AWE_FX_INIT_PITCH])); + if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH)) + offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH]; + else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH)) offset += cp->fx.val[AWE_FX_INIT_PITCH]; - } /* 0xe000: root pitch */ vp->apitch = 0xe000 + ap->rate_offset + offset; @@ -1373,20 +1620,27 @@ awe_calc_pitch_from_freq(int voice, int freq) voice_info *vp = &voices[voice]; awe_voice_info *ap; FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; int offset; int note; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + /* search voice information */ if ((ap = vp->sample) == NULL) return; if (ap->index < 0) { + DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); if (awe_set_sample(ap) < 0) return; } note = freq_to_note(freq); offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200; offset = (offset * ap->scaleTuning) / 100; - if (FX_ON(fx, AWE_FX_INIT_PITCH)) + if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH)) + offset += fx_lay->val[AWE_FX_INIT_PITCH]; + else if (FX_ON(fx, AWE_FX_INIT_PITCH)) offset += fx->val[AWE_FX_INIT_PITCH]; vp->apitch = 0xe000 + ap->rate_offset + offset; if (vp->apitch > 0xffff) @@ -1430,6 +1684,7 @@ awe_calc_volume(int voice) ap = vp->sample; if (ap->index < 0) { + DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); if (awe_set_sample(ap) < 0) return; } @@ -1437,6 +1692,7 @@ awe_calc_volume(int voice) /* 0 - 127 */ vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127); vol = vol * ap->amplitude / 127; + if (vol < 0) vol = 0; if (vol > 127) vol = 127; @@ -1450,56 +1706,138 @@ awe_calc_volume(int voice) } +/* set sostenuto on */ +static void awe_sostenuto_on(int voice, int forced) +{ + if (IS_NO_EFFECT(voice) && !forced) return; + voices[voice].sostenuto = 127; +} + + +/* drop sustain */ +static void awe_sustain_off(int voice, int forced) +{ + if (voices[voice].state == AWE_ST_SUSTAINED) { + awe_note_off(voice); + awe_fx_init(voices[voice].ch); + awe_voice_init(voice, FALSE); + } +} + + +/* terminate and initialize voice */ +static void awe_terminate_and_init(int voice, int forced) +{ + awe_terminate(voice); + awe_fx_init(voices[voice].ch); + awe_voice_init(voice, TRUE); +} + + /*================================================================ * synth operation routines *================================================================*/ #define AWE_VOICE_KEY(v) (0x8000 | (v)) #define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1)) +#define KEY_CHAN_MATCH(key,c) (((key) >> 8) == (c)) /* initialize the voice */ static void -awe_voice_init(int voice) +awe_voice_init(int voice, int init_all) { - voices[voice].note = -1; - voices[voice].velocity = 0; - voices[voice].sample = NULL; - voices[voice].state = AWE_ST_OFF; - voices[voice].cinfo = &channels[voice]; - voices[voice].ch = -1; - voices[voice].key = AWE_VOICE_KEY(voice); - voices[voice].time = current_alloc_time; + voice_info *vp = &voices[voice]; + + /* reset voice search key */ + if (playing_mode == AWE_PLAY_DIRECT) + vp->key = AWE_VOICE_KEY(voice); + else + vp->key = 0; /* clear voice mapping */ voice_alloc->map[voice] = 0; - /* emu8000 parameters */ - voices[voice].apitch = 0; - voices[voice].avol = 255; - voices[voice].apan = -1; + /* touch the timing flag */ + vp->time = current_alloc_time; - /* clear effects */ - if (! awe_channel_mode) - BZERO(&voices[voice].cinfo->fx, sizeof(FX_Rec)); + /* initialize other parameters if necessary */ + if (init_all) { + vp->note = -1; + vp->velocity = 0; + vp->sostenuto = 0; + + vp->sample = NULL; + vp->cinfo = &channels[voice]; + vp->ch = voice; + vp->state = AWE_ST_OFF; + + /* emu8000 parameters */ + vp->apitch = 0; + vp->avol = 255; + vp->apan = -1; + } +} + +/* clear effects */ +static void awe_fx_init(int ch) +{ + if (SINGLE_LAYER_MODE() && !misc_modes[AWE_MD_KEEP_EFFECT]) { + BZERO(&channels[ch].fx, sizeof(channels[ch].fx)); + BZERO(&channels[ch].fx_layer, sizeof(&channels[ch].fx_layer)); + } } /* initialize channel info */ -static void awe_channel_init(int ch) -{ - channels[ch].panning = 0; /* zero center */ - channels[ch].bender = 0; /* zero tune skew */ - channels[ch].bender_range = 200; /* sense * 100 */ - channels[ch].main_vol = 127; - channels[ch].expression_vol = 127; - if (awe_channel_mode && IS_DRUM_CHANNEL(ch)) - channels[ch].bank = AWE_DRUM_BANK; - else - channels[ch].bank = AWE_DEFAULT_BANK; - channels[ch].instr = 0; - channels[ch].vrec = NULL; - channels[ch].def_vrec = NULL; - channels[ch].sustained = 0; - BZERO(&channels[ch].fx, sizeof(FX_Rec)); +static void awe_channel_init(int ch, int init_all) +{ + awe_chan_info *cp = &channels[ch]; + cp->channel = ch; + if (init_all) { + cp->panning = 0; /* zero center */ + cp->bender_range = 200; /* sense * 100 */ + cp->main_vol = 127; + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) { + cp->instr = misc_modes[AWE_MD_DEF_DRUM]; + cp->bank = AWE_DRUM_BANK; + } else { + cp->instr = misc_modes[AWE_MD_DEF_PRESET]; + cp->bank = misc_modes[AWE_MD_DEF_BANK]; + } + cp->vrec = -1; + cp->def_vrec = -1; + } + + cp->bender = 0; /* zero tune skew */ + cp->expression_vol = 127; + cp->chan_press = 0; + cp->sustained = 0; + + if (! misc_modes[AWE_MD_KEEP_EFFECT]) { + BZERO(&cp->fx, sizeof(cp->fx)); + BZERO(&cp->fx_layer, sizeof(cp->fx_layer)); + } +} + + +/* change the voice parameters; voice = channel */ +static void awe_voice_change(int voice, fx_affect_func func) +{ + int i; + switch (playing_mode) { + case AWE_PLAY_DIRECT: + func(voice, FALSE); + break; + case AWE_PLAY_INDIRECT: + for (i = 0; i < awe_max_voices; i++) + if (voices[i].key == AWE_VOICE_KEY(voice)) + func(i, FALSE); + break; + default: + for (i = 0; i < awe_max_voices; i++) + if (KEY_CHAN_MATCH(voices[i].key, voice)) + func(i, FALSE); + break; + } } @@ -1517,17 +1855,17 @@ awe_open(int dev, int mode) return RET_ERROR(EBUSY); awe_busy = TRUE; - awe_reset(dev); - - /* clear sample position flag */ - loaded_once = 0; /* set default mode */ - init_atten = AWE_DEFAULT_ATTENUATION; /* 12dB below */ - awe_gus_bank = AWE_DEFAULT_BANK; + awe_init_misc_modes(FALSE); + init_atten = misc_modes[AWE_MD_ZERO_ATTEN]; drum_flags = DEFAULT_DRUM_FLAGS; - awe_exclusive_sound = TRUE; - awe_channel_mode = 0; + playing_mode = AWE_PLAY_INDIRECT; + + /* reset voices & channels */ + awe_reset(dev); + + patch_opened = 0; return 0; } @@ -1544,6 +1882,19 @@ awe_close(int dev) } +/* set miscellaneous mode parameters + */ +static void +awe_init_misc_modes(int init_all) +{ + int i; + for (i = 0; i < AWE_MD_END; i++) { + if (init_all || misc_modes_default[i].init_each_time) + misc_modes[i] = misc_modes_default[i].value; + } +} + + /* sequencer I/O control: */ static int @@ -1551,7 +1902,10 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg) { switch (cmd) { case SNDCTL_SYNTH_INFO: - awe_info.nr_voices = awe_max_voices; + if (playing_mode == AWE_PLAY_DIRECT) + awe_info.nr_voices = awe_max_voices; + else + awe_info.nr_voices = AWE_MAX_CHANNELS; IOCTL_TO_USER((char*)arg, 0, &awe_info, sizeof(awe_info)); return 0; break; @@ -1568,62 +1922,107 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg) break; case SNDCTL_SYNTH_MEMAVL: - DEBUG(0,printk("AWE32: [ioctl memavl = %d]\n", (int)free_mem_ptr)); - return awe_mem_size - free_mem_ptr*2; + return awe_mem_size - awe_free_mem_ptr() * 2; default: - ERRMSG(printk("AWE32: unsupported ioctl %d\n", cmd)); + printk("AWE32: unsupported ioctl %d\n", cmd); return RET_ERROR(EINVAL); } } +static int voice_in_range(int voice) +{ + if (playing_mode == AWE_PLAY_DIRECT) { + if (voice < 0 || voice >= awe_max_voices) + return FALSE; + } else { + if (voice < 0 || voice >= AWE_MAX_CHANNELS) + return FALSE; + } + return TRUE; +} + +static void release_voice(int voice, int do_sustain) +{ + if (IS_NO_SOUND(voice)) + return; + if (do_sustain && (voices[voice].cinfo->sustained == 127 || + voices[voice].sostenuto == 127)) + voices[voice].state = AWE_ST_SUSTAINED; + else { + awe_note_off(voice); + awe_fx_init(voices[voice].ch); + awe_voice_init(voice, FALSE); + } +} + +/* release all notes */ +static void awe_note_off_all(int do_sustain) +{ + int i; + for (i = 0; i < awe_max_voices; i++) + release_voice(i, do_sustain); +} + /* kill a voice: * not terminate, just release the voice. */ static int awe_kill_note(int dev, int voice, int note, int velocity) { - int i, key, besttime; + int i, v2, key; DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity)); - if (awe_channel_mode) { - if (awe_channel_mode == 2) { /* get channel */ - int v2 = voice_alloc->map[voice] >> 8; - voice_alloc->map[voice] = 0; - voice = v2; - } + if (! voice_in_range(voice)) + return RET_ERROR(EINVAL); + + switch (playing_mode) { + case AWE_PLAY_DIRECT: + case AWE_PLAY_INDIRECT: + key = AWE_VOICE_KEY(voice); + break; + + case AWE_PLAY_MULTI2: + v2 = voice_alloc->map[voice] >> 8; + voice_alloc->map[voice] = 0; + voice = v2; if (voice < 0 || voice >= AWE_MAX_CHANNELS) return RET_ERROR(EINVAL); - if (channels[voice].instr > 128) - note = channels[voice].instr - 128; + /* continue to below */ + default: key = AWE_CHAN_KEY(voice, note); - } else { - if (voice < 0 || voice >= awe_max_voices) - return RET_ERROR(EINVAL); - key = AWE_VOICE_KEY(voice); + break; } - besttime = current_alloc_time + 1; for (i = 0; i < awe_max_voices; i++) { - if (voices[i].key == key) { - if (voices[i].time < besttime) - besttime = voices[i].time; - } - } - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].key == key && - (!awe_exclusive_sound || voices[i].time == besttime)) { - if (voices[i].cinfo->sustained) - voices[i].state = AWE_ST_SUSTAINED; - else - awe_note_off(i); - } + if (voices[i].key == key) + release_voice(i, TRUE); } return 0; } +static void start_or_volume_change(int voice, int velocity) +{ + voices[voice].velocity = velocity; + awe_calc_volume(voice); + if (voices[voice].state == AWE_ST_STANDBY) + awe_note_on(voice); + else if (voices[voice].state == AWE_ST_ON) + awe_set_volume(voice, FALSE); +} + +static void set_and_start_voice(int voice, int state) +{ + /* calculate pitch & volume parameters */ + voices[voice].state = state; + awe_calc_pitch(voice); + awe_calc_volume(voice); + if (state == AWE_ST_ON) + awe_note_on(voice); +} + /* start a voice: * if note is 255, identical with aftertouch function. * Otherwise, start a voice with specified not and volume. @@ -1634,107 +2033,88 @@ awe_start_note(int dev, int voice, int note, int velocity) int i, key, state, volonly; DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity)); - volonly = 0; - if (awe_channel_mode) { - if (awe_channel_mode == 2) /* get channel */ - voice = voice_alloc->map[voice] >> 8; - else if (voice & 0x80) { /* channel volume mode */ - voice &= ~0x80; - volonly = 2; - } + if (! voice_in_range(voice)) + return RET_ERROR(EINVAL); + + if (velocity == 0) + state = AWE_ST_STANDBY; /* stand by for playing */ + else + state = AWE_ST_ON; /* really play */ + volonly = FALSE; + + switch (playing_mode) { + case AWE_PLAY_DIRECT: + case AWE_PLAY_INDIRECT: + key = AWE_VOICE_KEY(voice); + if (note == 255) + volonly = TRUE; + break; + + case AWE_PLAY_MULTI2: + voice = voice_alloc->map[voice] >> 8; if (voice < 0 || voice >= AWE_MAX_CHANNELS) return RET_ERROR(EINVAL); - if (channels[voice].instr > 128) - note = channels[voice].instr - 128; + /* continue to below */ + default: if (note >= 128) { /* key volume mode */ note -= 128; - volonly = 1; + volonly = TRUE; } key = AWE_CHAN_KEY(voice, note); - } else { - if (voice < 0 || voice >= awe_max_voices) - return RET_ERROR(EINVAL); - if (voices[voice].cinfo->instr > 128) - note = voices[voice].cinfo->instr - 128; - key = AWE_VOICE_KEY(voice); - if (note == 255) - volonly = 1; + break; } /* dynamic volume change */ if (volonly) { for (i = 0; i < awe_max_voices; i++) { - if ((volonly == 2 && voices[i].ch == voice) || - voices[i].key == key) { - voices[i].velocity = velocity; - if (velocity == 0) /* for GUS compatibility */ - return awe_kill_note(dev, voice, note, velocity); - awe_calc_volume(i); - state = voices[i].state; - voices[i].state = AWE_ST_ON; - if (state == AWE_ST_STANDBY) - awe_note_on(i); - else - awe_set_volume(i, FALSE); - } + if (voices[i].key == key) + start_or_volume_change(i, velocity); } return 0; } - /* stop the sound if still playing */ - if (awe_exclusive_sound) { - for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == key && - voices[i].state != AWE_ST_OFF) + /* if the same note still playing, stop it */ + for (i = 0; i < awe_max_voices; i++) + if (voices[i].key == key) { + if (voices[i].state == AWE_ST_ON) { awe_note_off(i); - } + awe_voice_init(i, FALSE); + } else if (voices[i].state == AWE_ST_STANDBY) + awe_voice_init(i, TRUE); + } /* allocate voices */ - if (awe_channel_mode) - awe_alloc_multi_voices(voice, note, velocity); - else + if (playing_mode == AWE_PLAY_DIRECT) awe_alloc_one_voice(voice, note, velocity); + else + awe_alloc_multi_voices(voice, note, velocity, key); - /* turn off other voices (for drums) */ + /* turn off other voices exlusively (for drums) */ for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == key && voices[i].sample) - awe_exclusive_off(i, voices[i].sample->exclusiveClass); - - if (velocity == 0) - state = AWE_ST_STANDBY; /* stand by for playing */ - else - state = AWE_ST_ON; /* really play */ + if (voices[i].key == key) + awe_exclusive_off(i); /* set up pitch and volume parameters */ - for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == key) { - /* calculate pitch & volume parameters */ - voices[i].state = state; - voices[i].note = note; - voices[i].velocity = velocity; - awe_calc_pitch(i); - awe_calc_volume(i); - if (state == AWE_ST_ON) - awe_note_on(i); - } + for (i = 0; i < awe_max_voices; i++) { + if (voices[i].key == key && voices[i].state == AWE_ST_OFF) + set_and_start_voice(i, state); + } return 0; } /* search instrument from preset table with the specified bank */ -static awe_voice_list * +static int awe_search_instr(int bank, int preset) { - awe_voice_list *p; - int maxc; + int i; - for (maxc = AWE_MAX_INFOS, p = preset_table[preset]; - p && maxc; p = p->next_bank, maxc--) { - if (p->bank == bank) - return p; + for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) { + if (infos[i].bank == bank) + return i; } - return NULL; + return -1; } @@ -1742,53 +2122,44 @@ awe_search_instr(int bank, int preset) static int awe_set_instr_2(int dev, int voice, int instr_no) { - if (awe_channel_mode == 2) + if (playing_mode == AWE_PLAY_MULTI2) { voice = voice_alloc->map[voice] >> 8; + if (voice < 0 || voice >= AWE_MAX_CHANNELS) + return RET_ERROR(EINVAL); + } return awe_set_instr(dev, voice, instr_no); } -/* assign the instrument to a voice */ +/* assign the instrument to a channel; voice is the channel number */ static int awe_set_instr(int dev, int voice, int instr_no) { awe_chan_info *cinfo; int def_bank; - if (awe_channel_mode) { - /* skip the percussion instr in SEQ2 mode */ - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return RET_ERROR(EINVAL); - cinfo = &channels[voice]; - if (IS_DRUM_CHANNEL(voice)) - def_bank = AWE_DRUM_BANK; - else - def_bank = cinfo->bank; - } else { - if (voice < 0 || voice >= awe_max_voices) - return RET_ERROR(EINVAL); - cinfo = voices[voice].cinfo; - def_bank = cinfo->bank; - } + if (! voice_in_range(voice)) + return RET_ERROR(EINVAL); if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS) return RET_ERROR(EINVAL); - cinfo->vrec = NULL; - cinfo->def_vrec = NULL; - if (instr_no > 128) { - cinfo->vrec = awe_search_instr(128, cinfo->bank); - if (cinfo->bank != 0) - cinfo->def_vrec = awe_search_instr(128, 0); - } else { - cinfo->vrec = awe_search_instr(def_bank, instr_no); - if (def_bank == AWE_DRUM_BANK) - cinfo->def_vrec = awe_search_instr(def_bank, 0); - else - cinfo->def_vrec = awe_search_instr(AWE_DEFAULT_BANK, instr_no); - } - if (cinfo->vrec == NULL && cinfo->def_vrec == NULL) { + cinfo = &channels[voice]; + + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice)) + def_bank = AWE_DRUM_BANK; /* always search drumset */ + else + def_bank = cinfo->bank; + + cinfo->vrec = -1; + cinfo->def_vrec = -1; + cinfo->vrec = awe_search_instr(def_bank, instr_no); + if (def_bank == AWE_DRUM_BANK) /* search default drumset */ + cinfo->def_vrec = awe_search_instr(def_bank, misc_modes[AWE_MD_DEF_DRUM]); + else /* search default preset */ + cinfo->def_vrec = awe_search_instr(misc_modes[AWE_MD_DEF_BANK], instr_no); + + if (cinfo->vrec < 0 && cinfo->def_vrec < 0) { DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no)); - return 0; } cinfo->instr = instr_no; @@ -1804,10 +2175,12 @@ awe_reset(int dev) int i; current_alloc_time = 0; /* don't turn off voice 31 and 32. they are used also for FM voices */ - for (i = 0; i < AWE_NORMAL_VOICES; i++) + for (i = 0; i < awe_max_voices; i++) { awe_terminate(i); + awe_voice_init(i, TRUE); + } for (i = 0; i < AWE_MAX_CHANNELS; i++) - awe_channel_init(i); + awe_channel_init(i, TRUE); for (i = 0; i < 16; i++) { awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127; awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127; @@ -1839,55 +2212,38 @@ awe_hw_control(int dev, unsigned char *event) static void awe_hw_gus_control(int dev, int cmd, unsigned char *event) { - int voice; + int voice, i, key; unsigned short p1; short p2; int plong; + if (MULTI_LAYER_MODE()) + return; + if (cmd == _GUS_NUMVOICES) + return; + voice = event[3]; + if (! voice_in_range(voice)) + return; + p1 = *(unsigned short *) &event[4]; p2 = *(short *) &event[6]; plong = *(int*) &event[4]; switch (cmd) { - case _GUS_NUMVOICES: - if (p1 >= awe_max_voices) - DEBUG(0,printk("AWE32: num_voices: voices out of range %d\n", p1)); - break; case _GUS_VOICESAMPLE: - if (voice < awe_max_voices) - awe_set_instr(dev, voice, p1); - break; - - case _GUS_VOICEON: - if (voice < awe_max_voices) - awe_note_on(voice); - break; - - case _GUS_VOICEOFF: - if (voice < awe_max_voices) - awe_note_off(voice); - break; - - case _GUS_VOICEMODE: - /* not supported */ - break; + awe_set_instr(dev, voice, p1); + return; case _GUS_VOICEBALA: /* 0 to 15 --> -128 to 127 */ - if (voice < awe_max_voices) - awe_panning(dev, voice, ((int)p1 << 4) - 128); - break; + awe_panning(dev, voice, ((int)p1 << 4) - 128); + return; - case _GUS_VOICEFREQ: - if (voice < awe_max_voices) - awe_calc_pitch_from_freq(voice, plong); - break; - case _GUS_VOICEVOL: case _GUS_VOICEVOL2: /* not supported yet */ - break; + return; case _GUS_RAMPRANGE: case _GUS_RAMPRATE: @@ -1895,43 +2251,50 @@ awe_hw_gus_control(int dev, int cmd, unsigned char *event) case _GUS_RAMPON: case _GUS_RAMPOFF: /* volume ramping not supported */ - break; + return; case _GUS_VOLUME_SCALE: - break; + return; case _GUS_VOICE_POS: - if (voice < awe_max_voices) { - FX_SET(&voices[voice].cinfo->fx, AWE_FX_SAMPLE_START, - (short)(plong & 0x7fff)); - FX_SET(&voices[voice].cinfo->fx, AWE_FX_COARSE_SAMPLE_START, - (plong >> 15) & 0xffff); + FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START, + (short)(plong & 0x7fff)); + FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START, + (plong >> 15) & 0xffff); + return; + } + + key = AWE_VOICE_KEY(voice); + for (i = 0; i < awe_max_voices; i++) { + if (voices[i].key == key) { + switch (cmd) { + case _GUS_VOICEON: + awe_note_on(i); + break; + + case _GUS_VOICEOFF: + awe_terminate(i); + awe_fx_init(voices[i].ch); + awe_voice_init(i, TRUE); + break; + + case _GUS_VOICEFADE: + awe_note_off(i); + awe_fx_init(voices[i].ch); + awe_voice_init(i, FALSE); + break; + + case _GUS_VOICEFREQ: + awe_calc_pitch_from_freq(i, plong); + break; + } } - break; } } #endif -/* converter function table for realtime paramter change */ - -static fx_affect_func fx_realtime[] = { - /* env1: delay, attack, hold, decay, release, sustain, pitch, cutoff*/ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - /* env2: delay, attack, hold, decay, release, sustain */ - NULL, NULL, NULL, NULL, NULL, NULL, - /* lfo1: delay, freq, volume, pitch, cutoff */ - NULL, awe_fx_tremfrq, awe_fx_tremfrq, awe_fx_fmmod, awe_fx_fmmod, - /* lfo2: delay, freq, pitch */ - NULL, awe_fx_fm2frq2, awe_fx_fm2frq2, - /* global: initpitch, chorus, reverb, cutoff, filterQ */ - awe_set_voice_pitch, NULL, NULL, awe_fx_cutoff, NULL, - /* sample: start, loopstart, loopend */ - NULL, NULL, NULL, -}; - - /* AWE32 specific controls */ static void awe_hw_awe_control(int dev, int cmd, unsigned char *event) @@ -1939,49 +2302,41 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) int voice; unsigned short p1; short p2; - int chn; awe_chan_info *cinfo; + FX_Rec *fx; int i; - chn = event[1]; voice = event[3]; - p1 = *(unsigned short *) &event[4]; - p2 = *(short *) &event[6]; - - if (awe_channel_mode) { + if (! voice_in_range(voice)) + return; + + if (playing_mode == AWE_PLAY_MULTI2) { + voice = voice_alloc->map[voice] >> 8; if (voice < 0 || voice >= AWE_MAX_CHANNELS) return; - cinfo = &channels[voice]; - } else { - if (voice < 0 || voice >= awe_max_voices) - return; - cinfo = voices[voice].cinfo; } + p1 = *(unsigned short *) &event[4]; + p2 = *(short *) &event[6]; + cinfo = &channels[voice]; + switch (cmd) { case _AWE_DEBUG_MODE: debug_mode = p1; printk("AWE32: debug mode = %d\n", debug_mode); break; case _AWE_REVERB_MODE: - if (p1 <= 7) { - reverb_mode = p1; - DEBUG(0,printk("AWE32: reverb mode %d\n", reverb_mode)); - awe_set_reverb_mode(reverb_mode); - } + awe_set_reverb_mode(p1); break; case _AWE_CHORUS_MODE: - if (p1 <= 7) { - chorus_mode = p1; - DEBUG(0,printk("AWE32: chorus mode %d\n", chorus_mode)); - awe_set_chorus_mode(chorus_mode); - } + awe_set_chorus_mode(p1); break; case _AWE_REMOVE_LAST_SAMPLES: DEBUG(0,printk("AWE32: remove last samples\n")); - awe_remove_samples(); + if (locked_sf_id > 0) + awe_remove_samples(locked_sf_id); break; case _AWE_INITIALIZE_CHIP: @@ -1989,83 +2344,92 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) break; case _AWE_SEND_EFFECT: + fx = &cinfo->fx; + i = FX_FLAG_SET; + if (p1 >= 0x100) { + int layer = (p1 >> 8); + if (layer >= 0 && layer < MAX_LAYERS) + fx = &cinfo->fx_layer[layer]; + p1 &= 0xff; + } + if (p1 & 0x40) i = FX_FLAG_OFF; + if (p1 & 0x80) i = FX_FLAG_ADD; + p1 &= 0x3f; if (p1 < AWE_FX_END) { - FX_SET(&cinfo->fx, p1, p2); - DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, cinfo->fx.val[p1])); - FX_SET(&cinfo->fx, p1, p2); - if (fx_realtime[p1]) { + DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, p2)); + if (i == FX_FLAG_SET) + FX_SET(fx, p1, p2); + else if (i == FX_FLAG_ADD) + FX_ADD(fx, p1, p2); + else + FX_UNSET(fx, p1); + if (i != FX_FLAG_OFF && parm_defs[p1].realtime) { DEBUG(0,printk("AWE32: fx_realtime (%d)\n", voice)); - awe_voice_change(voice, fx_realtime[p1]); + awe_voice_change(voice, parm_defs[p1].realtime); } } break; + case _AWE_RESET_CHANNEL: + awe_channel_init(voice, !p1); + break; + case _AWE_TERMINATE_ALL: - DEBUG(0,printk("AWE32: terminate all\n")); awe_reset(0); break; case _AWE_TERMINATE_CHANNEL: - awe_voice_change(voice, (fx_affect_func)awe_terminate); + awe_voice_change(voice, awe_terminate_and_init); break; + case _AWE_RELEASE_ALL: + awe_note_off_all(FALSE); + break; case _AWE_NOTEOFF_ALL: - for (i = 0; i < awe_max_voices; i++) - awe_note_off(i); + awe_note_off_all(TRUE); break; case _AWE_INITIAL_VOLUME: DEBUG(0,printk("AWE32: init attenuation %d\n", p1)); - init_atten = p1; + if (p2 == 0) /* absolute value */ + init_atten = (short)p1; + else /* relative value */ + init_atten = misc_modes[AWE_MD_ZERO_ATTEN] + (short)p1; + if (init_atten < 0) init_atten = 0; for (i = 0; i < awe_max_voices; i++) - awe_set_voice_vol(i, FALSE); + awe_set_voice_vol(i, TRUE); break; - case _AWE_SET_GUS_BANK: - DEBUG(0,printk("AWE32: set gus bank %d\n", p1)); - awe_gus_bank = p1; + case _AWE_CHN_PRESSURE: + cinfo->chan_press = p1; + p1 = p1 * misc_modes[AWE_MD_MOD_SENSE] / 1200; + FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, p1); + awe_voice_change(voice, awe_fx_fmmod); + FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, p1); + awe_voice_change(voice, awe_fx_fm2frq2); break; - - /* v0.3 stuffs */ + case _AWE_CHANNEL_MODE: DEBUG(0,printk("AWE32: channel mode = %d\n", p1)); - awe_channel_mode = p1; + playing_mode = p1; awe_reset(0); break; case _AWE_DRUM_CHANNELS: DEBUG(0,printk("AWE32: drum flags = %x\n", p1)); - drum_flags = p1; + drum_flags = *(unsigned int*)&event[4]; break; - case _AWE_EXCLUSIVE_SOUND: - DEBUG(0,printk("AWE32: exclusive mode = %d\n", p1)); - awe_exclusive_sound = p1; + case _AWE_MISC_MODE: + DEBUG(0,printk("AWE32: misc mode = %d %d\n", p1, p2)); + if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) + misc_modes[p1] = p2; + break; + + case _AWE_EQUALIZER: + awe_equalizer((int)p1, (int)p2); break; - case _AWE_GET_CURRENT_MODE: - { - awe_mode_rec tmprec; - tmprec.base_addr = awe_base; - tmprec.mem_size = awe_mem_size / 2; - tmprec.max_voices = awe_max_voices; - tmprec.max_infos = AWE_MAX_INFOS; - tmprec.max_samples = AWE_MAX_SAMPLES; - tmprec.current_sf_id = current_sf_id; - tmprec.free_mem = free_mem_ptr; - tmprec.free_info = free_info; - tmprec.free_sample = free_sample; - tmprec.reverb_mode = reverb_mode; - tmprec.chorus_mode = chorus_mode; - tmprec.init_atten = init_atten; - tmprec.channel_mode = awe_channel_mode; - tmprec.gus_bank = awe_gus_bank; - tmprec.exclusive_sound = awe_exclusive_sound; - tmprec.drum_flags = drum_flags; - tmprec.debug_mode = debug_mode; - IOCTL_TO_USER(*(awe_mode_rec**)&event[4], 0, &tmprec, sizeof(tmprec)); - break; - } default: DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice)); break; @@ -2073,6 +2437,218 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) } +/* voice pressure change */ +static void +awe_aftertouch(int dev, int voice, int pressure) +{ + int note; + + DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure)); + if (! voice_in_range(voice)) + return; + + switch (playing_mode) { + case AWE_PLAY_DIRECT: + case AWE_PLAY_INDIRECT: + awe_start_note(dev, voice, 255, pressure); + break; + case AWE_PLAY_MULTI2: + note = (voice_alloc->map[voice] & 0xff) - 1; + awe_start_note(dev, voice, note + 0x80, pressure); + break; + } +} + + +/* voice control change */ +static void +awe_controller(int dev, int voice, int ctrl_num, int value) +{ + int i; + awe_chan_info *cinfo; + + if (! voice_in_range(voice)) + return; + + if (playing_mode == AWE_PLAY_MULTI2) { + voice = voice_alloc->map[voice] >> 8; + if (voice < 0 || voice >= AWE_MAX_CHANNELS) + return; + } + + cinfo = &channels[voice]; + + switch (ctrl_num) { + case CTL_BANK_SELECT: /* MIDI control #0 */ + DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value)); + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) && + !misc_modes[AWE_MD_TOGGLE_DRUM_BANK]) + break; + cinfo->bank = value; + if (cinfo->bank == AWE_DRUM_BANK) + DRUM_CHANNEL_ON(cinfo->channel); + else + DRUM_CHANNEL_OFF(cinfo->channel); + awe_set_instr(dev, voice, cinfo->instr); + break; + + case CTL_MODWHEEL: /* MIDI control #1 */ + DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value)); + i = value * misc_modes[AWE_MD_MOD_SENSE] / 1200; + FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i); + awe_voice_change(voice, awe_fx_fmmod); + FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i); + awe_voice_change(voice, awe_fx_fm2frq2); + break; + + case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */ + DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value)); + /* zero centered */ + cinfo->bender = value; + awe_voice_change(voice, awe_set_voice_pitch); + break; + + case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */ + DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value)); + /* value = sense x 100 */ + cinfo->bender_range = value; + /* no audible pitch change yet.. */ + break; + + case CTL_EXPRESSION: /* MIDI control #11 */ + if (SINGLE_LAYER_MODE()) + value /= 128; + case CTRL_EXPRESSION: /* SEQ1 V2 control */ + DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value)); + /* 0 - 127 */ + cinfo->expression_vol = value; + awe_voice_change(voice, awe_set_voice_vol); + break; + + case CTL_PAN: /* MIDI control #10 */ + DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value)); + /* (0-127) -> signed 8bit */ + cinfo->panning = value * 2 - 128; + if (misc_modes[AWE_MD_REALTIME_PAN]) + awe_voice_change(voice, awe_set_pan); + break; + + case CTL_MAIN_VOLUME: /* MIDI control #7 */ + if (SINGLE_LAYER_MODE()) + value = (value * 100) / 16383; + case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */ + DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value)); + /* 0 - 127 */ + cinfo->main_vol = value; + awe_voice_change(voice, awe_set_voice_vol); + break; + + case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */ + DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value)); + FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2); + break; + + case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */ + DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value)); + FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2); + break; + +#ifdef AWE_ACCEPT_ALL_SOUNDS_CONTROLL + case 120: /* all sounds off */ + awe_note_off_all(FALSE); + break; + case 123: /* all notes off */ + awe_note_off_all(TRUE); + break; +#endif + + case CTL_SUSTAIN: /* MIDI control #64 */ + cinfo->sustained = value; + if (value != 127) + awe_voice_change(voice, awe_sustain_off); + break; + + case CTL_SOSTENUTO: /* MIDI control #66 */ + if (value == 127) + awe_voice_change(voice, awe_sostenuto_on); + else + awe_voice_change(voice, awe_sustain_off); + break; + + default: + DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n", + voice, ctrl_num, value)); + break; + } +} + + +/* voice pan change (value = -128 - 127) */ +static void +awe_panning(int dev, int voice, int value) +{ + awe_chan_info *cinfo; + + if (! voice_in_range(voice)) + return; + + if (playing_mode == AWE_PLAY_MULTI2) { + voice = voice_alloc->map[voice] >> 8; + if (voice < 0 || voice >= AWE_MAX_CHANNELS) + return; + } + + cinfo = &channels[voice]; + cinfo->panning = value; + DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning)); + if (misc_modes[AWE_MD_REALTIME_PAN]) + awe_voice_change(voice, awe_set_pan); +} + + +/* volume mode change */ +static void +awe_volume_method(int dev, int mode) +{ + /* not impremented */ + DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode)); +} + + +#ifndef AWE_NO_PATCHMGR +/* patch manager */ +static int +awe_patchmgr(int dev, struct patmgr_info *rec) +{ + printk("AWE32 Warning: patch manager control not supported\n"); + return 0; +} +#endif + + +/* pitch wheel change: 0-16384 */ +static void +awe_bender(int dev, int voice, int value) +{ + awe_chan_info *cinfo; + + if (! voice_in_range(voice)) + return; + + if (playing_mode == AWE_PLAY_MULTI2) { + voice = voice_alloc->map[voice] >> 8; + if (voice < 0 || voice >= AWE_MAX_CHANNELS) + return; + } + + /* convert to zero centered value */ + cinfo = &channels[voice]; + cinfo->bender = value - 8192; + DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender)); + awe_voice_change(voice, awe_set_voice_pitch); +} + + /*---------------------------------------------------------------- * load a sound patch: * three types of patches are accepted: AWE, GUS, and SYSEX. @@ -2094,12 +2670,12 @@ awe_load_patch(int dev, int format, const char *addr, /* no system exclusive message supported yet */ return 0; } else if (format != AWE_PATCH) { - FATALERR(printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format)); + printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format); return RET_ERROR(EINVAL); } if (count < AWE_PATCH_INFO_SIZE) { - FATALERR(printk("AWE32 Error: Patch header too short\n")); + printk("AWE32 Error: Patch header too short\n"); return RET_ERROR(EINVAL); } COPY_FROM_USER(((char*)&patch) + offs, addr, offs, @@ -2107,27 +2683,43 @@ awe_load_patch(int dev, int format, const char *addr, count -= AWE_PATCH_INFO_SIZE; if (count < patch.len) { - FATALERR(printk("AWE32 Warning: Patch record too short (%d<%d)\n", - count, (int)patch.len)); - patch.len = count; + printk("AWE32: sample: Patch record too short (%d<%d)\n", + count, patch.len); + return RET_ERROR(EINVAL); } switch (patch.type) { case AWE_LOAD_INFO: - rc = awe_load_info(&patch, addr); + rc = awe_load_info(&patch, addr, count); break; - case AWE_LOAD_DATA: - rc = awe_load_data(&patch, addr); - /* - if (!pmgr_flag && rc == 0) - pmgr_inform(dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); - */ + rc = awe_load_data(&patch, addr, count); + break; + case AWE_OPEN_PATCH: + rc = awe_open_patch(&patch, addr, count); + break; + case AWE_CLOSE_PATCH: + rc = awe_close_patch(&patch, addr, count); + break; + case AWE_UNLOAD_PATCH: + rc = awe_unload_patch(&patch, addr, count); + break; + case AWE_REPLACE_DATA: + rc = awe_replace_data(&patch, addr, count); + break; + case AWE_MAP_PRESET: + rc = awe_load_map(&patch, addr, count); + break; + case AWE_LOAD_CHORUS_FX: + rc = awe_load_chorus_fx(&patch, addr, count); + break; + case AWE_LOAD_REVERB_FX: + rc = awe_load_reverb_fx(&patch, addr, count); break; default: - FATALERR(printk("AWE32 Error: unknown patch format type %d\n", - patch.type)); + printk("AWE32 Error: unknown patch format type %d\n", + patch.type); rc = RET_ERROR(EINVAL); } @@ -2135,140 +2727,384 @@ awe_load_patch(int dev, int format, const char *addr, } +/* create an sflist record */ +static int +awe_create_sf(int type, char *name) +{ + sf_list *rec; + + /* terminate sounds */ + awe_reset(0); + if (current_sf_id >= max_sfs) { + int newsize = max_sfs + AWE_MAX_SF_LISTS; + sf_list *newlist = my_realloc(sflists, sizeof(sf_list)*max_sfs, + sizeof(sf_list)*newsize); + if (newlist == NULL) + return 1; + sflists = newlist; + max_sfs = newsize; + } + rec = &sflists[current_sf_id]; + rec->sf_id = current_sf_id + 1; + rec->type = type; + if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0) + locked_sf_id = current_sf_id + 1; + /* + if (name) + MEMCPY(rec->name, name, AWE_PATCH_NAME_LEN); + else + BZERO(rec->name, AWE_PATCH_NAME_LEN); + */ + rec->num_info = awe_free_info(); + rec->num_sample = awe_free_sample(); + rec->mem_ptr = awe_free_mem_ptr(); + rec->infos = -1; + rec->samples = -1; + + current_sf_id++; + return 0; +} + + +/* open patch; create sf list and set opened flag */ +static int +awe_open_patch(awe_patch_info *patch, const char *addr, int count) +{ + awe_open_parm parm; + COPY_FROM_USER(&parm, addr, AWE_PATCH_INFO_SIZE, sizeof(parm)); + if (awe_create_sf(parm.type, parm.name)) { + printk("AWE32: can't open: failed to alloc new list\n"); + return RET_ERROR(ENOSPC); + } + patch_opened = TRUE; + return current_sf_id; +} + +/* check if the patch is already opened */ +static int +check_patch_opened(int type, char *name) +{ + if (! patch_opened) { + if (awe_create_sf(type, name)) { + printk("AWE32: failed to alloc new list\n"); + return RET_ERROR(ENOSPC); + } + patch_opened = TRUE; + return current_sf_id; + } + return current_sf_id; +} + +/* close the patch; if no voice is loaded, remove the patch */ +static int +awe_close_patch(awe_patch_info *patch, const char *addr, int count) +{ + if (patch_opened && current_sf_id > 0) { + /* if no voice is loaded, release the current patch */ + if (sflists[current_sf_id-1].infos == -1) + awe_remove_samples(current_sf_id - 1); + } + patch_opened = 0; + return 0; +} + + +/* remove the latest patch */ +static int +awe_unload_patch(awe_patch_info *patch, const char *addr, int count) +{ + if (current_sf_id > 0) + awe_remove_samples(current_sf_id - 1); + return 0; +} + +/* allocate voice info list records */ +static int alloc_new_info(int nvoices) +{ + int newsize, free_info; + awe_voice_list *newlist; + free_info = awe_free_info(); + if (free_info + nvoices >= max_infos) { + do { + newsize = max_infos + AWE_MAX_INFOS; + } while (free_info + nvoices >= newsize); + newlist = my_realloc(infos, sizeof(awe_voice_list)*max_infos, + sizeof(awe_voice_list)*newsize); + if (newlist == NULL) { + printk("AWE32: can't alloc info table\n"); + return RET_ERROR(ENOSPC); + } + infos = newlist; + max_infos = newsize; + } + return 0; +} + +/* allocate sample info list records */ +static int alloc_new_sample(void) +{ + int newsize, free_sample; + awe_sample_list *newlist; + free_sample = awe_free_sample(); + if (free_sample >= max_samples) { + newsize = max_samples + AWE_MAX_SAMPLES; + newlist = my_realloc(samples, + sizeof(awe_sample_list)*max_samples, + sizeof(awe_sample_list)*newsize); + if (newlist == NULL) { + printk("AWE32: can't alloc sample table\n"); + return RET_ERROR(ENOSPC); + } + samples = newlist; + max_samples = newsize; + } + return 0; +} + +/* load voice map */ +static int +awe_load_map(awe_patch_info *patch, const char *addr, int count) +{ + awe_voice_map map; + awe_voice_list *rec; + int free_info; + + if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0) + return RET_ERROR(ENOSPC); + if (alloc_new_info(1) < 0) + return RET_ERROR(ENOSPC); + + COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map)); + + free_info = awe_free_info(); + rec = &infos[free_info]; + rec->bank = map.map_bank; + rec->instr = map.map_instr; + rec->type = V_ST_MAPPED; + rec->disabled = FALSE; + awe_init_voice_info(&rec->v); + if (map.map_key >= 0) { + rec->v.low = map.map_key; + rec->v.high = map.map_key; + } + rec->v.start = map.src_instr; + rec->v.end = map.src_bank; + rec->v.fixkey = map.src_key; + rec->v.sf_id = current_sf_id; + add_info_list(free_info); + add_sf_info(free_info); + + return 0; +} + /* load voice information data */ static int -awe_load_info(awe_patch_info *patch, const char *addr) +awe_load_info(awe_patch_info *patch, const char *addr, int count) { - awe_voice_list *rec, *curp; - long offset; - short i, nvoices; - unsigned char bank, instr; + int offset; + awe_voice_rec_hdr hdr; + int i; int total_size; - if (patch->len < AWE_VOICE_REC_SIZE) { - FATALERR(printk("AWE32 Error: invalid patch info length\n")); + if (count < AWE_VOICE_REC_SIZE) { + printk("AWE32 Error: invalid patch info length\n"); return RET_ERROR(EINVAL); } offset = AWE_PATCH_INFO_SIZE; - GET_BYTE_FROM_USER(bank, addr, offset); offset++; - GET_BYTE_FROM_USER(instr, addr, offset); offset++; - GET_SHORT_FROM_USER(nvoices, addr, offset); offset+=2; + COPY_FROM_USER((char*)&hdr, addr, offset, AWE_VOICE_REC_SIZE); + offset += AWE_VOICE_REC_SIZE; - if (nvoices <= 0 || nvoices >= 100) { - FATALERR(printk("AWE32 Error: Illegal voice number %d\n", nvoices)); + if (hdr.nvoices <= 0 || hdr.nvoices >= 100) { + printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices); return RET_ERROR(EINVAL); } - if (free_info + nvoices > AWE_MAX_INFOS) { - ERRMSG(printk("AWE32 Error: Too many voice informations\n")); - return RET_ERROR(ENOSPC); + total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices; + if (count < total_size) { + printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", + count, hdr.nvoices); + return RET_ERROR(EINVAL); } - total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * nvoices; - if (patch->len < total_size) { - ERRMSG(printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", - (int)patch->len, nvoices)); - return RET_ERROR(EINVAL); + if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0) + return RET_ERROR(ENOSPC); + +#if 0 /* it looks like not so useful.. */ + /* check if the same preset already exists in the info list */ + for (i = sflists[current_sf_id-1].infos; i >= 0; i = infos[i].next) { + if (infos[i].disabled) continue; + if (infos[i].bank == hdr.bank && infos[i].instr == hdr.instr) { + /* in exclusive mode, do skip loading this */ + if (hdr.write_mode == AWE_WR_EXCLUSIVE) + return 0; + /* in replace mode, disable the old data */ + else if (hdr.write_mode == AWE_WR_REPLACE) + infos[i].disabled = TRUE; + } } + if (hdr.write_mode == AWE_WR_REPLACE) + rebuild_preset_list(); +#endif - curp = awe_search_instr(bank, instr); - for (i = 0; i < nvoices; i++) { - rec = &infos[free_info + i]; + if (alloc_new_info(hdr.nvoices) < 0) + return RET_ERROR(ENOSPC); - rec->bank = bank; - rec->instr = instr; - if (i < nvoices - 1) - rec->next_instr = rec + 1; - else - rec->next_instr = curp; - rec->next_bank = NULL; + for (i = 0; i < hdr.nvoices; i++) { + int rec = awe_free_info(); + + infos[rec].bank = hdr.bank; + infos[rec].instr = hdr.instr; + infos[rec].type = V_ST_NORMAL; + infos[rec].disabled = FALSE; /* copy awe_voice_info parameters */ - COPY_FROM_USER(&rec->v, addr, offset, AWE_VOICE_INFO_SIZE); + COPY_FROM_USER(&infos[rec].v, addr, offset, AWE_VOICE_INFO_SIZE); offset += AWE_VOICE_INFO_SIZE; - rec->v.sf_id = current_sf_id; - if (rec->v.mode & AWE_MODE_INIT_PARM) - awe_init_voice_parm(&rec->v.parm); - awe_set_sample(&rec->v); + infos[rec].v.sf_id = current_sf_id; + if (infos[rec].v.mode & AWE_MODE_INIT_PARM) + awe_init_voice_parm(&infos[rec].v.parm); + awe_set_sample(&infos[rec].v); + add_info_list(rec); + add_sf_info(rec); } - /* prepend to top of the list */ - infos[free_info].next_bank = preset_table[instr]; - preset_table[instr] = &infos[free_info]; - free_info += nvoices; - return 0; } - /* load wave sample data */ static int -awe_load_data(awe_patch_info *patch, const char *addr) +awe_load_data(awe_patch_info *patch, const char *addr, int count) { - long offset; - int size; - int rc; + int offset, size; + int rc, free_sample; + awe_sample_info *rec; - if (free_sample >= AWE_MAX_SAMPLES) { - ERRMSG(printk("AWE32 Error: Sample table full\n")); + if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0) return RET_ERROR(ENOSPC); - } - size = (patch->len - AWE_SAMPLE_INFO_SIZE) / 2; + if (alloc_new_sample() < 0) + return RET_ERROR(ENOSPC); + + free_sample = awe_free_sample(); + rec = &samples[free_sample].v; + + size = (count - AWE_SAMPLE_INFO_SIZE) / 2; offset = AWE_PATCH_INFO_SIZE; - COPY_FROM_USER(&samples[free_sample], addr, offset, - AWE_SAMPLE_INFO_SIZE); + COPY_FROM_USER(rec, addr, offset, AWE_SAMPLE_INFO_SIZE); offset += AWE_SAMPLE_INFO_SIZE; - if (size != samples[free_sample].size) { - ERRMSG(printk("AWE32 Warning: sample size differed (%d != %d)\n", - (int)samples[free_sample].size, (int)size)); - samples[free_sample].size = size; + if (size != rec->size) { + printk("AWE32: load: sample size differed (%d != %d)\n", + rec->size, size); + return RET_ERROR(EINVAL); } - if (samples[free_sample].size > 0) - if ((rc = awe_write_wave_data(addr, offset, size)) != 0) + if (rec->size > 0) + if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0) return rc; - awe_check_loaded(); - samples[free_sample].sf_id = current_sf_id; + rec->sf_id = current_sf_id; + + add_sf_sample(free_sample); - free_sample++; return 0; } -/* check the other samples are already loaded */ -static void -awe_check_loaded(void) + +/* replace wave sample data */ +static int +awe_replace_data(awe_patch_info *patch, const char *addr, int count) { - if (!loaded_once) { - /* it's the first time */ - if (current_sf_id == 1) { - last_sample = free_sample; - last_info = free_info; - } - current_sf_id++; - loaded_once = 1; + int offset; + int size; + int rc, i; + int channels; + awe_sample_info cursmp; + int save_mem_ptr; + + if (! patch_opened) { + printk("AWE32: replace: patch not opened\n"); + return RET_ERROR(EINVAL); + } + + size = (count - AWE_SAMPLE_INFO_SIZE) / 2; + offset = AWE_PATCH_INFO_SIZE; + COPY_FROM_USER(&cursmp, addr, offset, AWE_SAMPLE_INFO_SIZE); + offset += AWE_SAMPLE_INFO_SIZE; + if (cursmp.size == 0 || size != cursmp.size) { + printk("AWE32: replace: illegal sample size (%d!=%d)\n", + cursmp.size, size); + return RET_ERROR(EINVAL); + } + channels = patch->optarg; + if (channels <= 0 || channels > AWE_NORMAL_VOICES) { + printk("AWE32: replace: illegal channels %d\n", channels); + return RET_ERROR(EINVAL); + } + + for (i = sflists[current_sf_id-1].samples; + i >= 0; i = samples[i].next) { + if (samples[i].v.sample == cursmp.sample) + break; + } + if (i < 0) { + printk("AWE32: replace: cannot find existing sample data %d\n", + cursmp.sample); + return RET_ERROR(EINVAL); } + + if (samples[i].v.size != cursmp.size) { + printk("AWE32: replace: exiting size differed (%d!=%d)\n", + samples[i].v.size, cursmp.size); + return RET_ERROR(EINVAL); + } + + save_mem_ptr = awe_free_mem_ptr(); + sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start; + MEMCPY(&samples[i].v, &cursmp, sizeof(cursmp)); + if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0) + return rc; + sflists[current_sf_id-1].mem_ptr = save_mem_ptr; + samples[i].v.sf_id = current_sf_id; + + return 0; } /*----------------------------------------------------------------*/ static const char *readbuf_addr; -static long readbuf_offs; +static int readbuf_offs; static int readbuf_flags; +#ifdef __FreeBSD__ +static unsigned short *readbuf_loop; +static int readbuf_loopstart, readbuf_loopend; +#endif /* initialize read buffer */ -static void -awe_init_readbuf(const char *addr, long offset, int size, int mode_flags) +static int +readbuf_init(const char *addr, int offset, awe_sample_info *sp) { +#ifdef __FreeBSD__ + readbuf_loop = NULL; + readbuf_loopstart = sp->loopstart; + readbuf_loopend = sp->loopend; + if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) { + int looplen = sp->loopend - sp->loopstart; + readbuf_loop = my_malloc(looplen * 2); + if (readbuf_loop == NULL) { + printk("AWE32: can't malloc temp buffer\n"); + return RET_ERROR(ENOSPC); + } + } +#endif readbuf_addr = addr; readbuf_offs = offset; - readbuf_flags = mode_flags; + readbuf_flags = sp->mode_flags; + return 0; } /* read directly from user buffer */ static unsigned short -awe_read_word(int pos) +readbuf_word(int pos) { unsigned short c; /* read from user buffer */ @@ -2281,10 +3117,43 @@ awe_read_word(int pos) } if (readbuf_flags & AWE_SAMPLE_UNSIGNED) c ^= 0x8000; /* unsigned -> signed */ +#ifdef __FreeBSD__ + /* write on cache for reverse loop */ + if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) { + if (pos >= readbuf_loopstart && pos < readbuf_loopend) + readbuf_loop[pos - readbuf_loopstart] = c; + } +#endif return c; } +#ifdef __FreeBSD__ +/* read from cache */ +static unsigned short +readbuf_word_cache(int pos) +{ + if (pos >= readbuf_loopstart && pos < readbuf_loopend) + return readbuf_loop[pos - readbuf_loopstart]; + return 0; +} + +static void +readbuf_end(void) +{ + if (readbuf_loop) { + my_free(readbuf_loop); + } + readbuf_loop = NULL; +} +#else + +#define readbuf_word_cache readbuf_word +#define readbuf_end() /**/ + +#endif + +/*----------------------------------------------------------------*/ #define BLANK_LOOP_START 8 #define BLANK_LOOP_END 40 @@ -2292,28 +3161,26 @@ awe_read_word(int pos) /* loading onto memory */ static int -awe_write_wave_data(const char *addr, long offset, int size) +awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels) { - awe_sample_info *sp = &samples[free_sample]; - int i, truesize; + int i, truesize, dram_offset; int rc; - unsigned long csum1, csum2; /* be sure loop points start < end */ if (sp->loopstart > sp->loopend) { - long tmp = sp->loopstart; + int tmp = sp->loopstart; sp->loopstart = sp->loopend; sp->loopend = tmp; } /* compute true data size to be loaded */ - truesize = size; + truesize = sp->size; if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) truesize += sp->loopend - sp->loopstart; if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) truesize += BLANK_LOOP_SIZE; - if (size > 0 && free_mem_ptr + truesize >= awe_mem_size/2) { - ERRMSG(printk("AWE32 Error: Sample memory full\n")); + if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) { + printk("AWE32 Error: Sample memory full\n"); return RET_ERROR(ENOSPC); } @@ -2321,32 +3188,36 @@ awe_write_wave_data(const char *addr, long offset, int size) sp->end -= sp->start; sp->loopstart -= sp->start; sp->loopend -= sp->start; - sp->size = truesize; - sp->start = free_mem_ptr + AWE_DRAM_OFFSET; - sp->end += free_mem_ptr + AWE_DRAM_OFFSET; - sp->loopstart += free_mem_ptr + AWE_DRAM_OFFSET; - sp->loopend += free_mem_ptr + AWE_DRAM_OFFSET; + dram_offset = awe_free_mem_ptr() + awe_mem_start; + sp->start = dram_offset; + sp->end += dram_offset; + sp->loopstart += dram_offset; + sp->loopend += dram_offset; - if ((rc = awe_open_dram_for_write(free_mem_ptr)) != 0) { + /* set the total size (store onto obsolete checksum value) */ + if (sp->size == 0) + sp->checksum = 0; + else + sp->checksum = truesize; + + if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0) return rc; - } - awe_init_readbuf(addr, offset, size, sp->mode_flags); - csum1 = 0; - for (i = 0; i < size; i++) { + if (readbuf_init(addr, offset, sp) < 0) + return RET_ERROR(ENOSPC); + + for (i = 0; i < sp->size; i++) { unsigned short c; - c = awe_read_word(i); - csum1 += c; + c = readbuf_word(i); awe_write_dram(c); if (i == sp->loopend && (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) { int looplen = sp->loopend - sp->loopstart; /* copy reverse loop */ int k; - for (k = 0; k < looplen; k++) { - /* non-buffered data */ - c = awe_read_word(i - k); + for (k = 1; k <= looplen; k++) { + c = readbuf_word_cache(i - k); awe_write_dram(c); } if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) { @@ -2357,6 +3228,7 @@ awe_write_wave_data(const char *addr, long offset, int size) } } } + readbuf_end(); /* if no blank loop is attached in the sample, add it */ if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) { @@ -2366,40 +3238,13 @@ awe_write_wave_data(const char *addr, long offset, int size) sp->loopstart = sp->end + BLANK_LOOP_START; sp->loopend = sp->end + BLANK_LOOP_END; } - sp->size += BLANK_LOOP_SIZE; } + sflists[current_sf_id-1].mem_ptr += truesize; awe_close_dram(); - if (sp->checksum_flag) { -#ifdef AWE_CHECKSUM_DATA - if (sp->checksum_flag != 2 && csum1 != sp->checksum) { - ERRMSG(printk("AWE32: [%d] checksum mismatch on data %x:%x\n", - free_sample, (int)sp->checksum, (int)csum1)); - return RET_ERROR(NO_DATA_ERR); - } -#endif /* AWE_CHECKSUM_DATA */ -#ifdef AWE_CHECKSUM_MEMORY - if (awe_open_dram_for_read(free_mem_ptr) == 0) { - csum2 = 0; - for (i = 0; i < size; i++) { - unsigned short c; - c = awe_peek(AWE_SMLD); - csum2 += c; - } - awe_close_dram_for_read(); - if (csum1 != csum2) { - ERRMSG(printk("AWE32: [%d] checksum mismatch on DRAM %x:%x\n", - free_sample, (int)csum1, (int)csum2)); - return RET_ERROR(NO_DATA_ERR); - } - } -#endif /* AWE_CHECKSUM_MEMORY */ - } - free_mem_ptr += sp->size; - /* re-initialize FM passthrough */ + /* initialize FM */ awe_init_fm(); - awe_tweak(); return 0; } @@ -2435,91 +3280,89 @@ static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag) { struct patch_info patch; - awe_voice_list *rec, *curp; - long sizeof_patch; - int note; + awe_voice_info *rec; + awe_sample_info *smp; + int sizeof_patch; + int note, free_sample, free_info; int rc; - sizeof_patch = (long)&patch.data[0] - (long)&patch; /* header size */ - if (free_sample >= AWE_MAX_SAMPLES) { - ERRMSG(printk("AWE32 Error: Sample table full\n")); - return RET_ERROR(ENOSPC); - } - if (free_info >= AWE_MAX_INFOS) { - ERRMSG(printk("AWE32 Error: Too many voice informations\n")); - return RET_ERROR(ENOSPC); - } + sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */ if (size < sizeof_patch) { - ERRMSG(printk("AWE32 Error: Patch header too short\n")); + printk("AWE32 Error: Patch header too short\n"); return RET_ERROR(EINVAL); } COPY_FROM_USER(((char*)&patch) + offs, addr, offs, sizeof_patch - offs); size -= sizeof_patch; if (size < patch.len) { - FATALERR(printk("AWE32 Warning: Patch record too short (%d<%d)\n", - size, (int)patch.len)); - patch.len = size; + printk("AWE32 Warning: Patch record too short (%d<%d)\n", + size, patch.len); + return RET_ERROR(EINVAL); } + if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0) + return RET_ERROR(ENOSPC); + if (alloc_new_sample() < 0) + return RET_ERROR(ENOSPC); + if (alloc_new_info(1)) + return RET_ERROR(ENOSPC); - samples[free_sample].sf_id = 0; - samples[free_sample].sample = free_sample; - samples[free_sample].start = 0; - samples[free_sample].end = patch.len; - samples[free_sample].loopstart = patch.loop_start; - samples[free_sample].loopend = patch.loop_end + 1; - samples[free_sample].size = patch.len; + free_sample = awe_free_sample(); + smp = &samples[free_sample].v; + + smp->sample = free_sample; + smp->start = 0; + smp->end = patch.len; + smp->loopstart = patch.loop_start; + smp->loopend = patch.loop_end; + smp->size = patch.len; /* set up mode flags */ - samples[free_sample].mode_flags = 0; + smp->mode_flags = 0; if (!(patch.mode & WAVE_16_BITS)) - samples[free_sample].mode_flags |= AWE_SAMPLE_8BITS; + smp->mode_flags |= AWE_SAMPLE_8BITS; if (patch.mode & WAVE_UNSIGNED) - samples[free_sample].mode_flags |= AWE_SAMPLE_UNSIGNED; - samples[free_sample].mode_flags |= AWE_SAMPLE_NO_BLANK; + smp->mode_flags |= AWE_SAMPLE_UNSIGNED; + smp->mode_flags |= AWE_SAMPLE_NO_BLANK; if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK))) - samples[free_sample].mode_flags |= AWE_SAMPLE_SINGLESHOT; + smp->mode_flags |= AWE_SAMPLE_SINGLESHOT; if (patch.mode & WAVE_BIDIR_LOOP) - samples[free_sample].mode_flags |= AWE_SAMPLE_BIDIR_LOOP; + smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP; if (patch.mode & WAVE_LOOP_BACK) - samples[free_sample].mode_flags |= AWE_SAMPLE_REVERSE_LOOP; + smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP; - DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, - samples[free_sample].mode_flags)); + DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags)); if (patch.mode & WAVE_16_BITS) { /* convert to word offsets */ - samples[free_sample].size /= 2; - samples[free_sample].end /= 2; - samples[free_sample].loopstart /= 2; - samples[free_sample].loopend /= 2; + smp->size /= 2; + smp->end /= 2; + smp->loopstart /= 2; + smp->loopend /= 2; } - samples[free_sample].checksum_flag = 0; - samples[free_sample].checksum = 0; + smp->checksum_flag = 0; + smp->checksum = 0; - if ((rc = awe_write_wave_data(addr, sizeof_patch, - samples[free_sample].size)) != 0) + if ((rc = awe_write_wave_data(addr, sizeof_patch, smp, -1)) != 0) return rc; - awe_check_loaded(); - samples[free_sample].sf_id = current_sf_id; - free_sample++; + smp->sf_id = current_sf_id; + add_sf_sample(free_sample); /* set up voice info */ - rec = &infos[free_info]; - awe_init_voice_info(&rec->v); - rec->v.sf_id = current_sf_id; - rec->v.sample = free_sample - 1; /* the last sample */ - rec->v.rate_offset = calc_rate_offset(patch.base_freq); + free_info = awe_free_info(); + rec = &infos[free_info].v; + awe_init_voice_info(rec); + rec->sample = free_sample; /* the last sample */ + rec->rate_offset = calc_rate_offset(patch.base_freq); note = freq_to_note(patch.base_note); - rec->v.root = note / 100; - rec->v.tune = -(note % 100); - rec->v.low = freq_to_note(patch.low_note) / 100; - rec->v.high = freq_to_note(patch.high_note) / 100; + rec->root = note / 100; + rec->tune = -(note % 100); + rec->low = freq_to_note(patch.low_note) / 100; + rec->high = freq_to_note(patch.high_note) / 100; DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n", - rec->v.rate_offset, note, - rec->v.low, rec->v.high, + rec->rate_offset, note, + rec->low, rec->high, patch.low_note, patch.high_note)); /* panning position; -128 - 127 => 0-127 */ - rec->v.pan = (patch.panning + 128) / 2; + rec->pan = (patch.panning + 128) / 2; /* detuning is ignored */ /* 6points volume envelope */ @@ -2542,367 +3385,215 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag) release += calc_gus_envelope_time (patch.env_rate[5], patch.env_offset[4], patch.env_offset[5]); - rec->v.parm.volatkhld = (calc_parm_attack(attack) << 8) | + rec->parm.volatkhld = (calc_parm_attack(attack) << 8) | calc_parm_hold(hold); - rec->v.parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | + rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | calc_parm_decay(decay); - rec->v.parm.volrelease = 0x8000 | calc_parm_decay(release); + rec->parm.volrelease = 0x8000 | calc_parm_decay(release); DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release)); - rec->v.attenuation = calc_gus_attenuation(patch.env_offset[0]); + rec->attenuation = calc_gus_attenuation(patch.env_offset[0]); } /* tremolo effect */ if (patch.mode & WAVE_TREMOLO) { int rate = (patch.tremolo_rate * 1000 / 38) / 42; - rec->v.parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate; + rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate; DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n", patch.tremolo_rate, patch.tremolo_depth, - rec->v.parm.tremfrq)); + rec->parm.tremfrq)); } /* vibrato effect */ if (patch.mode & WAVE_VIBRATO) { int rate = (patch.vibrato_rate * 1000 / 38) / 42; - rec->v.parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate; + rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate; DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n", patch.tremolo_rate, patch.tremolo_depth, - rec->v.parm.tremfrq)); + rec->parm.tremfrq)); } /* scale_freq, scale_factor, volume, and fractions not implemented */ - /* set the voice index */ - awe_set_sample(&rec->v); + /* append to the tail of the list */ + infos[free_info].bank = misc_modes[AWE_MD_GUS_BANK]; + infos[free_info].instr = patch.instr_no; + infos[free_info].disabled = FALSE; + infos[free_info].type = V_ST_NORMAL; + infos[free_info].v.sf_id = current_sf_id; + + add_info_list(free_info); + add_sf_info(free_info); - /* prepend to top of the list */ - curp = awe_search_instr(awe_gus_bank, patch.instr_no); - rec->bank = awe_gus_bank; - rec->instr = patch.instr_no; - rec->next_instr = curp; - rec->next_bank = preset_table[rec->instr]; - preset_table[rec->instr] = rec; - free_info++; + /* set the voice index */ + awe_set_sample(rec); return 0; } #endif /* AWE_HAS_GUS_COMPATIBILITY */ -/*----------------------------------------------------------------*/ +/*---------------------------------------------------------------- + * sample and voice list handlers + *----------------------------------------------------------------*/ -/* remove samples with different sf_id from instrument list */ -static awe_voice_list * -awe_get_removed_list(awe_voice_list *curp) -{ - awe_voice_list *lastp, **prevp; - int maxc; - lastp = curp; - prevp = &lastp; - for (maxc = AWE_MAX_INFOS; - curp && maxc; curp = curp->next_instr, maxc--) { - if (curp->v.sf_id != 1) - *prevp = curp->next_instr; - else - prevp = &curp->next_instr; +/* append this to the sf list */ +static void add_sf_info(int rec) +{ + int sf_id = infos[rec].v.sf_id; + if (sf_id == 0) return; + sf_id--; + if (sflists[sf_id].infos < 0) + sflists[sf_id].infos = rec; + else { + int i, prev; + prev = sflists[sf_id].infos; + while ((i = infos[prev].next) >= 0) + prev = i; + infos[prev].next = rec; } - return lastp; + infos[rec].next = -1; + sflists[sf_id].num_info++; } - -/* remove last loaded samples */ -static void -awe_remove_samples(void) +/* prepend this sample to sf list */ +static void add_sf_sample(int rec) { - awe_voice_list **prevp, *p, *nextp; - int maxc; - int i; - - /* no sample is loaded yet */ - if (last_sample == free_sample && last_info == free_info) - return; - - /* only the primary samples are loaded */ - if (current_sf_id <= 1) - return; - - /* remove the records from preset table */ - for (i = 0; i < AWE_MAX_PRESETS; i++) { - prevp = &preset_table[i]; - for (maxc = AWE_MAX_INFOS, p = preset_table[i]; - p && maxc; p = nextp, maxc--) { - nextp = p->next_bank; - p = awe_get_removed_list(p); - if (p == NULL) - *prevp = nextp; - else { - *prevp = p; - prevp = &p->next_bank; - } - } - } - - for (i = last_sample; i < free_sample; i++) - free_mem_ptr -= samples[i].size; - - free_sample = last_sample; - free_info = last_info; - current_sf_id = 1; - loaded_once = 0; + int sf_id = samples[rec].v.sf_id; + if (sf_id == 0) return; + sf_id--; + samples[rec].next = sflists[sf_id].samples; + sflists[sf_id].samples = rec; + sflists[sf_id].num_sample++; } - -/* search the specified sample */ -static short -awe_set_sample(awe_voice_info *vp) +/* purge the old records which don't belong with the same file id */ +static void purge_old_list(int rec, int next) { - int i; - for (i = 0; i < free_sample; i++) { - if (samples[i].sf_id == vp->sf_id && - samples[i].sample == vp->sample) { - /* set the actual sample offsets */ - vp->start += samples[i].start; - vp->end += samples[i].end; - vp->loopstart += samples[i].loopstart; - vp->loopend += samples[i].loopend; - /* copy mode flags */ - vp->mode = samples[i].mode_flags; - /* set index */ - vp->index = i; - return i; + infos[rec].next_instr = next; + if (infos[rec].bank == AWE_DRUM_BANK) { + /* remove samples with the same note range */ + int cur, *prevp = &infos[rec].next_instr; + int low = infos[rec].v.low; + int high = infos[rec].v.high; + for (cur = next; cur >= 0; cur = infos[cur].next_instr) { + if (infos[cur].v.low == low && + infos[cur].v.high == high && + infos[cur].v.sf_id != infos[rec].v.sf_id) + *prevp = infos[cur].next_instr; + prevp = &infos[cur].next_instr; } + } else { + if (infos[next].v.sf_id != infos[rec].v.sf_id) + infos[rec].next_instr = -1; } - return -1; } - -/* voice pressure change */ -static void -awe_aftertouch(int dev, int voice, int pressure) +/* prepend to top of the preset table */ +static void add_info_list(int rec) { - DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure)); - if (awe_channel_mode == 2) { - int note = (voice_alloc->map[voice] & 0xff) - 1; - awe_start_note(dev, voice, note + 0x80, pressure); - - } else if (awe_channel_mode == 0) { - if (voice < 0 || voice >= awe_max_voices) - return; - voices[voice].velocity = pressure; - awe_set_voice_vol(voice, FALSE); - } -} + int *prevp, cur; + int instr = infos[rec].instr; + int bank = infos[rec].bank; + if (infos[rec].disabled) + return; -/* voice control change */ -static void -awe_controller(int dev, int voice, int ctrl_num, int value) -{ - awe_chan_info *cinfo; - - if (awe_channel_mode) { - if (awe_channel_mode == 2) /* get channel */ - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - cinfo = &channels[voice]; - } else { - if (voice < 0 || voice >= awe_max_voices) + prevp = &preset_table[instr]; + cur = *prevp; + while (cur >= 0) { + /* search the first record with the same bank number */ + if (infos[cur].bank == bank) { + /* replace the list with the new record */ + infos[rec].next_bank = infos[cur].next_bank; + *prevp = rec; + purge_old_list(rec, cur); return; - cinfo = voices[voice].cinfo; - } - - switch (ctrl_num) { - case CTL_BANK_SELECT: /* SEQ1 control */ - DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value)); - cinfo->bank = value; - awe_set_instr(dev, voice, cinfo->instr); - break; - - case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */ - DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value)); - /* zero centered */ - cinfo->bender = value; - awe_voice_change(voice, awe_set_voice_pitch); - break; - - case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */ - DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value)); - /* value = sense x 100 */ - cinfo->bender_range = value; - /* no audible pitch change yet.. */ - break; - - case CTL_EXPRESSION: /* SEQ1 control */ - if (!awe_channel_mode) - value /= 128; - case CTRL_EXPRESSION: /* SEQ1 V2 control */ - DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value)); - /* 0 - 127 */ - cinfo->expression_vol = value; - awe_voice_change(voice, awe_set_voice_vol); - break; - - case CTL_PAN: /* SEQ1 control */ - DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value)); - /* (0-127) -> signed 8bit */ - cinfo->panning = value * 2 - 128; - awe_voice_change(voice, awe_set_pan); - break; - - case CTL_MAIN_VOLUME: /* SEQ1 control */ - if (!awe_channel_mode) - value = (value * 100) / 16383; - case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */ - DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value)); - /* 0 - 127 */ - cinfo->main_vol = value; - awe_voice_change(voice, awe_set_voice_vol); - break; - - case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */ - DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value)); - FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2); - break; - - case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */ - DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value)); - FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2); - break; - -#ifdef AWE_ACCEPT_ALL_SOUNDS_CONTROLL - case 120: /* all sounds off */ - {int i; for (i = 0; i < AWE_NORMAL_VOICES; i++) - awe_terminate(i); - } - /*awe_reset(0);*/ - break; - case 123: /* all notes off */ - {int i; - for (i = 0; i < awe_max_voices; i++) - awe_note_off(i); } - break; -#endif - - case CTL_SUSTAIN: /* sustain the channel */ - cinfo->sustained = value; - if (value == 0) - awe_voice_change(voice, awe_sustain_off); - break; - - default: - DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n", - voice, ctrl_num, value)); - break; + prevp = &infos[cur].next_bank; + cur = infos[cur].next_bank; } -} - + /* this is the first bank record.. just add this */ + infos[rec].next_instr = -1; + infos[rec].next_bank = preset_table[instr]; + preset_table[instr] = rec; +} -/* change the voice parameters */ -static void awe_voice_change(int voice, fx_affect_func func) +/* remove samples later than the specified sf_id */ +static void +awe_remove_samples(int sf_id) { - int i; - if (! awe_channel_mode) { - func(voice, FALSE); + if (sf_id <= 0) { + awe_reset_samples(); return; } + /* already removed? */ + if (current_sf_id <= sf_id) + return; - for (i = 0; i < awe_max_voices; i++) - if (voices[i].ch == voice) - func(i, FALSE); -} - + current_sf_id = sf_id; + if (locked_sf_id > sf_id) + locked_sf_id = sf_id; -/* drop sustain */ -static void awe_sustain_off(int voice, int forced) -{ - if (voices[voice].state == AWE_ST_SUSTAINED) - awe_note_off(voice); + rebuild_preset_list(); } - -/* voice pan change (value = -128 - 127) */ -static void -awe_panning(int dev, int voice, int value) +/* rebuild preset search list */ +static void rebuild_preset_list(void) { - awe_chan_info *cinfo; - if (awe_channel_mode) { - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - cinfo = &channels[voice]; - } else { - if (voice < 0 || voice >= awe_max_voices) - return; - cinfo = voices[voice].cinfo; - } - - cinfo->panning = value; - DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning)); - awe_voice_change(voice, awe_set_pan); -} + int i, j; + for (i = 0; i < AWE_MAX_PRESETS; i++) + preset_table[i] = -1; -/* volume mode change */ -static void -awe_volume_method(int dev, int mode) -{ - /* not impremented */ - DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode)); + for (i = 0; i < current_sf_id; i++) { + for (j = sflists[i].infos; j >= 0; j = infos[j].next) + add_info_list(j); + } } - -#ifndef AWE_NO_PATCHMGR -/* patch manager */ -static int -awe_patchmgr(int dev, struct patmgr_info *rec) +/* search the specified sample */ +static short +awe_set_sample(awe_voice_info *vp) { - FATALERR(printk("AWE32 Warning: patch manager control not supported\n")); - return 0; + int i; + vp->index = -1; + for (i = sflists[vp->sf_id-1].samples; i >= 0; i = samples[i].next) { + if (samples[i].v.sample == vp->sample) { + /* set the actual sample offsets */ + vp->start += samples[i].v.start; + vp->end += samples[i].v.end; + vp->loopstart += samples[i].v.loopstart; + vp->loopend += samples[i].v.loopend; + /* copy mode flags */ + vp->mode = samples[i].v.mode_flags; + /* set index */ + vp->index = i; + return i; + } + } + return -1; } -#endif -/* pitch wheel change: 0-16384 */ -static void -awe_bender(int dev, int voice, int value) -{ - awe_chan_info *cinfo; - if (awe_channel_mode) { - if (awe_channel_mode == 2) - voice = voice_alloc->map[voice] >> 8; - if (voice < 0 || voice >= AWE_MAX_CHANNELS) - return; - cinfo = &channels[voice]; - } else { - if (voice < 0 || voice >= awe_max_voices) - return; - cinfo = voices[voice].cinfo; - } - /* convert to zero centered value */ - cinfo->bender = value - 8192; - DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender)); - awe_voice_change(voice, awe_set_voice_pitch); -} +/*---------------------------------------------------------------- + * voice allocation + *----------------------------------------------------------------*/ -/* calculate the number of voices for this note & velocity */ +/* look for all voices associated with the specified note & velocity */ static int -awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist) +awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist) { - int maxc; int nvoices; - unsigned short sf_id; - sf_id = current_sf_id; nvoices = 0; - for (maxc = AWE_MAX_INFOS; - rec && maxc; rec = rec->next_instr, maxc--) { - if (rec->v.low <= note && note <= rec->v.high && - velocity >= rec->v.vellow && velocity <= rec->v.velhigh) { - if (nvoices == 0) - sf_id = rec->v.sf_id; - else if (rec->v.sf_id != sf_id) - continue; - vlist[nvoices] = &rec->v; + for (; rec >= 0; rec = infos[rec].next_instr) { + if (note >= infos[rec].v.low && + note <= infos[rec].v.high && + velocity >= infos[rec].v.vellow && + velocity <= infos[rec].v.velhigh) { + vlist[nvoices] = &infos[rec].v; + if (infos[rec].type == V_ST_MAPPED) /* mapper */ + return -1; nvoices++; if (nvoices >= AWE_MAX_VOICES) break; @@ -2911,112 +3602,182 @@ awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_i return nvoices; } +/* store the voice list from the specified note and velocity. + if the preset is mapped, seek for the destination preset, and rewrite + the note number if necessary. + */ +static int +really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_info **vlist, int level) +{ + int nvoices; + + nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); + if (nvoices == 0) + nvoices = awe_search_multi_voices(def_vrec, *note, velocity, vlist); + if (nvoices < 0) { /* mapping */ + int preset = vlist[0]->start; + int bank = vlist[0]->end; + int key = vlist[0]->fixkey; + if (level > 5) { + printk("AWE32: too deep mapping level\n"); + return 0; + } + vrec = awe_search_instr(bank, preset); + if (bank == AWE_DRUM_BANK) + def_vrec = awe_search_instr(bank, 0); + else + def_vrec = awe_search_instr(0, preset); + if (key >= 0) + *note = key; + return really_alloc_voices(vrec, def_vrec, note, velocity, vlist, level+1); + } + + return nvoices; +} + /* allocate voices corresponding note and velocity; supports multiple insts. */ static void -awe_alloc_multi_voices(int ch, int note, int velocity) +awe_alloc_multi_voices(int ch, int note, int velocity, int key) { int i, v, nvoices; awe_voice_info *vlist[AWE_MAX_VOICES]; - if (channels[ch].vrec == NULL && channels[ch].def_vrec == NULL) + if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0) awe_set_instr(0, ch, channels[ch].instr); - nvoices = awe_search_multi_voices(channels[ch].vrec, note, velocity, vlist); - if (nvoices == 0) - nvoices = awe_search_multi_voices(channels[ch].def_vrec, note, velocity, vlist); + /* check the possible voices; note may be changeable if mapped */ + nvoices = really_alloc_voices(channels[ch].vrec, channels[ch].def_vrec, + ¬e, velocity, vlist, 0); - /* allocate the voices */ + /* set the voices */ current_alloc_time++; for (i = 0; i < nvoices; i++) { v = awe_clear_voice(); - voices[v].key = AWE_CHAN_KEY(ch, note); + voices[v].key = key; voices[v].ch = ch; + voices[v].note = note; + voices[v].velocity = velocity; voices[v].time = current_alloc_time; voices[v].cinfo = &channels[ch]; voices[v].sample = vlist[i]; voices[v].state = AWE_ST_MARK; + voices[v].layer = nvoices - i - 1; /* in reverse order */ } /* clear the mark in allocated voices */ - for (i = 0; i < awe_max_voices; i++) + for (i = 0; i < awe_max_voices; i++) { if (voices[i].state == AWE_ST_MARK) voices[i].state = AWE_ST_OFF; + + } } -/* search an empty voice; used internally */ +/* search the best voice from the specified status condition */ static int -awe_clear_voice(void) +search_best_voice(int condition) { int i, time, best; - - /* looking for the oldest empty voice */ best = -1; - time = 0x7fffffff; + time = current_alloc_time + 1; for (i = 0; i < awe_max_voices; i++) { - if (voices[i].state == AWE_ST_OFF && voices[i].time < time) { + if ((voices[i].state & condition) && + (best < 0 || voices[i].time < time)) { best = i; time = voices[i].time; } } - if (best >= 0) - return best; + /* clear voice */ + if (best >= 0) { + if (voices[best].state != AWE_ST_OFF) + awe_terminate(best); + awe_voice_init(best, TRUE); + } + + return best; +} + +/* search an empty voice. + if no empty voice is found, at least terminate a voice + */ +static int +awe_clear_voice(void) +{ + int best; + /* looking for the oldest empty voice */ + if ((best = search_best_voice(AWE_ST_OFF)) >= 0) + return best; + if ((best = search_best_voice(AWE_ST_RELEASED)) >= 0) + return best; /* looking for the oldest sustained voice */ - time = 0x7fffffff; - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].state == AWE_ST_SUSTAINED && - voices[i].time < time) { - best = i; - time = voices[i].time; - } - } - if (best >= 0) { - awe_note_off(best); + if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0) return best; - } - /* looking for the oldest voice not marked */ - time = 0x7fffffff; - best = 0; - for (i = 0; i < awe_max_voices; i++) { - if (voices[i].state != AWE_ST_MARK && voices[i].time < time) { - best = i; - time = voices[i].time; +#ifdef AWE_LOOKUP_MIDI_PRIORITY + if (MULTI_LAYER_MODE() && misc_modes[AWE_MD_CHN_PRIOR]) { + int ch = -1; + int time = current_alloc_time + 1; + int i; + /* looking for the voices from high channel (except drum ch) */ + for (i = 0; i < awe_max_voices; i++) { + if (IS_DRUM_CHANNEL(voices[i].ch)) continue; + if (voices[i].ch < ch) continue; + if (voices[i].state != AWE_ST_MARK && + (voices[i].ch > ch || voices[i].time < time)) { + best = i; + time = voices[i].time; + ch = voices[i].ch; + } } } - /*awe_terminate(best);*/ - awe_note_off(best); - return best; +#endif + if (best < 0) + best = search_best_voice(~AWE_ST_MARK); + + if (best >= 0) + return best; + + return 0; } -/* allocate a voice corresponding note and velocity; single instrument */ +/* search sample for the specified note & velocity and set it on the voice; + * note that voice is the voice index (not channel index) + */ static void awe_alloc_one_voice(int voice, int note, int velocity) { - int nvoices; + int ch, nvoices; awe_voice_info *vlist[AWE_MAX_VOICES]; - if (voices[voice].cinfo->vrec == NULL && voices[voice].cinfo->def_vrec == NULL) - awe_set_instr(0, voice, voices[voice].cinfo->instr); - - nvoices = awe_search_multi_voices(voices[voice].cinfo->vrec, note, velocity, vlist); - if (nvoices == 0) - nvoices = awe_search_multi_voices(voices[voice].cinfo->def_vrec, note, velocity, vlist); + ch = voices[voice].ch; + if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0) + awe_set_instr(0, ch, channels[ch].instr); + nvoices = really_alloc_voices(voices[voice].cinfo->vrec, + voices[voice].cinfo->def_vrec, + ¬e, velocity, vlist, 0); if (nvoices > 0) { voices[voice].time = ++current_alloc_time; voices[voice].sample = vlist[0]; /* use the first one */ + voices[voice].layer = 0; + voices[voice].note = note; + voices[voice].velocity = velocity; } } +/*---------------------------------------------------------------- + * sequencer2 functions + *----------------------------------------------------------------*/ + /* search an empty voice; used by sequencer2 */ static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) { - awe_channel_mode = 2; + playing_mode = AWE_PLAY_MULTI2; + awe_info.nr_voices = AWE_MAX_CHANNELS; return awe_clear_voice(); } @@ -3053,6 +3814,75 @@ awe_setup_voice(int dev, int voice, int chn) } +#ifdef CONFIG_AWE32_MIXER +/*================================================================ + * AWE32 mixer device control + *================================================================*/ + +static int +awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + int i, level; + + if (((cmd >> 8) & 0xff) != 'M') + return RET_ERROR(EINVAL); + + level = (int)IOCTL_IN(arg); + level = ((level & 0xff) + (level >> 8)) / 2; + DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level)); + + if (IO_WRITE_CHECK(cmd)) { + switch (cmd & 0xff) { + case SOUND_MIXER_BASS: + awe_bass_level = level * 12 / 100; + if (awe_bass_level >= 12) + awe_bass_level = 11; + awe_equalizer(awe_bass_level, awe_treble_level); + break; + case SOUND_MIXER_TREBLE: + awe_treble_level = level * 12 / 100; + if (awe_treble_level >= 12) + awe_treble_level = 11; + awe_equalizer(awe_bass_level, awe_treble_level); + break; + case SOUND_MIXER_VOLUME: + level = level * 127 / 100; + if (level >= 128) level = 127; + init_atten = vol_table[level]; + for (i = 0; i < awe_max_voices; i++) + awe_set_voice_vol(i, TRUE); + break; + } + } + switch (cmd & 0xff) { + case SOUND_MIXER_BASS: + level = awe_bass_level * 100 / 24; + level = (level << 8) | level; + break; + case SOUND_MIXER_TREBLE: + level = awe_treble_level * 100 / 24; + level = (level << 8) | level; + break; + case SOUND_MIXER_VOLUME: + for (i = 127; i > 0; i--) { + if (init_atten <= vol_table[i]) + break; + } + level = i * 100 / 127; + level = (level << 8) | level; + break; + case SOUND_MIXER_DEVMASK: + level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME; + break; + default: + level = 0; + break; + } + return IOCTL_OUT(arg, level); +} +#endif /* CONFIG_AWE32_MIXER */ + + /*================================================================ * initialization of AWE32 *================================================================*/ @@ -3299,16 +4129,22 @@ awe_init_fm(void) awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 | (DEF_FM_CHORUS_DEPTH << 24)); awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8)); - awe_poke_dw(AWE_CPF(31), 0); + awe_poke_dw(AWE_CPF(31), 0x8000); awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3); /* skew volume & cutoff */ awe_poke_dw(AWE_VTFT(30), 0x8000FFFF); awe_poke_dw(AWE_VTFT(31), 0x8000FFFF); + voices[30].state = AWE_ST_FM; + voices[31].state = AWE_ST_FM; + /* change maximum channels to 30 */ awe_max_voices = AWE_NORMAL_VOICES; - awe_info.nr_voices = awe_max_voices; + if (playing_mode == AWE_PLAY_DIRECT) + awe_info.nr_voices = awe_max_voices; + else + awe_info.nr_voices = AWE_MAX_CHANNELS; voice_alloc->max_voice = awe_max_voices; } @@ -3318,20 +4154,32 @@ awe_init_fm(void) /* open DRAM write accessing mode */ static int -awe_open_dram_for_write(int offset) +awe_open_dram_for_write(int offset, int channels) { + int vidx[AWE_NORMAL_VOICES]; int i; + if (channels < 0 || channels >= AWE_NORMAL_VOICES) { + channels = AWE_NORMAL_VOICES; + for (i = 0; i < AWE_NORMAL_VOICES; i++) + vidx[i] = i; + } else { + for (i = 0; i < channels; i++) + vidx[i] = awe_clear_voice(); + } + /* use all channels for DMA transfer */ - for (i = 0; i < AWE_NORMAL_VOICES; i++) { - awe_poke(AWE_DCYSUSV(i), 0x80); - awe_poke_dw(AWE_VTFT(i), 0); - awe_poke_dw(AWE_CVCF(i), 0); - awe_poke_dw(AWE_PTRX(i), 0x40000000); - awe_poke_dw(AWE_CPF(i), 0x40000000); - awe_poke_dw(AWE_PSST(i), 0); - awe_poke_dw(AWE_CSL(i), 0); - awe_poke_dw(AWE_CCCA(i), 0x06000000); + for (i = 0; i < channels; i++) { + if (vidx[i] < 0) continue; + awe_poke(AWE_DCYSUSV(vidx[i]), 0x80); + awe_poke_dw(AWE_VTFT(vidx[i]), 0); + awe_poke_dw(AWE_CVCF(vidx[i]), 0); + awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000); + awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000); + awe_poke_dw(AWE_PSST(vidx[i]), 0); + awe_poke_dw(AWE_CSL(vidx[i]), 0); + awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000); + voices[vidx[i]].state = AWE_ST_DRAM; } /* point channels 31 & 32 to ROM samples for DRAM refresh */ awe_poke_dw(AWE_VTFT(30), 0); @@ -3342,16 +4190,20 @@ awe_open_dram_for_write(int offset) awe_poke_dw(AWE_PSST(31), 0x1d8); awe_poke_dw(AWE_CSL(31), 0x1e0); awe_poke_dw(AWE_CCCA(31), 0x1d8); + voices[30].state = AWE_ST_FM; + voices[31].state = AWE_ST_FM; /* if full bit is on, not ready to write on */ if (awe_peek_dw(AWE_SMALW) & 0x80000000) { - for (i = 0; i < AWE_NORMAL_VOICES; i++) - awe_poke_dw(AWE_CCCA(i), 0); + for (i = 0; i < channels; i++) { + awe_poke_dw(AWE_CCCA(vidx[i]), 0); + voices[i].state = AWE_ST_OFF; + } return RET_ERROR(ENOSPC); } /* set address to write */ - awe_poke_dw(AWE_SMALW, offset + AWE_DRAM_OFFSET); + awe_poke_dw(AWE_SMALW, offset); return 0; } @@ -3373,6 +4225,7 @@ awe_open_dram_for_check(void) awe_poke_dw(AWE_CCCA(i), 0x06000000); else /* DMA read */ awe_poke_dw(AWE_CCCA(i), 0x04000000); + voices[i].state = AWE_ST_DRAM; } } @@ -3390,79 +4243,14 @@ awe_close_dram(void) } for (i = 0; i < AWE_NORMAL_VOICES; i++) { - awe_poke_dw(AWE_CCCA(i), 0); - awe_poke(AWE_DCYSUSV(i), 0x807F); - } -} - - -#ifdef AWE_CHECKSUM_MEMORY -/* open DRAM read accessing mode */ -static int -awe_open_dram_for_read(int offset) -{ - int i; - - /* use all channels for DMA transfer */ - for (i = 0; i < AWE_NORMAL_VOICES; i++) { - awe_poke(AWE_DCYSUSV(i), 0x80); - awe_poke_dw(AWE_VTFT(i), 0); - awe_poke_dw(AWE_CVCF(i), 0); - awe_poke_dw(AWE_PTRX(i), 0x40000000); - awe_poke_dw(AWE_CPF(i), 0x40000000); - awe_poke_dw(AWE_PSST(i), 0); - awe_poke_dw(AWE_CSL(i), 0); - awe_poke_dw(AWE_CCCA(i), 0x04000000); - } - /* point channels 31 & 32 to ROM samples for DRAM refresh */ - awe_poke_dw(AWE_VTFT(30), 0); - awe_poke_dw(AWE_PSST(30), 0x1d8); - awe_poke_dw(AWE_CSL(30), 0x1e0); - awe_poke_dw(AWE_CCCA(30), 0x1d8); - awe_poke_dw(AWE_VTFT(31), 0); - awe_poke_dw(AWE_PSST(31), 0x1d8); - awe_poke_dw(AWE_CSL(31), 0x1e0); - awe_poke_dw(AWE_CCCA(31), 0x1d8); - - /* if empty flag is on, not ready to read */ - if (awe_peek_dw(AWE_SMALR) & 0x80000000) { - for (i = 0; i < AWE_NORMAL_VOICES; i++) + if (voices[i].state == AWE_ST_DRAM) { awe_poke_dw(AWE_CCCA(i), 0); - return RET_ERROR(ENOSPC); - } - - /* set address to read */ - awe_poke_dw(AWE_SMALR, offset + AWE_DRAM_OFFSET); - /* drop stale data */ - awe_peek(AWE_SMLD); - return 0; -} - -/* close dram access for read */ -static void -awe_close_dram_for_read(void) -{ - int i; - /* wait until FULL bit in SMAxW register be false */ - for (i = 0; i < 10000; i++) { - if (!(awe_peek_dw(AWE_SMALR) & 0x80000000)) - break; - awe_wait(10); - } - for (i = 0; i < AWE_NORMAL_VOICES; i++) { - awe_poke_dw(AWE_CCCA(i), 0); - awe_poke(AWE_DCYSUSV(i), 0x807F); + awe_poke(AWE_DCYSUSV(i), 0x807F); + voices[i].state = AWE_ST_OFF; + } } } -#endif /* AWE_CHECKSUM_MEMORY */ - -/* write a word data */ -static void -awe_write_dram(unsigned short c) -{ - awe_poke(AWE_SMLD, c); -} /*================================================================ * detect presence of AWE32 and check memory size @@ -3488,18 +4276,14 @@ static int awe_detect(void) { int base; -#ifdef AWE_DEFAULT_BASE_ADDR - if (awe_detect_base(AWE_DEFAULT_BASE_ADDR)) - return 1; -#endif if (awe_base == 0) { for (base = 0x620; base <= 0x680; base += 0x20) if (awe_detect_base(base)) return 1; + DEBUG(0,printk("AWE32 not found\n")); + return 0; } - FATALERR(printk("AWE32 not found\n")); - awe_base = 0; - return 0; + return 1; } @@ -3515,14 +4299,20 @@ awe_detect(void) static int awe_check_dram(void) { + if (awe_mem_size > 0) { + awe_mem_size *= 1024; /* convert to Kbytes */ + return awe_mem_size; + } + awe_open_dram_for_check(); + awe_mem_size = 0; + /* set up unique two id numbers */ awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET); awe_poke(AWE_SMLD, UNIQUE_ID1); awe_poke(AWE_SMLD, UNIQUE_ID2); - awe_mem_size = 0; while (awe_mem_size < AWE_MAX_DRAM_SIZE) { awe_wait(2); /* read a data on the DRAM start address */ @@ -3540,14 +4330,17 @@ awe_check_dram(void) */ awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L); awe_poke(AWE_SMLD, UNIQUE_ID3); + awe_wait(2); + /* read a data on the just written DRAM address */ + awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L); + awe_peek(AWE_SMLD); /* discard stale data */ + if (awe_peek(AWE_SMLD) != UNIQUE_ID3) + break; } awe_close_dram(); - DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", (int)awe_mem_size)); -#ifdef AWE_DEFAULT_MEM_SIZE - if (awe_mem_size == 0) - awe_mem_size = AWE_DEFAULT_MEM_SIZE; -#endif + DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", awe_mem_size)); + /* convert to Kbytes */ awe_mem_size *= 1024; return awe_mem_size; @@ -3559,26 +4352,49 @@ awe_check_dram(void) *================================================================*/ /* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */ -static unsigned short chorus_parm[8][5] = { - {0xE600, 0x03F6, 0xBC2C ,0x0000, 0x006D}, /* chorus 1 */ - {0xE608, 0x031A, 0xBC6E, 0x0000, 0x017C}, /* chorus 2 */ - {0xE610, 0x031A, 0xBC84, 0x0000, 0x0083}, /* chorus 3 */ - {0xE620, 0x0269, 0xBC6E, 0x0000, 0x017C}, /* chorus 4 */ - {0xE680, 0x04D3, 0xBCA6, 0x0000, 0x005B}, /* feedback */ - {0xE6E0, 0x044E, 0xBC37, 0x0000, 0x0026}, /* flanger */ - {0xE600, 0x0B06, 0xBC00, 0xE000, 0x0083}, /* short delay */ - {0xE6C0, 0x0B06, 0xBC00, 0xE000, 0x0083}, /* short delay + feedback */ +static char chorus_defined[AWE_CHORUS_NUMBERS]; +static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = { + {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */ + {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */ + {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */ + {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */ + {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */ + {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */ + {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */ + {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */ }; -static void awe_set_chorus_mode(int effect) +static int +awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count) +{ + if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) { + printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg); + return RET_ERROR(EINVAL); + } + if (count < sizeof(awe_chorus_fx_rec)) { + printk("AWE32 Error: too short chorus fx parameters\n"); + return RET_ERROR(EINVAL); + } + COPY_FROM_USER(&chorus_parm[patch->optarg], addr, AWE_PATCH_INFO_SIZE, + sizeof(awe_chorus_fx_rec)); + chorus_defined[patch->optarg] = TRUE; + return 0; +} + +static void +awe_set_chorus_mode(int effect) { - awe_poke(AWE_INIT3(9), chorus_parm[effect][0]); - awe_poke(AWE_INIT3(12), chorus_parm[effect][1]); - awe_poke(AWE_INIT4(3), chorus_parm[effect][2]); - awe_poke_dw(AWE_HWCF4, (unsigned long)chorus_parm[effect][3]); - awe_poke_dw(AWE_HWCF5, (unsigned long)chorus_parm[effect][4]); + if (effect < 0 || effect >= AWE_CHORUS_NUMBERS || + (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect])) + return; + awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback); + awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset); + awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth); + awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay); + awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq); awe_poke_dw(AWE_HWCF6, 0x8000); awe_poke_dw(AWE_HWCF7, 0x0000); + chorus_mode = effect; } /*----------------------------------------------------------------*/ @@ -3586,55 +4402,56 @@ static void awe_set_chorus_mode(int effect) /* reverb mode settings; write the following 28 data of 16 bit length * on the corresponding ports in the reverb_cmds array */ -static unsigned short reverb_parm[8][28] = { -{ /* room 1 */ +static char reverb_defined[AWE_CHORUS_NUMBERS]; +static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = { +{{ /* room 1 */ 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4, 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516, 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}, -{ /* room 2 */ +}}, +{{ /* room 2 */ 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284, 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}, -{ /* room 3 */ +}}, +{{ /* room 3 */ 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284, 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516, 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A, -}, -{ /* hall 1 */ +}}, +{{ /* hall 1 */ 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284, 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, -}, -{ /* hall 2 */ +}}, +{{ /* hall 2 */ 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254, 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3, 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}, -{ /* plate */ +}}, +{{ /* plate */ 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548, 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, -}, -{ /* delay */ +}}, +{{ /* delay */ 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204, 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, -}, -{ /* panning delay */ +}}, +{{ /* panning delay */ 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204, 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, -}, +}}, }; static struct ReverbCmdPair { @@ -3649,13 +4466,112 @@ static struct ReverbCmdPair { {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)}, }; +static int +awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count) +{ + if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) { + printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg); + return RET_ERROR(EINVAL); + } + if (count < sizeof(awe_reverb_fx_rec)) { + printk("AWE32 Error: too short reverb fx parameters\n"); + return RET_ERROR(EINVAL); + } + COPY_FROM_USER(&reverb_parm[patch->optarg], addr, AWE_PATCH_INFO_SIZE, + sizeof(awe_reverb_fx_rec)); + reverb_defined[patch->optarg] = TRUE; + return 0; +} -static void awe_set_reverb_mode(int effect) +static void +awe_set_reverb_mode(int effect) { int i; + if (effect < 0 || effect >= AWE_REVERB_NUMBERS || + (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect])) + return; for (i = 0; i < 28; i++) awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port, - reverb_parm[effect][i]); + reverb_parm[effect].parms[i]); + reverb_mode = effect; } +/*================================================================ + * treble/bass equalizer control + *================================================================*/ + +static unsigned short bass_parm[12][3] = { + {0xD26A, 0xD36A, 0x0000}, /* -12 dB */ + {0xD25B, 0xD35B, 0x0000}, /* -8 */ + {0xD24C, 0xD34C, 0x0000}, /* -6 */ + {0xD23D, 0xD33D, 0x0000}, /* -4 */ + {0xD21F, 0xD31F, 0x0000}, /* -2 */ + {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */ + {0xC219, 0xC319, 0x0001}, /* +2 */ + {0xC22A, 0xC32A, 0x0001}, /* +4 */ + {0xC24C, 0xC34C, 0x0001}, /* +6 */ + {0xC26E, 0xC36E, 0x0001}, /* +8 */ + {0xC248, 0xC348, 0x0002}, /* +10 */ + {0xC26A, 0xC36A, 0x0002}, /* +12 dB */ +}; + +static unsigned short treble_parm[12][9] = { + {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */ + {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, + {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, + {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, + {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, + {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002}, + {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002}, + {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002}, + {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002}, + {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */ + {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, + {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */ +}; + + +/* + * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB] + */ +static void +awe_equalizer(int bass, int treble) +{ + unsigned short w; + + if (bass < 0 || bass > 11 || treble < 0 || treble > 11) + return; + awe_bass_level = bass; + awe_treble_level = treble; + awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]); + awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]); + awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]); + awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]); + awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]); + awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]); + awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]); + awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]); + awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]); + awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]); + w = bass_parm[bass][2] + treble_parm[treble][8]; + awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262)); + awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362)); +} + + #endif /* CONFIG_AWE32_SYNTH */ + +#ifdef MODULE +int init_module(void) +{ + attach_awe(); + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + unload_awe(); + SOUND_LOCK_END; +} +#endif diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index f4f86ff57..f1f6559c4 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -6,7 +6,7 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> /* * sound/mad16.c * @@ -59,8 +59,18 @@ */ #include "sound_config.h" +#include "soundmodule.h" + +#ifdef MODULE +#define MAD16_CDSEL mad16_cdsel +#define MAD16_CONF mad16_conf + +static int mad16_conf; +static int mad16_cdsel; + +#endif -#if defined(CONFIG_MAD16) +#if defined(CONFIG_MAD16) || defined(MODULE) #include "sb.h" @@ -108,127 +118,121 @@ static int *mad16_osp; #endif static unsigned char -mad_read (int port) +mad_read(int port) { - unsigned long flags; - unsigned char tmp; - - save_flags (flags); - cli (); - - switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb ((0xE2), PASSWD_REG); - break; - - case C929: - outb ((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - outb ((0xE5), PASSWD_REG); - break; - } - - if (board_type == C930) - { - outb ((port - MC0_PORT), 0xe0e); /* Write to index reg */ - tmp = inb (0xe0f); /* Read from data reg */ - } - else - tmp = inb (port); - restore_flags (flags); - - return tmp; + unsigned long flags; + unsigned char tmp; + + save_flags(flags); + cli(); + + switch (board_type) /* Output password */ + { + case C928: + case MOZART: + outb((0xE2), PASSWD_REG); + break; + + case C929: + outb((0xE3), PASSWD_REG); + break; + + case C930: + /* outb(( 0xE4), PASSWD_REG); */ + break; + + case C924: + outb((0xE5), PASSWD_REG); + break; + } + + if (board_type == C930) + { + outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ + tmp = inb(0xe0f); /* Read from data reg */ + } else + tmp = inb(port); + restore_flags(flags); + + return tmp; } static void -mad_write (int port, int value) +mad_write(int port, int value) { - unsigned long flags; - - save_flags (flags); - cli (); - - switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb ((0xE2), PASSWD_REG); - break; - - case C929: - outb ((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - outb ((0xE5), PASSWD_REG); - break; - } - - if (board_type == C930) - { - outb ((port - MC0_PORT), 0xe0e); /* Write to index reg */ - outb (((unsigned char) (value & 0xff)), 0xe0f); - } - else - outb (((unsigned char) (value & 0xff)), port); - restore_flags (flags); + unsigned long flags; + + save_flags(flags); + cli(); + + switch (board_type) /* Output password */ + { + case C928: + case MOZART: + outb((0xE2), PASSWD_REG); + break; + + case C929: + outb((0xE3), PASSWD_REG); + break; + + case C930: + /* outb(( 0xE4), PASSWD_REG); */ + break; + + case C924: + outb((0xE5), PASSWD_REG); + break; + } + + if (board_type == C930) + { + outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ + outb(((unsigned char) (value & 0xff)), 0xe0f); + } else + outb(((unsigned char) (value & 0xff)), port); + restore_flags(flags); } static int -detect_c930 (void) +detect_c930(void) { - unsigned char tmp = mad_read (MC1_PORT); - - if ((tmp & 0x06) != 0x06) - { - DDB (printk ("Wrong C930 signature (%x)\n", tmp)); - /* return 0; */ - } - - mad_write (MC1_PORT, 0); - - if (mad_read (MC1_PORT) != 0x06) - { - DDB (printk ("Wrong C930 signature2 (%x)\n", tmp)); - /* return 0; */ - } - - mad_write (MC1_PORT, tmp); /* Restore bits */ - - mad_write (MC7_PORT, 0); - if ((tmp = mad_read (MC7_PORT)) != 0) - { - DDB (printk ("MC7 not writable (%x)\n", tmp)); - return 0; - } - - mad_write (MC7_PORT, 0xcb); - if ((tmp = mad_read (MC7_PORT)) != 0xcb) - { - DDB (printk ("MC7 not writable2 (%x)\n", tmp)); - return 0; - } - - return 1; + unsigned char tmp = mad_read(MC1_PORT); + + if ((tmp & 0x06) != 0x06) + { + DDB(printk("Wrong C930 signature (%x)\n", tmp)); + /* return 0; */ + } + mad_write(MC1_PORT, 0); + + if (mad_read(MC1_PORT) != 0x06) + { + DDB(printk("Wrong C930 signature2 (%x)\n", tmp)); + /* return 0; */ + } + mad_write(MC1_PORT, tmp); /* Restore bits */ + + mad_write(MC7_PORT, 0); + if ((tmp = mad_read(MC7_PORT)) != 0) + { + DDB(printk("MC7 not writable (%x)\n", tmp)); + return 0; + } + mad_write(MC7_PORT, 0xcb); + if ((tmp = mad_read(MC7_PORT)) != 0xcb) + { + DDB(printk("MC7 not writable2 (%x)\n", tmp)); + return 0; + } + return 1; } static int -detect_mad16 (void) +detect_mad16(void) { - unsigned char tmp, tmp2; - int i; + unsigned char tmp, tmp2; + int i; /* * Check that reading a register doesn't return bus float (0xff) @@ -236,570 +240,716 @@ detect_mad16 (void) * the card is in low power mode. Normally at least the power saving mode * bit should be 0. */ - if ((tmp = mad_read (MC1_PORT)) == 0xff) - { - DDB (printk ("MC1_PORT returned 0xff\n")); - return 0; - } - - for (i = 0xf8d; i <= 0xf98; i++) - DDB (printk ("Port %0x (init value) = %0x\n", i, mad_read (i))); - - if (board_type == C930) - return detect_c930 (); + if ((tmp = mad_read(MC1_PORT)) == 0xff) + { + DDB(printk("MC1_PORT returned 0xff\n")); + return 0; + } + for (i = 0xf8d; i <= 0xf98; i++) + DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i))); + + if (board_type == C930) + return detect_c930(); /* * Now check that the gate is closed on first I/O after writing * the password. (This is how a MAD16 compatible card works). */ - if ((tmp2 = inb (MC1_PORT)) == tmp) /* It didn't close */ - { - DDB (printk ("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); - return 0; - } - - mad_write (MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ - if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ - { - mad_write (MC1_PORT, tmp); /* Restore */ - DDB (printk ("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); - return 0; - } - - mad_write (MC1_PORT, tmp); /* Restore */ - return 1; /* Bingo */ + if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */ + { + DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); + return 0; + } + mad_write(MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ + if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ + { + mad_write(MC1_PORT, tmp); /* Restore */ + DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); + return 0; + } + mad_write(MC1_PORT, tmp); /* Restore */ + return 1; /* Bingo */ } static int -wss_init (struct address_info *hw_config) +wss_init(struct address_info *hw_config) { - int ad_flags = 0; + int ad_flags = 0; /* * Verify the WSS parameters */ - if (check_region (hw_config->io_base, 8)) - { - printk ("MSS: I/O port conflict\n"); - return 0; - } - - if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return 0; - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. - */ - - if ((inb (hw_config->io_base + 3) & 0x3f) != 0x04 && - (inb (hw_config->io_base + 3) & 0x3f) != 0x00) - { - DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n", - hw_config->io_base, inb (hw_config->io_base + 3))); - return 0; - } - - if (hw_config->irq > 11) - { - printk ("MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } - - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk ("MSS: Bad DMA %d\n", hw_config->dma); - return 0; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - - if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - } - - return 1; + if (check_region(hw_config->io_base, 8)) + { + printk("MSS: I/O port conflict\n"); + return 0; + } + if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) + return 0; + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00. + */ + + if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 && + (inb(hw_config->io_base + 3) & 0x3f) != 0x00) + { + DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3))); + return 0; + } + if (hw_config->irq > 11) + { + printk("MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk("MSS: Bad DMA %d\n", hw_config->dma); + return 0; + } + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } + if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + } + return 1; } static int -init_c930 (struct address_info *hw_config) +init_c930(struct address_info *hw_config) { - unsigned char cfg; - - cfg = (mad_read (MC1_PORT) & ~0x30); - /* mad_write(MC1_PORT, 0); */ - - switch (hw_config->io_base) - { - case 0x530: - cfg |= 0x00; - break; - case 0xe80: - cfg |= 0x10; - break; - case 0xf40: - cfg |= 0x20; - break; - case 0x604: - cfg |= 0x30; - break; - - default: - printk ("MAD16: Invalid codec port %x\n", hw_config->io_base); - return 0; - } - mad_write (MC1_PORT, cfg); - - /* MC2 is CD configuration. Don't touch it. */ - - mad_write (MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ - mad_write (MC4_PORT, 0x52); /* ??? */ - mad_write (MC5_PORT, 0x3C); /* Init it into mode2 */ - mad_write (MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ - mad_write (MC7_PORT, 0xCB); - mad_write (MC10_PORT, 0x11); - - return wss_init (hw_config); + unsigned char cfg; + + cfg = (mad_read(MC1_PORT) & ~0x30); + /* mad_write(MC1_PORT, 0); */ + + switch (hw_config->io_base) + { + case 0x530: + cfg |= 0x00; + break; + case 0xe80: + cfg |= 0x10; + break; + case 0xf40: + cfg |= 0x20; + break; + case 0x604: + cfg |= 0x30; + break; + + default: + printk("MAD16: Invalid codec port %x\n", hw_config->io_base); + return 0; + } + mad_write(MC1_PORT, cfg); + + /* MC2 is CD configuration. Don't touch it. */ + + mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ + mad_write(MC4_PORT, 0x52); /* ??? */ + mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */ + mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ + mad_write(MC7_PORT, 0xCB); + mad_write(MC10_PORT, 0x11); + + return wss_init(hw_config); } static int -chip_detect (void) +chip_detect(void) { - int i; + int i; /* * Then try to detect with the old password */ - board_type = C924; + board_type = C924; - DDB (printk ("Detect using password = 0xE5\n")); + DDB(printk("Detect using password = 0xE5\n")); - if (!detect_mad16 ()) /* No luck. Try different model */ - { - board_type = C928; + if (!detect_mad16()) /* No luck. Try different model */ + { + board_type = C928; - DDB (printk ("Detect using password = 0xE2\n")); + DDB(printk("Detect using password = 0xE2\n")); - if (!detect_mad16 ()) - { - board_type = C929; + if (!detect_mad16()) + { + board_type = C929; - DDB (printk ("Detect using password = 0xE3\n")); + DDB(printk("Detect using password = 0xE3\n")); - if (!detect_mad16 ()) - { - if (inb (PASSWD_REG) != 0xff) - return 0; + if (!detect_mad16()) + { + if (inb(PASSWD_REG) != 0xff) + return 0; /* * First relocate MC# registers to 0xe0e/0xe0f, disable password */ - outb ((0xE4), PASSWD_REG); - outb ((0x80), PASSWD_REG); - - board_type = C930; - - DDB (printk ("Detect using password = 0xE4\n")); - - for (i = 0xf8d; i <= 0xf93; i++) - DDB (printk ("port %03x = %02x\n", i, mad_read (i))); - - if (!detect_mad16 ()) - return 0; - - DDB (printk ("mad16.c: 82C930 detected\n")); - } - else - { - DDB (printk ("mad16.c: 82C929 detected\n")); - } - } - else - { - unsigned char model; - - if (((model = mad_read (MC3_PORT)) & 0x03) == 0x03) - { - DDB (printk ("mad16.c: Mozart detected\n")); - board_type = MOZART; - } - else - { - DDB (printk ("mad16.c: 82C928 detected???\n")); - board_type = C928; - } - } - } - - return 1; + outb((0xE4), PASSWD_REG); + outb((0x80), PASSWD_REG); + + board_type = C930; + + DDB(printk("Detect using password = 0xE4\n")); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); + + if (!detect_mad16()) + return 0; + + DDB(printk("mad16.c: 82C930 detected\n")); + } else + { + DDB(printk("mad16.c: 82C929 detected\n")); + } + } else + { + unsigned char model; + + if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) + { + DDB(printk("mad16.c: Mozart detected\n")); + board_type = MOZART; + } else + { + DDB(printk("mad16.c: 82C928 detected???\n")); + board_type = C928; + } + } + } + return 1; } int -probe_mad16 (struct address_info *hw_config) +probe_mad16(struct address_info *hw_config) { - int i; - static int valid_ports[] = - {0x530, 0xe80, 0xf40, 0x604}; - unsigned char tmp; - unsigned char cs4231_mode = 0; + int i; + static int valid_ports[] = + {0x530, 0xe80, 0xf40, 0x604}; + unsigned char tmp; + unsigned char cs4231_mode = 0; - int ad_flags = 0; + int ad_flags = 0; - if (already_initialized) - return 0; + if (already_initialized) + return 0; - mad16_osp = hw_config->osp; + mad16_osp = hw_config->osp; /* * Check that all ports return 0xff (bus float) when no password * is written to the password register. */ - DDB (printk ("--- Detecting MAD16 / Mozart ---\n")); - if (!chip_detect ()) - return 0; + DDB(printk("--- Detecting MAD16 / Mozart ---\n")); + if (!chip_detect()) + return 0; - if (board_type == C930) - return init_c930 (hw_config); + if (board_type == C930) + return init_c930(hw_config); - for (i = 0xf8d; i <= 0xf93; i++) - DDB (printk ("port %03x = %02x\n", i, mad_read (i))); + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); /* * Set the WSS address */ - tmp = (mad_read (MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ - - for (i = 0; i < 5; i++) - { - if (i > 3) /* Not a valid port */ - { - printk ("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); - return 0; - } - - if (valid_ports[i] == hw_config->io_base) - { - tmp |= i << 4; /* WSS port select bits */ - break; - } - } + tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ + + for (i = 0; i < 5; i++) + { + if (i > 3) /* Not a valid port */ + { + printk("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); + return 0; + } + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 4; /* WSS port select bits */ + break; + } + } /* * Set optional CD-ROM and joystick settings. */ #ifdef MAD16_CONF - tmp &= ~0x0f; - tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */ + tmp &= ~0x0f; + tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */ #endif - mad_write (MC1_PORT, tmp); + mad_write(MC1_PORT, tmp); #if defined(MAD16_CONF) && defined(MAD16_CDSEL) - tmp = MAD16_CDSEL; + tmp = MAD16_CDSEL; #else - tmp = mad_read (MC2_PORT); + tmp = mad_read(MC2_PORT); #endif #ifdef MAD16_OPL4 - tmp |= 0x20; /* Enable OPL4 access */ + tmp |= 0x20; /* Enable OPL4 access */ #endif - mad_write (MC2_PORT, tmp); - mad_write (MC3_PORT, 0xf0); /* Disable SB */ + mad_write(MC2_PORT, tmp); + mad_write(MC3_PORT, 0xf0); /* Disable SB */ - if (board_type == C924) /* Specific C924 init values */ - { - mad_write (MC4_PORT, 0xA0); - mad_write (MC5_PORT, 0x05); - mad_write (MC6_PORT, 0x03); - } - - if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return 0; + if (board_type == C924) /* Specific C924 init values */ + { + mad_write(MC4_PORT, 0xA0); + mad_write(MC5_PORT, 0x05); + mad_write(MC6_PORT, 0x03); + } + if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) + return 0; - if (ad_flags & (AD_F_CS4231 | AD_F_CS4248)) - cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ + if (ad_flags & (AD_F_CS4231 | AD_F_CS4248)) + cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ - if (board_type == C929) - { - mad_write (MC4_PORT, 0xa2); - mad_write (MC5_PORT, 0xA5 | cs4231_mode); - mad_write (MC6_PORT, 0x03); /* Disable MPU401 */ - } - else - { - mad_write (MC4_PORT, 0x02); - mad_write (MC5_PORT, 0x30 | cs4231_mode); - } + if (board_type == C929) + { + mad_write(MC4_PORT, 0xa2); + mad_write(MC5_PORT, 0xA5 | cs4231_mode); + mad_write(MC6_PORT, 0x03); /* Disable MPU401 */ + } else + { + mad_write(MC4_PORT, 0x02); + mad_write(MC5_PORT, 0x30 | cs4231_mode); + } - for (i = 0xf8d; i <= 0xf93; i++) - DDB (printk ("port %03x after init = %02x\n", i, mad_read (i))); + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x after init = %02x\n", i, mad_read(i))); - wss_init (hw_config); + wss_init(hw_config); - return 1; + return 1; } void -attach_mad16 (struct address_info *hw_config) +attach_mad16(struct address_info *hw_config) { - static char interrupt_bits[12] = - { - -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - char bits; + static char interrupt_bits[12] = + { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; + char bits; - static char dma_bits[4] = - { - 1, 2, 0, 3 - }; + static char dma_bits[4] = + { + 1, 2, 0, 3 + }; - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; - int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2; - unsigned char dma2_bit = 0; + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2; + unsigned char dma2_bit = 0; - already_initialized = 1; + already_initialized = 1; - if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return; + if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) + return; - /* - * Set the IRQ and DMA addresses. - */ - if (board_type == C930) - interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ + /* + * Set the IRQ and DMA addresses. + */ + if (board_type == C930) + interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ - bits = interrupt_bits[hw_config->irq]; - if (bits == -1) - return; + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + return; - outb ((bits | 0x40), config_port); - if ((inb (version_port) & 0x40) == 0) - printk ("[IRQ Conflict?]"); + outb((bits | 0x40), config_port); + if ((inb(version_port) & 0x40) == 0) + printk("[IRQ Conflict?]"); /* * Handle the capture DMA channel */ - if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; - - dma = dma2; - dma2 = tmp; - } - - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } - else - { - printk ("MAD16: Invalid capture DMA\n"); - dma2 = dma; - } - } - else - dma2 = dma; - - outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - - ad1848_init ("MAD16 WSS", hw_config->io_base + 4, - hw_config->irq, - dma, - dma2, 0, - hw_config->osp); - request_region (hw_config->io_base, 4, "MAD16 WSS config"); + if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) + { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } else + { + printk("MAD16: Invalid capture DMA\n"); + dma2 = dma; + } + } else + dma2 = dma; + + outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ + + hw_config->slots[0] = ad1848_init("MAD16 WSS", hw_config->io_base + 4, + hw_config->irq, + dma, + dma2, 0, + hw_config->osp); + request_region(hw_config->io_base, 4, "MAD16 WSS config"); } void -attach_mad16_mpu (struct address_info *hw_config) +attach_mad16_mpu(struct address_info *hw_config) { - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { -#ifdef CONFIG_MIDI + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { +#if defined(CONFIG_MIDI) - if (mad_read (MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; - hw_config->name = "Mad16/Mozart"; - sb_dsp_init (hw_config); + hw_config->name = "Mad16/Mozart"; + sb_dsp_init(hw_config); #endif - return; - } - + return; + } #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (!already_initialized) - return; + if (!already_initialized) + return; - hw_config->driver_use_1 = SB_MIDI_ONLY; - hw_config->name = "Mad16/Mozart"; - attach_uart401 (hw_config); + hw_config->driver_use_1 = SB_MIDI_ONLY; + hw_config->name = "Mad16/Mozart"; + attach_uart401(hw_config); #endif } int -probe_mad16_mpu (struct address_info *hw_config) +probe_mad16_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - static int mpu_attached = 0; - static int valid_ports[] = - {0x330, 0x320, 0x310, 0x300}; - static short valid_irqs[] = - {9, 10, 5, 7}; - unsigned char tmp; - - int i; /* A variable with secret power */ - - if (!already_initialized) /* The MSS port must be initialized first */ - return 0; - - if (mpu_attached) /* Don't let them call this twice */ - return 0; - mpu_attached = 1; + static int mpu_attached = 0; + static int valid_ports[] = + {0x330, 0x320, 0x310, 0x300}; + static short valid_irqs[] = + {9, 10, 5, 7}; + unsigned char tmp; - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { + int i; /* A variable with secret power */ -#ifdef CONFIG_MIDI - unsigned char tmp; - - tmp = mad_read (MC3_PORT); - - /* - * MAD16 SB base is defined by the WSS base. It cannot be changed - * alone. - * Ignore configured I/O base. Use the active setting. - */ - - if (mad_read (MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; + if (!already_initialized) /* The MSS port must be initialized first */ + return 0; - switch (hw_config->irq) - { - case 5: - tmp = (tmp & 0x3f) | 0x80; - break; - case 7: - tmp = (tmp & 0x3f); - break; - case 11: - tmp = (tmp & 0x3f) | 0x40; - break; - default: - printk ("mad16/Mozart: Invalid MIDI IRQ\n"); - return 0; - } - - mad_write (MC3_PORT, tmp | 0x04); - hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect (hw_config); + if (mpu_attached) /* Don't let them call this twice */ + return 0; + mpu_attached = 1; + + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { + +#if defined(CONFIG_MIDI) + unsigned char tmp; + + tmp = mad_read(MC3_PORT); + + /* + * MAD16 SB base is defined by the WSS base. It cannot be changed + * alone. + * Ignore configured I/O base. Use the active setting. + */ + + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; + + switch (hw_config->irq) + { + case 5: + tmp = (tmp & 0x3f) | 0x80; + break; + case 7: + tmp = (tmp & 0x3f); + break; + case 11: + tmp = (tmp & 0x3f) | 0x40; + break; + default: + printk("mad16/Mozart: Invalid MIDI IRQ\n"); + return 0; + } + + mad_write(MC3_PORT, tmp | 0x04); + hw_config->driver_use_1 = SB_MIDI_ONLY; + return sb_dsp_detect(hw_config); #else - return 0; + return 0; #endif - } - - tmp = mad_read (MC6_PORT) & 0x83; - tmp |= 0x80; /* MPU-401 enable */ + } + tmp = mad_read(MC6_PORT) & 0x83; + tmp |= 0x80; /* MPU-401 enable */ /* * Set the MPU base bits */ - for (i = 0; i < 5; i++) - { - if (i > 3) /* Out of array bounds */ - { - printk ("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); - return 0; - } - - if (valid_ports[i] == hw_config->io_base) - { - tmp |= i << 5; - break; - } - } + for (i = 0; i < 5; i++) + { + if (i > 3) /* Out of array bounds */ + { + printk("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); + return 0; + } + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 5; + break; + } + } /* * Set the MPU IRQ bits */ - for (i = 0; i < 5; i++) - { - if (i > 3) /* Out of array bounds */ - { - printk ("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); - return 0; - } - - if (valid_irqs[i] == hw_config->irq) - { - tmp |= i << 3; - break; - } - } - mad_write (MC6_PORT, tmp); /* Write MPU401 config */ - - return probe_uart401 (hw_config); + for (i = 0; i < 5; i++) + { + if (i > 3) /* Out of array bounds */ + { + printk("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); + return 0; + } + if (valid_irqs[i] == hw_config->irq) + { + tmp |= i << 3; + break; + } + } + mad_write(MC6_PORT, tmp); /* Write MPU401 config */ + + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } void -unload_mad16 (struct address_info *hw_config) +unload_mad16(struct address_info *hw_config) { - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0); - release_region (hw_config->io_base, 4); + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma2, 0); + release_region(hw_config->io_base, 4); + sound_unload_audiodev(hw_config->slots[0]); } void -unload_mad16_mpu (struct address_info *hw_config) +unload_mad16_mpu(struct address_info *hw_config) { -#ifdef CONFIG_MIDI - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { - sb_dsp_unload (hw_config); - return; - } +#if defined(CONFIG_MIDI) + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { + sb_dsp_unload(hw_config); + return; + } #endif #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unload_uart401 (hw_config); + unload_uart401(hw_config); #endif } +#ifdef MODULE + +int io = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int irq = -1; + +int cdtype = 0; +int cdirq = 0; +int cdport = 0x340; +int cddma = 3; +int opl4 = 0; +int joystick = 0; + +static int found_mpu; + + +static int dma_map[2][8] = +{ + {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02}, + {0x03, -1, 0x01, 0x00, -1, -1, -1, -1} +}; + +static int irq_map[16] = +{ + 0x00, -1, -1, 0x0A, + -1, 0x04, -1, 0x08, + -1, 0x10, 0x14, 0x18, + -1, -1, -1, -1 +}; + +struct address_info config; + +int +init_module(void) +{ + int dmatype = 0; + + printk("MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, DMA and irq are mandatory\n"); + return -EINVAL; + } + printk("CDROM "); + switch (cdtype) + { + case 0x00: + printk("Disabled"); + cdirq = 0; + break; + case 0x02: + printk("Sony CDU31A"); + dmatype = 2; + break; + case 0x04: + printk("Mitsumi"); + dmatype = 1; + break; + case 0x06: + printk("Panasonic Lasermate"); + dmatype = 2; + break; + case 0x08: + printk("Secondary IDE"); + dmatype = 1; + break; + case 0x0A: + printk("Primary IDE"); + dmatype = 1; + break; + default: + printk("\nInvalid CDROM type\n"); + return -EINVAL; + } + + if (dmatype) + { + if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) + { + printk("\nInvalid CDROM DMA\n"); + return -EINVAL; + } + if (cddma) + printk(", DMA %d", cddma); + else + printk(", no DMA"); + } + if (cdtype && !cdirq) + printk(", no IRQ"); + else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) + { + printk(", invalid IRQ (disabling)"); + cdirq = 0; + } else + printk(", IRQ %d", cdirq); + + printk(".\nJoystick port "); + if (joystick == 1) + printk("enabled.\n"); + else + { + joystick = 0; + printk("disabled.\n"); + } + + /* + * Build the config words + */ + + mad16_conf = (joystick ^ 1) | cdtype; + mad16_cdsel = 0; + if (opl4) + mad16_cdsel |= 0x20; + mad16_cdsel |= dma_map[dmatype][cddma]; + + if (cdtype < 0x08) + { + switch (cdport) + { + case 0x340: + mad16_cdsel |= 0x00; + break; + case 0x330: + mad16_cdsel |= 0x40; + break; + case 0x360: + mad16_cdsel |= 0x80; + break; + case 0x320: + mad16_cdsel |= 0xC0; + break; + default: + printk("Unknown CDROM I/O base %d\n", cdport); + return -EINVAL; + } + } + mad16_cdsel |= irq_map[cdirq]; + + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + + if (!probe_mad16(&config)) + return -ENODEV; + found_mpu = probe_mad16_mpu(&config); + + attach_mad16(&config); + + if (found_mpu) + attach_mad16_mpu(&config); + + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (found_mpu) + unload_mad16_mpu(&config); + unload_mad16(&config); + SOUND_LOCK_END; +} + +#endif + /* That's all folks */ diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index 6fa104905..37f4966b6 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -11,14 +11,16 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" +#include "soundmodule.h" +#include "sound_firmware.h" -#if defined(CONFIG_MAUI) +#if defined(CONFIG_MAUI) || defined(MODULE) static int maui_base = 0x330; @@ -37,7 +39,7 @@ static int *maui_osp; #define STAT_RX_IENA 0x01 static int (*orig_load_patch) (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) = NULL; + int offs, int count, int pmgr_flag) = NULL; #ifdef HAVE_MAUI_BOOT #include "maui_boot.h" @@ -52,440 +54,472 @@ static volatile struct snd_wait maui_sleep_flag = {0}; static int -maui_wait (int mask) +maui_wait(int mask) { - int i; + int i; /* * Perform a short initial wait without sleeping */ - for (i = 0; i < 100; i++) - { - if (inb (HOST_STAT_PORT) & mask) - { - return 1; - } - } + for (i = 0; i < 100; i++) + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + } /* * Wait up to 15 seconds with sleeping */ - for (i = 0; i < 150; i++) - { - if (inb (HOST_STAT_PORT) & mask) - { - return 1; - } - - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - maui_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&maui_sleeper); - if (!(maui_sleep_flag.opts & WK_WAKEUP)) + for (i = 0; i < 150; i++) { - if (jiffies >= tlimit) - maui_sleep_flag.opts |= WK_TIMEOUT; + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + maui_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&maui_sleeper); + if (!(maui_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + maui_sleep_flag.opts |= WK_TIMEOUT; + } + maui_sleep_flag.opts &= ~WK_SLEEP; + }; + if ((current->signal & ~current->blocked)) + { + return 0; + } } - maui_sleep_flag.opts &= ~WK_SLEEP; - }; - if ((current->signal & ~current->blocked)) - { - return 0; - } - } - - return 0; + + return 0; } static int -maui_read (void) +maui_read(void) { - if (maui_wait (STAT_RX_AVAIL)) - return inb (HOST_DATA_PORT); + if (maui_wait(STAT_RX_AVAIL)) + return inb(HOST_DATA_PORT); - return -1; + return -1; } static int -maui_write (unsigned char data) +maui_write(unsigned char data) { - if (maui_wait (STAT_TX_AVAIL)) - { - outb ((data), HOST_DATA_PORT); - return 1; - } - printk ("Maui: Write timeout\n"); - - return 0; + if (maui_wait(STAT_TX_AVAIL)) + { + outb((data), HOST_DATA_PORT); + return 1; + } + printk("Maui: Write timeout\n"); + + return 0; } static void -mauiintr (int irq, void *dev_id, struct pt_regs *dummy) +mauiintr(int irq, void *dev_id, struct pt_regs *dummy) { - irq_ok = 1; + irq_ok = 1; } static int -download_code (void) +download_code(void) { - int i, lines = 0; - int eol_seen = 0, done = 0; - int skip = 1; + int i, lines = 0; + int eol_seen = 0, done = 0; + int skip = 1; - printk ("Code download (%d bytes): ", maui_osLen); + printk("Code download (%d bytes): ", maui_osLen); - for (i = 0; i < maui_osLen; i++) - { - if (maui_os[i] != '\r') - if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) + for (i = 0; i < maui_osLen; i++) { - skip = 0; - - if (maui_os[i] == '\n') - eol_seen = skip = 1; - else if (maui_os[i] == 'S') - { - if (maui_os[i + 1] == '8') - done = 1; - if (!maui_write (0xF1)) - goto failure; - if (!maui_write ('S')) - goto failure; - } - else - { - if (!maui_write (maui_os[i])) - goto failure; - } - - if (eol_seen) - { - int c = 0; - - int n; - - eol_seen = 0; - - for (n = 0; n < 2; n++) - if (maui_wait (STAT_RX_AVAIL)) - { - c = inb (HOST_DATA_PORT); - break; - } - - if (c != 0x80) - { - printk ("Download not acknowledged\n"); - return 0; - } - else if (!(lines++ % 10)) - printk ("."); - - if (done) - { - printk ("\nDownload complete\n"); - return 1; - } - } + if (maui_os[i] != '\r') + if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) + { + skip = 0; + + if (maui_os[i] == '\n') + eol_seen = skip = 1; + else if (maui_os[i] == 'S') + { + if (maui_os[i + 1] == '8') + done = 1; + if (!maui_write(0xF1)) + goto failure; + if (!maui_write('S')) + goto failure; + } else + { + if (!maui_write(maui_os[i])) + goto failure; + } + + if (eol_seen) + { + int c = 0; + + int n; + + eol_seen = 0; + + for (n = 0; n < 2; n++) + if (maui_wait(STAT_RX_AVAIL)) + { + c = inb(HOST_DATA_PORT); + break; + } + if (c != 0x80) + { + printk("Download not acknowledged\n"); + return 0; + } else if (!(lines++ % 10)) + printk("."); + + if (done) + { + printk("\nDownload complete\n"); + return 1; + } + } + } } - } -failure: + failure: - printk ("\nDownload failed!!!\n"); - return 0; + printk("\nDownload failed!!!\n"); + return 0; } static int -maui_init (int irq) +maui_init(int irq) { - int i; - unsigned char bits; + int i; + unsigned char bits; - switch (irq) - { - case 9: - bits = 0x00; - break; - case 5: - bits = 0x08; - break; - case 12: - bits = 0x10; - break; - case 15: - bits = 0x18; - break; - - default: - printk ("Maui: Invalid IRQ %d\n", irq); - return 0; - } - - outb ((0x00), HOST_CTRL_PORT); /* Reset */ + switch (irq) + { + case 9: + bits = 0x00; + break; + case 5: + bits = 0x08; + break; + case 12: + bits = 0x10; + break; + case 15: + bits = 0x18; + break; + + default: + printk("Maui: Invalid IRQ %d\n", irq); + return 0; + } - outb ((bits), HOST_DATA_PORT); /* Set the IRQ bits */ - outb ((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ + outb((0x00), HOST_CTRL_PORT); /* Reset */ - outb ((0x80), HOST_CTRL_PORT); /* Leave reset */ - outb ((0x80), HOST_CTRL_PORT); /* Leave reset */ + outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */ + outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ - outb ((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ + outb((0x80), HOST_CTRL_PORT); /* Leave reset */ + outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - for (i = 0; i < 1000000 && !irq_ok; i++); + outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ - if (!irq_ok) - return 0; + for (i = 0; i < 1000000 && !irq_ok; i++); - outb ((0x80), HOST_CTRL_PORT); /* Leave reset */ + if (!irq_ok) + return 0; - printk ("Turtle Beach Maui initialization\n"); + outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - if (!download_code ()) - return 0; + printk("Turtle Beach Maui initialization\n"); - outb ((0xE0), HOST_CTRL_PORT); /* Normal operation */ + if (!download_code()) + return 0; - /* Select mpu401 mode */ + outb((0xE0), HOST_CTRL_PORT); /* Normal operation */ - maui_write (0xf0); - maui_write (1); - if (maui_read () != 0x80) - { - maui_write (0xf0); - maui_write (1); - if (maui_read () != 0x80) - printk ("Maui didn't acknowledge set HW mode command\n"); - } + /* Select mpu401 mode */ - printk ("Maui initialized OK\n"); - return 1; + maui_write(0xf0); + maui_write(1); + if (maui_read() != 0x80) + { + maui_write(0xf0); + maui_write(1); + if (maui_read() != 0x80) + printk("Maui didn't acknowledge set HW mode command\n"); + } + printk("Maui initialized OK\n"); + return 1; } static int -maui_short_wait (int mask) +maui_short_wait(int mask) { - int i; + int i; - for (i = 0; i < 1000; i++) - { - if (inb (HOST_STAT_PORT) & mask) - { - return 1; - } - } + for (i = 0; i < 1000; i++) + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + } - return 0; + return 0; } static int -maui_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +maui_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - struct sysex_info header; - unsigned long left, src_offs; - int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; - int i; - - if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ - return orig_load_patch (dev, format, addr, offs, count, pmgr_flag); - - if (format != MAUI_PATCH) - { - printk ("Maui: Unknown patch format\n"); - } + struct sysex_info header; + unsigned long left, src_offs; + int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; + int i; - if (count < hdr_size) - { - printk ("Maui error: Patch header too short\n"); - return -EINVAL; - } + if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ + return orig_load_patch(dev, format, addr, offs, count, pmgr_flag); - count -= hdr_size; - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - copy_from_user (&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); + if (format != MAUI_PATCH) + { + printk("Maui: Unknown patch format\n"); + } + if (count < hdr_size) + { + printk("Maui error: Patch header too short\n"); + return -EINVAL; + } + count -= hdr_size; - if (count < header.len) - { - printk ("Maui warning: Host command record too short (%d<%d)\n", - count, (int) header.len); - header.len = count; - } + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ - left = header.len; - src_offs = 0; + copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); - for (i = 0; i < left; i++) - { - unsigned char data; + if (count < header.len) + { + printk("Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); + header.len = count; + } + left = header.len; + src_offs = 0; - get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); - if (i == 0 && !(data & 0x80)) - return -EINVAL; + for (i = 0; i < left; i++) + { + unsigned char data; - if (maui_write (data) == -1) - return -EIO; - } + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); + if (i == 0 && !(data & 0x80)) + return -EINVAL; - if ((i = maui_read ()) != 0x80) - { - if (i != -1) - printk ("Maui: Error status %02x\n", i); + if (maui_write(data) == -1) + return -EIO; + } - return -EIO; - } + if ((i = maui_read()) != 0x80) + { + if (i != -1) + printk("Maui: Error status %02x\n", i); - return 0; + return -EIO; + } + return 0; } int -probe_maui (struct address_info *hw_config) +probe_maui(struct address_info *hw_config) { - int i; - int tmp1, tmp2, ret; + int i; + int tmp1, tmp2, ret; - if (check_region (hw_config->io_base, 8)) - return 0; + if (check_region(hw_config->io_base, 8)) + return 0; - maui_base = hw_config->io_base; - maui_osp = hw_config->osp; + maui_base = hw_config->io_base; + maui_osp = hw_config->osp; - if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0) - return 0; + if (snd_set_irq_handler(hw_config->irq, mauiintr, "Maui", maui_osp) < 0) + return 0; - maui_sleep_flag.opts = WK_NONE; + maui_sleep_flag.opts = WK_NONE; /* * Initialize the processor if necessary */ - if (maui_osLen > 0) - { - if (!(inb (HOST_STAT_PORT) & STAT_TX_AVAIL) || - !maui_write (0x9F) || /* Report firmware version */ - !maui_short_wait (STAT_RX_AVAIL) || - maui_read () == -1 || maui_read () == -1) - if (!maui_init (hw_config->irq)) + if (maui_osLen > 0) + { + if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || + !maui_write(0x9F) || /* Report firmware version */ + !maui_short_wait(STAT_RX_AVAIL) || + maui_read() == -1 || maui_read() == -1) + if (!maui_init(hw_config->irq)) + { + snd_release_irq(hw_config->irq); + return 0; + } + } + if (!maui_write(0xCF)) /* Report hardware version */ + { + printk("No WaveFront firmware detected (card uninitialized?)\n"); + snd_release_irq(hw_config->irq); + return 0; + } + if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) + { + printk("No WaveFront firmware detected (card uninitialized?)\n"); + snd_release_irq(hw_config->irq); + return 0; + } + if (tmp1 == 0xff || tmp2 == 0xff) + { + snd_release_irq(hw_config->irq); + return 0; + } + if (trace_init) + printk("WaveFront hardware version %d.%d\n", tmp1, tmp2); + + if (!maui_write(0x9F)) /* Report firmware version */ + return 0; + if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) + return 0; + + if (trace_init) + printk("WaveFront firmware version %d.%d\n", tmp1, tmp2); + + if (!maui_write(0x85)) /* Report free DRAM */ + return 0; + tmp1 = 0; + for (i = 0; i < 4; i++) { - snd_release_irq (hw_config->irq); - return 0; + tmp1 |= maui_read() << (7 * i); } - } - - if (!maui_write (0xCF)) /* Report hardware version */ - { - printk ("No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq (hw_config->irq); - return 0; - } - - if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1) - { - printk ("No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq (hw_config->irq); - return 0; - } - - if (tmp1 == 0xff || tmp2 == 0xff) - { - snd_release_irq (hw_config->irq); - return 0; - } - - if (trace_init) - printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2); - - if (!maui_write (0x9F)) /* Report firmware version */ - return 0; - if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1) - return 0; - - if (trace_init) - printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2); - - if (!maui_write (0x85)) /* Report free DRAM */ - return 0; - tmp1 = 0; - for (i = 0; i < 4; i++) - { - tmp1 |= maui_read () << (7 * i); - } - if (trace_init) - printk ("Available DRAM %dk\n", tmp1 / 1024); - - for (i = 0; i < 1000; i++) - if (probe_mpu401 (hw_config)) - break; - - ret = probe_mpu401 (hw_config); - - if (ret) - request_region (hw_config->io_base + 2, 6, "Maui"); - - return ret; + if (trace_init) + printk("Available DRAM %dk\n", tmp1 / 1024); + + for (i = 0; i < 1000; i++) + if (probe_mpu401(hw_config)) + break; + + ret = probe_mpu401(hw_config); + + if (ret) + request_region(hw_config->io_base + 2, 6, "Maui"); + + return ret; } void -attach_maui (struct address_info *hw_config) +attach_maui(struct address_info *hw_config) { - int this_dev = num_midis; - - conf_printf ("Maui", hw_config); - - hw_config->irq *= -1; - hw_config->name = "Maui"; - attach_mpu401 (hw_config); - - if (num_midis > this_dev) /* The MPU401 driver installed itself */ - { - struct synth_operations *synth; - - /* - * Intercept patch loading calls so that they can be handled - * by the Maui driver. - */ - - synth = midi_devs[this_dev]->converter; - synth->id = "MAUI"; - - if (synth != NULL) - { - orig_load_patch = synth->load_patch; - synth->load_patch = &maui_load_patch; - } - else - printk ("Maui: Can't install patch loader\n"); - } + int this_dev; + + conf_printf("Maui", hw_config); + + hw_config->irq *= -1; + hw_config->name = "Maui"; + attach_mpu401(hw_config); + + if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ + { + struct synth_operations *synth; + + this_dev = hw_config->slots[1]; + + /* + * Intercept patch loading calls so that they can be handled + * by the Maui driver. + */ + + synth = midi_devs[this_dev]->converter; + synth->id = "MAUI"; + + if (synth != NULL) + { + orig_load_patch = synth->load_patch; + synth->load_patch = &maui_load_patch; + } else + printk(KERN_ERR "Maui: Can't install patch loader\n"); + } } void -unload_maui (struct address_info *hw_config) +unload_maui(struct address_info *hw_config) { - int irq = hw_config->irq; + int irq = hw_config->irq; - release_region (hw_config->io_base + 2, 6); + release_region(hw_config->io_base + 2, 6); - unload_mpu401 (hw_config); + unload_mpu401(hw_config); - if (irq < 0) - irq = -irq; + if (irq < 0) + irq = -irq; - if (irq > 0) - snd_release_irq (irq); + if (irq > 0) + snd_release_irq(irq); } +#ifdef MODULE + +int io = -1; +int irq = -1; + +static int fw_load = 0; + +struct address_info cfg; + +/* + * Install a CS4232 based card. Need to have ad1848 and mpu401 + * loaded ready. + */ + +int +init_module(void) +{ + printk("Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); + if (io == -1 || irq == -1) + { + printk("maui: irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + + if (maui_os == NULL) + { + fw_load = 1; + maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); + } + if (probe_maui(&cfg) == 0) + return -ENODEV; + attach_maui(&cfg); + SOUND_LOCK; + return 0; +} +void +cleanup_module(void) +{ + if (fw_load && maui_os) + kfree(maui_os); + unload_maui(&cfg); + SOUND_LOCK_END; +} +#endif #endif diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 454fc7471..3885a650b 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -12,13 +12,12 @@ */ #include <linux/config.h> - #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" -#if defined(CONFIG_MIDI) +#if defined(CONFIG_MIDI) || defined (MODULE) #define _MIDI_SYNTH_C_ @@ -33,7 +32,7 @@ static int sysex_state[MAX_MIDI_DEV] = {0}; static unsigned char prev_out_status[MAX_MIDI_DEV]; -#ifndef CONFIG_SEQUENCER +#if !defined(CONFIG_SEQUENCER) && !defined(MODULE) #define STORE(cmd) #else #define STORE(cmd) \ @@ -50,696 +49,686 @@ static unsigned char prev_out_status[MAX_MIDI_DEV]; #define _SEQ_ADVBUF(x) len=x void -do_midi_msg (int synthno, unsigned char *msg, int mlen) +do_midi_msg(int synthno, unsigned char *msg, int mlen) { - switch (msg[0] & 0xf0) - { - case 0x90: - if (msg[2] != 0) - { - STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - } - msg[2] = 64; - - case 0x80: - STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xA0: - STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xB0: - STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f, - msg[1], msg[2])); - break; - - case 0xC0: - STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xD0: - STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xE0: - STORE (SEQ_BENDER (synthno, msg[0] & 0x0f, - (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); - break; - - default: - /* printk ("MPU: Unknown midi channel message %02x\n", msg[0]); */ - ; - } + switch (msg[0] & 0xf0) + { + case 0x90: + if (msg[2] != 0) + { + STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + } + msg[2] = 64; + + case 0x80: + STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xA0: + STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xB0: + STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, + msg[1], msg[2])); + break; + + case 0xC0: + STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xD0: + STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xE0: + STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, + (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + break; + + default: + /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ + ; + } } static void -midi_outc (int midi_dev, int data) +midi_outc(int midi_dev, int data) { - int timeout; + int timeout; - for (timeout = 0; timeout < 3200; timeout++) - if (midi_devs[midi_dev]->outputc (midi_dev, (unsigned char) (data & 0xff))) - { - if (data & 0x80) /* - * Status byte - */ - prev_out_status[midi_dev] = - (unsigned char) (data & 0xff); /* - * Store for running status + for (timeout = 0; timeout < 3200; timeout++) + if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff))) + { + if (data & 0x80) /* + * Status byte */ - return; /* - * Mission complete - */ - } - - /* - * Sorry! No space on buffers. - */ - printk ("Midi send timed out\n"); + prev_out_status[midi_dev] = + (unsigned char) (data & 0xff); /* + * Store for running status + */ + return; /* + * Mission complete + */ + } + /* + * Sorry! No space on buffers. + */ + printk("Midi send timed out\n"); } static int -prefix_cmd (int midi_dev, unsigned char status) +prefix_cmd(int midi_dev, unsigned char status) { - if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) - return 1; + if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) + return 1; - return midi_devs[midi_dev]->prefix_cmd (midi_dev, status); + return midi_devs[midi_dev]->prefix_cmd(midi_dev, status); } static void -midi_synth_input (int orig_dev, unsigned char data) +midi_synth_input(int orig_dev, unsigned char data) { - int dev; - struct midi_input_info *inc; - - static unsigned char len_tab[] = /* # of data bytes following a status - */ - { - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ - }; - - if (orig_dev < 0 || orig_dev > num_midis) - return; - - if (data == 0xfe) /* Ignore active sensing */ - return; - - dev = midi2synth[orig_dev]; - inc = &midi_devs[orig_dev]->in_info; - - switch (inc->m_state) - { - case MST_INIT: - if (data & 0x80) /* MIDI status byte */ - { - if ((data & 0xf0) == 0xf0) /* Common message */ - { - switch (data) - { - case 0xf0: /* Sysex */ - inc->m_state = MST_SYSEX; - break; /* Sysex */ - - case 0xf1: /* MTC quarter frame */ - case 0xf3: /* Song select */ - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = 1; - inc->m_buf[0] = data; - break; + int dev; + struct midi_input_info *inc; - case 0xf2: /* Song position pointer */ - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = 2; - inc->m_buf[0] = data; - break; - - default: - inc->m_buf[0] = data; - inc->m_ptr = 1; - do_midi_msg (dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - inc->m_left = 0; - } - } - else - { - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = len_tab[(data >> 4) - 8]; - inc->m_buf[0] = inc->m_prev_status = data; - } - } - else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ - { /* Data byte (use running status) */ - inc->m_state = MST_DATA; - inc->m_ptr = 2; - inc->m_left = len_tab[(data >> 4) - 8] - 1; - inc->m_buf[0] = inc->m_prev_status; - inc->m_buf[1] = data; - } - break; /* MST_INIT */ - - case MST_DATA: - inc->m_buf[inc->m_ptr++] = data; - if (--inc->m_left <= 0) - { - inc->m_state = MST_INIT; - do_midi_msg (dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - } - break; /* MST_DATA */ - - case MST_SYSEX: - if (data == 0xf7) /* Sysex end */ + static unsigned char len_tab[] = /* # of data bytes following a status + */ { - inc->m_state = MST_INIT; - inc->m_left = 0; - inc->m_ptr = 0; - } - break; /* MST_SYSEX */ - - default: - printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, - (int) data); - inc->m_state = MST_INIT; - } + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ + }; + + if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + return; + + if (data == 0xfe) /* Ignore active sensing */ + return; + + dev = midi2synth[orig_dev]; + inc = &midi_devs[orig_dev]->in_info; + + switch (inc->m_state) + { + case MST_INIT: + if (data & 0x80) /* MIDI status byte */ + { + if ((data & 0xf0) == 0xf0) /* Common message */ + { + switch (data) + { + case 0xf0: /* Sysex */ + inc->m_state = MST_SYSEX; + break; /* Sysex */ + + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* Song select */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 1; + inc->m_buf[0] = data; + break; + + case 0xf2: /* Song position pointer */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 2; + inc->m_buf[0] = data; + break; + + default: + inc->m_buf[0] = data; + inc->m_ptr = 1; + do_midi_msg(dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + inc->m_left = 0; + } + } else + { + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = len_tab[(data >> 4) - 8]; + inc->m_buf[0] = inc->m_prev_status = data; + } + } else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ + { /* Data byte (use running status) */ + inc->m_state = MST_DATA; + inc->m_ptr = 2; + inc->m_left = len_tab[(data >> 4) - 8] - 1; + inc->m_buf[0] = inc->m_prev_status; + inc->m_buf[1] = data; + } + break; /* MST_INIT */ + + case MST_DATA: + inc->m_buf[inc->m_ptr++] = data; + if (--inc->m_left <= 0) + { + inc->m_state = MST_INIT; + do_midi_msg(dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } + break; /* MST_DATA */ + + case MST_SYSEX: + if (data == 0xf7) /* Sysex end */ + { + inc->m_state = MST_INIT; + inc->m_left = 0; + inc->m_ptr = 0; + } + break; /* MST_SYSEX */ + + default: + printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); + inc->m_state = MST_INIT; + } } static void -leave_sysex (int dev) +leave_sysex(int dev) { - int orig_dev = synth_devs[dev]->midi_dev; - int timeout = 0; + int orig_dev = synth_devs[dev]->midi_dev; + int timeout = 0; - if (!sysex_state[dev]) - return; + if (!sysex_state[dev]) + return; - sysex_state[dev] = 0; + sysex_state[dev] = 0; - while (!midi_devs[orig_dev]->outputc (orig_dev, 0xf7) && - timeout < 1000) - timeout++; + while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && + timeout < 1000) + timeout++; - sysex_state[dev] = 0; + sysex_state[dev] = 0; } static void -midi_synth_output (int dev) +midi_synth_output(int dev) { - /* - * Currently NOP - */ + /* + * Currently NOP + */ } int -midi_synth_ioctl (int dev, - unsigned int cmd, caddr_t arg) +midi_synth_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - /* - * int orig_dev = synth_devs[dev]->midi_dev; - */ + /* + * int orig_dev = synth_devs[dev]->midi_dev; + */ - switch (cmd) - { + switch (cmd) + { - case SNDCTL_SYNTH_INFO: - memcpy ((&((char *) arg)[0]), (char *) synth_devs[dev]->info, sizeof (struct synth_info)); + case SNDCTL_SYNTH_INFO: + memcpy((&((char *) arg)[0]), (char *) synth_devs[dev]->info, sizeof(struct synth_info)); - return 0; - break; + return 0; + break; - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } int -midi_synth_kill_note (int dev, int channel, int note, int velocity) +midi_synth_kill_note(int dev, int channel, int note, int velocity) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; - if (note < 0 || note > 127) - return 0; - if (channel < 0 || channel > 15) - return 0; - if (velocity < 0) - velocity = 0; - if (velocity > 127) - velocity = 127; + if (note < 0 || note > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + if (velocity < 0) + velocity = 0; + if (velocity > 127) + velocity = 127; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; - if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) - { /* + if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) + { /* * Use running status */ - if (!prefix_cmd (orig_dev, note)) - return 0; + if (!prefix_cmd(orig_dev, note)) + return 0; - midi_outc (orig_dev, note); + midi_outc(orig_dev, note); - if (msg == 0x90) /* - * Running status = Note on - */ - midi_outc (orig_dev, 0); /* - * Note on with velocity 0 == note - * off + if (msg == 0x90) /* + * Running status = Note on */ - else - midi_outc (orig_dev, velocity); - } - else - { - if (velocity == 64) - { - if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /* - * Note on - */ - midi_outc (orig_dev, note); - midi_outc (orig_dev, 0); /* - * Zero G - */ - } - else - { - if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0x80 | (channel & 0x0f)); /* - * Note off - */ - midi_outc (orig_dev, note); - midi_outc (orig_dev, velocity); - } - } - - return 0; + midi_outc(orig_dev, 0); /* + * Note on with velocity 0 == note + * off + */ + else + midi_outc(orig_dev, velocity); + } else + { + if (velocity == 64) + { + if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* + * Note on + */ + midi_outc(orig_dev, note); + midi_outc(orig_dev, 0); /* + * Zero G + */ + } else + { + if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* + * Note off + */ + midi_outc(orig_dev, note); + midi_outc(orig_dev, velocity); + } + } + + return 0; } int -midi_synth_set_instr (int dev, int channel, int instr_no) +midi_synth_set_instr(int dev, int channel, int instr_no) { - int orig_dev = synth_devs[dev]->midi_dev; + int orig_dev = synth_devs[dev]->midi_dev; - if (instr_no < 0 || instr_no > 127) - instr_no = 0; - if (channel < 0 || channel > 15) - return 0; + if (instr_no < 0 || instr_no > 127) + instr_no = 0; + if (channel < 0 || channel > 15) + return 0; - leave_sysex (dev); + leave_sysex(dev); - if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0xc0 | (channel & 0x0f)); /* + if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0xc0 | (channel & 0x0f)); /* * Program change */ - midi_outc (orig_dev, instr_no); + midi_outc(orig_dev, instr_no); - return 0; + return 0; } int -midi_synth_start_note (int dev, int channel, int note, int velocity) +midi_synth_start_note(int dev, int channel, int note, int velocity) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; - if (note < 0 || note > 127) - return 0; - if (channel < 0 || channel > 15) - return 0; - if (velocity < 0) - velocity = 0; - if (velocity > 127) - velocity = 127; + if (note < 0 || note > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + if (velocity < 0) + velocity = 0; + if (velocity > 127) + velocity = 127; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; - if (chn == channel && msg == 0x90) - { /* + if (chn == channel && msg == 0x90) + { /* * Use running status */ - if (!prefix_cmd (orig_dev, note)) + if (!prefix_cmd(orig_dev, note)) + return 0; + midi_outc(orig_dev, note); + midi_outc(orig_dev, velocity); + } else + { + if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* + * Note on + */ + midi_outc(orig_dev, note); + midi_outc(orig_dev, velocity); + } return 0; - midi_outc (orig_dev, note); - midi_outc (orig_dev, velocity); - } - else - { - if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /* - * Note on - */ - midi_outc (orig_dev, note); - midi_outc (orig_dev, velocity); - } - return 0; } void -midi_synth_reset (int dev) +midi_synth_reset(int dev) { - leave_sysex (dev); + leave_sysex(dev); } int -midi_synth_open (int dev, int mode) +midi_synth_open(int dev, int mode) { - int orig_dev = synth_devs[dev]->midi_dev; - int err; - unsigned long flags; - struct midi_input_info *inc; - - if (orig_dev < 0 || orig_dev > num_midis) - return -ENXIO; - - midi2synth[orig_dev] = dev; - sysex_state[dev] = 0; - prev_out_status[orig_dev] = 0; - - if ((err = midi_devs[orig_dev]->open (orig_dev, mode, - midi_synth_input, midi_synth_output)) < 0) - return err; - - inc = &midi_devs[orig_dev]->in_info; + int orig_dev = synth_devs[dev]->midi_dev; + int err; + unsigned long flags; + struct midi_input_info *inc; + + if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + return -ENXIO; + + midi2synth[orig_dev] = dev; + sysex_state[dev] = 0; + prev_out_status[orig_dev] = 0; + + if ((err = midi_devs[orig_dev]->open(orig_dev, mode, + midi_synth_input, midi_synth_output)) < 0) + return err; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + inc = &midi_devs[orig_dev]->in_info; - save_flags (flags); - cli (); - inc->m_busy = 0; - inc->m_state = MST_INIT; - inc->m_ptr = 0; - inc->m_left = 0; - inc->m_prev_status = 0x00; - restore_flags (flags); + save_flags(flags); + cli(); + inc->m_busy = 0; + inc->m_state = MST_INIT; + inc->m_ptr = 0; + inc->m_left = 0; + inc->m_prev_status = 0x00; + restore_flags(flags); - sysex_sleep_flag.opts = WK_NONE; + sysex_sleep_flag.opts = WK_NONE; - return 1; + return 1; } void -midi_synth_close (int dev) +midi_synth_close(int dev) { - int orig_dev = synth_devs[dev]->midi_dev; + int orig_dev = synth_devs[dev]->midi_dev; - leave_sysex (dev); + leave_sysex(dev); - /* - * Shut up the synths by sending just single active sensing message. - */ - midi_devs[orig_dev]->outputc (orig_dev, 0xfe); + /* + * Shut up the synths by sending just single active sensing message. + */ + midi_devs[orig_dev]->outputc(orig_dev, 0xfe); - midi_devs[orig_dev]->close (orig_dev); + midi_devs[orig_dev]->close(orig_dev); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif } void -midi_synth_hw_control (int dev, unsigned char *event) +midi_synth_hw_control(int dev, unsigned char *event) { } int -midi_synth_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +midi_synth_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - int orig_dev = synth_devs[dev]->midi_dev; - - struct sysex_info sysex; - int i; - unsigned long left, src_offs, eox_seen = 0; - int first_byte = 1; - int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; - - leave_sysex (dev); - - if (!prefix_cmd (orig_dev, 0xf0)) - return 0; - - if (format != SYSEX_PATCH) - { - printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } - - if (count < hdr_size) - { - printk ("MIDI Error: Patch header too short\n"); - return -EINVAL; - } - - count -= hdr_size; - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - copy_from_user (&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs); - - if (count < sysex.len) - { - printk ("MIDI Warning: Sysex record too short (%d<%d)\n", - count, (int) sysex.len); - sysex.len = count; - } - - left = sysex.len; - src_offs = 0; - - sysex_sleep_flag.opts = WK_NONE; - - for (i = 0; i < left && !(current->signal & ~current->blocked); i++) - { - unsigned char data; - - get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); - - eox_seen = (i > 0 && data & 0x80); /* End of sysex */ - - if (eox_seen && data != 0xf7) - data = 0xf7; - - if (i == 0) - { - if (data != 0xf0) - { - printk ("Error: Sysex start missing\n"); - return -EINVAL; - } - } - - while (!midi_devs[orig_dev]->outputc (orig_dev, (unsigned char) (data & 0xff)) && - !(current->signal & ~current->blocked)) - - { - unsigned long tlimit; - - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sysex_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sysex_sleeper); - if (!(sysex_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sysex_sleep_flag.opts |= WK_TIMEOUT; - } - sysex_sleep_flag.opts &= ~WK_SLEEP; - }; /* Wait for timeout */ - - if (!first_byte && data & 0x80) + int orig_dev = synth_devs[dev]->midi_dev; + + struct sysex_info sysex; + int i; + unsigned long left, src_offs, eox_seen = 0; + int first_byte = 1; + int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; + + leave_sysex(dev); + + if (!prefix_cmd(orig_dev, 0xf0)) + return 0; + + if (format != SYSEX_PATCH) + { + printk("MIDI Error: Invalid patch format (key) 0x%x\n", format); + return -EINVAL; + } + if (count < hdr_size) + { + printk("MIDI Error: Patch header too short\n"); + return -EINVAL; + } + count -= hdr_size; + + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ + + copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs); + + if (count < sysex.len) + { + printk("MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len); + sysex.len = count; + } + left = sysex.len; + src_offs = 0; + + sysex_sleep_flag.opts = WK_NONE; + + for (i = 0; i < left && !(current->signal & ~current->blocked); i++) + { + unsigned char data; + + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); + + eox_seen = (i > 0 && data & 0x80); /* End of sysex */ + + if (eox_seen && data != 0xf7) + data = 0xf7; + + if (i == 0) + { + if (data != 0xf0) + { + printk("Error: Sysex start missing\n"); + return -EINVAL; + } + } + while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && + !(current->signal & ~current->blocked)) + + { + unsigned long tlimit; + + if (1) + current->timeout = tlimit = jiffies + (1); + else + tlimit = (unsigned long) -1; + sysex_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sysex_sleeper); + if (!(sysex_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sysex_sleep_flag.opts |= WK_TIMEOUT; + } + sysex_sleep_flag.opts &= ~WK_SLEEP; + }; /* Wait for timeout */ + + if (!first_byte && data & 0x80) + return 0; + first_byte = 0; + } + + if (!eox_seen) + midi_outc(orig_dev, 0xf7); return 0; - first_byte = 0; - } - - if (!eox_seen) - midi_outc (orig_dev, 0xf7); - return 0; } void -midi_synth_panning (int dev, int channel, int pressure) +midi_synth_panning(int dev, int channel, int pressure) { } void -midi_synth_aftertouch (int dev, int channel, int pressure) +midi_synth_aftertouch(int dev, int channel, int pressure) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; - if (pressure < 0 || pressure > 127) - return; - if (channel < 0 || channel > 15) - return; + if (pressure < 0 || pressure > 127) + return; + if (channel < 0 || channel > 15) + return; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (msg != 0xd0 || chn != channel) /* - * Test for running status - */ - { - if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f))) - return; - midi_outc (orig_dev, 0xd0 | (channel & 0x0f)); /* - * Channel pressure - */ - } - else if (!prefix_cmd (orig_dev, pressure)) - return; + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; - midi_outc (orig_dev, pressure); + if (msg != 0xd0 || chn != channel) /* + * Test for running status + */ + { + if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f))) + return; + midi_outc(orig_dev, 0xd0 | (channel & 0x0f)); /* + * Channel pressure + */ + } else if (!prefix_cmd(orig_dev, pressure)) + return; + + midi_outc(orig_dev, pressure); } void -midi_synth_controller (int dev, int channel, int ctrl_num, int value) +midi_synth_controller(int dev, int channel, int ctrl_num, int value) { - int orig_dev = synth_devs[dev]->midi_dev; - int chn, msg; - - if (ctrl_num < 0 || ctrl_num > 127) - return; - if (channel < 0 || channel > 15) - return; - - leave_sysex (dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (msg != 0xb0 || chn != channel) - { - if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f))) - return; - midi_outc (orig_dev, 0xb0 | (channel & 0x0f)); - } - else if (!prefix_cmd (orig_dev, ctrl_num)) - return; - - midi_outc (orig_dev, ctrl_num); - midi_outc (orig_dev, value & 0x7f); + int orig_dev = synth_devs[dev]->midi_dev; + int chn, msg; + + if (ctrl_num < 0 || ctrl_num > 127) + return; + if (channel < 0 || channel > 15) + return; + + leave_sysex(dev); + + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; + + if (msg != 0xb0 || chn != channel) + { + if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f))) + return; + midi_outc(orig_dev, 0xb0 | (channel & 0x0f)); + } else if (!prefix_cmd(orig_dev, ctrl_num)) + return; + + midi_outc(orig_dev, ctrl_num); + midi_outc(orig_dev, value & 0x7f); } void -midi_synth_bender (int dev, int channel, int value) +midi_synth_bender(int dev, int channel, int value) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, prev_chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, prev_chn; - if (channel < 0 || channel > 15) - return; + if (channel < 0 || channel > 15) + return; - if (value < 0 || value > 16383) - return; + if (value < 0 || value > 16383) + return; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - prev_chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + prev_chn = prev_out_status[orig_dev] & 0x0f; - if (msg != 0xd0 || prev_chn != channel) /* - * Test for running status - */ - { - if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f))) - return; - midi_outc (orig_dev, 0xe0 | (channel & 0x0f)); - } - else if (!prefix_cmd (orig_dev, value & 0x7f)) - return; - - midi_outc (orig_dev, value & 0x7f); - midi_outc (orig_dev, (value >> 7) & 0x7f); + if (msg != 0xd0 || prev_chn != channel) /* + * Test for running status + */ + { + if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f))) + return; + midi_outc(orig_dev, 0xe0 | (channel & 0x0f)); + } else if (!prefix_cmd(orig_dev, value & 0x7f)) + return; + + midi_outc(orig_dev, value & 0x7f); + midi_outc(orig_dev, (value >> 7) & 0x7f); } void -midi_synth_setup_voice (int dev, int voice, int channel) +midi_synth_setup_voice(int dev, int voice, int channel) { } int -midi_synth_send_sysex (int dev, unsigned char *bytes, int len) +midi_synth_send_sysex(int dev, unsigned char *bytes, int len) { - int orig_dev = synth_devs[dev]->midi_dev; - int i; - - for (i = 0; i < len; i++) - { - switch (bytes[i]) - { - case 0xf0: /* Start sysex */ - if (!prefix_cmd (orig_dev, 0xf0)) - return 0; - sysex_state[dev] = 1; - break; - - case 0xf7: /* End sysex */ - if (!sysex_state[dev]) /* Orphan sysex end */ - return 0; - sysex_state[dev] = 0; - break; - - default: - if (!sysex_state[dev]) - return 0; - - if (bytes[i] & 0x80) /* Error. Another message before sysex end */ - { - bytes[i] = 0xf7; /* Sysex end */ - sysex_state[dev] = 0; - } - } - - if (!midi_devs[orig_dev]->outputc (orig_dev, bytes[i])) - { + int orig_dev = synth_devs[dev]->midi_dev; + int i; + + for (i = 0; i < len; i++) + { + switch (bytes[i]) + { + case 0xf0: /* Start sysex */ + if (!prefix_cmd(orig_dev, 0xf0)) + return 0; + sysex_state[dev] = 1; + break; + + case 0xf7: /* End sysex */ + if (!sysex_state[dev]) /* Orphan sysex end */ + return 0; + sysex_state[dev] = 0; + break; + + default: + if (!sysex_state[dev]) + return 0; + + if (bytes[i] & 0x80) /* Error. Another message before sysex end */ + { + bytes[i] = 0xf7; /* Sysex end */ + sysex_state[dev] = 0; + } + } + + if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i])) + { /* * Hardware level buffer is full. Abort the sysex message. */ - int timeout = 0; + int timeout = 0; - bytes[i] = 0xf7; - sysex_state[dev] = 0; + bytes[i] = 0xf7; + sysex_state[dev] = 0; - while (!midi_devs[orig_dev]->outputc (orig_dev, bytes[i]) && - timeout < 1000) - timeout++; - } + while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) && + timeout < 1000) + timeout++; + } + if (!sysex_state[dev]) + return 0; + } - if (!sysex_state[dev]) return 0; - } - - return 0; } + #endif diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index c4271e87b..ad2f5780a 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -16,7 +16,7 @@ #include "sound_config.h" -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI /* * Don't make MAX_QUEUE_SIZE larger than 4000 @@ -28,24 +28,24 @@ static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] = {NULL}; static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { - {0}}; + {0}}; static struct wait_queue *input_sleeper[MAX_MIDI_DEV] = {NULL}; static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { - {0}}; + {0}}; struct midi_buf { - int len, head, tail; - unsigned char queue[MAX_QUEUE_SIZE]; + int len, head, tail; + unsigned char queue[MAX_QUEUE_SIZE]; }; struct midi_parms { - int prech_timeout; /* - * Timeout before the first ch - */ + int prech_timeout; /* + * Timeout before the first ch + */ }; static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = @@ -54,7 +54,7 @@ static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL}; static struct midi_parms parms[MAX_MIDI_DEV]; -static void midi_poll (unsigned long dummy); +static void midi_poll(unsigned long dummy); static struct timer_list poll_timer = @@ -85,458 +85,446 @@ static volatile int open_devs = 0; } static void -drain_midi_queue (int dev) +drain_midi_queue(int dev) { - /* - * Give the Midi driver time to drain its output queues - */ - - if (midi_devs[dev]->buffer_status != NULL) - while (!(current->signal & ~current->blocked) && - midi_devs[dev]->buffer_status (dev)) - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; + /* + * Give the Midi driver time to drain its output queues + */ + + if (midi_devs[dev]->buffer_status != NULL) + while (!(current->signal & ~current->blocked) && + midi_devs[dev]->buffer_status(dev)) + + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper[dev]); + if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag[dev].opts |= WK_TIMEOUT; + } + midi_sleep_flag[dev].opts &= ~WK_SLEEP; + }; } static void -midi_input_intr (int dev, unsigned char data) +midi_input_intr(int dev, unsigned char data) { - if (midi_in_buf[dev] == NULL) - return; + if (midi_in_buf[dev] == NULL) + return; - if (data == 0xfe) /* + if (data == 0xfe) /* * Active sensing */ - return; /* + return; /* * Ignore */ - if (SPACE_AVAIL (midi_in_buf[dev])) - { - QUEUE_BYTE (midi_in_buf[dev], data); - if ((input_sleep_flag[dev].opts & WK_SLEEP)) - { - input_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&input_sleeper[dev]); - }; - } - + if (SPACE_AVAIL(midi_in_buf[dev])) + { + QUEUE_BYTE(midi_in_buf[dev], data); + if ((input_sleep_flag[dev].opts & WK_SLEEP)) + { + input_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&input_sleeper[dev]); + }; + } } static void -midi_output_intr (int dev) +midi_output_intr(int dev) { - /* - * Currently NOP - */ + /* + * Currently NOP + */ } static void -midi_poll (unsigned long dummy) +midi_poll(unsigned long dummy) { - unsigned long flags; - int dev; - - save_flags (flags); - cli (); - if (open_devs) - { - for (dev = 0; dev < num_midis; dev++) - if (midi_out_buf[dev] != NULL) - { - int ok = 1; - - while (DATA_AVAIL (midi_out_buf[dev]) && ok) - { - int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; - - restore_flags (flags); /* Give some time to others */ - ok = midi_devs[dev]->outputc (dev, c); - save_flags (flags); - cli (); - midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; - midi_out_buf[dev]->len--; - } - - if (DATA_AVAIL (midi_out_buf[dev]) < 100 && - (midi_sleep_flag[dev].opts & WK_SLEEP)) - { - midi_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&midi_sleeper[dev]); - }; - } + unsigned long flags; + int dev; - { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; /* + save_flags(flags); + cli(); + if (open_devs) + { + for (dev = 0; dev < num_midis; dev++) + if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) + { + int ok = 1; + + while (DATA_AVAIL(midi_out_buf[dev]) && ok) + { + int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; + + restore_flags(flags); /* Give some time to others */ + ok = midi_devs[dev]->outputc(dev, c); + save_flags(flags); + cli(); + midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; + midi_out_buf[dev]->len--; + } + + if (DATA_AVAIL(midi_out_buf[dev]) < 100 && + (midi_sleep_flag[dev].opts & WK_SLEEP)) + { + midi_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&midi_sleeper[dev]); + }; + } + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; /* * Come back later */ - } - restore_flags (flags); + } + restore_flags(flags); } int -MIDIbuf_open (int dev, struct fileinfo *file) +MIDIbuf_open(int dev, struct fileinfo *file) { - int mode, err; - - dev = dev >> 4; - mode = file->mode & O_ACCMODE; - - if (num_midis > MAX_MIDI_DEV) - { - printk ("Sound: FATAL ERROR: Too many midi interfaces\n"); - num_midis = MAX_MIDI_DEV; - } - - if (dev < 0 || dev >= num_midis) - { - printk ("Sound: Nonexistent MIDI interface %d\n", dev); - return -ENXIO; - } - - /* - * Interrupts disabled. Be careful - */ - - if ((err = midi_devs[dev]->open (dev, mode, - midi_input_intr, midi_output_intr)) < 0) - { - return err; - } - - parms[dev].prech_timeout = 0; - - midi_in_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf)); - - if (midi_in_buf[dev] == NULL) - { - printk ("midi: Can't allocate buffer\n"); - midi_devs[dev]->close (dev); - return -EIO; - } - midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - - midi_out_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf)); - - if (midi_out_buf[dev] == NULL) - { - printk ("midi: Can't allocate buffer\n"); - midi_devs[dev]->close (dev); - vfree (midi_in_buf[dev]); - midi_in_buf[dev] = NULL; - return -EIO; - } - midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; - open_devs++; - - midi_sleep_flag[dev].opts = WK_NONE; - input_sleep_flag[dev].opts = WK_NONE; - - if (open_devs < 2) /* This was first open */ - { - ; - - { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; /* Start polling */ - } - - return err; + int mode, err; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + if (num_midis > MAX_MIDI_DEV) + { + printk("Sound: FATAL ERROR: Too many midi interfaces\n"); + num_midis = MAX_MIDI_DEV; + } + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + { + printk("Sound: Nonexistent MIDI interface %d\n", dev); + return -ENXIO; + } + /* + * Interrupts disabled. Be careful + */ + + if ((err = midi_devs[dev]->open(dev, mode, + midi_input_intr, midi_output_intr)) < 0) + { + return err; + } + parms[dev].prech_timeout = 0; + + midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); + + if (midi_in_buf[dev] == NULL) + { + printk("midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + return -EIO; + } + midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; + + midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); + + if (midi_out_buf[dev] == NULL) + { + printk("midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + vfree(midi_in_buf[dev]); + midi_in_buf[dev] = NULL; + return -EIO; + } + midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; + open_devs++; + + midi_sleep_flag[dev].opts = WK_NONE; + input_sleep_flag[dev].opts = WK_NONE; + + if (open_devs < 2) /* This was first open */ + { + ; + + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; /* Start polling */ + } + return err; } void -MIDIbuf_release (int dev, struct fileinfo *file) +MIDIbuf_release(int dev, struct fileinfo *file) { - int mode; - unsigned long flags; + int mode; + unsigned long flags; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - if (dev < 0 || dev >= num_midis) - return; + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + return; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* - * Wait until the queue is empty - */ + /* + * Wait until the queue is empty + */ - if (mode != OPEN_READ) - { - midi_devs[dev]->outputc (dev, 0xfe); /* - * Active sensing to shut the - * devices - */ - - while (!(current->signal & ~current->blocked) && - DATA_AVAIL (midi_out_buf[dev])) - - { - unsigned long tlimit; - - if (0) - current->timeout = tlimit = jiffies + (0); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; /* + if (mode != OPEN_READ) + { + midi_devs[dev]->outputc(dev, 0xfe); /* + * Active sensing to shut the + * devices + */ + + while (!(current->signal & ~current->blocked) && + DATA_AVAIL(midi_out_buf[dev])) + + { + unsigned long tlimit; + + if (0) + current->timeout = tlimit = jiffies + (0); + else + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper[dev]); + if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag[dev].opts |= WK_TIMEOUT; + } + midi_sleep_flag[dev].opts &= ~WK_SLEEP; + }; /* * Sync */ - drain_midi_queue (dev); /* - * Ensure the output queues are empty - */ - } - - restore_flags (flags); + drain_midi_queue(dev); /* + * Ensure the output queues are empty + */ + } + restore_flags(flags); - midi_devs[dev]->close (dev); + midi_devs[dev]->close(dev); - vfree (midi_in_buf[dev]); - vfree (midi_out_buf[dev]); - midi_in_buf[dev] = NULL; - midi_out_buf[dev] = NULL; - if (open_devs < 2) - del_timer (&poll_timer);; - open_devs--; + vfree(midi_in_buf[dev]); + vfree(midi_out_buf[dev]); + midi_in_buf[dev] = NULL; + midi_out_buf[dev] = NULL; + if (open_devs < 2) + del_timer(&poll_timer);; + open_devs--; } int -MIDIbuf_write (int dev, struct fileinfo *file, const char *buf, int count) +MIDIbuf_write(int dev, struct fileinfo *file, const char *buf, int count) { - unsigned long flags; - int c, n, i; - unsigned char tmp_data; + unsigned long flags; + int c, n, i; + unsigned char tmp_data; - dev = dev >> 4; + dev = dev >> 4; - if (!count) - return 0; + if (!count) + return 0; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - c = 0; + c = 0; - while (c < count) - { - n = SPACE_AVAIL (midi_out_buf[dev]); + while (c < count) + { + n = SPACE_AVAIL(midi_out_buf[dev]); - if (n == 0) /* + if (n == 0) /* * No space just now. We have to sleep */ - { - - { - unsigned long tlimit; - - if (0) - current->timeout = tlimit = jiffies + (0); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((current->signal & ~current->blocked)) - { - restore_flags (flags); - return -EINTR; - } - - n = SPACE_AVAIL (midi_out_buf[dev]); - } - - if (n > (count - c)) - n = count - c; - - for (i = 0; i < n; i++) - { - copy_from_user ((char *) &tmp_data, &(buf)[c], 1); - QUEUE_BYTE (midi_out_buf[dev], tmp_data); - c++; - } - } + { + + { + unsigned long tlimit; + + if (0) + current->timeout = tlimit = jiffies + (0); + else + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper[dev]); + if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag[dev].opts |= WK_TIMEOUT; + } + midi_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((current->signal & ~current->blocked)) + { + restore_flags(flags); + return -EINTR; + } + n = SPACE_AVAIL(midi_out_buf[dev]); + } + if (n > (count - c)) + n = count - c; + + for (i = 0; i < n; i++) + { + copy_from_user((char *) &tmp_data, &(buf)[c], 1); + QUEUE_BYTE(midi_out_buf[dev], tmp_data); + c++; + } + } - restore_flags (flags); + restore_flags(flags); - return c; + return c; } int -MIDIbuf_read (int dev, struct fileinfo *file, char *buf, int count) +MIDIbuf_read(int dev, struct fileinfo *file, char *buf, int count) { - int n, c = 0; - unsigned long flags; - unsigned char tmp_data; + int n, c = 0; + unsigned long flags; + unsigned char tmp_data; - dev = dev >> 4; + dev = dev >> 4; - save_flags (flags); - cli (); - - if (!DATA_AVAIL (midi_in_buf[dev])) /* - * No data yet, wait - */ - { - - { - unsigned long tlimit; - - if (parms[dev].prech_timeout) - current->timeout = tlimit = jiffies + (parms[dev].prech_timeout); - else - tlimit = (unsigned long) -1; - input_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&input_sleeper[dev]); - if (!(input_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - input_sleep_flag[dev].opts |= WK_TIMEOUT; - } - input_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((current->signal & ~current->blocked)) - c = -EINTR; /* - * The user is getting restless - */ - } + save_flags(flags); + cli(); - if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /* - * Got some bytes + if (!DATA_AVAIL(midi_in_buf[dev])) /* + * No data yet, wait */ - { - n = DATA_AVAIL (midi_in_buf[dev]); - if (n > count) - n = count; - c = 0; - - while (c < n) - { - REMOVE_BYTE (midi_in_buf[dev], tmp_data); { - char *fixit = (char *) &tmp_data; - - copy_to_user (&(buf)[c], fixit, 1); - }; - c++; - } - } - restore_flags (flags); + { + unsigned long tlimit; + + if (parms[dev].prech_timeout) + current->timeout = tlimit = jiffies + (parms[dev].prech_timeout); + else + tlimit = (unsigned long) -1; + input_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&input_sleeper[dev]); + if (!(input_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + input_sleep_flag[dev].opts |= WK_TIMEOUT; + } + input_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((current->signal & ~current->blocked)) + c = -EINTR; /* + * The user is getting restless + */ + } + if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /* + * Got some bytes + */ + { + n = DATA_AVAIL(midi_in_buf[dev]); + if (n > count) + n = count; + c = 0; + + while (c < n) + { + REMOVE_BYTE(midi_in_buf[dev], tmp_data); + { + char *fixit = (char *) &tmp_data; + + copy_to_user(&(buf)[c], fixit, 1); + }; + c++; + } + } + restore_flags(flags); - return c; + return c; } int -MIDIbuf_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +MIDIbuf_ioctl(int dev, struct fileinfo *file, + unsigned int cmd, caddr_t arg) { - int val; - - dev = dev >> 4; - - if (((cmd >> 8) & 0xff) == 'C') - { - if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ - return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0); - else - printk ("/dev/midi%d: No coprocessor for this device\n", dev); - - return -ENXIO; - } - else - switch (cmd) - { - - case SNDCTL_MIDI_PRETIME: - val = *(int *) arg; - if (val < 0) - val = 0; - - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return (*(int *) arg = val); - break; - - default: - return midi_devs[dev]->ioctl (dev, cmd, arg); - } + int val; + + dev = dev >> 4; + + if (((cmd >> 8) & 0xff) == 'C') + { + if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ + return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk("/dev/midi%d: No coprocessor for this device\n", dev); + + return -ENXIO; + } else + switch (cmd) + { + + case SNDCTL_MIDI_PRETIME: + val = *(int *) arg; + if (val < 0) + val = 0; + + val = (HZ * val) / 10; + parms[dev].prech_timeout = val; + return (*(int *) arg = val); + break; + + default: + return midi_devs[dev]->ioctl(dev, cmd, arg); + } } int -MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) +MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) { - dev = dev >> 4; - - switch (sel_type) - { - case SEL_IN: - if (!DATA_AVAIL (midi_in_buf[dev])) - { - - input_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&input_sleeper[dev], wait); - return 0; - } - return 1; - break; - - case SEL_OUT: - if (SPACE_AVAIL (midi_out_buf[dev])) - { + dev = dev >> 4; - midi_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&midi_sleeper[dev], wait); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } + switch (sel_type) + { + case SEL_IN: + if (!DATA_AVAIL(midi_in_buf[dev])) + { + + input_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&input_sleeper[dev], wait); + return 0; + } + return 1; + break; + + case SEL_OUT: + if (SPACE_AVAIL(midi_out_buf[dev])) + { + + midi_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&midi_sleeper[dev], wait); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; + } - return 0; + return 0; } void -MIDIbuf_init (void) +MIDIbuf_init(void) { } diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index 5a5e90e27..f504a5d9d 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -11,88 +11,89 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" +#include "soundmodule.h" -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) || defined(MODULE) #include "coproc.h" -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; #endif struct mpu_config { - int base; /* + int base; /* * I/O base */ - int irq; - int opened; /* - * Open mode - */ - int devno; - int synthno; - int uart_mode; - int initialized; - int mode; + int irq; + int opened; /* + * Open mode + */ + int devno; + int synthno; + int uart_mode; + int initialized; + int mode; #define MODE_MIDI 1 #define MODE_SYNTH 2 - unsigned char version, revision; - unsigned int capabilities; + unsigned char version, revision; + unsigned int capabilities; #define MPU_CAP_INTLG 0x10000000 #define MPU_CAP_SYNC 0x00000010 #define MPU_CAP_FSK 0x00000020 #define MPU_CAP_CLS 0x00000040 #define MPU_CAP_SMPTE 0x00000080 #define MPU_CAP_2PORT 0x00000001 - int timer_flag; + int timer_flag; #define MBUF_MAX 10 #define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \ - {printk("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;} - int m_busy; - unsigned char m_buf[MBUF_MAX]; - int m_ptr; - int m_state; - int m_left; - unsigned char last_status; - void (*inputintr) (int dev, unsigned char data); - int shared_irq; - int *osp; + {printk( "MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;} + int m_busy; + unsigned char m_buf[MBUF_MAX]; + int m_ptr; + int m_state; + int m_left; + unsigned char last_status; + void (*inputintr) (int dev, unsigned char data); + int shared_irq; + int *osp; }; #define DATAPORT(base) (base) #define COMDPORT(base) (base+1) #define STATPORT(base) (base+1) -static int -mpu401_status (struct mpu_config *devc) +static int +mpu401_status(struct mpu_config *devc) { - return inb (STATPORT (devc->base)); + return inb(STATPORT(devc->base)); } #define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY)) -static void -write_command (struct mpu_config *devc, unsigned char cmd) +static void +write_command(struct mpu_config *devc, unsigned char cmd) { - outb ((cmd), COMDPORT (devc->base)); + outb((cmd), COMDPORT(devc->base)); } -static int -read_data (struct mpu_config *devc) +static int +read_data(struct mpu_config *devc) { - return inb (DATAPORT (devc->base)); + return inb(DATAPORT(devc->base)); } -static void -write_data (struct mpu_config *devc, unsigned char byte) +static void +write_data(struct mpu_config *devc, unsigned char byte) { - outb ((byte), DATAPORT (devc->base)); + outb((byte), DATAPORT(devc->base)); } #define OUTPUT_READY 0x40 @@ -103,19 +104,19 @@ write_data (struct mpu_config *devc, unsigned char byte) static struct mpu_config dev_conf[MAX_MIDI_DEV] = { - {0}}; + {0}}; static int n_mpu_devs = 0; static volatile int irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static int reset_mpu401 (struct mpu_config *devc); -static void set_uart_mode (int dev, struct mpu_config *devc, int arg); +static int reset_mpu401(struct mpu_config *devc); +static void set_uart_mode(int dev, struct mpu_config *devc, int arg); -static void mpu_timer_init (int midi_dev); -static void mpu_timer_interrupt (void); -static void timer_ext_event (struct mpu_config *devc, int event, int parm); +static int mpu_timer_init(int midi_dev); +static void mpu_timer_interrupt(void); +static void timer_ext_event(struct mpu_config *devc, int event, int parm); static struct synth_info mpu_synth_info_proto = {"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT}; @@ -139,17 +140,17 @@ static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; static unsigned char len_tab[] = /* # of data bytes following a status */ { - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ }; -#ifndef CONFIG_SEQUENCER +#if !defined(CONFIG_SEQUENCER) && !defined(MODULE) #define STORE(cmd) #else #define STORE(cmd) \ @@ -166,779 +167,750 @@ static unsigned char len_tab[] = /* # of data bytes following a status #define _SEQ_ADVBUF(x) len=x static int -mpu_input_scanner (struct mpu_config *devc, unsigned char midic) +mpu_input_scanner(struct mpu_config *devc, unsigned char midic) { - switch (devc->m_state) - { - case ST_INIT: - switch (midic) - { - case 0xf8: - /* Timer overflow */ - break; - - case 0xfc: - printk ("<all end>"); - break; - - case 0xfd: - if (devc->timer_flag) - mpu_timer_interrupt (); - break; - - case 0xfe: - return MPU_ACK; - break; - - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - printk ("<Trk data rq #%d>", midic & 0x0f); - break; - - case 0xf9: - printk ("<conductor rq>"); - break; - - case 0xff: - devc->m_state = ST_SYSMSG; - break; - - default: - if (midic <= 0xef) - { - /* printk("mpu time: %d ", midic); */ - devc->m_state = ST_TIMED; - } - else - printk ("<MPU: Unknown event %02x> ", midic); - } - break; - - case ST_TIMED: - { - int msg = ((int) (midic & 0xf0) >> 4); - - devc->m_state = ST_DATABYTE; - - if (msg < 8) /* Data byte */ + switch (devc->m_state) { - /* printk("midi msg (running status) "); */ - msg = ((int) (devc->last_status & 0xf0) >> 4); - msg -= 8; - devc->m_left = len_tab[msg] - 1; - - devc->m_ptr = 2; - devc->m_buf[0] = devc->last_status; - devc->m_buf[1] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } + case ST_INIT: + switch (midic) + { + case 0xf8: + /* Timer overflow */ + break; + + case 0xfc: + printk("<all end>"); + break; + + case 0xfd: + if (devc->timer_flag) + mpu_timer_interrupt(); + break; + + case 0xfe: + return MPU_ACK; + break; + + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + printk("<Trk data rq #%d>", midic & 0x0f); + break; + + case 0xf9: + printk("<conductor rq>"); + break; + + case 0xff: + devc->m_state = ST_SYSMSG; + break; + + default: + if (midic <= 0xef) + { + /* printk( "mpu time: %d ", midic); */ + devc->m_state = ST_TIMED; + } else + printk("<MPU: Unknown event %02x> ", midic); + } + break; + + case ST_TIMED: + { + int msg = ((int) (midic & 0xf0) >> 4); + + devc->m_state = ST_DATABYTE; + + if (msg < 8) /* Data byte */ + { + /* printk( "midi msg (running status) "); */ + msg = ((int) (devc->last_status & 0xf0) >> 4); + msg -= 8; + devc->m_left = len_tab[msg] - 1; + + devc->m_ptr = 2; + devc->m_buf[0] = devc->last_status; + devc->m_buf[1] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } else if (msg == 0xf) /* MPU MARK */ + { + devc->m_state = ST_INIT; + + switch (midic) + { + case 0xf8: + /* printk( "NOP "); */ + break; + + case 0xf9: + /* printk( "meas end "); */ + break; + + case 0xfc: + /* printk( "data end "); */ + break; + + default: + printk("Unknown MPU mark %02x\n", midic); + } + } else + { + devc->last_status = midic; + /* printk( "midi msg "); */ + msg -= 8; + devc->m_left = len_tab[msg]; + + devc->m_ptr = 1; + devc->m_buf[0] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } + } + break; + + case ST_SYSMSG: + switch (midic) + { + case 0xf0: + printk("<SYX>"); + devc->m_state = ST_SYSEX; + break; + + case 0xf1: + devc->m_state = ST_MTC; + break; + + case 0xf2: + devc->m_state = ST_SONGPOS; + devc->m_ptr = 0; + break; + + case 0xf3: + devc->m_state = ST_SONGSEL; + break; + + case 0xf6: + /* printk( "tune_request\n"); */ + devc->m_state = ST_INIT; + + /* + * Real time messages + */ + case 0xf8: + /* midi clock */ + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_CLOCK, 0); + break; + + case 0xfA: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_START, 0); + break; + + case 0xFB: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_CONTINUE, 0); + break; + + case 0xFC: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_STOP, 0); + break; + + case 0xFE: + /* active sensing */ + devc->m_state = ST_INIT; + break; + + case 0xff: + /* printk( "midi hard reset"); */ + devc->m_state = ST_INIT; + break; + + default: + printk("unknown MIDI sysmsg %0x\n", midic); + devc->m_state = ST_INIT; + } + break; + + case ST_MTC: + devc->m_state = ST_INIT; + printk("MTC frame %x02\n", midic); + break; + + case ST_SYSEX: + if (midic == 0xf7) + { + printk("<EOX>"); + devc->m_state = ST_INIT; + } else + printk("%02x ", midic); + break; + + case ST_SONGPOS: + BUFTEST(devc); + devc->m_buf[devc->m_ptr++] = midic; + if (devc->m_ptr == 2) + { + devc->m_state = ST_INIT; + devc->m_ptr = 0; + timer_ext_event(devc, TMR_SPP, + ((devc->m_buf[1] & 0x7f) << 7) | + (devc->m_buf[0] & 0x7f)); + } + break; + + case ST_DATABYTE: + BUFTEST(devc); + devc->m_buf[devc->m_ptr++] = midic; + if ((--devc->m_left) <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + break; + + default: + printk("Bad state %d ", devc->m_state); + devc->m_state = ST_INIT; } - else if (msg == 0xf) /* MPU MARK */ - { - devc->m_state = ST_INIT; - - switch (midic) - { - case 0xf8: - /* printk("NOP "); */ - break; - case 0xf9: - /* printk("meas end "); */ - break; - - case 0xfc: - /* printk("data end "); */ - break; - - default: - printk ("Unknown MPU mark %02x\n", midic); - } - } - else - { - devc->last_status = midic; - /* printk ("midi msg "); */ - msg -= 8; - devc->m_left = len_tab[msg]; - - devc->m_ptr = 1; - devc->m_buf[0] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - } - } - break; - - case ST_SYSMSG: - switch (midic) - { - case 0xf0: - printk ("<SYX>"); - devc->m_state = ST_SYSEX; - break; - - case 0xf1: - devc->m_state = ST_MTC; - break; - - case 0xf2: - devc->m_state = ST_SONGPOS; - devc->m_ptr = 0; - break; - - case 0xf3: - devc->m_state = ST_SONGSEL; - break; - - case 0xf6: - /* printk("tune_request\n"); */ - devc->m_state = ST_INIT; - - /* - * Real time messages - */ - case 0xf8: - /* midi clock */ - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_CLOCK, 0); - break; - - case 0xfA: - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_START, 0); - break; - - case 0xFB: - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_CONTINUE, 0); - break; - - case 0xFC: - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_STOP, 0); - break; - - case 0xFE: - /* active sensing */ - devc->m_state = ST_INIT; - break; - - case 0xff: - /* printk("midi hard reset"); */ - devc->m_state = ST_INIT; - break; - - default: - printk ("unknown MIDI sysmsg %0x\n", midic); - devc->m_state = ST_INIT; - } - break; - - case ST_MTC: - devc->m_state = ST_INIT; - printk ("MTC frame %x02\n", midic); - break; - - case ST_SYSEX: - if (midic == 0xf7) - { - printk ("<EOX>"); - devc->m_state = ST_INIT; - } - else - printk ("%02x ", midic); - break; - - case ST_SONGPOS: - BUFTEST (devc); - devc->m_buf[devc->m_ptr++] = midic; - if (devc->m_ptr == 2) - { - devc->m_state = ST_INIT; - devc->m_ptr = 0; - timer_ext_event (devc, TMR_SPP, - ((devc->m_buf[1] & 0x7f) << 7) | - (devc->m_buf[0] & 0x7f)); - } - break; - - case ST_DATABYTE: - BUFTEST (devc); - devc->m_buf[devc->m_ptr++] = midic; - if ((--devc->m_left) <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - break; - - default: - printk ("Bad state %d ", devc->m_state); - devc->m_state = ST_INIT; - } - - return 1; + return 1; } static void -mpu401_input_loop (struct mpu_config *devc) +mpu401_input_loop(struct mpu_config *devc) { - unsigned long flags; - int busy; - int n; + unsigned long flags; + int busy; + int n; - save_flags (flags); - cli (); - busy = devc->m_busy; - devc->m_busy = 1; - restore_flags (flags); + save_flags(flags); + cli(); + busy = devc->m_busy; + devc->m_busy = 1; + restore_flags(flags); - if (busy) /* Already inside the scanner */ - return; + if (busy) /* Already inside the scanner */ + return; - n = 50; + n = 50; - while (input_avail (devc) && n-- > 0) - { - unsigned char c = read_data (devc); + while (input_avail(devc) && n-- > 0) + { + unsigned char c = read_data(devc); - if (devc->mode == MODE_SYNTH) - { - mpu_input_scanner (devc, c); - } - else if (devc->opened & OPEN_READ && devc->inputintr != NULL) - devc->inputintr (devc->devno, c); - } + if (devc->mode == MODE_SYNTH) + { + mpu_input_scanner(devc, c); + } else if (devc->opened & OPEN_READ && devc->inputintr != NULL) + devc->inputintr(devc->devno, c); + } - devc->m_busy = 0; + devc->m_busy = 0; } void -mpuintr (int irq, void *dev_id, struct pt_regs *dummy) +mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { - struct mpu_config *devc; - int dev; + struct mpu_config *devc; + int dev; - sti (); + sti(); /* * FreeBSD (and some others) pass unit number to the interrupt handler. * In this case we have to scan the table for first handler. */ - if (irq < 1 || irq > 15) - { - dev = -1; - } - else - dev = irq2dev[irq]; - - if (dev == -1) - { - int origirq = irq; - - for (irq = 0; irq <= 16; irq++) - if (irq2dev[irq] != -1) - break; - if (irq > 15) - { - printk ("MPU-401: Bogus interrupt #%d?\n", origirq); - return; - } - dev = irq2dev[irq]; - devc = &dev_conf[dev]; - } - else - devc = &dev_conf[dev]; - - if (input_avail (devc)) - if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) - mpu401_input_loop (devc); - else - { - /* Dummy read (just to acknowledge the interrupt) */ - read_data (devc); - } + if (irq < 1 || irq > 15) + { + dev = -1; + } else + dev = irq2dev[irq]; + if (dev == -1) + { + int origirq = irq; + + for (irq = 0; irq <= 16; irq++) + if (irq2dev[irq] != -1) + break; + if (irq > 15) + { + printk("MPU-401: Bogus interrupt #%d?\n", origirq); + return; + } + dev = irq2dev[irq]; + devc = &dev_conf[dev]; + } else + devc = &dev_conf[dev]; + + if (input_avail(devc)) + if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) + mpu401_input_loop(devc); + else + { + /* Dummy read (just to acknowledge the interrupt) */ + read_data(devc); + } } static int -mpu401_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +mpu401_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - int err; - struct mpu_config *devc; - - if (dev < 0 || dev >= num_midis) - return -ENXIO; - - devc = &dev_conf[dev]; - - if (devc->opened) - { - printk ("MPU-401: Midi busy\n"); - return -EBUSY; - } - - /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. - */ - - if (!devc->initialized) - { - if (mpu401_status (devc) == 0xff) /* Bus float */ - { - printk ("MPU-401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401 (devc); - } + int err; + struct mpu_config *devc; - irq2dev[devc->irq] = dev; + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + return -ENXIO; - if (midi_devs[dev]->coproc) - if ((err = midi_devs[dev]->coproc-> - open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) - { - printk ("MPU-401: Can't access coprocessor device\n"); + devc = &dev_conf[dev]; - return err; - } + if (devc->opened) + { + printk("MPU-401: Midi busy\n"); + return -EBUSY; + } + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloading its microcode. + */ + + if (!devc->initialized) + { + if (mpu401_status(devc) == 0xff) /* Bus float */ + { + printk("MPU-401: Device not initialized properly\n"); + return -EIO; + } + reset_mpu401(devc); + } + irq2dev[devc->irq] = dev; + + if (midi_devs[dev]->coproc) + if ((err = midi_devs[dev]->coproc-> + open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) + { + printk("MPU-401: Can't access coprocessor device\n"); - set_uart_mode (dev, devc, 1); - devc->mode = MODE_MIDI; - devc->synthno = 0; + return err; + } + set_uart_mode(dev, devc, 1); + devc->mode = MODE_MIDI; + devc->synthno = 0; - mpu401_input_loop (devc); + mpu401_input_loop(devc); - devc->inputintr = input; - devc->opened = mode; + devc->inputintr = input; + devc->opened = mode; - return 0; + return 0; } static void -mpu401_close (int dev) +mpu401_close(int dev) { - struct mpu_config *devc; + struct mpu_config *devc; - devc = &dev_conf[dev]; + devc = &dev_conf[dev]; - if (devc->uart_mode) - reset_mpu401 (devc); /* - * This disables the UART mode - */ - devc->mode = 0; + if (devc->uart_mode) + reset_mpu401(devc); /* + * This disables the UART mode + */ + devc->mode = 0; - devc->inputintr = NULL; + devc->inputintr = NULL; - if (midi_devs[dev]->coproc) - midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI); - devc->opened = 0; + if (midi_devs[dev]->coproc) + midi_devs[dev]->coproc->close(midi_devs[dev]->coproc->devc, COPR_MIDI); + devc->opened = 0; } static int -mpu401_out (int dev, unsigned char midi_byte) +mpu401_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; - - struct mpu_config *devc; + int timeout; + unsigned long flags; - devc = &dev_conf[dev]; + struct mpu_config *devc; - /* - * Sometimes it takes about 30000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ + devc = &dev_conf[dev]; - for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); + /* + * Sometimes it takes about 30000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ - save_flags (flags); - cli (); - if (!output_ready (devc)) - { - printk ("MPU-401: Send data timeout\n"); - restore_flags (flags); - return 0; - } + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - write_data (devc, midi_byte); - restore_flags (flags); - return 1; + save_flags(flags); + cli(); + if (!output_ready(devc)) + { + printk("MPU-401: Send data timeout\n"); + restore_flags(flags); + return 0; + } + write_data(devc, midi_byte); + restore_flags(flags); + return 1; } static int -mpu401_command (int dev, mpu_command_rec * cmd) +mpu401_command(int dev, mpu_command_rec * cmd) { - int i, timeout, ok; - int ret = 0; - unsigned long flags; - struct mpu_config *devc; + int i, timeout, ok; + int ret = 0; + unsigned long flags; + struct mpu_config *devc; - devc = &dev_conf[dev]; + devc = &dev_conf[dev]; - if (devc->uart_mode) /* + if (devc->uart_mode) /* * Not possible in UART mode */ - { - printk ("MPU-401 commands not possible in the UART mode\n"); - return -EINVAL; - } - - /* - * Test for input since pending input seems to block the output. - */ - if (input_avail (devc)) - mpu401_input_loop (devc); - - /* - * Sometimes it takes about 50000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - timeout = 50000; -retry: - if (timeout-- <= 0) - { - printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; - } - - save_flags (flags); - cli (); - - if (!output_ready (devc)) - { - restore_flags (flags); - goto retry; - } - - write_command (devc, cmd->cmd); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_avail (devc)) - { - if (devc->opened && devc->mode == MODE_SYNTH) { - if (mpu_input_scanner (devc, read_data (devc)) == MPU_ACK) - ok = 1; + printk("MPU-401 commands not possible in the UART mode\n"); + return -EINVAL; } - else - { /* Device is not currently open. Use simpler method */ - if (read_data (devc) == MPU_ACK) - ok = 1; + /* + * Test for input since pending input seems to block the output. + */ + if (input_avail(devc)) + mpu401_input_loop(devc); + + /* + * Sometimes it takes about 50000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + timeout = 50000; + retry: + if (timeout-- <= 0) + { + printk("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); + return -EIO; } - } - - if (!ok) - { - restore_flags (flags); - /* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ - return -EIO; - } + save_flags(flags); + cli(); - if (cmd->nr_args) - for (i = 0; i < cmd->nr_args; i++) - { - for (timeout = 3000; timeout > 0 && !output_ready (devc); timeout--); - - if (!mpu401_out (dev, cmd->data[i])) + if (!output_ready(devc)) { - restore_flags (flags); - printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; + restore_flags(flags); + goto retry; } - } - - ret = 0; - cmd->data[0] = 0; + write_command(devc, cmd->cmd); - if (cmd->nr_returns) - for (i = 0; i < cmd->nr_returns; i++) - { ok = 0; - for (timeout = 5000; timeout > 0 && !ok; timeout--) - if (input_avail (devc)) - { - cmd->data[i] = read_data (devc); - ok = 1; - } - + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail(devc)) + { + if (devc->opened && devc->mode == MODE_SYNTH) + { + if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK) + ok = 1; + } else + { /* Device is not currently open. Use simpler method */ + if (read_data(devc) == MPU_ACK) + ok = 1; + } + } if (!ok) { - restore_flags (flags); - /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ - return -EIO; + restore_flags(flags); + /* printk( "MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ + return -EIO; } - } - - restore_flags (flags); - - return ret; + if (cmd->nr_args) + for (i = 0; i < cmd->nr_args; i++) + { + for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--); + + if (!mpu401_out(dev, cmd->data[i])) + { + restore_flags(flags); + printk("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); + return -EIO; + } + } + ret = 0; + cmd->data[0] = 0; + + if (cmd->nr_returns) + for (i = 0; i < cmd->nr_returns; i++) + { + ok = 0; + for (timeout = 5000; timeout > 0 && !ok; timeout--) + if (input_avail(devc)) + { + cmd->data[i] = read_data(devc); + ok = 1; + } + if (!ok) + { + restore_flags(flags); + /* printk( "MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ + return -EIO; + } + } + restore_flags(flags); + + return ret; } static int -mpu_cmd (int dev, int cmd, int data) +mpu_cmd(int dev, int cmd, int data) { - int ret; + int ret; - static mpu_command_rec rec; + static mpu_command_rec rec; - rec.cmd = cmd & 0xff; - rec.nr_args = ((cmd & 0xf0) == 0xE0); - rec.nr_returns = ((cmd & 0xf0) == 0xA0); - rec.data[0] = data & 0xff; + rec.cmd = cmd & 0xff; + rec.nr_args = ((cmd & 0xf0) == 0xE0); + rec.nr_returns = ((cmd & 0xf0) == 0xA0); + rec.data[0] = data & 0xff; - if ((ret = mpu401_command (dev, &rec)) < 0) - { - return ret; - } - return (unsigned char) rec.data[0]; + if ((ret = mpu401_command(dev, &rec)) < 0) + { + return ret; + } + return (unsigned char) rec.data[0]; } static int -mpu401_prefix_cmd (int dev, unsigned char status) +mpu401_prefix_cmd(int dev, unsigned char status) { - struct mpu_config *devc = &dev_conf[dev]; - - if (devc->uart_mode) - return 1; - - if (status < 0xf0) - { - if (mpu_cmd (dev, 0xD0, 0) < 0) - { - return 0; - } + struct mpu_config *devc = &dev_conf[dev]; - return 1; - } + if (devc->uart_mode) + return 1; - switch (status) - { - case 0xF0: - if (mpu_cmd (dev, 0xDF, 0) < 0) - { - return 0; - } - - return 1; - break; - - default: - return 0; - } + if (status < 0xf0) + { + if (mpu_cmd(dev, 0xD0, 0) < 0) + { + return 0; + } + return 1; + } + switch (status) + { + case 0xF0: + if (mpu_cmd(dev, 0xDF, 0) < 0) + { + return 0; + } + return 1; + break; + + default: + return 0; + } } static int -mpu401_start_read (int dev) +mpu401_start_read(int dev) { - return 0; + return 0; } static int -mpu401_end_read (int dev) +mpu401_end_read(int dev) { - return 0; + return 0; } static int -mpu401_ioctl (int dev, unsigned cmd, caddr_t arg) +mpu401_ioctl(int dev, unsigned cmd, caddr_t arg) { - struct mpu_config *devc; - int val; - - devc = &dev_conf[dev]; - - switch (cmd) - { - case SNDCTL_MIDI_MPUMODE: - if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ - { - printk ("MPU-401: Intelligent mode not supported by the HW\n"); - return -EINVAL; - } - val = *(int *) arg; - set_uart_mode (dev, devc, !val); - return 0; - break; - - case SNDCTL_MIDI_MPUCMD: - { - int ret; - mpu_command_rec rec; - - memcpy ((char *) &rec, (&((char *) arg)[0]), sizeof (rec)); - - if ((ret = mpu401_command (dev, &rec)) < 0) - return ret; + struct mpu_config *devc; + int val; - memcpy ((&((char *) arg)[0]), (char *) &rec, sizeof (rec)); - return 0; - } - break; + devc = &dev_conf[dev]; - default: - return -EINVAL; - } + switch (cmd) + { + case SNDCTL_MIDI_MPUMODE: + if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ + { + printk("MPU-401: Intelligent mode not supported by the HW\n"); + return -EINVAL; + } + val = *(int *) arg; + set_uart_mode(dev, devc, !val); + return 0; + break; + + case SNDCTL_MIDI_MPUCMD: + { + int ret; + mpu_command_rec rec; + + memcpy((char *) &rec, (&((char *) arg)[0]), sizeof(rec)); + + if ((ret = mpu401_command(dev, &rec)) < 0) + return ret; + + memcpy((&((char *) arg)[0]), (char *) &rec, sizeof(rec)); + return 0; + } + break; + + default: + return -EINVAL; + } } static void -mpu401_kick (int dev) +mpu401_kick(int dev) { } static int -mpu401_buffer_status (int dev) +mpu401_buffer_status(int dev) { - return 0; /* + return 0; /* * No data in buffers */ } static int -mpu_synth_ioctl (int dev, - unsigned int cmd, caddr_t arg) +mpu_synth_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - int midi_dev; - struct mpu_config *devc; + int midi_dev; + struct mpu_config *devc; - midi_dev = synth_devs[dev]->midi_dev; + midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis) - return -ENXIO; + if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + return -ENXIO; - devc = &dev_conf[midi_dev]; + devc = &dev_conf[midi_dev]; - switch (cmd) - { + switch (cmd) + { - case SNDCTL_SYNTH_INFO: - memcpy ((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof (struct synth_info)); + case SNDCTL_SYNTH_INFO: + memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info)); - return 0; - break; + return 0; + break; - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } static int -mpu_synth_open (int dev, int mode) +mpu_synth_open(int dev, int mode) { - int midi_dev, err; - struct mpu_config *devc; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev > num_midis) - { - return -ENXIO; - } - - devc = &dev_conf[midi_dev]; + int midi_dev, err; + struct mpu_config *devc; - /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. - */ + midi_dev = synth_devs[dev]->midi_dev; - if (!devc->initialized) - { - if (mpu401_status (devc) == 0xff) /* Bus float */ - { - printk ("MPU-401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401 (devc); - } - - if (devc->opened) - { - printk ("MPU-401: Midi busy\n"); - return -EBUSY; - } - - devc->mode = MODE_SYNTH; - devc->synthno = dev; + if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + { + return -ENXIO; + } + devc = &dev_conf[midi_dev]; - devc->inputintr = NULL; - irq2dev[devc->irq] = midi_dev; + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloading its microcode. + */ - if (midi_devs[midi_dev]->coproc) - if ((err = midi_devs[midi_dev]->coproc-> - open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) - { - printk ("MPU-401: Can't access coprocessor device\n"); + if (!devc->initialized) + { + if (mpu401_status(devc) == 0xff) /* Bus float */ + { + printk("MPU-401: Device not initialized properly\n"); + return -EIO; + } + reset_mpu401(devc); + } + if (devc->opened) + { + printk("MPU-401: Midi busy\n"); + return -EBUSY; + } + devc->mode = MODE_SYNTH; + devc->synthno = dev; - return err; - } + devc->inputintr = NULL; + irq2dev[devc->irq] = midi_dev; - devc->opened = mode; - reset_mpu401 (devc); + if (midi_devs[midi_dev]->coproc) + if ((err = midi_devs[midi_dev]->coproc-> + open(midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) + { + printk("MPU-401: Can't access coprocessor device\n"); - if (mode & OPEN_READ) - { - mpu_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ - mpu_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ - mpu_cmd (midi_dev, 0x87, 0); /* Enable pitch & controller */ - } + return err; + } + devc->opened = mode; + reset_mpu401(devc); - return 0; + if (mode & OPEN_READ) + { + mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */ + mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ + mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */ + } + return 0; } static void -mpu_synth_close (int dev) +mpu_synth_close(int dev) { - int midi_dev; - struct mpu_config *devc; + int midi_dev; + struct mpu_config *devc; - midi_dev = synth_devs[dev]->midi_dev; + midi_dev = synth_devs[dev]->midi_dev; - devc = &dev_conf[midi_dev]; - mpu_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ - mpu_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */ + devc = &dev_conf[midi_dev]; + mpu_cmd(midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ + mpu_cmd(midi_dev, 0x8a, 0); /* Disable data in stopped mode */ - devc->inputintr = NULL; + devc->inputintr = NULL; - if (midi_devs[midi_dev]->coproc) - midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI); - devc->opened = 0; - devc->mode = 0; + if (midi_devs[midi_dev]->coproc) + midi_devs[midi_dev]->coproc->close(midi_devs[midi_dev]->coproc->devc, COPR_MIDI); + devc->opened = 0; + devc->mode = 0; } #define MIDI_SYNTH_NAME "MPU-401 UART Midi" @@ -947,376 +919,369 @@ mpu_synth_close (int dev) static struct synth_operations mpu401_synth_proto = { - "MPU401", - NULL, - 0, - SYNTH_TYPE_MIDI, - 0, - mpu_synth_open, - mpu_synth_close, - mpu_synth_ioctl, - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - midi_synth_hw_control, - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, - midi_synth_bender, - NULL, /* alloc */ - midi_synth_setup_voice, - midi_synth_send_sysex + "MPU401", + NULL, + 0, + SYNTH_TYPE_MIDI, + 0, + mpu_synth_open, + mpu_synth_close, + mpu_synth_ioctl, + midi_synth_kill_note, + midi_synth_start_note, + midi_synth_set_instr, + midi_synth_reset, + midi_synth_hw_control, + midi_synth_load_patch, + midi_synth_aftertouch, + midi_synth_controller, + midi_synth_panning, + NULL, + midi_synth_bender, + NULL, /* alloc */ + midi_synth_setup_voice, + midi_synth_send_sysex }; static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV]; static struct midi_operations mpu401_midi_proto = { - {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - NULL, - {0}, - mpu401_open, - mpu401_close, - mpu401_ioctl, - mpu401_out, - mpu401_start_read, - mpu401_end_read, - mpu401_kick, - NULL, - mpu401_buffer_status, - mpu401_prefix_cmd + {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + NULL, + {0}, + mpu401_open, + mpu401_close, + mpu401_ioctl, + mpu401_out, + mpu401_start_read, + mpu401_end_read, + mpu401_kick, + NULL, + mpu401_buffer_status, + mpu401_prefix_cmd }; static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; static void -mpu401_chk_version (struct mpu_config *devc) +mpu401_chk_version(int n, struct mpu_config *devc) { - int tmp; - unsigned long flags; - - devc->version = devc->revision = 0; - - save_flags (flags); - cli (); - if ((tmp = mpu_cmd (num_midis, 0xAC, 0)) < 0) - { - restore_flags (flags); - return; - } - - if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ - { - restore_flags (flags); - return; - } - - devc->version = tmp; - - if ((tmp = mpu_cmd (num_midis, 0xAD, 0)) < 0) - { - devc->version = 0; - restore_flags (flags); - return; - } - devc->revision = tmp; - - restore_flags (flags); + int tmp; + unsigned long flags; + + devc->version = devc->revision = 0; + + save_flags(flags); + cli(); + if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0) + { + restore_flags(flags); + return; + } + if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ + { + restore_flags(flags); + return; + } + devc->version = tmp; + + if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) + { + devc->version = 0; + restore_flags(flags); + return; + } + devc->revision = tmp; + + restore_flags(flags); } void -attach_mpu401 (struct address_info *hw_config) +attach_mpu401(struct address_info *hw_config) { - unsigned long flags; - char revision_char; - - struct mpu_config *devc; - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("MPU-401: Too many midi devices detected\n"); - return; - } - - devc = &dev_conf[num_midis]; - - devc->base = hw_config->io_base; - devc->osp = hw_config->osp; - devc->irq = hw_config->irq; - devc->opened = 0; - devc->uart_mode = 0; - devc->initialized = 0; - devc->version = 0; - devc->revision = 0; - devc->capabilities = 0; - devc->timer_flag = 0; - devc->m_busy = 0; - devc->m_state = ST_INIT; - devc->shared_irq = hw_config->always_detect; - devc->irq = hw_config->irq; - - if (devc->irq < 0) - { - devc->irq *= -1; - devc->shared_irq = 1; - } - irq2dev[devc->irq] = num_midis; - - if (!hw_config->always_detect) - { - /* Verify the hardware again */ - if (!reset_mpu401 (devc)) - { - printk ("MPU401: Device didn't respond\n"); - return; - } + unsigned long flags; + char revision_char; + + int m; + struct mpu_config *devc; - if (!devc->shared_irq) - if (snd_set_irq_handler (devc->irq, mpuintr, "mpu401", devc->osp) < 0) + hw_config->slots[1] = -1; + m = sound_alloc_mididev(); + if (m == -1) { - printk ("MPU401: Failed to allocate IRQ%d\n", devc->irq); - return; + printk(KERN_WARNING "MPU-401: Too many midi devices detected\n"); + return; } + devc = &dev_conf[m]; + devc->base = hw_config->io_base; + devc->osp = hw_config->osp; + devc->irq = hw_config->irq; + devc->opened = 0; + devc->uart_mode = 0; + devc->initialized = 0; + devc->version = 0; + devc->revision = 0; + devc->capabilities = 0; + devc->timer_flag = 0; + devc->m_busy = 0; + devc->m_state = ST_INIT; + devc->shared_irq = hw_config->always_detect; + devc->irq = hw_config->irq; + + if (devc->irq < 0) + { + devc->irq *= -1; + devc->shared_irq = 1; + } + irq2dev[devc->irq] = m; - save_flags (flags); - cli (); - mpu401_chk_version (devc); - if (devc->version == 0) - mpu401_chk_version (devc); - restore_flags (flags); - } - - request_region (hw_config->io_base, 2, "mpu401"); - - if (devc->version != 0) - if (mpu_cmd (num_midis, 0xC5, 0) >= 0) /* Set timebase OK */ - if (mpu_cmd (num_midis, 0xE0, 120) >= 0) /* Set tempo OK */ - devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - - - mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - - if (mpu401_synth_operations[num_midis] == NULL) - { - printk ("mpu401: Can't allocate memory\n"); - return; - } - - if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ - { - memcpy ((char *) mpu401_synth_operations[num_midis], - (char *) &std_midi_synth, - sizeof (struct synth_operations)); - } - else - { - memcpy ((char *) mpu401_synth_operations[num_midis], - (char *) &mpu401_synth_proto, - sizeof (struct synth_operations)); - } - - memcpy ((char *) &mpu401_midi_operations[num_midis], - (char *) &mpu401_midi_proto, - sizeof (struct midi_operations)); - - mpu401_midi_operations[num_midis].converter = - mpu401_synth_operations[num_midis]; - - memcpy ((char *) &mpu_synth_info[num_midis], - (char *) &mpu_synth_info_proto, - sizeof (struct synth_info)); - - n_mpu_devs++; - - if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ - { - int ports = (devc->revision & 0x08) ? 32 : 16; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | - MPU_CAP_CLS | MPU_CAP_2PORT; - - revision_char = (devc->revision == 0x7f) ? 'M' : ' '; - sprintf (mpu_synth_info[num_midis].name, - "MQX-%d%c MIDI Interface #%d", - ports, - revision_char, - n_mpu_devs); - } - else - { - - revision_char = devc->revision ? devc->revision + '@' : ' '; - if ((int) devc->revision > ('Z' - '@')) - revision_char = '+'; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - - if (hw_config->name) - sprintf (mpu_synth_info[num_midis].name, "%s (MPU401)", hw_config->name); - else - sprintf (mpu_synth_info[num_midis].name, - "MPU-401 %d.%d%c Midi interface #%d", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char, - n_mpu_devs); - } - - strcpy (mpu401_midi_operations[num_midis].info.name, - mpu_synth_info[num_midis].name); - - conf_printf (mpu_synth_info[num_midis].name, hw_config); - - mpu401_synth_operations[num_midis]->midi_dev = devc->devno = num_midis; - mpu401_synth_operations[devc->devno]->info = - &mpu_synth_info[devc->devno]; - - if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */ - mpu_timer_init (num_midis); - - irq2dev[devc->irq] = num_midis; - midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; - sequencer_init (); -} + if (!hw_config->always_detect) + { + /* Verify the hardware again */ + if (!reset_mpu401(devc)) + { + printk(KERN_WARNING "mpu401: Device didn't respond\n"); + sound_unload_mididev(m); + return; + } + if (!devc->shared_irq) + if (snd_set_irq_handler(devc->irq, mpuintr, "mpu401", devc->osp) < 0) + { + printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq); + sound_unload_mididev(m); + return; + } + save_flags(flags); + cli(); + mpu401_chk_version(m, devc); + if (devc->version == 0) + mpu401_chk_version(m, devc); + restore_flags(flags); + } + request_region(hw_config->io_base, 2, "mpu401"); -static int -reset_mpu401 (struct mpu_config *devc) -{ - unsigned long flags; - int ok, timeout, n; - int timeout_limit; + if (devc->version != 0) + if (mpu_cmd(m, 0xC5, 0) >= 0) /* Set timebase OK */ + if (mpu_cmd(m, 0xE0, 120) >= 0) /* Set tempo OK */ + devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - /* - * Send the RESET command. Try again if no success at the first time. - * (If the device is in the UART mode, it will not ack the reset cmd). - */ - ok = 0; + mpu401_synth_operations[m] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - timeout_limit = devc->initialized ? 30000 : 100000; - devc->initialized = 1; + if (sound_nblocks < 1024) + sound_nblocks++;; - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) - ok = output_ready (devc); + if (mpu401_synth_operations[m] == NULL) + { + sound_unload_mididev(m); + printk(KERN_ERR "mpu401: Can't allocate memory\n"); + return; + } + if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ + { + memcpy((char *) mpu401_synth_operations[m], + (char *) &std_midi_synth, + sizeof(struct synth_operations)); + } else + { + memcpy((char *) mpu401_synth_operations[m], + (char *) &mpu401_synth_proto, + sizeof(struct synth_operations)); + } - write_command (devc, MPU_RESET); /* - * Send MPU-401 RESET Command - */ + memcpy((char *) &mpu401_midi_operations[m], + (char *) &mpu401_midi_proto, + sizeof(struct midi_operations)); - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ + mpu401_midi_operations[m].converter = + mpu401_synth_operations[m]; - for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) - { - save_flags (flags); - cli (); - if (input_avail (devc)) - if (read_data (devc) == MPU_ACK) - ok = 1; - restore_flags (flags); - } + memcpy((char *) &mpu_synth_info[m], + (char *) &mpu_synth_info_proto, + sizeof(struct synth_info)); - } + n_mpu_devs++; - devc->m_state = ST_INIT; - devc->m_ptr = 0; - devc->m_left = 0; - devc->last_status = 0; - devc->uart_mode = 0; + if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ + { + int ports = (devc->revision & 0x08) ? 32 : 16; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | + MPU_CAP_CLS | MPU_CAP_2PORT; + + revision_char = (devc->revision == 0x7f) ? 'M' : ' '; + sprintf(mpu_synth_info[m].name, + "MQX-%d%c MIDI Interface #%d", + ports, + revision_char, + n_mpu_devs); + } else + { - return ok; + revision_char = devc->revision ? devc->revision + '@' : ' '; + if ((int) devc->revision > ('Z' - '@')) + revision_char = '+'; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; + + if (hw_config->name) + sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name); + else + sprintf(mpu_synth_info[m].name, + "MPU-401 %d.%d%c Midi interface #%d", + (int) (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char, + n_mpu_devs); + } + + strcpy(mpu401_midi_operations[m].info.name, + mpu_synth_info[m].name); + + conf_printf(mpu_synth_info[m].name, hw_config); + + mpu401_synth_operations[m]->midi_dev = devc->devno = m; + mpu401_synth_operations[devc->devno]->info = + &mpu_synth_info[devc->devno]; + + if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */ + hw_config->slots[2] = mpu_timer_init(m); + + irq2dev[devc->irq] = m; + midi_devs[m] = &mpu401_midi_operations[devc->devno]; + hw_config->slots[1] = m; + sequencer_init(); } -static void -set_uart_mode (int dev, struct mpu_config *devc, int arg) +static int +reset_mpu401(struct mpu_config *devc) { - if (!arg && (devc->capabilities & MPU_CAP_INTLG)) - { - return; - } + unsigned long flags; + int ok, timeout, n; + int timeout_limit; + + /* + * Send the RESET command. Try again if no success at the first time. + * (If the device is in the UART mode, it will not ack the reset cmd). + */ - if ((devc->uart_mode == 0) == (arg == 0)) - { - return; /* Already set */ - } + ok = 0; - reset_mpu401 (devc); /* This exits the uart mode */ + timeout_limit = devc->initialized ? 30000 : 100000; + devc->initialized = 1; - if (arg) - { - if (mpu_cmd (dev, UART_MODE_ON, 0) < 0) - { - printk ("MPU%d: Can't enter UART mode\n", devc->devno); - devc->uart_mode = 0; - return; - } - } - devc->uart_mode = arg; + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) + ok = output_ready(devc); + + write_command(devc, MPU_RESET); /* + * Send MPU-401 RESET Command + */ + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) + { + save_flags(flags); + cli(); + if (input_avail(devc)) + if (read_data(devc) == MPU_ACK) + ok = 1; + restore_flags(flags); + } + + } + + devc->m_state = ST_INIT; + devc->m_ptr = 0; + devc->m_left = 0; + devc->last_status = 0; + devc->uart_mode = 0; + + return ok; +} + +static void +set_uart_mode(int dev, struct mpu_config *devc, int arg) +{ + if (!arg && (devc->capabilities & MPU_CAP_INTLG)) + { + return; + } + if ((devc->uart_mode == 0) == (arg == 0)) + { + return; /* Already set */ + } + reset_mpu401(devc); /* This exits the uart mode */ + + if (arg) + { + if (mpu_cmd(dev, UART_MODE_ON, 0) < 0) + { + printk("MPU%d: Can't enter UART mode\n", devc->devno); + devc->uart_mode = 0; + return; + } + } + devc->uart_mode = arg; } int -probe_mpu401 (struct address_info *hw_config) +probe_mpu401(struct address_info *hw_config) { - int ok = 0; - struct mpu_config tmp_devc; - - if (check_region (hw_config->io_base, 2)) - { - printk ("\n\nmpu401.c: I/O port %x already in use\n\n", - hw_config->io_base); - return 0; - } - - tmp_devc.base = hw_config->io_base; - tmp_devc.irq = hw_config->irq; - tmp_devc.initialized = 0; - tmp_devc.opened = 0; - tmp_devc.osp = hw_config->osp; - - if (hw_config->always_detect) - return 1; - - if (inb (hw_config->io_base + 1) == 0xff) - { - DDB (printk ("MPU401: Port %x looks dead.\n", hw_config->io_base)); - return 0; /* Just bus float? */ - } - - ok = reset_mpu401 (&tmp_devc); - - if (!ok) - { - DDB (printk ("MPU401: Reset failed on port %x\n", hw_config->io_base)); - } - - return ok; + int ok = 0; + struct mpu_config tmp_devc; + + if (check_region(hw_config->io_base, 2)) + { + printk("\n\nmpu401.c: I/O port %x already in use\n\n", hw_config->io_base); + return 0; + } + tmp_devc.base = hw_config->io_base; + tmp_devc.irq = hw_config->irq; + tmp_devc.initialized = 0; + tmp_devc.opened = 0; + tmp_devc.osp = hw_config->osp; + + if (hw_config->always_detect) + return 1; + + if (inb(hw_config->io_base + 1) == 0xff) + { + DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base)); + return 0; /* Just bus float? */ + } + ok = reset_mpu401(&tmp_devc); + + if (!ok) + { + DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base)); + } + return ok; } void -unload_mpu401 (struct address_info *hw_config) +unload_mpu401(struct address_info *hw_config) { - release_region (hw_config->io_base, 2); - if (hw_config->always_detect == 0 && hw_config->irq > 0) - snd_release_irq (hw_config->irq); + release_region(hw_config->io_base, 2); + if (hw_config->always_detect == 0 && hw_config->irq > 0) + snd_release_irq(hw_config->irq); + sound_unload_mididev(hw_config->slots[1]); + sound_unload_timerdev(hw_config->slots[2]); } /***************************************************** * Timer stuff ****************************************************/ -#if defined(CONFIG_SEQUENCER) +#if defined(CONFIG_SEQUENCER) || defined(MODULE) static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; static volatile int curr_tempo, curr_timebase, hw_timebase; @@ -1327,525 +1292,566 @@ static unsigned long prev_event_time; static int metronome_mode; static unsigned long -clocks2ticks (unsigned long clocks) +clocks2ticks(unsigned long clocks) { - /* - * The MPU-401 supports just a limited set of possible timebase values. - * Since the applications require more choices, the driver has to - * program the HW to do its best and to convert between the HW and - * actual timebases. - */ - - return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; + /* + * The MPU-401 supports just a limited set of possible timebase values. + * Since the applications require more choices, the driver has to + * program the HW to do its best and to convert between the HW and + * actual timebases. + */ + + return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; } static void -set_timebase (int midi_dev, int val) +set_timebase(int midi_dev, int val) { - int hw_val; - - if (val < 48) - val = 48; - if (val > 1000) - val = 1000; - - hw_val = val; - hw_val = (hw_val + 12) / 24; - if (hw_val > max_timebase) - hw_val = max_timebase; - - if (mpu_cmd (midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) - { - printk ("MPU: Can't set HW timebase to %d\n", hw_val * 24); - return; - } - hw_timebase = hw_val * 24; - curr_timebase = val; + int hw_val; + + if (val < 48) + val = 48; + if (val > 1000) + val = 1000; + + hw_val = val; + hw_val = (hw_val + 12) / 24; + if (hw_val > max_timebase) + hw_val = max_timebase; + + if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) + { + printk("MPU: Can't set HW timebase to %d\n", hw_val * 24); + return; + } + hw_timebase = hw_val * 24; + curr_timebase = val; } static void -tmr_reset (void) +tmr_reset(void) { - unsigned long flags; - - save_flags (flags); - cli (); - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = curr_clocks = 0; - restore_flags (flags); + unsigned long flags; + + save_flags(flags); + cli(); + next_event_time = (unsigned long) -1; + prev_event_time = 0; + curr_ticks = curr_clocks = 0; + restore_flags(flags); } static void -set_timer_mode (int midi_dev) +set_timer_mode(int midi_dev) { - if (timer_mode & TMR_MODE_CLS) - mpu_cmd (midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */ - - if (timer_mode & TMR_INTERNAL) - { - mpu_cmd (midi_dev, 0x80, 0); /* Use MIDI sync */ - } - else - { - if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) - { - mpu_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ - mpu_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ - } - else if (timer_mode & TMR_MODE_FSK) - mpu_cmd (midi_dev, 0x81, 0); /* Use FSK sync */ - } + if (timer_mode & TMR_MODE_CLS) + mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ + + if (timer_mode & TMR_INTERNAL) + { + mpu_cmd(midi_dev, 0x80, 0); /* Use MIDI sync */ + } else + { + if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) + { + mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */ + mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ + } else if (timer_mode & TMR_MODE_FSK) + mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */ + } } static void -stop_metronome (int midi_dev) +stop_metronome(int midi_dev) { - mpu_cmd (midi_dev, 0x84, 0); /* Disable metronome */ + mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ } static void -setup_metronome (int midi_dev) +setup_metronome(int midi_dev) { - int numerator, denominator; - int clks_per_click, num_32nds_per_beat; - int beats_per_measure; - - numerator = ((unsigned) metronome_mode >> 24) & 0xff; - denominator = ((unsigned) metronome_mode >> 16) & 0xff; - clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff; - num_32nds_per_beat = (unsigned) metronome_mode & 0xff; - beats_per_measure = (numerator * 4) >> denominator; - - if (!metronome_mode) - mpu_cmd (midi_dev, 0x84, 0); /* Disable metronome */ - else - { - mpu_cmd (midi_dev, 0xE4, clks_per_click); - mpu_cmd (midi_dev, 0xE6, beats_per_measure); - mpu_cmd (midi_dev, 0x83, 0); /* Enable metronome without accents */ - } + int numerator, denominator; + int clks_per_click, num_32nds_per_beat; + int beats_per_measure; + + numerator = ((unsigned) metronome_mode >> 24) & 0xff; + denominator = ((unsigned) metronome_mode >> 16) & 0xff; + clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff; + num_32nds_per_beat = (unsigned) metronome_mode & 0xff; + beats_per_measure = (numerator * 4) >> denominator; + + if (!metronome_mode) + mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ + else + { + mpu_cmd(midi_dev, 0xE4, clks_per_click); + mpu_cmd(midi_dev, 0xE6, beats_per_measure); + mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */ + } } static int -mpu_start_timer (int midi_dev) +mpu_start_timer(int midi_dev) { - tmr_reset (); - set_timer_mode (midi_dev); - - if (tmr_running) - return TIMER_NOT_ARMED; /* Already running */ - - if (timer_mode & TMR_INTERNAL) - { - mpu_cmd (midi_dev, 0x02, 0); /* Send MIDI start */ - tmr_running = 1; - return TIMER_NOT_ARMED; - } - else - { - mpu_cmd (midi_dev, 0x35, 0); /* Enable mode messages to PC */ - mpu_cmd (midi_dev, 0x38, 0); /* Enable sys common messages to PC */ - mpu_cmd (midi_dev, 0x39, 0); /* Enable real time messages to PC */ - mpu_cmd (midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ - } - - return TIMER_ARMED; + tmr_reset(); + set_timer_mode(midi_dev); + + if (tmr_running) + return TIMER_NOT_ARMED; /* Already running */ + + if (timer_mode & TMR_INTERNAL) + { + mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */ + tmr_running = 1; + return TIMER_NOT_ARMED; + } else + { + mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */ + mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */ + mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */ + mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ + } + + return TIMER_ARMED; } static int -mpu_timer_open (int dev, int mode) +mpu_timer_open(int dev, int mode) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; - if (timer_open) - return -EBUSY; + if (timer_open) + return -EBUSY; - tmr_reset (); - curr_tempo = 50; - mpu_cmd (midi_dev, 0xE0, 50); - curr_timebase = hw_timebase = 120; - set_timebase (midi_dev, 120); - timer_open = 1; - metronome_mode = 0; - set_timer_mode (midi_dev); + tmr_reset(); + curr_tempo = 50; + mpu_cmd(midi_dev, 0xE0, 50); + curr_timebase = hw_timebase = 120; + set_timebase(midi_dev, 120); + timer_open = 1; + metronome_mode = 0; + set_timer_mode(midi_dev); - mpu_cmd (midi_dev, 0xe7, 0x04); /* Send all clocks to host */ - mpu_cmd (midi_dev, 0x95, 0); /* Enable clock to host */ + mpu_cmd(midi_dev, 0xe7, 0x04); /* Send all clocks to host */ + mpu_cmd(midi_dev, 0x95, 0); /* Enable clock to host */ - return 0; + return 0; } static void -mpu_timer_close (int dev) +mpu_timer_close(int dev) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; - timer_open = tmr_running = 0; - mpu_cmd (midi_dev, 0x15, 0); /* Stop all */ - mpu_cmd (midi_dev, 0x94, 0); /* Disable clock to host */ - mpu_cmd (midi_dev, 0x8c, 0); /* Disable measure end messages to host */ - stop_metronome (midi_dev); + timer_open = tmr_running = 0; + mpu_cmd(midi_dev, 0x15, 0); /* Stop all */ + mpu_cmd(midi_dev, 0x94, 0); /* Disable clock to host */ + mpu_cmd(midi_dev, 0x8c, 0); /* Disable measure end messages to host */ + stop_metronome(midi_dev); } static int -mpu_timer_event (int dev, unsigned char *event) +mpu_timer_event(int dev, unsigned char *event) { - unsigned char command = event[1]; - unsigned long parm = *(unsigned int *) &event[4]; - int midi_dev = sound_timer_devs[dev]->devlink; - - switch (command) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; + unsigned char command = event[1]; + unsigned long parm = *(unsigned int *) &event[4]; + int midi_dev = sound_timer_devs[dev]->devlink; - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - if (tmr_running) - break; - return mpu_start_timer (midi_dev); - break; - - case TMR_STOP: - mpu_cmd (midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome (midi_dev); - tmr_running = 0; - break; - - case TMR_CONTINUE: - if (tmr_running) - break; - mpu_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */ - setup_metronome (midi_dev); - tmr_running = 1; - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - - if (mpu_cmd (midi_dev, 0xE0, parm) < 0) - printk ("MPU: Can't set tempo to %d\n", (int) parm); - curr_tempo = parm; - } - break; - - case TMR_ECHO: - seq_copy_to_input (event, 8); - break; - - case TMR_TIMESIG: - if (metronome_mode) /* Metronome enabled */ - { - metronome_mode = parm; - setup_metronome (midi_dev); - } - break; - - default:; - } + switch (command) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + if (tmr_running) + break; + return mpu_start_timer(midi_dev); + break; + + case TMR_STOP: + mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome(midi_dev); + tmr_running = 0; + break; + + case TMR_CONTINUE: + if (tmr_running) + break; + mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ + setup_metronome(midi_dev); + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + + if (mpu_cmd(midi_dev, 0xE0, parm) < 0) + printk("MPU: Can't set tempo to %d\n", (int) parm); + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; + + case TMR_TIMESIG: + if (metronome_mode) /* Metronome enabled */ + { + metronome_mode = parm; + setup_metronome(midi_dev); + } + break; + + default:; + } - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static unsigned long -mpu_timer_get_time (int dev) +mpu_timer_get_time(int dev) { - if (!timer_open) - return 0; + if (!timer_open) + return 0; - return curr_ticks; + return curr_ticks; } static int -mpu_timer_ioctl (int dev, - unsigned int command, caddr_t arg) +mpu_timer_ioctl(int dev, + unsigned int command, caddr_t arg) { - int midi_dev = sound_timer_devs[dev]->devlink; - - switch (command) - { - case SNDCTL_TMR_SOURCE: - { - int parm; - - parm = *(int *) arg; - parm &= timer_caps; + int midi_dev = sound_timer_devs[dev]->devlink; - if (parm != 0) + switch (command) { - timer_mode = parm; - - if (timer_mode & TMR_MODE_CLS) - mpu_cmd (midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */ + case SNDCTL_TMR_SOURCE: + { + int parm; + + parm = *(int *) arg; + parm &= timer_caps; + + if (parm != 0) + { + timer_mode = parm; + + if (timer_mode & TMR_MODE_CLS) + mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ + } + return (*(int *) arg = timer_mode); + } + break; + + case SNDCTL_TMR_START: + mpu_start_timer(midi_dev); + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome(midi_dev); + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + if (tmr_running) + return 0; + tmr_running = 1; + mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val; + + val = *(int *) arg; + if (val) + set_timebase(midi_dev, val); + + return (*(int *) arg = curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val; + int ret; + + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) + { + printk("MPU: Can't set tempo to %d\n", (int) val); + return ret; + } + curr_tempo = val; + } + return (*(int *) arg = curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + { + int val; + + val = *(int *) arg; + if (val != 0) /* Can't change */ + return -EINVAL; + + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + } + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + break; + + case SNDCTL_TMR_METRONOME: + metronome_mode = *(int *) arg; + setup_metronome(midi_dev); + return 0; + break; + + default:; } - return (*(int *) arg = timer_mode); - } - break; - - case SNDCTL_TMR_START: - mpu_start_timer (midi_dev); - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - mpu_cmd (midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome (midi_dev); - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - if (tmr_running) - return 0; - tmr_running = 1; - mpu_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */ - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - - val = *(int *) arg; - if (val) - set_timebase (midi_dev, val); - - return (*(int *) arg = curr_timebase); - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - int ret; - - val = *(int *) arg; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - if ((ret = mpu_cmd (midi_dev, 0xE0, val)) < 0) - { - printk ("MPU: Can't set tempo to %d\n", (int) val); - return ret; - } - - curr_tempo = val; - } - - return (*(int *) arg = curr_tempo); - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - - val = *(int *) arg; - if (val != 0) /* Can't change */ - return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - } - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - metronome_mode = *(int *) arg; - setup_metronome (midi_dev); - return 0; - break; - - default:; - } - - return -EINVAL; + return -EINVAL; } static void -mpu_timer_arm (int dev, long time) +mpu_timer_arm(int dev, long time) { - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; - next_event_time = prev_event_time = time; + next_event_time = prev_event_time = time; - return; + return; } static struct sound_timer_operations mpu_timer = { - {"MPU-401 Timer", 0}, - 10, /* Priority */ - 0, /* Local device link */ - mpu_timer_open, - mpu_timer_close, - mpu_timer_event, - mpu_timer_get_time, - mpu_timer_ioctl, - mpu_timer_arm + {"MPU-401 Timer", 0}, + 10, /* Priority */ + 0, /* Local device link */ + mpu_timer_open, + mpu_timer_close, + mpu_timer_event, + mpu_timer_get_time, + mpu_timer_ioctl, + mpu_timer_arm }; static void -mpu_timer_interrupt (void) +mpu_timer_interrupt(void) { - if (!timer_open) - return; - - if (!tmr_running) - return; + if (!timer_open) + return; - curr_clocks++; - curr_ticks = clocks2ticks (curr_clocks); + if (!tmr_running) + return; - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer (0); - } -} - -static void -timer_ext_event (struct mpu_config *devc, int event, int parm) -{ - int midi_dev = devc->devno; + curr_clocks++; + curr_ticks = clocks2ticks(curr_clocks); - if (!devc->timer_flag) - return; - - switch (event) - { - case TMR_CLOCK: - printk ("<MIDI clk>"); - break; - - case TMR_START: - printk ("Ext MIDI start\n"); - if (!tmr_running) - if (timer_mode & TMR_EXTERNAL) + if (curr_ticks >= next_event_time) { - tmr_running = 1; - setup_metronome (midi_dev); - next_event_time = 0; - STORE (SEQ_START_TIMER ()); + next_event_time = (unsigned long) -1; + sequencer_timer(0); } - break; +} - case TMR_STOP: - printk ("Ext MIDI stop\n"); - if (timer_mode & TMR_EXTERNAL) - { - tmr_running = 0; - stop_metronome (midi_dev); - STORE (SEQ_STOP_TIMER ()); - } - break; +static void timer_ext_event(struct mpu_config *devc, int event, int parm) +{ + int midi_dev = devc->devno; - case TMR_CONTINUE: - printk ("Ext MIDI continue\n"); - if (timer_mode & TMR_EXTERNAL) - { - tmr_running = 1; - setup_metronome (midi_dev); - STORE (SEQ_CONTINUE_TIMER ()); - } - break; + if (!devc->timer_flag) + return; - case TMR_SPP: - printk ("Songpos: %d\n", parm); - if (timer_mode & TMR_EXTERNAL) + switch (event) { - STORE (SEQ_SONGPOS (parm)); + case TMR_CLOCK: + printk("<MIDI clk>"); + break; + + case TMR_START: + printk("Ext MIDI start\n"); + if (!tmr_running) + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 1; + setup_metronome(midi_dev); + next_event_time = 0; + STORE(SEQ_START_TIMER()); + } + break; + + case TMR_STOP: + printk("Ext MIDI stop\n"); + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 0; + stop_metronome(midi_dev); + STORE(SEQ_STOP_TIMER()); + } + break; + + case TMR_CONTINUE: + printk("Ext MIDI continue\n"); + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 1; + setup_metronome(midi_dev); + STORE(SEQ_CONTINUE_TIMER()); + } + break; + + case TMR_SPP: + printk("Songpos: %d\n", parm); + if (timer_mode & TMR_EXTERNAL) + { + STORE(SEQ_SONGPOS(parm)); + } + break; } - break; - } } -static void -mpu_timer_init (int midi_dev) +static int mpu_timer_init(int midi_dev) { - struct mpu_config *devc; - int n; + struct mpu_config *devc; + int n; - devc = &dev_conf[midi_dev]; + devc = &dev_conf[midi_dev]; - if (timer_initialized) - return; /* There is already a similar timer */ + if (timer_initialized) + return -1; /* There is already a similar timer */ - timer_initialized = 1; + timer_initialized = 1; - mpu_timer.devlink = midi_dev; - dev_conf[midi_dev].timer_flag = 1; + mpu_timer.devlink = midi_dev; + dev_conf[midi_dev].timer_flag = 1; - if (num_sound_timers >= MAX_TIMER_DEV) - n = 0; /* Overwrite the system timer */ - else - n = num_sound_timers++; - sound_timer_devs[n] = &mpu_timer; + n = sound_alloc_timerdev(); + if (n == -1) + n = 0; + sound_timer_devs[n] = &mpu_timer; - if (devc->version < 0x20) /* Original MPU-401 */ - timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI; - else - { - /* - * The version number 2.0 is used (at least) by the - * MusicQuest cards and the Roland Super-MPU. - * - * MusicQuest has given a special meaning to the bits of the - * revision number. The Super-MPU returns 0. - */ + if (devc->version < 0x20) /* Original MPU-401 */ + timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI; + else + { + /* + * The version number 2.0 is used (at least) by the + * MusicQuest cards and the Roland Super-MPU. + * + * MusicQuest has given a special meaning to the bits of the + * revision number. The Super-MPU returns 0. + */ - if (devc->revision) - timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; + if (devc->revision) + timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; - if (devc->revision & 0x02) - timer_caps |= TMR_MODE_CLS; + if (devc->revision & 0x02) + timer_caps |= TMR_MODE_CLS; - if (devc->revision & 0x40) - max_timebase = 10; /* Has the 216 and 240 ppqn modes */ - } + if (devc->revision & 0x40) + max_timebase = 10; /* Has the 216 and 240 ppqn modes */ + } - timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; + timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; + return n; } #endif +EXPORT_SYMBOL(probe_mpu401); +EXPORT_SYMBOL(attach_mpu401); +EXPORT_SYMBOL(unload_mpu401); +EXPORT_SYMBOL(mpuintr); + +#ifdef MODULE + +MODULE_PARM(irq, "i"); +MODULE_PARM(io, "i"); + +int io = -1; +int irq = -1; +struct address_info hw; + +int init_module(void) +{ + /* Can be loaded either for module use or to provide functions + to others */ + if (io != -1 && irq != -1) + { + hw.irq = irq; + hw.io_base = io; + if (probe_mpu401(&hw) == 0) + return -ENODEV; + attach_mpu401(&hw); + } + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + if (io != -1 && irq != -1) + { + unload_mpu401(&hw); + } + /* FREE SYMTAB */ + SOUND_LOCK_END; +} +#else + +void +export_mpu401_syms(void) +{ + register_symtab(&mpu401_syms); +} + + +#endif #endif diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 5c71dc585..beb146710 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -11,7 +11,7 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> /* * Major improvements to the FM handling 30AUG92 by Rob Hooft, @@ -21,8 +21,9 @@ */ #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_YM3812) +#if defined(CONFIG_YM3812) || defined(MODULE) #include "opl3.h" @@ -30,265 +31,248 @@ #define OFFS_4OP 11 struct voice_info - { - unsigned char keyon_byte; - long bender; - long bender_range; - unsigned long orig_freq; - unsigned long current_freq; - int volume; - int mode; - int panning; /* 0xffff means not set */ - }; +{ + unsigned char keyon_byte; + long bender; + long bender_range; + unsigned long orig_freq; + unsigned long current_freq; + int volume; + int mode; + int panning; /* 0xffff means not set */ +}; typedef struct opl_devinfo - { - int base; - int left_io, right_io; - int nr_voice; - int lv_map[MAX_VOICE]; +{ + int base; + int left_io, right_io; + int nr_voice; + int lv_map[MAX_VOICE]; - struct voice_info voc[MAX_VOICE]; - struct voice_alloc_info *v_alloc; - struct channel_info *chn_info; + struct voice_info voc[MAX_VOICE]; + struct voice_alloc_info *v_alloc; + struct channel_info *chn_info; - struct sbi_instrument i_map[SBFM_MAXINSTR]; - struct sbi_instrument *act_i[MAX_VOICE]; + struct sbi_instrument i_map[SBFM_MAXINSTR]; + struct sbi_instrument *act_i[MAX_VOICE]; - struct synth_info fm_info; + struct synth_info fm_info; - int busy; - int model; - unsigned char cmask; + int busy; + int model; + unsigned char cmask; - int is_opl4; - int *osp; - } -opl_devinfo; + int is_opl4; + int *osp; +} opl_devinfo; static struct opl_devinfo *devc = NULL; static int detected_model; -static int store_instr (int instr_no, struct sbi_instrument *instr); -static void freq_to_fnum (int freq, int *block, int *fnum); -static void opl3_command (int io_addr, unsigned int addr, unsigned int val); -static int opl3_kill_note (int dev, int voice, int note, int velocity); +static int store_instr(int instr_no, struct sbi_instrument *instr); +static void freq_to_fnum(int freq, int *block, int *fnum); +static void opl3_command(int io_addr, unsigned int addr, unsigned int val); +static int opl3_kill_note(int dev, int voice, int note, int velocity); -static void -enter_4op_mode (void) +static void enter_4op_mode(void) { - int i; - static int v4op[MAX_VOICE] = - {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17}; - - devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */ - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f); - - for (i = 0; i < 3; i++) - pv_map[i].voice_mode = 4; - for (i = 3; i < 6; i++) - pv_map[i].voice_mode = 0; - - for (i = 9; i < 12; i++) - pv_map[i].voice_mode = 4; - for (i = 12; i < 15; i++) - pv_map[i].voice_mode = 0; - - for (i = 0; i < 12; i++) - devc->lv_map[i] = v4op[i]; - devc->v_alloc->max_voice = devc->nr_voice = 12; + int i; + static int v4op[MAX_VOICE] = { + 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17 + }; + + devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */ + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f); + + for (i = 0; i < 3; i++) + pv_map[i].voice_mode = 4; + for (i = 3; i < 6; i++) + pv_map[i].voice_mode = 0; + + for (i = 9; i < 12; i++) + pv_map[i].voice_mode = 4; + for (i = 12; i < 15; i++) + pv_map[i].voice_mode = 0; + + for (i = 0; i < 12; i++) + devc->lv_map[i] = v4op[i]; + devc->v_alloc->max_voice = devc->nr_voice = 12; } -static int -opl3_ioctl (int dev, - unsigned int cmd, caddr_t arg) +static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg) { - switch (cmd) - { - - case SNDCTL_FM_LOAD_INSTR: - { - struct sbi_instrument ins; - - memcpy ((char *) &ins, (&((char *) arg)[0]), sizeof (ins)); - printk("Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); - - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) - { - printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - - return store_instr (ins.channel, &ins); - } - break; - - case SNDCTL_SYNTH_INFO: - devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - - memcpy ((&((char *) arg)[0]), (char *) &devc->fm_info, sizeof (devc->fm_info)); - return 0; - break; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; - - case SNDCTL_FM_4OP_ENABLE: - if (devc->model == 2) - enter_4op_mode (); - return 0; - break; - - default: - return -EINVAL; - } + switch (cmd) + { + case SNDCTL_FM_LOAD_INSTR: + { + struct sbi_instrument ins; + + printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); + memcpy((char *) &ins, (&((char *) arg)[0]), sizeof(ins)); + + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) + { + printk("FM Error: Invalid instrument number %d\n", ins.channel); + return -EINVAL; + } + return store_instr(ins.channel, &ins); + } + + case SNDCTL_SYNTH_INFO: + devc->fm_info.nr_voices = + (devc->nr_voice == 12) ? 6 : devc->nr_voice; + memcpy((&((char *) arg)[0]), (char *) &devc->fm_info, sizeof(devc->fm_info)); + return 0; + + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + + case SNDCTL_FM_4OP_ENABLE: + if (devc->model == 2) + enter_4op_mode(); + return 0; + + default: + return -EINVAL; + } } -int -opl3_detect (int ioaddr, int *osp) +int opl3_detect(int ioaddr, int *osp) { - /* - * This function returns 1 if the FM chip is present at the given I/O port - * The detection algorithm plays with the timer built in the FM chip and - * looks for a change in the status register. - * - * Note! The timers of the FM chip are not connected to AdLib (and compatible) - * boards. - * - * Note2! The chip is initialized if detected. - */ - - unsigned char stat1, signature; - int i; - - if (devc != NULL) - return 0; - - - devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (*devc))); - sound_mem_sizes[sound_nblocks] = sizeof (*devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - - if (devc == NULL) - { - printk ("OPL3: Can't allocate memory for the device control structure\n"); - return 0; - } - - devc->osp = osp; - devc->base = ioaddr; - - /* Reset timers 1 and 2 */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - - /* Reset the IRQ of the FM chip */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); - - signature = stat1 = inb (ioaddr); /* Status register */ - - if (signature != 0x00 && signature != 0x06 && signature != 0x02 && - signature != 0x0f) - { - DDB (printk ("OPL3 not detected %x\n", signature)); - return 0; - } - - if (signature == 0x06) /* OPL2 */ - { - detected_model = 2; - } - else if (signature == 0x00 || signature == 0x0f) /* OPL3 or OPL4 */ - { - unsigned char tmp; - - detected_model = 3; - - /* - * Detect availability of OPL4 (_experimental_). Works probably - * only after a cold boot. In addition the OPL4 port - * of the chip may not be connected to the PC bus at all. - */ - - opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, 0x00); - opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); - - if ((tmp = inb (ioaddr)) == 0x02) /* Have a OPL4 */ + /* + * This function returns 1 if the FM chip is present at the given I/O port + * The detection algorithm plays with the timer built in the FM chip and + * looks for a change in the status register. + * + * Note! The timers of the FM chip are not connected to AdLib (and compatible) + * boards. + * + * Note2! The chip is initialized if detected. + */ + + unsigned char stat1, signature; + int i; + + if (devc != NULL) { - detected_model = 4; + printk(KERN_ERR "opl3: Only one OPL3 supported.\n"); + return 0; } - if (!check_region (ioaddr - 8, 2)) /* OPL4 port is free */ + devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(*devc))); + sound_mem_sizes[sound_nblocks] = sizeof(*devc); + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (devc == NULL) { - int tmp; - - outb ((0x02), ioaddr - 8); /* Select OPL4 ID register */ - tenmicrosec (devc->osp); - tmp = inb (ioaddr - 7); /* Read it */ - tenmicrosec (devc->osp); - - if (tmp == 0x20) /* OPL4 should return 0x20 here */ - { - detected_model = 4; - - outb ((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ - tenmicrosec (devc->osp); - outb ((0x1B), ioaddr - 7); /* Write value */ - tenmicrosec (devc->osp); - } - else - detected_model = 3; + printk(KERN_ERR "OPL3: Can't allocate memory for the device control " + "structure \n "); + return 0; } + devc->osp = osp; + devc->base = ioaddr; - opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, 0); + /* Reset timers 1 and 2 */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - } + /* Reset the IRQ of the FM chip */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); - for (i = 0; i < 9; i++) - opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* - * Note off - */ + signature = stat1 = inb(ioaddr); /* Status register */ - opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl3_command (ioaddr, PERCOSSION_REGISTER, 0x00); /* - * Melodic mode. - */ + if (signature != 0x00 && signature != 0x06 && signature != 0x02 && + signature != 0x0f) + { + MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature)); + return 0; + } + + if (signature == 0x06) /* OPL2 */ + { + detected_model = 2; + } + else if (signature == 0x00 || signature == 0x0f) /* OPL3 or OPL4 */ + { + unsigned char tmp; + + detected_model = 3; + + /* + * Detect availability of OPL4 (_experimental_). Works probably + * only after a cold boot. In addition the OPL4 port + * of the chip may not be connected to the PC bus at all. + */ + + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00); + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); + + if ((tmp = inb(ioaddr)) == 0x02) /* Have a OPL4 */ + { + detected_model = 4; + } + + if (!check_region(ioaddr - 8, 2)) /* OPL4 port is free */ + { + int tmp; + + outb((0x02), ioaddr - 8); /* Select OPL4 ID register */ + tenmicrosec(devc->osp); + tmp = inb(ioaddr - 7); /* Read it */ + tenmicrosec(devc->osp); + + if (tmp == 0x20) /* OPL4 should return 0x20 here */ + { + detected_model = 4; + outb((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ + tenmicrosec(devc->osp); + outb((0x1B), ioaddr - 7); /* Write value */ + tenmicrosec(devc->osp); + } + else + detected_model = 3; + } + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); + } + for (i = 0; i < 9; i++) + opl3_command(ioaddr, KEYON_BLOCK + i, 0); /* + * Note off + */ - return 1; + opl3_command(ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); + opl3_command(ioaddr, PERCOSSION_REGISTER, 0x00); /* + * Melodic mode. + */ + return 1; } -static int -opl3_kill_note (int devno, int voice, int note, int velocity) +static int opl3_kill_note (int devno, int voice, int note, int velocity) { - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return 0; + struct physical_voice_info *map; - devc->v_alloc->map[voice] = 0; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - map = &pv_map[devc->lv_map[voice]]; + devc->v_alloc->map[voice] = 0; - DEB (printk ("Kill note %d\n", voice)); + map = &pv_map[devc->lv_map[voice]]; + DEB(printk("Kill note %d\n", voice)); - if (map->voice_mode == 0) - return 0; + if (map->voice_mode == 0) + return 0; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20); - - devc->voc[voice].keyon_byte = 0; - devc->voc[voice].bender = 0; - devc->voc[voice].volume = 64; - devc->voc[voice].panning = 0xffff; /* Not set */ - devc->voc[voice].bender_range = 200; - devc->voc[voice].orig_freq = 0; - devc->voc[voice].current_freq = 0; - devc->voc[voice].mode = 0; - - return 0; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20); + devc->voc[voice].keyon_byte = 0; + devc->voc[voice].bender = 0; + devc->voc[voice].volume = 64; + devc->voc[voice].panning = 0xffff; /* Not set */ + devc->voc[voice].bender_range = 200; + devc->voc[voice].orig_freq = 0; + devc->voc[voice].current_freq = 0; + devc->voc[voice].mode = 0; + return 0; } #define HIHAT 0 @@ -299,28 +283,23 @@ opl3_kill_note (int devno, int voice, int note, int velocity) #define UNDEFINED TOMTOM #define DEFAULT TOMTOM -static int -store_instr (int instr_no, struct sbi_instrument *instr) +static int store_instr(int instr_no, struct sbi_instrument *instr) { - - if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || devc->model != 2)) - printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key); - memcpy ((char *) &(devc->i_map[instr_no]), (char *) instr, sizeof (*instr)); - - return 0; + if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || devc->model != 2)) + printk(KERN_WARNING "FM warning: Invalid patch format field (key) 0x%x\n", instr->key); + memcpy((char *) &(devc->i_map[instr_no]), (char *) instr, sizeof(*instr)); + return 0; } -static int -opl3_set_instr (int dev, int voice, int instr_no) +static int opl3_set_instr (int dev, int voice, int instr_no) { - if (voice < 0 || voice >= devc->nr_voice) - return 0; - - if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) - instr_no = 0; /* Acoustic piano (usually) */ + if (voice < 0 || voice >= devc->nr_voice) + return 0; + if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) + instr_no = 0; /* Acoustic piano (usually) */ - devc->act_i[voice] = &devc->i_map[instr_no]; - return 0; + devc->act_i[voice] = &devc->i_map[instr_no]; + return 0; } /* @@ -332,882 +311,911 @@ opl3_set_instr (int dev, int voice, int instr_no) * volume -8 it was implemented as a table because it is only 128 bytes and * it saves a lot of log() calculations. (RH) */ -static char fm_volume_table[128] = -{-64, -48, -40, -35, -32, -29, -27, -26, - -24, -23, -21, -20, -19, -18, -18, -17, - -16, -15, -15, -14, -13, -13, -12, -12, - -11, -11, -10, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -6, -6, -6, - -5, -5, -5, -5, -4, -4, -4, -4, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -1, -1, -1, -1, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 4, - 4, 4, 4, 4, 4, 4, 4, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 8, 8, 8, 8, 8}; - -static void -calc_vol (unsigned char *regbyte, int volume, int main_vol) + +static char fm_volume_table[128] = { - int level = (~*regbyte & 0x3f); + -64, -48, -40, -35, -32, -29, -27, -26, + -24, -23, -21, -20, -19, -18, -18, -17, + -16, -15, -15, -14, -13, -13, -12, -12, + -11, -11, -10, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -6, -6, -6, + -5, -5, -5, -5, -4, -4, -4, -4, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -1, -1, -1, -1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8 +}; - if (main_vol > 127) - main_vol = 127; +static void calc_vol(unsigned char *regbyte, int volume, int main_vol) +{ + int level = (~*regbyte & 0x3f); - volume = (volume * main_vol) / 127; + if (main_vol > 127) + main_vol = 127; + volume = (volume * main_vol) / 127; - if (level) - level += fm_volume_table[volume]; + if (level) + level += fm_volume_table[volume]; - if (level > 0x3f) - level = 0x3f; - if (level < 0) - level = 0; + if (level > 0x3f) + level = 0x3f; + if (level < 0) + level = 0; - *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); + *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); } -static void -set_voice_volume (int voice, int volume, int main_vol) +static void set_voice_volume(int voice, int volume, int main_vol) { - unsigned char vol1, vol2, vol3, vol4; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return; + unsigned char vol1, vol2, vol3, vol4; + struct sbi_instrument *instr; + struct physical_voice_info *map; - map = &pv_map[devc->lv_map[voice]]; + if (voice < 0 || voice >= devc->nr_voice) + return; - instr = devc->act_i[voice]; + map = &pv_map[devc->lv_map[voice]]; + instr = devc->act_i[voice]; - if (!instr) - instr = &devc->i_map[0]; + if (!instr) + instr = &devc->i_map[0]; - if (instr->channel < 0) - return; + if (instr->channel < 0) + return; - if (devc->voc[voice].mode == 0) - return; + if (devc->voc[voice].mode == 0) + return; - if (devc->voc[voice].mode == 2) - { - - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - - if ((instr->operators[10] & 0x01)) + if (devc->voc[voice].mode == 2) { - calc_vol (&vol1, volume, main_vol); - calc_vol (&vol2, volume, main_vol); + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + if ((instr->operators[10] & 0x01)) + { + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol2, volume, main_vol); + } + else + { + calc_vol(&vol2, volume, main_vol); + } + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); } - else - { - calc_vol (&vol2, volume, main_vol); - } - - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); - } - else - { /* - * 4 OP voice - */ - int connection; - - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - vol3 = instr->operators[OFFS_4OP + 2]; - vol4 = instr->operators[OFFS_4OP + 3]; - - /* - * The connection method for 4 OP devc->voc is defined by the rightmost - * bits at the offsets 10 and 10+OFFS_4OP - */ - - connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - - switch (connection) - { - case 0: - calc_vol (&vol4, volume, main_vol); - break; - - case 1: - calc_vol (&vol2, volume, main_vol); - calc_vol (&vol4, volume, main_vol); - break; - - case 2: - calc_vol (&vol1, volume, main_vol); - calc_vol (&vol4, volume, main_vol); - break; - - case 3: - calc_vol (&vol1, volume, main_vol); - calc_vol (&vol3, volume, main_vol); - calc_vol (&vol4, volume, main_vol); - break; - - default:; + else + { /* + * 4 OP voice + */ + int connection; + + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + vol3 = instr->operators[OFFS_4OP + 2]; + vol4 = instr->operators[OFFS_4OP + 3]; + + /* + * The connection method for 4 OP devc->voc is defined by the rightmost + * bits at the offsets 10 and 10+OFFS_4OP + */ + + connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + + switch (connection) + { + case 0: + calc_vol(&vol4, volume, main_vol); + break; + + case 1: + calc_vol(&vol2, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + case 2: + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + case 3: + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol3, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + default: + ; + } + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], vol3); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], vol4); } - - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], vol3); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], vol4); - } } -static int -opl3_start_note (int dev, int voice, int note, int volume) +static int opl3_start_note (int dev, int voice, int note, int volume) { - unsigned char data, fpc; - int block, fnum, freq, voice_mode, pan; - struct sbi_instrument *instr; - struct physical_voice_info *map; + unsigned char data, fpc; + int block, fnum, freq, voice_mode, pan; + struct sbi_instrument *instr; + struct physical_voice_info *map; - if (voice < 0 || voice >= devc->nr_voice) - return 0; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - map = &pv_map[devc->lv_map[voice]]; - pan = devc->voc[voice].panning; + map = &pv_map[devc->lv_map[voice]]; + pan = devc->voc[voice].panning; - if (map->voice_mode == 0) - return 0; + if (map->voice_mode == 0) + return 0; - if (note == 255) /* + if (note == 255) /* * Just change the volume */ - { - set_voice_volume (voice, volume, devc->voc[voice].volume); - return 0; - } - - /* - * Kill previous note before playing - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* - * Carrier - * volume to - * min - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* - * Modulator - * volume to - */ + { + set_voice_volume(voice, volume, devc->voc[voice].volume); + return 0; + } + + /* + * Kill previous note before playing + */ + + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* + * Carrier + * volume to + * min + */ + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* + * Modulator + * volume to + */ - if (map->voice_mode == 4) - { - opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], 0xff); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff); - } + if (map->voice_mode == 4) + { + opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], 0xff); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], 0xff); + } - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* * Note * off */ - instr = devc->act_i[voice]; + instr = devc->act_i[voice]; + + if (!instr) + instr = &devc->i_map[0]; - if (!instr) - instr = &devc->i_map[0]; - - if (instr->channel < 0) - { - printk ( - "OPL3: Initializing voice %d with undefined instrument\n", - voice); - return 0; - } + if (instr->channel < 0) + { + printk(KERN_WARNING "OPL3: Initializing voice %d with undefined instrument\n", voice); + return 0; + } - if (map->voice_mode == 2 && instr->key == OPL3_PATCH) - return 0; /* + if (map->voice_mode == 2 && instr->key == OPL3_PATCH) + return 0; /* * Cannot play */ - voice_mode = map->voice_mode; + voice_mode = map->voice_mode; - if (voice_mode == 4) - { - int voice_shift; + if (voice_mode == 4) + { + int voice_shift; - voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; - voice_shift += map->voice_num; + voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; + voice_shift += map->voice_num; - if (instr->key != OPL3_PATCH) /* - * Just 2 OP patch - */ - { - voice_mode = 2; - devc->cmask &= ~(1 << voice_shift); + if (instr->key != OPL3_PATCH) /* + * Just 2 OP patch + */ + { + voice_mode = 2; + devc->cmask &= ~(1 << voice_shift); + } + else + { + devc->cmask |= (1 << voice_shift); + } + + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); } - else + + /* + * Set Sound Characteristics + */ + + opl3_command(map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); + opl3_command(map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); + + /* + * Set Attack/Decay + */ + + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); + + /* + * Set Sustain/Release + */ + + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); + + /* + * Set Wave Select + */ + + opl3_command(map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); + opl3_command(map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); + + /* + * Set Feedback/Connection + */ + + fpc = instr->operators[10]; + + if (pan != 0xffff) { - devc->cmask |= (1 << voice_shift); + fpc &= ~STEREO_BITS; + if (pan < -64) + fpc |= VOICE_TO_LEFT; + else + if (pan > 64) + fpc |= VOICE_TO_RIGHT; + else + fpc |= (VOICE_TO_LEFT | VOICE_TO_RIGHT); } - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - } - - /* - * Set Sound Characteristics - */ - opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); - opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); - - /* - * Set Attack/Decay - */ - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); - - /* - * Set Sustain/Release - */ - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); - - /* - * Set Wave Select - */ - opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); - opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); - - /* - * Set Feedback/Connection - */ - fpc = instr->operators[10]; - - if (pan != 0xffff) - { - fpc &= ~STEREO_BITS; - - if (pan < -64) - fpc |= VOICE_TO_LEFT; - else if (pan > 64) - fpc |= VOICE_TO_RIGHT; - else - fpc |= (VOICE_TO_LEFT | VOICE_TO_RIGHT); - } - - if (!(fpc & 0x30)) - fpc |= 0x30; /* - * Ensure that at least one chn is enabled - */ - opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, - fpc); - - /* - * If the voice is a 4 OP one, initialize the operators 3 and 4 also - */ - - if (voice_mode == 4) - { - - /* - * Set Sound Characteristics - */ - opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); - opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); - - /* - * Set Attack/Decay - */ - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); - - /* - * Set Sustain/Release - */ - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); - - /* - * Set Wave Select - */ - opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); - opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); - - /* - * Set Feedback/Connection - */ - fpc = instr->operators[OFFS_4OP + 10]; - if (!(fpc & 0x30)) - fpc |= 0x30; /* + if (!(fpc & 0x30)) + fpc |= 0x30; /* * Ensure that at least one chn is enabled */ - opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); - } + opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc); - devc->voc[voice].mode = voice_mode; + /* + * If the voice is a 4 OP one, initialize the operators 3 and 4 also + */ - set_voice_volume (voice, volume, devc->voc[voice].volume); + if (voice_mode == 4) + { + /* + * Set Sound Characteristics + */ + + opl3_command(map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); + opl3_command(map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); + + /* + * Set Attack/Decay + */ + + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); + + /* + * Set Sustain/Release + */ + + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); + + /* + * Set Wave Select + */ + + opl3_command(map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); + opl3_command(map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); + + /* + * Set Feedback/Connection + */ + + fpc = instr->operators[OFFS_4OP + 10]; + if (!(fpc & 0x30)) + fpc |= 0x30; /* + * Ensure that at least one chn is enabled + */ + opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); + } + + devc->voc[voice].mode = voice_mode; + set_voice_volume(voice, volume, devc->voc[voice].volume); - freq = devc->voc[voice].orig_freq = note_to_freq (note) / 1000; + freq = devc->voc[voice].orig_freq = note_to_freq(note) / 1000; - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ - freq = compute_finetune (devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); - devc->voc[voice].current_freq = freq; + freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); + devc->voc[voice].current_freq = freq; - freq_to_fnum (freq, &block, &fnum); + freq_to_fnum(freq, &block, &fnum); - /* - * Play note - */ + /* + * Play note + */ - data = fnum & 0xff; /* + data = fnum & 0xff; /* * Least significant bits of fnumber */ - opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); - if (voice_mode == 4) - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + devc->voc[voice].keyon_byte = data; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); + if (voice_mode == 4) + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); - return 0; + return 0; } -static void -freq_to_fnum (int freq, int *block, int *fnum) +static void freq_to_fnum (int freq, int *block, int *fnum) { - int f, octave; + int f, octave; - /* - * Converts the note frequency to block and fnum values for the FM chip - */ - /* - * First try to compute the block -value (octave) where the note belongs - */ + /* + * Converts the note frequency to block and fnum values for the FM chip + */ + /* + * First try to compute the block -value (octave) where the note belongs + */ - f = freq; + f = freq; - octave = 5; + octave = 5; - if (f == 0) - octave = 0; - else if (f < 261) - { - while (f < 261) + if (f == 0) + octave = 0; + else if (f < 261) { - octave--; - f <<= 1; + while (f < 261) + { + octave--; + f <<= 1; + } } - } - else if (f > 493) - { - while (f > 493) + else if (f > 493) { - octave++; - f >>= 1; + while (f > 493) + { + octave++; + f >>= 1; + } } - } - if (octave > 7) - octave = 7; + if (octave > 7) + octave = 7; - *fnum = freq * (1 << (20 - octave)) / 49716; - *block = octave; + *fnum = freq * (1 << (20 - octave)) / 49716; + *block = octave; } -static void -opl3_command (int io_addr, unsigned int addr, unsigned int val) +static void opl3_command (int io_addr, unsigned int addr, unsigned int val) { - int i; - - /* - * The original 2-OP synth requires a quite long delay after writing to a - * register. The OPL-3 survives with just two INBs - */ - - outb (((unsigned char) (addr & 0xff)), io_addr); - - if (devc->model != 2) - tenmicrosec (devc->osp); - else - for (i = 0; i < 2; i++) - inb (io_addr); - - outb (((unsigned char) (val & 0xff)), io_addr + 1); - - if (devc->model != 2) - { - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - } - else - for (i = 0; i < 2; i++) - inb (io_addr); -} + int i; -static void -opl3_reset (int devno) -{ - int i; + /* + * The original 2-OP synth requires a quite long delay after writing to a + * register. The OPL-3 survives with just two INBs + */ - for (i = 0; i < 18; i++) - devc->lv_map[i] = i; + outb(((unsigned char) (addr & 0xff)), io_addr); - for (i = 0; i < devc->nr_voice; i++) - { - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); + if (devc->model != 2) + tenmicrosec(devc->osp); + else + for (i = 0; i < 2; i++) + inb(io_addr); - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); + outb(((unsigned char) (val & 0xff)), io_addr + 1); - if (pv_map[devc->lv_map[i]].voice_mode == 4) + if (devc->model != 2) { - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); - - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); } + else + for (i = 0; i < 2; i++) + inb(io_addr); +} + +static void opl3_reset(int devno) +{ + int i; + + for (i = 0; i < 18; i++) + devc->lv_map[i] = i; + + for (i = 0; i < devc->nr_voice; i++) + { + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); + + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); - opl3_kill_note (devno, i, 0, 64); - } + if (pv_map[devc->lv_map[i]].voice_mode == 4) + { + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); - if (devc->model == 2) - { - devc->v_alloc->max_voice = devc->nr_voice = 18; + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); + } - for (i = 0; i < 18; i++) - pv_map[i].voice_mode = 2; + opl3_kill_note(devno, i, 0, 64); + } + + if (devc->model == 2) + { + devc->v_alloc->max_voice = devc->nr_voice = 18; - } + for (i = 0; i < 18; i++) + pv_map[i].voice_mode = 2; + } } -static int -opl3_open (int dev, int mode) +static int opl3_open(int dev, int mode) { - int i; + int i; - if (devc->busy) - return -EBUSY; - devc->busy = 1; + if (devc->busy) + return -EBUSY; + MOD_INC_USE_COUNT; + devc->busy = 1; - devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; - devc->v_alloc->timestamp = 0; + devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; + devc->v_alloc->timestamp = 0; - for (i = 0; i < 18; i++) - { - devc->v_alloc->map[i] = 0; - devc->v_alloc->alloc_times[i] = 0; - } + for (i = 0; i < 18; i++) + { + devc->v_alloc->map[i] = 0; + devc->v_alloc->alloc_times[i] = 0; + } - devc->cmask = 0x00; /* + devc->cmask = 0x00; /* * Just 2 OP mode */ - if (devc->model == 2) - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - return 0; + if (devc->model == 2) + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); + return 0; } -static void -opl3_close (int dev) +static void opl3_close(int dev) { - devc->busy = 0; - devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; + devc->busy = 0; + devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; - devc->fm_info.nr_drums = 0; - devc->fm_info.perc_mode = 0; + devc->fm_info.nr_drums = 0; + devc->fm_info.perc_mode = 0; - opl3_reset (dev); + opl3_reset(dev); + MOD_DEC_USE_COUNT; } -static void -opl3_hw_control (int dev, unsigned char *event) +static void opl3_hw_control(int dev, unsigned char *event) { } -static int -opl3_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +static int opl3_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - struct sbi_instrument ins; + struct sbi_instrument ins; - if (count < sizeof (ins)) - { - printk ("FM Error: Patch record too short\n"); - return -EINVAL; - } + if (count <sizeof(ins)) + { + printk(KERN_WARNING "FM Error: Patch record too short\n"); + return -EINVAL; + } - copy_from_user (&((char *) &ins)[offs], &(addr)[offs], sizeof (ins) - offs); + copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs); - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) - { - printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - ins.key = format; + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) + { + printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel); + return -EINVAL; + } + ins.key = format; - return store_instr (ins.channel, &ins); + return store_instr(ins.channel, &ins); } -static void -opl3_panning (int dev, int voice, int value) +static void opl3_panning(int dev, int voice, int value) { - devc->voc[voice].panning = value; + devc->voc[voice].panning = value; } -static void -opl3_volume_method (int dev, int mode) +static void opl3_volume_method(int dev, int mode) { } #define SET_VIBRATO(cell) { \ - tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ - if (pressure > 110) \ - tmp |= 0x40; /* Vibrato on */ \ - opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} + tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ + if (pressure > 110) \ + tmp |= 0x40; /* Vibrato on */ \ + opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} -static void -opl3_aftertouch (int dev, int voice, int pressure) +static void opl3_aftertouch(int dev, int voice, int pressure) { - int tmp; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return; + int tmp; + struct sbi_instrument *instr; + struct physical_voice_info *map; - map = &pv_map[devc->lv_map[voice]]; + if (voice < 0 || voice >= devc->nr_voice) + return; - DEB (printk ("Aftertouch %d\n", voice)); + map = &pv_map[devc->lv_map[voice]]; - if (map->voice_mode == 0) - return; + DEB(printk("Aftertouch %d\n", voice)); - /* - * Adjust the amount of vibrato depending the pressure - */ + if (map->voice_mode == 0) + return; - instr = devc->act_i[voice]; + /* + * Adjust the amount of vibrato depending the pressure + */ - if (!instr) - instr = &devc->i_map[0]; + instr = devc->act_i[voice]; - if (devc->voc[voice].mode == 4) - { - int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + if (!instr) + instr = &devc->i_map[0]; - switch (connection) + if (devc->voc[voice].mode == 4) + { + int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + + switch (connection) + { + case 0: + SET_VIBRATO(4); + break; + + case 1: + SET_VIBRATO(2); + SET_VIBRATO(4); + break; + + case 2: + SET_VIBRATO(1); + SET_VIBRATO(4); + break; + + case 3: + SET_VIBRATO(1); + SET_VIBRATO(3); + SET_VIBRATO(4); + break; + + } + /* + * Not implemented yet + */ + } + else { - case 0: - SET_VIBRATO (4); - break; - - case 1: - SET_VIBRATO (2); - SET_VIBRATO (4); - break; - - case 2: - SET_VIBRATO (1); - SET_VIBRATO (4); - break; - - case 3: - SET_VIBRATO (1); - SET_VIBRATO (3); - SET_VIBRATO (4); - break; + SET_VIBRATO(1); + if ((instr->operators[10] & 0x01)) /* + * Additive synthesis + */ + SET_VIBRATO(2); } - /* - * Not implemented yet - */ - } - else - { - SET_VIBRATO (1); - - if ((instr->operators[10] & 0x01)) /* - * Additive synthesis - */ - SET_VIBRATO (2); - } } #undef SET_VIBRATO -static void -bend_pitch (int dev, int voice, int value) +static void bend_pitch(int dev, int voice, int value) { - unsigned char data; - int block, fnum, freq; - struct physical_voice_info *map; + unsigned char data; + int block, fnum, freq; + struct physical_voice_info *map; - map = &pv_map[devc->lv_map[voice]]; + map = &pv_map[devc->lv_map[voice]]; - if (map->voice_mode == 0) - return; + if (map->voice_mode == 0) + return; - devc->voc[voice].bender = value; - if (!value) - return; - if (!(devc->voc[voice].keyon_byte & 0x20)) - return; /* - * Not keyed on - */ + devc->voc[voice].bender = value; + if (!value) + return; + if (!(devc->voc[voice].keyon_byte & 0x20)) + return; /* + * Not keyed on + */ - freq = compute_finetune (devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); - devc->voc[voice].current_freq = freq; + freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); + devc->voc[voice].current_freq = freq; - freq_to_fnum (freq, &block, &fnum); + freq_to_fnum(freq, &block, &fnum); - data = fnum & 0xff; /* + data = fnum & 0xff; /* * Least significant bits of fnumber */ - opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + devc->voc[voice].keyon_byte = data; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); } -static void -opl3_controller (int dev, int voice, int ctrl_num, int value) +static void opl3_controller (int dev, int voice, int ctrl_num, int value) { - if (voice < 0 || voice >= devc->nr_voice) - return; - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - bend_pitch (dev, voice, value); - break; - - case CTRL_PITCH_BENDER_RANGE: - devc->voc[voice].bender_range = value; - break; - - case CTL_MAIN_VOLUME: - devc->voc[voice].volume = value / 128; - break; - - case CTL_PAN: - devc->voc[voice].panning = (value * 2) - 128; - break; - } + if (voice < 0 || voice >= devc->nr_voice) + return; + + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + bend_pitch(dev, voice, value); + break; + + case CTRL_PITCH_BENDER_RANGE: + devc->voc[voice].bender_range = value; + break; + + case CTL_MAIN_VOLUME: + devc->voc[voice].volume = value / 128; + break; + + case CTL_PAN: + devc->voc[voice].panning = (value * 2) - 128; + break; + } } -static void -opl3_bender (int dev, int voice, int value) +static void opl3_bender(int dev, int voice, int value) { - if (voice < 0 || voice >= devc->nr_voice) - return; + if (voice < 0 || voice >= devc->nr_voice) + return; - bend_pitch (dev, voice, value - 8192); + bend_pitch(dev, voice, value - 8192); } -static int -opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) +static int opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best, first, avail, best_time = 0x7fffffff; - struct sbi_instrument *instr; - int is4op; - int instr_no; - - if (chn < 0 || chn > 15) - instr_no = 0; - else - instr_no = devc->chn_info[chn].pgm_num; - - instr = &devc->i_map[instr_no]; - if (instr->channel < 0 || /* Instrument not loaded */ - devc->nr_voice != 12) /* Not in 4 OP mode */ - is4op = 0; - else if (devc->nr_voice == 12) /* 4 OP mode */ - is4op = (instr->key == OPL3_PATCH); - else - is4op = 0; - - if (is4op) - { - first = p = 0; - avail = 6; - } - else - { - if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP only' operators first */ - first = p = 6; - else - first = p = 0; - avail = devc->nr_voice; - } - - /* - * Now try to find a free voice - */ - best = first; - - for (i = 0; i < avail; i++) - { - if (alloc->map[p] == 0) + int i, p, best, first, avail, best_time = 0x7fffffff; + struct sbi_instrument *instr; + int is4op; + int instr_no; + + if (chn < 0 || chn > 15) + instr_no = 0; + else + instr_no = devc->chn_info[chn].pgm_num; + + instr = &devc->i_map[instr_no]; + if (instr->channel < 0 || /* Instrument not loaded */ + devc->nr_voice != 12) /* Not in 4 OP mode */ + is4op = 0; + else if (devc->nr_voice == 12) /* 4 OP mode */ + is4op = (instr->key == OPL3_PATCH); + else + is4op = 0; + + if (is4op) { - return p; + first = p = 0; + avail = 6; } - if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ + else + { + if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP only' operators first */ + first = p = 6; + else + first = p = 0; + avail = devc->nr_voice; + } + + /* + * Now try to find a free voice + */ + best = first; + + for (i = 0; i < avail; i++) { - best_time = alloc->alloc_times[p]; - best = p; + if (alloc->map[p] == 0) + { + return p; + } + if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ + { + best_time = alloc->alloc_times[p]; + best = p; + } + p = (p + 1) % avail; } - p = (p + 1) % avail; - } - /* - * Insert some kind of priority mechanism here. - */ + /* + * Insert some kind of priority mechanism here. + */ - if (best < 0) - best = 0; - if (best > devc->nr_voice) - best -= devc->nr_voice; + if (best < 0) + best = 0; + if (best > devc->nr_voice) + best -= devc->nr_voice; - return best; /* All devc->voc in use. Select the first one. */ + return best; /* All devc->voc in use. Select the first one. */ } -static void -opl3_setup_voice (int dev, int voice, int chn) +static void opl3_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; - opl3_set_instr (dev, voice, - info->pgm_num); + opl3_set_instr(dev, voice, info->pgm_num); - devc->voc[voice].bender = 0; - devc->voc[voice].bender_range = info->bender_range; - devc->voc[voice].volume = - info->controllers[CTL_MAIN_VOLUME]; - devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; + devc->voc[voice].bender = 0; + devc->voc[voice].bender_range = info->bender_range; + devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; + devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; } static struct synth_operations opl3_operations = { - "OPL", - NULL, - 0, - SYNTH_TYPE_FM, - FM_TYPE_ADLIB, - opl3_open, - opl3_close, - opl3_ioctl, - opl3_kill_note, - opl3_start_note, - opl3_set_instr, - opl3_reset, - opl3_hw_control, - opl3_load_patch, - opl3_aftertouch, - opl3_controller, - opl3_panning, - opl3_volume_method, - opl3_bender, - opl3_alloc_voice, - opl3_setup_voice + "OPL", + NULL, + 0, + SYNTH_TYPE_FM, + FM_TYPE_ADLIB, + opl3_open, + opl3_close, + opl3_ioctl, + opl3_kill_note, + opl3_start_note, + opl3_set_instr, + opl3_reset, + opl3_hw_control, + opl3_load_patch, + opl3_aftertouch, + opl3_controller, + opl3_panning, + opl3_volume_method, + opl3_bender, + opl3_alloc_voice, + opl3_setup_voice }; -void -opl3_init (int ioaddr, int *osp) +int opl3_init(int ioaddr, int *osp) { - int i; - - if (num_synths >= MAX_SYNTH_DEV) - { - printk ("OPL3 Error: Too many synthesizers\n"); - return; - } - - if (devc == NULL) - { - printk ("OPL3: Device control structure not initialized.\n"); - return; - } - - memset ((char *) devc, 0x00, sizeof (*devc)); - devc->osp = osp; - devc->base = ioaddr; - - devc->nr_voice = 9; - strcpy (devc->fm_info.name, "OPL2"); - - devc->fm_info.device = 0; - devc->fm_info.synth_type = SYNTH_TYPE_FM; - devc->fm_info.synth_subtype = FM_TYPE_ADLIB; - devc->fm_info.perc_mode = 0; - devc->fm_info.nr_voices = 9; - devc->fm_info.nr_drums = 0; - devc->fm_info.instr_bank_size = SBFM_MAXINSTR; - devc->fm_info.capabilities = 0; - devc->left_io = ioaddr; - devc->right_io = ioaddr + 2; - - if (detected_model <= 2) - devc->model = 1; - else - { - devc->model = 2; - if (detected_model == 4) - devc->is_opl4 = 1; - } - - opl3_operations.info = &devc->fm_info; - - synth_devs[num_synths++] = &opl3_operations; - sequencer_init (); - devc->v_alloc = &opl3_operations.alloc; - devc->chn_info = &opl3_operations.chn_info[0]; - - if (devc->model == 2) - { - if (devc->is_opl4) - conf_printf2 ("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); - else - conf_printf2 ("Yamaha OPL3 FM", ioaddr, 0, -1, -1); - - devc->v_alloc->max_voice = devc->nr_voice = 18; - devc->fm_info.nr_drums = 0; - devc->fm_info.synth_subtype = FM_TYPE_OPL3; - devc->fm_info.capabilities |= SYNTH_CAP_OPL3; - strcpy (devc->fm_info.name, "Yamaha OPL-3"); - - for (i = 0; i < 18; i++) - if (pv_map[i].ioaddr == USE_LEFT) - pv_map[i].ioaddr = devc->left_io; + int i; + int me; + + if (devc == NULL) + { + printk(KERN_ERR "opl3_init: Device control structure not initialized.\n"); + return -1; + } + + if ((me = sound_alloc_synthdev()) == -1) + { + printk(KERN_WARNING "opl3: Too many synthesizers\n"); + return -1; + } + + memset((char *) devc, 0x00, sizeof(*devc)); + devc->osp = osp; + devc->base = ioaddr; + + devc->nr_voice = 9; + strcpy(devc->fm_info.name, "OPL2"); + + devc->fm_info.device = 0; + devc->fm_info.synth_type = SYNTH_TYPE_FM; + devc->fm_info.synth_subtype = FM_TYPE_ADLIB; + devc->fm_info.perc_mode = 0; + devc->fm_info.nr_voices = 9; + devc->fm_info.nr_drums = 0; + devc->fm_info.instr_bank_size = SBFM_MAXINSTR; + devc->fm_info.capabilities = 0; + devc->left_io = ioaddr; + devc->right_io = ioaddr + 2; + + if (detected_model <= 2) + devc->model = 1; + else + { + devc->model = 2; + if (detected_model == 4) + devc->is_opl4 = 1; + } + + opl3_operations.info = &devc->fm_info; + + synth_devs[me] = &opl3_operations; + sequencer_init(); + devc->v_alloc = &opl3_operations.alloc; + devc->chn_info = &opl3_operations.chn_info[0]; + + if (devc->model == 2) + { + if (devc->is_opl4) + conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); + else + conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1); + + devc->v_alloc->max_voice = devc->nr_voice = 18; + devc->fm_info.nr_drums = 0; + devc->fm_info.synth_subtype = FM_TYPE_OPL3; + devc->fm_info.capabilities |= SYNTH_CAP_OPL3; + strcpy(devc->fm_info.name, "Yamaha OPL-3"); + + for (i = 0; i < 18; i++) + { + if (pv_map[i].ioaddr == USE_LEFT) + pv_map[i].ioaddr = devc->left_io; + else + pv_map[i].ioaddr = devc->right_io; + } + opl3_command(devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE); + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x00); + } else - pv_map[i].ioaddr = devc->right_io; + { + conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1); + devc->v_alloc->max_voice = devc->nr_voice = 9; + devc->fm_info.nr_drums = 0; + + for (i = 0; i < 18; i++) + pv_map[i].ioaddr = devc->left_io; + }; + + for (i = 0; i < SBFM_MAXINSTR; i++) + devc->i_map[i].channel = -1; + + return me; +} - opl3_command (devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE); - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, 0x00); - } - else - { - conf_printf2 ("Yamaha OPL2 FM", ioaddr, 0, -1, -1); - devc->v_alloc->max_voice = devc->nr_voice = 9; - devc->fm_info.nr_drums = 0; +#ifdef MODULE - for (i = 0; i < 18; i++) - pv_map[i].ioaddr = devc->left_io; - }; +/* + * We provide OPL3 functions. + */ - for (i = 0; i < SBFM_MAXINSTR; i++) - devc->i_map[i].channel = -1; +int io = -1; +int me; +int init_module (void) +{ + printk("YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); + if (io != -1) /* User loading pure OPL3 module */ + { + if (!opl3_detect(io, NULL)) + { + return -ENODEV; + } + me = opl3_init(io, NULL); + } + SOUND_LOCK; + return 0; } +void cleanup_module(void) +{ + if (devc) + { + vfree(devc); + devc = NULL; + sound_unload_synthdev(me); + } + SOUND_LOCK_END; +} + +#else + #endif +#endif + +EXPORT_SYMBOL(opl3_init); +EXPORT_SYMBOL(opl3_detect); +MODULE_PARM(io, "i"); diff --git a/drivers/sound/opl3sa.c b/drivers/sound/opl3sa.c new file mode 100644 index 000000000..39adf4357 --- /dev/null +++ b/drivers/sound/opl3sa.c @@ -0,0 +1,277 @@ +/* + * sound/Xopl3sa.c + * + * Low level driver for Yamaha YMF701B aka OPL3-SA chip + * + */ +/* + * 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> + +#undef SB_OK + +#include "sound_config.h" +#ifdef SB_OK +#include "sb.h" +static int sb_initialized = 0; + +#endif + +#ifdef CONFIG_OPL3SA1 + +static int kilroy_was_here = 0; /* Don't detect twice */ +static int mpu_initialized = 0; + +static int *opl3sa_osp = NULL; + +static unsigned char +opl3sa_read(int addr) +{ + unsigned long flags; + unsigned char tmp; + + save_flags(flags); + cli(); + outb((0x1d), 0xf86); /* password */ + outb(((unsigned char) addr), 0xf86); /* address */ + tmp = inb(0xf87); /* data */ + restore_flags(flags); + + return tmp; +} + +static void +opl3sa_write(int addr, int data) +{ + unsigned long flags; + + save_flags(flags); + cli(); + outb((0x1d), 0xf86); /* password */ + outb(((unsigned char) addr), 0xf86); /* address */ + outb(((unsigned char) data), 0xf87); /* data */ + restore_flags(flags); +} + +static int +opl3sa_detect(void) +{ + int tmp; + + if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04) + { + DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01))); + /* return 0; */ + } +/* + * Check that the password feature has any effect + */ + if (inb(0xf87) == tmp) + { + DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87))); + return 0; + } + tmp = (opl3sa_read(0x04) & 0xe0) >> 5; + + if (tmp != 0 && tmp != 1) + { + DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp)); + return 0; + } + DDB(printk("OPL3-SA mode %x detected\n", tmp)); + + opl3sa_write(0x01, 0x00); /* Disable MSS */ + opl3sa_write(0x02, 0x00); /* Disable SB */ + opl3sa_write(0x03, 0x00); /* Disable MPU */ + + return 1; +} + +/* + * Probe and attach routines for the Windows Sound System mode of + * OPL3-SA + */ + +int +probe_opl3sa_wss(struct address_info *hw_config) +{ + int ret; + unsigned char tmp = 0x24; /* WSS enable */ + + if (check_region(0xf86, 2)) /* Control port is busy */ + return 0; + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (OPL3-SA for example) + * return 0x00. + */ + if (check_region(hw_config->io_base, 8)) + { + printk("OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + opl3sa_osp = hw_config->osp; + + if (!opl3sa_detect()) + { + printk("OSS: OPL3-SA chip not found\n"); + return 0; + } + switch (hw_config->io_base) + { + case 0x530: + tmp |= 0x00; + break; + case 0xe80: + tmp |= 0x08; + break; + case 0xf40: + tmp |= 0x10; + break; + case 0x604: + tmp |= 0x18; + break; + default: + printk("OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); + return 0; + } + + opl3sa_write(0x01, tmp); /* WSS setup register */ + kilroy_was_here = 1; + + ret = probe_ms_sound(hw_config); + if (ret) + request_region(0xf86, 2, "OPL3-SA"); + + return ret; +} + +void +attach_opl3sa_wss(struct address_info *hw_config) +{ + int nm = num_mixers; + + attach_ms_sound(hw_config); + if (num_mixers > nm) /* A mixer was installed */ + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } +} + + +void +attach_opl3sa_mpu(struct address_info *hw_config) +{ +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + hw_config->name = "OPL3-SA (MPU401)"; + attach_uart401(hw_config); +#endif +} + +int +probe_opl3sa_mpu(struct address_info *hw_config) +{ +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4}; + + if (!kilroy_was_here) + { + return 0; /* OPL3-SA has not been detected earlier */ + } + if (mpu_initialized) + { + DDB(printk("OPL3-SA: MPU mode already initialized\n")); + return 0; + } + if (check_region(hw_config->io_base, 4)) + { + printk("OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + if (hw_config->irq > 10) + { + printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + if (irq_bits[hw_config->irq] == -1) + { + printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x332: + conf = 0x20; + break; + case 0x334: + conf = 0x40; + break; + case 0x300: + conf = 0x60; + break; + default: + return 0; /* Invalid port */ + } + + conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */ + conf |= irq_bits[hw_config->irq] << 2; + + opl3sa_write(0x03, conf); + + mpu_initialized = 1; + + return probe_uart401(hw_config); +#else + return 0; +#endif +} + +void +unload_opl3sa_wss(struct address_info *hw_config) +{ + int dma2 = hw_config->dma2; + + if (dma2 == -1) + dma2 = hw_config->dma; + + release_region(0xf86, 2); + release_region(hw_config->io_base, 4); + + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + dma2, + 0); +} + +void +unload_opl3sa_mpu(struct address_info *hw_config) +{ +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + unload_uart401(hw_config); +#endif +} +#ifdef SB_OK +void +unload_opl3sa_sb(struct address_info *hw_config) +{ +#ifdef CONFIG_SBDSP + sb_dsp_unload(hw_config); +#endif +} +#endif + + +#endif diff --git a/drivers/sound/os.h b/drivers/sound/os.h index 4b1abd06e..1acffb768 100644 --- a/drivers/sound/os.h +++ b/drivers/sound/os.h @@ -1,21 +1,13 @@ - -#ifdef __alpha__ -#else -#endif - #define ALLOW_SELECT #undef NO_INLINE_ASM #define SHORT_BANNERS #define MANUAL_PNP -#undef DO_TIMINGS +#undef DO_TIMINGS #ifdef MODULE #define __NO_VERSION__ #include <linux/module.h> #include <linux/version.h> -#ifdef MODVERSIONS -#include <linux/modversions.h> -#endif #endif #if LINUX_VERSION_CODE > 131328 #define LINUX21X @@ -41,19 +33,14 @@ #include <linux/poll.h> #include <linux/pci.h> #include <linux/bios32.h> -#else #endif #include <linux/wrapper.h> - #include <linux/soundcard.h> - #define FALSE 0 #define TRUE 1 - - struct snd_wait { volatile int opts; }; @@ -70,8 +57,6 @@ extern caddr_t sound_mem_blocks[1024]; extern int sound_mem_sizes[1024]; extern int sound_nblocks; - - #undef PSEUDO_DMA_AUTOINIT #define ALLOW_BUFFER_MAPPING diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index b109b22f1..7e3c23f59 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -5,9 +5,11 @@ */ #include <linux/config.h> +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_PAS) +#if defined(CONFIG_PAS) || defined(MODULE) static unsigned char dma_bits[] = {4, 1, 2, 3, 0, 5, 6, 7}; @@ -23,13 +25,13 @@ static unsigned char sb_dma_bits[] = * be relative to the given base -register */ -int translate_code; +int translate_code = 0; static int pas_intr_mask = 0; static int pas_irq = 0; static int pas_sb_base = 0; -char pas_model; +char pas_model = 0; static char *pas_model_names[] = {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"}; @@ -38,310 +40,359 @@ static char *pas_model_names[] = * These routines perform the I/O address translation required * to support other than the default base address */ -extern void mix_write (unsigned char data, int ioaddr); +extern void mix_write(unsigned char data, int ioaddr); unsigned char -pas_read (int ioaddr) +pas_read(int ioaddr) { - return inb (ioaddr ^ translate_code); + return inb(ioaddr ^ translate_code); } void -pas_write (unsigned char data, int ioaddr) +pas_write(unsigned char data, int ioaddr) { - outb ((data), ioaddr ^ translate_code); + outb((data), ioaddr ^ translate_code); } /******************* Begin of the Interrupt Handler ********************/ static void -pasintr (int irq, void *dev_id, struct pt_regs *dummy) +pasintr(int irq, void *dev_id, struct pt_regs *dummy) { - int status; + int status; - status = pas_read (0x0B89); - pas_write (status, 0x0B89); /* Clear interrupt */ + status = pas_read(0x0B89); + pas_write(status, 0x0B89); /* Clear interrupt */ - if (status & 0x08) - { + if (status & 0x08) + { #ifdef CONFIG_AUDIO - pas_pcm_interrupt (status, 1); + pas_pcm_interrupt(status, 1); #endif - status &= ~0x08; - } - if (status & 0x10) - { -#ifdef CONFIG_MIDI - pas_midi_interrupt (); + status &= ~0x08; + } + if (status & 0x10) + { +#if defined(CONFIG_MIDI) + pas_midi_interrupt(); #endif - status &= ~0x10; - } + status &= ~0x10; + } } int -pas_set_intr (int mask) +pas_set_intr(int mask) { - if (!mask) - return 0; + if (!mask) + return 0; - pas_intr_mask |= mask; + pas_intr_mask |= mask; - pas_write (pas_intr_mask, 0x0B8B); - return 0; + pas_write(pas_intr_mask, 0x0B8B); + return 0; } int -pas_remove_intr (int mask) +pas_remove_intr(int mask) { - if (!mask) - return 0; + if (!mask) + return 0; - pas_intr_mask &= ~mask; - pas_write (pas_intr_mask, 0x0B8B); + pas_intr_mask &= ~mask; + pas_write(pas_intr_mask, 0x0B8B); - return 0; + return 0; } /******************* End of the Interrupt handler **********************/ /******************* Begin of the Initialization Code ******************/ +extern struct address_info sbhw_config; + static int -config_pas_hw (struct address_info *hw_config) +config_pas_hw(struct address_info *hw_config) { - char ok = 1; - unsigned int_ptrs; /* scsi/sound interrupt pointers */ - - pas_irq = hw_config->irq; - - pas_write (0x00, 0x0B8B); - pas_write (0x36, 0x138B); - pas_write (0x36, 0x1388); - pas_write (0, 0x1388); - pas_write (0x74, 0x138B); - pas_write (0x74, 0x1389); - pas_write (0, 0x1389); - - pas_write (0x80 | 0x40 | 0x20 | 1, 0x0B8A); - pas_write (0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); - pas_write (0x01 | 0x02 | 0x04 | 0x10 /* - * | - * 0x80 - */ , 0xB88); - - pas_write (0x80 + char ok = 1; + unsigned int_ptrs; /* scsi/sound interrupt pointers */ + + pas_irq = hw_config->irq; + + pas_write(0x00, 0x0B8B); + pas_write(0x36, 0x138B); + pas_write(0x36, 0x1388); + pas_write(0, 0x1388); + pas_write(0x74, 0x138B); + pas_write(0x74, 0x1389); + pas_write(0, 0x1389); + + pas_write(0x80 | 0x40 | 0x20 | 1, 0x0B8A); + pas_write(0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); + pas_write(0x01 | 0x02 | 0x04 | 0x10 /* + * | + * 0x80 + */ , 0xB88); + + pas_write(0x80 #ifdef PAS_JOYSTICK_ENABLE - | 0x40 + | 0x40 #endif - ,0xF388); - - if (pas_irq < 0 || pas_irq > 15) - { - printk ("PAS16: Invalid IRQ %d", pas_irq); - ok = 0; - } - else - { - int_ptrs = pas_read (0xF38A); - int_ptrs |= irq_bits[pas_irq] & 0xf; - pas_write (int_ptrs, 0xF38A); - if (!irq_bits[pas_irq]) - { - printk ("PAS16: Invalid IRQ %d", pas_irq); - ok = 0; - } - else - { - if (snd_set_irq_handler (pas_irq, pasintr, "PAS16", hw_config->osp) < 0) - ok = 0; - } - } - - if (hw_config->dma < 0 || hw_config->dma > 7) - { - printk ("PAS16: Invalid DMA selection %d", hw_config->dma); - ok = 0; - } - else - { - pas_write (dma_bits[hw_config->dma], 0xF389); - if (!dma_bits[hw_config->dma]) - { - printk ("PAS16: Invalid DMA selection %d", hw_config->dma); - ok = 0; - } - else - { - if (sound_alloc_dma (hw_config->dma, "PAS16")) - { - printk ("pas2_card.c: Can't allocate DMA channel\n"); - ok = 0; - } - } - } + ,0xF388); + + if (pas_irq < 0 || pas_irq > 15) + { + printk("PAS16: Invalid IRQ %d", pas_irq); + ok = 0; + } else + { + int_ptrs = pas_read(0xF38A); + int_ptrs |= irq_bits[pas_irq] & 0xf; + pas_write(int_ptrs, 0xF38A); + if (!irq_bits[pas_irq]) + { + printk("PAS16: Invalid IRQ %d", pas_irq); + ok = 0; + } else + { + if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0) + ok = 0; + } + } + + if (hw_config->dma < 0 || hw_config->dma > 7) + { + printk("PAS16: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } else + { + pas_write(dma_bits[hw_config->dma], 0xF389); + if (!dma_bits[hw_config->dma]) + { + printk("PAS16: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } else + { + if (sound_alloc_dma(hw_config->dma, "PAS16")) + { + printk("pas2_card.c: Can't allocate DMA channel\n"); + ok = 0; + } + } + } - /* - * This fixes the timing problems of the PAS due to the Symphony chipset - * as per Media Vision. Only define this if your PAS doesn't work correctly. - */ + /* + * This fixes the timing problems of the PAS due to the Symphony chipset + * as per Media Vision. Only define this if your PAS doesn't work correctly. + */ #ifdef SYMPHONY_PAS - outb ((0x05), 0xa8); - outb ((0x60), 0xa9); + outb((0x05), 0xa8); + outb((0x60), 0xa9); #endif #ifdef BROKEN_BUS_CLOCK - pas_write (0x01 | 0x10 | 0x20 | 0x04, 0x8388); + pas_write(0x01 | 0x10 | 0x20 | 0x04, 0x8388); #else - /* - * pas_write(0x01, 0x8388); - */ - pas_write (0x01 | 0x10 | 0x20, 0x8388); -#endif - pas_write (0x18, 0x838A); /* ??? */ - pas_write (0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ - pas_write (8, 0xBF8A); - - mix_write (0x80 | 5, 0x078B); - mix_write (5, 0x078B); - -#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) - - { - struct address_info *sb_config; - - if ((sb_config = sound_getconf (SNDCARD_SB))) - { - unsigned char irq_dma; - - /* - * Turn on Sound Blaster compatibility - * bit 1 = SB emulation - * bit 0 = MPU401 emulation (CDPC only :-( ) - */ - pas_write (0x02, 0xF788); - /* - * "Emulation address" + * pas_write(0x01, 0x8388); */ - pas_write ((sb_config->io_base >> 4) & 0x0f, 0xF789); - pas_sb_base = sb_config->io_base; + pas_write(0x01 | 0x10 | 0x20, 0x8388); +#endif + pas_write(0x18, 0x838A); /* ??? */ + pas_write(0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ + pas_write(8, 0xBF8A); - if (!sb_dma_bits[sb_config->dma]) - printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", - sb_config->dma); + mix_write(0x80 | 5, 0x078B); + mix_write(5, 0x078B); - if (!sb_irq_bits[sb_config->irq]) - printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", - sb_config->irq); +#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) - irq_dma = sb_dma_bits[sb_config->dma] | - sb_irq_bits[sb_config->irq]; + { + struct address_info *sb_config; - pas_write (irq_dma, 0xFB8A); - } - else - pas_write (0x00, 0xF788); - } +#ifndef MODULE + if ((sb_config = sound_getconf(SNDCARD_SB))) +#else + sb_config = &sbhw_config; + if (sb_config->io_base) +#endif + { + unsigned char irq_dma; + + /* + * Turn on Sound Blaster compatibility + * bit 1 = SB emulation + * bit 0 = MPU401 emulation (CDPC only :-( ) + */ + pas_write(0x02, 0xF788); + + /* + * "Emulation address" + */ + pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); + pas_sb_base = sb_config->io_base; + + if (!sb_dma_bits[sb_config->dma]) + printk("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); + + if (!sb_irq_bits[sb_config->irq]) + printk("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); + + irq_dma = sb_dma_bits[sb_config->dma] | + sb_irq_bits[sb_config->irq]; + + pas_write(irq_dma, 0xFB8A); + } else + pas_write(0x00, 0xF788); + } #else - pas_write (0x00, 0xF788); + pas_write(0x00, 0xF788); #endif - if (!ok) - printk ("PAS16: Driver not enabled\n"); + if (!ok) + printk("PAS16: Driver not enabled\n"); - return ok; + return ok; } static int -detect_pas_hw (struct address_info *hw_config) +detect_pas_hw(struct address_info *hw_config) { - unsigned char board_id, foo; + unsigned char board_id, foo; - /* - * WARNING: Setting an option like W:1 or so that disables warm boot reset - * of the card will screw up this detect code something fierce. Adding code - * to handle this means possibly interfering with other cards on the bus if - * you have something on base port 0x388. SO be forewarned. - */ + /* + * WARNING: Setting an option like W:1 or so that disables warm boot reset + * of the card will screw up this detect code something fierce. Adding code + * to handle this means possibly interfering with other cards on the bus if + * you have something on base port 0x388. SO be forewarned. + */ - outb ((0xBC), 0x9A01); /* Activate first board */ - outb ((hw_config->io_base >> 2), 0x9A01); /* Set base address */ - translate_code = 0x388 ^ hw_config->io_base; - pas_write (1, 0xBF88); /* Select one wait states */ + outb((0xBC), 0x9A01); /* Activate first board */ + outb((hw_config->io_base >> 2), 0x9A01); /* Set base address */ + translate_code = 0x388 ^ hw_config->io_base; + pas_write(1, 0xBF88); /* Select one wait states */ - board_id = pas_read (0x0B8B); + board_id = pas_read(0x0B8B); - if (board_id == 0xff) - return 0; + if (board_id == 0xff) + return 0; - /* - * We probably have a PAS-series board, now check for a PAS16-series board - * by trying to change the board revision bits. PAS16-series hardware won't - * let you do this - the bits are read-only. - */ + /* + * We probably have a PAS-series board, now check for a PAS16-series board + * by trying to change the board revision bits. PAS16-series hardware won't + * let you do this - the bits are read-only. + */ - foo = board_id ^ 0xe0; + foo = board_id ^ 0xe0; - pas_write (foo, 0x0B8B); - foo = pas_read (0x0B8B); - pas_write (board_id, 0x0B8B); + pas_write(foo, 0x0B8B); + foo = pas_read(0x0B8B); + pas_write(board_id, 0x0B8B); - if (board_id != foo) - return 0; + if (board_id != foo) + return 0; - pas_model = pas_read (0xFF88); + pas_model = pas_read(0xFF88); - return pas_model; + return pas_model; } void -attach_pas_card (struct address_info *hw_config) +attach_pas_card(struct address_info *hw_config) { - pas_irq = hw_config->irq; - - if (detect_pas_hw (hw_config)) - { - - if ((pas_model = pas_read (0xFF88))) - { - char temp[100]; - - sprintf (temp, - "%s rev %d", pas_model_names[(int) pas_model], - pas_read (0x2789)); - conf_printf (temp, hw_config); - } - - if (config_pas_hw (hw_config)) - { + pas_irq = hw_config->irq; + + if (detect_pas_hw(hw_config)) + { + + if ((pas_model = pas_read(0xFF88))) + { + char temp[100]; + + sprintf(temp, + "%s rev %d", pas_model_names[(int) pas_model], + pas_read(0x2789)); + conf_printf(temp, hw_config); + } + if (config_pas_hw(hw_config)) + { #ifdef CONFIG_AUDIO - pas_pcm_init (hw_config); + pas_pcm_init(hw_config); #endif -#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) +#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) - sb_dsp_disable_midi (pas_sb_base); /* No MIDI capability */ + sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif -#ifdef CONFIG_MIDI - pas_midi_init (); +#if defined(CONFIG_MIDI) + pas_midi_init(); #endif - pas_init_mixer (); - } - } + pas_init_mixer(); + } + } } int -probe_pas (struct address_info *hw_config) +probe_pas(struct address_info *hw_config) { - return detect_pas_hw (hw_config); + return detect_pas_hw(hw_config); } void -unload_pas (struct address_info *hw_config) +unload_pas(struct address_info *hw_config) { - sound_free_dma (hw_config->dma); - snd_release_irq (hw_config->irq); + sound_free_dma(hw_config->dma); + snd_release_irq(hw_config->irq); } +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ + +int sb_io = 0; +int sb_irq = -1; +int sb_dma = -1; +int sb_dma16 = -1; + +struct address_info config; +struct address_info sbhw_config; + +int init_module(void) +{ + printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + + sbhw_config.io_base = sb_io; + sbhw_config.irq = sb_irq; + sbhw_config.dma = sb_dma; + sbhw_config.dma2 = sb_dma16; + + if (!probe_pas(&config)) + return -ENODEV; + attach_pas_card(&config); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + unload_pas(&config); + SOUND_LOCK_END; +} + + +#endif #endif diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c index 05a509f91..45b60fefd 100644 --- a/drivers/sound/pas2_midi.c +++ b/drivers/sound/pas2_midi.c @@ -15,7 +15,7 @@ #include "sound_config.h" -#if defined(CONFIG_PAS) && defined(CONFIG_MIDI) +#if ( defined(MODULE) || defined(CONFIG_PAS) ) && defined(CONFIG_MIDI) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -27,87 +27,86 @@ static volatile unsigned char qhead, qtail; static void (*midi_input_intr) (int dev, unsigned char data); static int -pas_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +pas_midi_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - int err; - unsigned long flags; - unsigned char ctrl; + int err; + unsigned long flags; + unsigned char ctrl; - if (midi_busy) - { - printk ("PAS16: Midi busy\n"); - return -EBUSY; - } - - /* - * Reset input and output FIFO pointers - */ - pas_write (0x20 | 0x40, - 0x178b); - - save_flags (flags); - cli (); - - if ((err = pas_set_intr (0x10)) < 0) - return err; - - /* - * Enable input available and output FIFO empty interrupts - */ + if (midi_busy) + { + printk("PAS16: Midi busy\n"); + return -EBUSY; + } + /* + * Reset input and output FIFO pointers + */ + pas_write(0x20 | 0x40, + 0x178b); - ctrl = 0; - input_opened = 0; - midi_input_intr = input; + save_flags(flags); + cli(); - if (mode == OPEN_READ || mode == OPEN_READWRITE) - { - ctrl |= 0x04; /* Enable input */ - input_opened = 1; - } + if ((err = pas_set_intr(0x10)) < 0) + { + restore_flags(flags); + return err; + } + /* + * Enable input available and output FIFO empty interrupts + */ - if (mode == OPEN_WRITE || mode == OPEN_READWRITE) - { - ctrl |= 0x08 | 0x10; /* Enable output */ - } + ctrl = 0; + input_opened = 0; + midi_input_intr = input; - pas_write (ctrl, 0x178b); + if (mode == OPEN_READ || mode == OPEN_READWRITE) + { + ctrl |= 0x04; /* Enable input */ + input_opened = 1; + } + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + { + ctrl |= 0x08 | 0x10; /* Enable output */ + } + pas_write(ctrl, 0x178b); - /* - * Acknowledge any pending interrupts - */ + /* + * Acknowledge any pending interrupts + */ - pas_write (0xff, 0x1B88); + pas_write(0xff, 0x1B88); - restore_flags (flags); + restore_flags(flags); - midi_busy = 1; - qlen = qhead = qtail = 0; - return 0; + midi_busy = 1; + qlen = qhead = qtail = 0; + return 0; } static void -pas_midi_close (int dev) +pas_midi_close(int dev) { - /* - * Reset FIFO pointers, disable intrs - */ - pas_write (0x20 | 0x40, 0x178b); + /* + * Reset FIFO pointers, disable intrs + */ + pas_write(0x20 | 0x40, 0x178b); - pas_remove_intr (0x10); - midi_busy = 0; + pas_remove_intr(0x10); + midi_busy = 0; } static int -dump_to_midi (unsigned char midi_byte) +dump_to_midi(unsigned char midi_byte) { - int fifo_space, x; + int fifo_space, x; - fifo_space = ((x = pas_read (0x1B89)) >> 4) & 0x0f; + fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f; /* * The MIDI FIFO space register and it's documentation is nonunderstandable. @@ -117,91 +116,90 @@ dump_to_midi (unsigned char midi_byte) * means that the buffer is empty. */ - if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */ - { - return 0; /* Ask upper layers to retry after some time */ - } - - pas_write (midi_byte, 0x178A); + if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */ + { + return 0; /* Ask upper layers to retry after some time */ + } + pas_write(midi_byte, 0x178A); - return 1; + return 1; } static int -pas_midi_out (int dev, unsigned char midi_byte) +pas_midi_out(int dev, unsigned char midi_byte) { - unsigned long flags; + unsigned long flags; - /* - * Drain the local queue first - */ + /* + * Drain the local queue first + */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } - restore_flags (flags); + restore_flags(flags); - /* - * Output the byte if the local queue is empty. - */ + /* + * Output the byte if the local queue is empty. + */ - if (!qlen) - if (dump_to_midi (midi_byte)) - return 1; + if (!qlen) + if (dump_to_midi(midi_byte)) + return 1; - /* - * Put to the local queue - */ + /* + * Put to the local queue + */ - if (qlen >= 256) - return 0; /* Local queue full */ + if (qlen >= 256) + return 0; /* Local queue full */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; + tmp_queue[qtail] = midi_byte; + qlen++; + qtail++; - restore_flags (flags); + restore_flags(flags); - return 1; + return 1; } static int -pas_midi_start_read (int dev) +pas_midi_start_read(int dev) { - return 0; + return 0; } static int -pas_midi_end_read (int dev) +pas_midi_end_read(int dev) { - return 0; + return 0; } static int -pas_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +pas_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -pas_midi_kick (int dev) +pas_midi_kick(int dev) { } static int -pas_buffer_status (int dev) +pas_buffer_status(int dev) { - return qlen; + return qlen; } #define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi" @@ -210,80 +208,76 @@ pas_buffer_status (int dev) static struct midi_operations pas_midi_operations = { - {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, - &std_midi_synth, - {0}, - pas_midi_open, - pas_midi_close, - pas_midi_ioctl, - pas_midi_out, - pas_midi_start_read, - pas_midi_end_read, - pas_midi_kick, - NULL, - pas_buffer_status, - NULL + {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, + &std_midi_synth, + {0}, + pas_midi_open, + pas_midi_close, + pas_midi_ioctl, + pas_midi_out, + pas_midi_start_read, + pas_midi_end_read, + pas_midi_kick, + NULL, + pas_buffer_status, + NULL }; void -pas_midi_init (void) +pas_midi_init(void) { - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &pas_midi_operations; - sequencer_init (); + int dev = sound_alloc_mididev(); + + if (dev == -1) + { + printk(KERN_WARNING "pas_midi_init: Too many midi devices detected\n"); + return; + } + std_midi_synth.midi_dev = my_dev = dev; + midi_devs[dev] = &pas_midi_operations; + sequencer_init(); } void -pas_midi_interrupt (void) +pas_midi_interrupt(void) { - unsigned char stat; - int i, incount; - unsigned long flags; - - stat = pas_read (0x1B88); + unsigned char stat; + int i, incount; + unsigned long flags; - if (stat & 0x04) /* Input data available */ - { - incount = pas_read (0x1B89) & 0x0f; /* Input FIFO size */ - if (!incount) - incount = 16; + stat = pas_read(0x1B88); - for (i = 0; i < incount; i++) - if (input_opened) + if (stat & 0x04) /* Input data available */ { - midi_input_intr (my_dev, pas_read (0x178A)); + incount = pas_read(0x1B89) & 0x0f; /* Input FIFO size */ + if (!incount) + incount = 16; + + for (i = 0; i < incount; i++) + if (input_opened) + { + midi_input_intr(my_dev, pas_read(0x178A)); + } else + pas_read(0x178A); /* Flush */ } - else - pas_read (0x178A); /* Flush */ - } - - if (stat & (0x08 | 0x10)) - { - save_flags (flags); - cli (); - - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - restore_flags (flags); - } - + if (stat & (0x08 | 0x10)) + { + save_flags(flags); + cli(); - if (stat & 0x40) - { - printk ("MIDI output overrun %x,%x\n", pas_read (0x1B89), stat); - } + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } - pas_write (stat, 0x1B88); /* Acknowledge interrupts */ + restore_flags(flags); + } + if (stat & 0x40) + { + printk("MIDI output overrun %x,%x\n", pas_read(0x1B89), stat); + } + pas_write(stat, 0x1B88); /* Acknowledge interrupts */ } #endif diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c index 8a240e28b..335e7dd39 100644 --- a/drivers/sound/pas2_mixer.c +++ b/drivers/sound/pas2_mixer.c @@ -1,3 +1,4 @@ + /* * sound/pas2_mixer.c * @@ -15,7 +16,7 @@ #include "sound_config.h" -#if defined(CONFIG_PAS) +#if defined(CONFIG_PAS) || defined(MODULE) #ifndef DEB #define DEB(what) /* (what) */ @@ -40,325 +41,317 @@ static int *levels; static int default_levels[32] = { - 0x3232, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x5050, /* FM */ - 0x4b4b, /* PCM */ - 0x3232, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x4b4b, /* Mic */ - 0x4b4b, /* CD */ - 0x6464, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x6464 /* Recording level */ + 0x3232, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x5050, /* FM */ + 0x4b4b, /* PCM */ + 0x3232, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x4b4b, /* Mic */ + 0x4b4b, /* CD */ + 0x6464, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x6464 /* Recording level */ }; void -mix_write (unsigned char data, int ioaddr) +mix_write(unsigned char data, int ioaddr) { - /* - * The Revision D cards have a problem with their MVA508 interface. The - * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and - * MSBs out of the output byte and to do a 16-bit out to the mixer port - - * 1. We need to do this because it isn't timing problem but chip access - * sequence problem. - */ - - if (pas_model == 4) - { - outw (data | (data << 8), (ioaddr ^ translate_code) - 1); - outb ((0x80), 0); - } - else - pas_write (data, ioaddr); + /* + * The Revision D cards have a problem with their MVA508 interface. The + * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and + * MSBs out of the output byte and to do a 16-bit out to the mixer port - + * 1. We need to do this because it isn't timing problem but chip access + * sequence problem. + */ + + if (pas_model == 4) + { + outw(data | (data << 8), (ioaddr ^ translate_code) - 1); + outb((0x80), 0); + } else + pas_write(data, ioaddr); } static int -mixer_output (int right_vol, int left_vol, int div, int bits, - int mixer) /* Input or output mixer */ +mixer_output(int right_vol, int left_vol, int div, int bits, + int mixer) /* Input or output mixer */ { - int left = left_vol * div / 100; - int right = right_vol * div / 100; - - - if (bits & 0x10) - { - left |= mixer; - right |= mixer; - } - - if (bits == 0x03 || bits == 0x04) - { - mix_write (0x80 | bits, 0x078B); - mix_write (left, 0x078B); - right_vol = left_vol; - } - else - { - mix_write (0x80 | 0x20 | bits, 0x078B); - mix_write (left, 0x078B); - mix_write (0x80 | 0x40 | bits, 0x078B); - mix_write (right, 0x078B); - } - - return (left_vol | (right_vol << 8)); + int left = left_vol * div / 100; + int right = right_vol * div / 100; + + + if (bits & 0x10) + { + left |= mixer; + right |= mixer; + } + if (bits == 0x03 || bits == 0x04) + { + mix_write(0x80 | bits, 0x078B); + mix_write(left, 0x078B); + right_vol = left_vol; + } else + { + mix_write(0x80 | 0x20 | bits, 0x078B); + mix_write(left, 0x078B); + mix_write(0x80 | 0x40 | bits, 0x078B); + mix_write(right, 0x078B); + } + + return (left_vol | (right_vol << 8)); } static void -set_mode (int new_mode) +set_mode(int new_mode) { - mix_write (0x80 | 0x05, 0x078B); - mix_write (new_mode, 0x078B); + mix_write(0x80 | 0x05, 0x078B); + mix_write(new_mode, 0x078B); - mode_control = new_mode; + mode_control = new_mode; } static int -pas_mixer_set (int whichDev, unsigned int level) +pas_mixer_set(int whichDev, unsigned int level) { - int left, right, devmask, changed, i, mixer = 0; - - DEB (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); - - left = level & 0x7f; - right = (level & 0x7f00) >> 8; - - if (whichDev < SOUND_MIXER_NRDEVICES) - if ((1 << whichDev) & rec_devices) - mixer = 0x20; - else - mixer = 0x00; - - switch (whichDev) - { - case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ - levels[whichDev] = mixer_output (right, left, 63, 0x01, 0); - break; - - /* - * Note! Bass and Treble are mono devices. Will use just the left - * channel. - */ - case SOUND_MIXER_BASS: /* Bass (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, 0x03, 0); - break; - case SOUND_MIXER_TREBLE: /* Treble (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, 0x04, 0); - break; - - case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x00, mixer); - break; - case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x05, mixer); - break; - case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x07, mixer); - break; - case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x06, mixer); - break; - case SOUND_MIXER_LINE: /* External line (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x02, mixer); - break; - case SOUND_MIXER_CD: /* CD (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x03, mixer); - break; - case SOUND_MIXER_MIC: /* External microphone (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x04, mixer); - break; - case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x01, - 0x00); - break; - case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ - levels[whichDev] = mixer_output (right, left, 15, 0x02, 0); - break; - - - case SOUND_MIXER_RECSRC: - devmask = level & POSSIBLE_RECORDING_DEVICES; - - changed = devmask ^ rec_devices; - rec_devices = devmask; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (changed & (1 << i)) + int left, right, devmask, changed, i, mixer = 0; + + DEB(printk("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); + + left = level & 0x7f; + right = (level & 0x7f00) >> 8; + + if (whichDev < SOUND_MIXER_NRDEVICES) + if ((1 << whichDev) & rec_devices) + mixer = 0x20; + else + mixer = 0x00; + + switch (whichDev) { - pas_mixer_set (i, levels[i]); + case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ + levels[whichDev] = mixer_output(right, left, 63, 0x01, 0); + break; + + /* + * Note! Bass and Treble are mono devices. Will use just the left + * channel. + */ + case SOUND_MIXER_BASS: /* Bass (0-12) */ + levels[whichDev] = mixer_output(right, left, 12, 0x03, 0); + break; + case SOUND_MIXER_TREBLE: /* Treble (0-12) */ + levels[whichDev] = mixer_output(right, left, 12, 0x04, 0); + break; + + case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x00, mixer); + break; + case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x05, mixer); + break; + case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x07, mixer); + break; + case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x06, mixer); + break; + case SOUND_MIXER_LINE: /* External line (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x02, mixer); + break; + case SOUND_MIXER_CD: /* CD (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x03, mixer); + break; + case SOUND_MIXER_MIC: /* External microphone (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x04, mixer); + break; + case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x01, + 0x00); + break; + case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ + levels[whichDev] = mixer_output(right, left, 15, 0x02, 0); + break; + + + case SOUND_MIXER_RECSRC: + devmask = level & POSSIBLE_RECORDING_DEVICES; + + changed = devmask ^ rec_devices; + rec_devices = devmask; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (changed & (1 << i)) + { + pas_mixer_set(i, levels[i]); + } + return rec_devices; + break; + + default: + return -EINVAL; } - return rec_devices; - break; - default: - return -EINVAL; - } - - return (levels[whichDev]); + return (levels[whichDev]); } /*****/ static void -pas_mixer_reset (void) +pas_mixer_reset(void) { - int foo; + int foo; - DEB (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); + DEB(printk("pas2_mixer.c: void pas_mixer_reset(void)\n")); - for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) - pas_mixer_set (foo, levels[foo]); + for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) + pas_mixer_set(foo, levels[foo]); - set_mode (0x04 | 0x01); + set_mode(0x04 | 0x01); } static int -pas_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +pas_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - DEB (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); - - if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */ - { - int level; - - level = *(int *) arg; - - if (level == -1) /* Return current settings */ - { - if (mode_control & 0x04) - return (*(int *) arg = 1); - else - return (*(int *) arg = 0); - } - else - { - mode_control &= ~0x04; - if (level) - mode_control |= 0x04; - set_mode (mode_control); - return (*(int *) arg = !!level); /* 0 or 1 */ - } - } - - - if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */ - { - int level; - - level = *(int *) arg; - - if (level == -1) /* Return current settings */ - { - if (!(mode_control & 0x03)) - return (*(int *) arg = 0); - return (*(int *) arg = ((mode_control & 0x03) + 1) * 20); - } - else - { - int i = 0; - - level &= 0x7f; - if (level) - i = (level / 20) - 1; - - mode_control &= ~0x03; - mode_control |= i & 0x03; - set_mode (mode_control); - - if (i) - i = (i + 1) * 20; - - return i; - } - } - - if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */ - { - int level; - - level = *(int *) arg; - - if (level == -1) /* Return current settings */ - { - return (*(int *) arg = !(pas_read (0x0B8A) & 0x20)); - } - else - { - if (level) - pas_write (pas_read (0x0B8A) & (~0x20), - 0x0B8A); - else - pas_write (pas_read (0x0B8A) | 0x20, - 0x0B8A); - - return !(pas_read (0x0B8A) & 0x20); - } - } - - if (((cmd >> 8) & 0xff) == 'M') - { - int v; - - v = *(int *) arg; - - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - return (*(int *) arg = pas_mixer_set (cmd & 0xff, v)); - else - { - - switch (cmd & 0xff) - { - - case SOUND_MIXER_RECSRC: - return (*(int *) arg = rec_devices); - break; - - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE)); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = SUPPORTED_MIXER_DEVICES); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); /* No special capabilities */ - break; - - - default: - return (*(int *) arg = levels[cmd & 0xff]); - } - } - } - return -EINVAL; + DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + + if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */ + { + int level; + + level = *(int *) arg; + + if (level == -1) /* Return current settings */ + { + if (mode_control & 0x04) + return (*(int *) arg = 1); + else + return (*(int *) arg = 0); + } else + { + mode_control &= ~0x04; + if (level) + mode_control |= 0x04; + set_mode(mode_control); + return (*(int *) arg = !!level); /* 0 or 1 */ + } + } + if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */ + { + int level; + + level = *(int *) arg; + + if (level == -1) /* Return current settings */ + { + if (!(mode_control & 0x03)) + return (*(int *) arg = 0); + return (*(int *) arg = ((mode_control & 0x03) + 1) * 20); + } else + { + int i = 0; + + level &= 0x7f; + if (level) + i = (level / 20) - 1; + + mode_control &= ~0x03; + mode_control |= i & 0x03; + set_mode(mode_control); + + if (i) + i = (i + 1) * 20; + + return i; + } + } + if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */ + { + int level; + + level = *(int *) arg; + + if (level == -1) /* Return current settings */ + { + return (*(int *) arg = !(pas_read(0x0B8A) & 0x20)); + } else + { + if (level) + pas_write(pas_read(0x0B8A) & (~0x20), + 0x0B8A); + else + pas_write(pas_read(0x0B8A) | 0x20, + 0x0B8A); + + return !(pas_read(0x0B8A) & 0x20); + } + } + if (((cmd >> 8) & 0xff) == 'M') + { + int v; + + v = *(int *) arg; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + return (*(int *) arg = pas_mixer_set(cmd & 0xff, v)); + else + { + + switch (cmd & 0xff) + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = rec_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return (*(int *) arg = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE)); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = SUPPORTED_MIXER_DEVICES); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = 0); /* No special capabilities */ + break; + + + default: + return (*(int *) arg = levels[cmd & 0xff]); + } + } + } + return -EINVAL; } static struct mixer_operations pas_mixer_operations = { - "PAS16", - "Pro Audio Spectrum 16", - pas_mixer_ioctl + "PAS16", + "Pro Audio Spectrum 16", + pas_mixer_ioctl }; int -pas_init_mixer (void) +pas_init_mixer(void) { - levels = load_mixer_volumes ("PAS16_1", default_levels, 1); + int d; + + levels = load_mixer_volumes("PAS16_1", default_levels, 1); - pas_mixer_reset (); + pas_mixer_reset(); - if (num_mixers < MAX_MIXER_DEV) - { - audio_devs[pas_audiodev]->mixer_dev = num_mixers; - mixer_devs[num_mixers++] = &pas_mixer_operations; - } - return 1; + if ((d = sound_alloc_mixerdev()) != -1) + { + audio_devs[pas_audiodev]->mixer_dev = d; + mixer_devs[d] = &pas_mixer_operations; + } + return 1; } #endif diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index e082fc9cc..99e897161 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -12,7 +12,7 @@ #include "sound_config.h" -#if defined(CONFIG_PAS) && defined(CONFIG_AUDIO) +#if defined(MODULE) || ( defined(CONFIG_PAS) && defined(CONFIG_AUDIO) ) #ifndef DEB #define DEB(WHAT) @@ -39,424 +39,418 @@ int pas_audiodev = 0; static int open_mode = 0; static int -pcm_set_speed (int arg) +pcm_set_speed(int arg) { - int foo, tmp; - unsigned long flags; - - if (arg == 0) - return pcm_speed; - - if (arg > 44100) - arg = 44100; - if (arg < 5000) - arg = 5000; - - if (pcm_channels & 2) - { - foo = (596590 + (arg / 2)) / arg; - arg = (596590 + (foo / 2)) / foo; - } - else - { - foo = (1193180 + (arg / 2)) / arg; - arg = (1193180 + (foo / 2)) / foo; - } - - pcm_speed = arg; - - tmp = pas_read (0x0B8A); - - /* - * Set anti-aliasing filters according to sample rate. You really *NEED* - * to enable this feature for all normal recording unless you want to - * experiment with aliasing effects. - * These filters apply to the selected "recording" source. - * I (pfw) don't know the encoding of these 5 bits. The values shown - * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. - * - * I cleared bit 5 of these values, since that bit controls the master - * mute flag. (Olav Wölfelschneider) - * - */ + int foo, tmp; + unsigned long flags; + + if (arg == 0) + return pcm_speed; + + if (arg > 44100) + arg = 44100; + if (arg < 5000) + arg = 5000; + + if (pcm_channels & 2) + { + foo = (596590 + (arg / 2)) / arg; + arg = (596590 + (foo / 2)) / foo; + } else + { + foo = (1193180 + (arg / 2)) / arg; + arg = (1193180 + (foo / 2)) / foo; + } + + pcm_speed = arg; + + tmp = pas_read(0x0B8A); + + /* + * Set anti-aliasing filters according to sample rate. You really *NEED* + * to enable this feature for all normal recording unless you want to + * experiment with aliasing effects. + * These filters apply to the selected "recording" source. + * I (pfw) don't know the encoding of these 5 bits. The values shown + * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + * + * I cleared bit 5 of these values, since that bit controls the master + * mute flag. (Olav Wölfelschneider) + * + */ #if !defined NO_AUTO_FILTER_SET - tmp &= 0xe0; - if (pcm_speed >= 2 * 17897) - tmp |= 0x01; - else if (pcm_speed >= 2 * 15909) - tmp |= 0x02; - else if (pcm_speed >= 2 * 11931) - tmp |= 0x09; - else if (pcm_speed >= 2 * 8948) - tmp |= 0x11; - else if (pcm_speed >= 2 * 5965) - tmp |= 0x19; - else if (pcm_speed >= 2 * 2982) - tmp |= 0x04; - pcm_filter = tmp; + tmp &= 0xe0; + if (pcm_speed >= 2 * 17897) + tmp |= 0x01; + else if (pcm_speed >= 2 * 15909) + tmp |= 0x02; + else if (pcm_speed >= 2 * 11931) + tmp |= 0x09; + else if (pcm_speed >= 2 * 8948) + tmp |= 0x11; + else if (pcm_speed >= 2 * 5965) + tmp |= 0x19; + else if (pcm_speed >= 2 * 2982) + tmp |= 0x04; + pcm_filter = tmp; #endif - save_flags (flags); - cli (); + save_flags(flags); + cli(); - pas_write (tmp & ~(0x40 | 0x80), 0x0B8A); - pas_write (0x00 | 0x30 | 0x04, 0x138B); - pas_write (foo & 0xff, 0x1388); - pas_write ((foo >> 8) & 0xff, 0x1388); - pas_write (tmp, 0x0B8A); + pas_write(tmp & ~(0x40 | 0x80), 0x0B8A); + pas_write(0x00 | 0x30 | 0x04, 0x138B); + pas_write(foo & 0xff, 0x1388); + pas_write((foo >> 8) & 0xff, 0x1388); + pas_write(tmp, 0x0B8A); - restore_flags (flags); + restore_flags(flags); - return pcm_speed; + return pcm_speed; } static int -pcm_set_channels (int arg) +pcm_set_channels(int arg) { - if ((arg != 1) && (arg != 2)) - return pcm_channels; + if ((arg != 1) && (arg != 2)) + return pcm_channels; - if (arg != pcm_channels) - { - pas_write (pas_read (0xF8A) ^ 0x20, 0xF8A); + if (arg != pcm_channels) + { + pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A); - pcm_channels = arg; - pcm_set_speed (pcm_speed); /* The speed must be reinitialized */ - } - - return pcm_channels; + pcm_channels = arg; + pcm_set_speed(pcm_speed); /* The speed must be reinitialized */ + } + return pcm_channels; } static int -pcm_set_bits (int arg) +pcm_set_bits(int arg) { - if (arg == 0) - return pcm_bits; - - if ((arg & pcm_bitsok) != arg) - return pcm_bits; + if (arg == 0) + return pcm_bits; - if (arg != pcm_bits) - { - pas_write (pas_read (0x8389) ^ 0x04, 0x8389); + if ((arg & pcm_bitsok) != arg) + return pcm_bits; - pcm_bits = arg; - } + if (arg != pcm_bits) + { + pas_write(pas_read(0x8389) ^ 0x04, 0x8389); - return pcm_bits; + pcm_bits = arg; + } + return pcm_bits; } static int -pas_audio_ioctl (int dev, unsigned int cmd, caddr_t arg) +pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int val; + int val; - DEB (printk ("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - val = *(int *) arg; - return (*(int *) arg = pcm_set_speed (val)); - break; + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + val = *(int *) arg; + return (*(int *) arg = pcm_set_speed(val)); + break; - case SOUND_PCM_READ_RATE: - return (*(int *) arg = pcm_speed); - break; + case SOUND_PCM_READ_RATE: + return (*(int *) arg = pcm_speed); + break; - case SNDCTL_DSP_STEREO: - val = *(int *) arg; - return (*(int *) arg = pcm_set_channels (val + 1) - 1); - break; + case SNDCTL_DSP_STEREO: + val = *(int *) arg; + return (*(int *) arg = pcm_set_channels(val + 1) - 1); + break; - case SOUND_PCM_WRITE_CHANNELS: - val = *(int *) arg; - return (*(int *) arg = pcm_set_channels (val)); - break; + case SOUND_PCM_WRITE_CHANNELS: + val = *(int *) arg; + return (*(int *) arg = pcm_set_channels(val)); + break; - case SOUND_PCM_READ_CHANNELS: - return (*(int *) arg = pcm_channels); - break; + case SOUND_PCM_READ_CHANNELS: + return (*(int *) arg = pcm_channels); + break; - case SNDCTL_DSP_SETFMT: - val = *(int *) arg; - return (*(int *) arg = pcm_set_bits (val)); - break; + case SNDCTL_DSP_SETFMT: + val = *(int *) arg; + return (*(int *) arg = pcm_set_bits(val)); + break; - case SOUND_PCM_READ_BITS: - return (*(int *) arg = pcm_bits); + case SOUND_PCM_READ_BITS: + return (*(int *) arg = pcm_bits); - default: - return -EINVAL; - } + default: + return -EINVAL; + } - return -EINVAL; + return -EINVAL; } static void -pas_audio_reset (int dev) +pas_audio_reset(int dev) { - DEB (printk ("pas2_pcm.c: static void pas_audio_reset(void)\n")); + DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n")); - pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ + pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ } static int -pas_audio_open (int dev, int mode) +pas_audio_open(int dev, int mode) { - int err; - unsigned long flags; - - DEB (printk ("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); + int err; + unsigned long flags; - save_flags (flags); - cli (); - if (pcm_busy) - { - restore_flags (flags); - return -EBUSY; - } + DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); - pcm_busy = 1; - restore_flags (flags); + save_flags(flags); + cli(); + if (pcm_busy) + { + restore_flags(flags); + return -EBUSY; + } + pcm_busy = 1; + restore_flags(flags); - if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0) - return err; + if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) + return err; - pcm_count = 0; - open_mode = mode; + pcm_count = 0; + open_mode = mode; - return 0; + return 0; } static void -pas_audio_close (int dev) +pas_audio_close(int dev) { - unsigned long flags; + unsigned long flags; - DEB (printk ("pas2_pcm.c: static void pas_audio_close(void)\n")); + DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n")); - save_flags (flags); - cli (); + save_flags(flags); + cli(); - pas_audio_reset (dev); - pas_remove_intr (PAS_PCM_INTRBITS); - pcm_mode = PCM_NON; + pas_audio_reset(dev); + pas_remove_intr(PAS_PCM_INTRBITS); + pcm_mode = PCM_NON; - pcm_busy = 0; - restore_flags (flags); + pcm_busy = 0; + restore_flags(flags); } static void -pas_audio_output_block (int dev, unsigned long buf, int count, - int intrflag) +pas_audio_output_block(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags, cnt; + unsigned long flags, cnt; - DEB (printk ("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); + DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; + cnt = count; + if (audio_devs[dev]->dmap_out->dma > 3) + cnt >>= 1; - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; + if (audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == pcm_count) + return; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - pas_write (pas_read (0xF8A) & ~0x40, - 0xF8A); + pas_write(pas_read(0xF8A) & ~0x40, + 0xF8A); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; - if (count != pcm_count) - { - pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); - pas_write (0x40 | 0x30 | 0x04, 0x138B); - pas_write (count & 0xff, 0x1389); - pas_write ((count >> 8) & 0xff, 0x1389); - pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); + if (count != pcm_count) + { + pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); + pas_write(0x40 | 0x30 | 0x04, 0x138B); + pas_write(count & 0xff, 0x1389); + pas_write((count >> 8) & 0xff, 0x1389); + pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); - pcm_count = count; - } - pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); + pcm_count = count; + } + pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); + pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); #endif - pcm_mode = PCM_DAC; + pcm_mode = PCM_DAC; - restore_flags (flags); + restore_flags(flags); } static void -pas_audio_start_input (int dev, unsigned long buf, int count, - int intrflag) +pas_audio_start_input(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags; - int cnt; + unsigned long flags; + int cnt; - DEB (printk ("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); + DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; + cnt = count; + if (audio_devs[dev]->dmap_out->dma > 3) + cnt >>= 1; - if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; + if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && + intrflag && + cnt == pcm_count) + return; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; - if (count != pcm_count) - { - pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); - pas_write (0x40 | 0x30 | 0x04, 0x138B); - pas_write (count & 0xff, 0x1389); - pas_write ((count >> 8) & 0xff, 0x1389); - pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); + if (count != pcm_count) + { + pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); + pas_write(0x40 | 0x30 | 0x04, 0x138B); + pas_write(count & 0xff, 0x1389); + pas_write((count >> 8) & 0xff, 0x1389); + pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); - pcm_count = count; - } - pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); + pcm_count = count; + } + pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); + pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); #endif - pcm_mode = PCM_ADC; + pcm_mode = PCM_ADC; - restore_flags (flags); + restore_flags(flags); } #ifndef NO_TRIGGER static void -pas_audio_trigger (int dev, int state) +pas_audio_trigger(int dev, int state) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - state &= open_mode; + save_flags(flags); + cli(); + state &= open_mode; - if (state & PCM_ENABLE_OUTPUT) - pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); - else if (state & PCM_ENABLE_INPUT) - pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); - else - pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); + if (state & PCM_ENABLE_OUTPUT) + pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); + else if (state & PCM_ENABLE_INPUT) + pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); + else + pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); - restore_flags (flags); + restore_flags(flags); } #endif static int -pas_audio_prepare_for_input (int dev, int bsize, int bcount) +pas_audio_prepare_for_input(int dev, int bsize, int bcount) { - pas_audio_reset (dev); - return 0; + pas_audio_reset(dev); + return 0; } static int -pas_audio_prepare_for_output (int dev, int bsize, int bcount) +pas_audio_prepare_for_output(int dev, int bsize, int bcount) { - pas_audio_reset (dev); - return 0; + pas_audio_reset(dev); + return 0; } static struct audio_driver pas_audio_driver = { - pas_audio_open, - pas_audio_close, - pas_audio_output_block, - pas_audio_start_input, - pas_audio_ioctl, - pas_audio_prepare_for_input, - pas_audio_prepare_for_output, - pas_audio_reset, - NULL, - NULL, - NULL, - NULL, - pas_audio_trigger + pas_audio_open, + pas_audio_close, + pas_audio_output_block, + pas_audio_start_input, + pas_audio_ioctl, + pas_audio_prepare_for_input, + pas_audio_prepare_for_output, + pas_audio_reset, + NULL, + NULL, + NULL, + NULL, + pas_audio_trigger }; void -pas_pcm_init (struct address_info *hw_config) +pas_pcm_init(struct address_info *hw_config) { - DEB (printk ("pas2_pcm.c: long pas_pcm_init()\n")); - - pcm_bitsok = 8; - if (pas_read (0xEF8B) & 0x08) - pcm_bitsok |= 16; - - pcm_set_speed (DSP_DEFAULT_SPEED); - - if (num_audiodevs < MAX_AUDIO_DEV) - { - - if ((pas_audiodev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - "Pro Audio Spectrum", - &pas_audio_driver, - sizeof (struct audio_driver), - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, - NULL, - hw_config->dma, - hw_config->dma)) < 0) - { - return; - } - } - else - printk ("PAS16: Too many PCM devices available\n"); + DEB(printk("pas2_pcm.c: long pas_pcm_init()\n")); + + pcm_bitsok = 8; + if (pas_read(0xEF8B) & 0x08) + pcm_bitsok |= 16; + + pcm_set_speed(DSP_DEFAULT_SPEED); + + if ((pas_audiodev = sound_alloc_audiodev()) != -1) + { + + if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + "Pro Audio Spectrum", + &pas_audio_driver, + sizeof(struct audio_driver), + DMA_AUTOMODE, + AFMT_U8 | AFMT_S16_LE, + NULL, + hw_config->dma, + hw_config->dma)) < 0) + { + return; + } + } else + printk(KERN_WARNING "PAS16: Too many PCM devices available\n"); } void -pas_pcm_interrupt (unsigned char status, int cause) +pas_pcm_interrupt(unsigned char status, int cause) { - if (cause == 1) - { - /* - * Halt the PCM first. Otherwise we don't have time to start a new - * block before the PCM chip proceeds to the next sample - */ - - if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) - { - pas_write (pas_read (0xF8A) & ~0x40, - 0xF8A); - } - - switch (pcm_mode) - { - - case PCM_DAC: - DMAbuf_outputintr (pas_audiodev, 1); - break; - - case PCM_ADC: - DMAbuf_inputintr (pas_audiodev); - break; - - default: - printk ("PAS: Unexpected PCM interrupt\n"); - } - } + if (cause == 1) + { + /* + * Halt the PCM first. Otherwise we don't have time to start a new + * block before the PCM chip proceeds to the next sample + */ + + if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) + { + pas_write(pas_read(0xF8A) & ~0x40, + 0xF8A); + } + switch (pcm_mode) + { + + case PCM_DAC: + DMAbuf_outputintr(pas_audiodev, 1); + break; + + case PCM_ADC: + DMAbuf_inputintr(pas_audiodev); + break; + + default: + printk("PAS: Unexpected PCM interrupt\n"); + } + } } #endif diff --git a/drivers/sound/pnp.c b/drivers/sound/pnp.c deleted file mode 100644 index 9e07fa3ab..000000000 --- a/drivers/sound/pnp.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * sound/pnp.c - Temporary kludge for PnP soundcards. - * - * Copyright by Hannu Savolainen 1997. - * - * This file is just a temporary solution to be used with - * PnP soundcards until final kernel PnP support gets ready. - * The code contained in this file is largely untested and - * may cause failures in some systems. In particular it will - * cause troubles with other PnP ISA cards such as network cards. - * This file is also incompatible with (future) PnP support in kernel. - * - * For the above reasons I don't want this file to be widely distributed. - * You have permission to use this file with this particular sound driver - * and only for your own evaluation purposes. Any other use of this file - * or parts of it requires written permission by the author. - */ -extern int pnp_trace; -int pnp_trace_io = 0; - -#define UDELAY(x) udelay(x) - -#ifdef TEST_PNP -#include "pnp.h" -#include <malloc.h> -#include <stdio.h> -#define printk printf - -#define MALLOC(sz) malloc(sz) - -unsigned char res[10000]; -int rp; - -#else -#include "sound_config.h" -#endif diff --git a/drivers/sound/pnp.h b/drivers/sound/pnp.h deleted file mode 100644 index eb18c13eb..000000000 --- a/drivers/sound/pnp.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef _PNP_H_ -#define _PNP_H_ - -#define MAX_PNP_CARDS 16 - -#define PNP_DEVID(a, b, c, id) \ - ((a-'@')<<26) | ((b-'@')<<21) | ((c-'@') << 16) | (id&0xffff) - -#define NO_PORT 0 -#define NO_IRQ 0 -#define NO_DMA 4 - -struct pnp_port_resource -{ - short range_min, range_max; - unsigned char align, len; -}; - -struct pnp_func - { - struct pnp_dev *dev; - unsigned long flags; - struct pnp_func *next; - int nports; - struct pnp_port_resource ports[8]; - int nirq; - unsigned short irq[2]; - int ndma; - unsigned char dma[2]; - }; - -struct pnp_dev - { - int key; /* A PnP device id identifying this device */ - char *name; /* ANSI identifier string */ - int devno; /* Logical device number within a card */ - int ncompat; /* Number of compatible device idents */ - int compat_keys[8]; /* List of PnP compatible device idents */ - struct pnp_card *card; /* Link to the card which holds this device */ - struct pnp_dev *next; /* Pointer to next logical device or NULL */ - - int nports, nirq, ndma; - - int nfunc; /* Number of dependent function records */ - struct pnp_func *functions; /* List of dependent functions */ - int driver; /* Driver signature or 0 */ - int preconfig; /* 1 if config has been set manully */ - - }; - -struct pnp_card - { - int key; /* Unique PnP device identifier */ - char *name; /* ANSI identifier string of the card */ - int csn; /* Card select number */ - - char pnp_version; - char vendor_version; - - int driven; /* 0=No driver assigned, */ - /* 1=Drivers assigned to some of logical devices */ - /* 2=Card and all of it's devices have a driver */ - int relocated; /* 0=Card is inactive, 1=card is up and running */ - - int ndevs; /* Number of logical devices on the card */ - struct pnp_dev *devices; /* Pointer to first function entry */ - }; - -typedef struct pnp_card_info { - struct pnp_card card; - char name[64]; -} pnp_card_info; - -extern int pnp_card_count; -extern struct pnp_card *pnp_cards[MAX_PNP_CARDS]; -extern struct pnp_dev *pnp_device_list; - -extern int pnp_trace; - -/* - * Callable functions - */ - -extern void pnp_init(void); /* Called by kernel during boot */ -extern void terminate_pnp(void); - -extern int pnp_connect(char *driver_name); -extern void pnp_disconnect(int driver_signature); - -/* - * pnp_get_descr() returns an ASCII desctription string for a device. - * The parameter is an compressed EISA identifier of the device/card. - */ -extern char *pnp_get_descr (int id); - -extern void pnp_enable_device(struct pnp_dev *dev, int state); -extern void pnp_set_port(struct pnp_dev *dev, int selec, unsigned short base); -extern void pnp_set_irq(struct pnp_dev *dev, int selec, unsigned short val); -extern void pnp_set_dma(struct pnp_dev *dev, int selec, unsigned short val); -extern unsigned short pnp_get_port(struct pnp_dev *dev, int selec); -extern unsigned short pnp_get_irq(struct pnp_dev *dev, int selec); -extern unsigned short pnp_get_dma(struct pnp_dev *dev, int selec); -extern int pnp_allocate_device(int driver_sig, struct pnp_dev *dev, int basemask, int irqmask, - int dmamask, int memmask); -extern void pnp_release_device(int driver_sig, struct pnp_dev *dev); -extern int pnp_asc2devid(char *name); -extern char *pnp_devid2asc(int id); -extern void pnp_dump_resources(void); -extern int pnp_device_status (struct pnp_dev *dev); -struct pnp_dev *pnp_get_next_device(int driver_sig, struct pnp_dev *prev); -unsigned char pnp_readreg (struct pnp_dev *dev, int reg); -#endif diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 52374790f..2a9080a8f 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -11,11 +11,13 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "sound_firmware.h" +#include "soundmodule.h" -#if defined(CONFIG_PSS) && defined(CONFIG_AUDIO) +#if (defined(CONFIG_PSS) && defined(CONFIG_AUDIO))||defined(MODULE) /* * PSS registers. @@ -60,10 +62,10 @@ NULL; typedef struct pss_confdata { - int base; - int irq; - int dma; - int *osp; + int base; + int irq; + int dma; + int *osp; } pss_confdata; @@ -75,819 +77,844 @@ static int pss_initialized = 0; static int nonstandard_microcode = 0; static void -pss_write (int data) +pss_write(int data) { - int i, limit; - - limit = jiffies + 10; /* The timeout is 0.1 seconds */ - /* - * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 5000000 && jiffies < limit; i++) - { - if (inw (devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) - { - outw (devc->base + PSS_DATA, data); - return; - } - } - printk ("PSS: DSP Command (%04x) Timeout.\n", data); + int i, limit; + + limit = jiffies + 10; /* The timeout is 0.1 seconds */ + /* + * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 5000000 && jiffies < limit; i++) + { + if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) + { + outw(devc->base + PSS_DATA, data); + return; + } + } + printk("PSS: DSP Command (%04x) Timeout.\n", data); } int -probe_pss (struct address_info *hw_config) +probe_pss(struct address_info *hw_config) { - unsigned short id; - int irq, dma; - - devc->base = hw_config->io_base; - irq = devc->irq = hw_config->irq; - dma = devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - - if (devc->base != 0x220 && devc->base != 0x240) - if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ - return 0; - - if (check_region (devc->base, 16)) - { - printk ("PSS: I/O port conflict\n"); - return 0; - } - - id = inw (REG (PSS_ID)); - if ((id >> 8) != 'E') - { - /* printk ("No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ - return 0; - } - - return 1; + unsigned short id; + int irq, dma; + + devc->base = hw_config->io_base; + irq = devc->irq = hw_config->irq; + dma = devc->dma = hw_config->dma; + devc->osp = hw_config->osp; + + if (devc->base != 0x220 && devc->base != 0x240) + if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ + return 0; + + if (check_region(devc->base, 16)) + { + printk("PSS: I/O port conflict\n"); + return 0; + } + id = inw(REG(PSS_ID)); + if ((id >> 8) != 'E') + { + /* printk( "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ + return 0; + } + return 1; } static int -set_irq (pss_confdata * devc, int dev, int irq) +set_irq(pss_confdata * devc, int dev, int irq) { - static unsigned short irq_bits[16] = - { - 0x0000, 0x0000, 0x0000, 0x0008, - 0x0000, 0x0010, 0x0000, 0x0018, - 0x0000, 0x0020, 0x0028, 0x0030, - 0x0038, 0x0000, 0x0000, 0x0000 - }; - - unsigned short tmp, bits; + static unsigned short irq_bits[16] = + { + 0x0000, 0x0000, 0x0000, 0x0008, + 0x0000, 0x0010, 0x0000, 0x0018, + 0x0000, 0x0020, 0x0028, 0x0030, + 0x0038, 0x0000, 0x0000, 0x0000 + }; - if (irq < 0 || irq > 15) - return 0; + unsigned short tmp, bits; - tmp = inw (REG (dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ + if (irq < 0 || irq > 15) + return 0; - if ((bits = irq_bits[irq]) == 0 && irq != 0) - { - printk ("PSS: Invalid IRQ %d\n", irq); - return 0; - } + tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ - outw (tmp | bits, REG (dev)); - return 1; + if ((bits = irq_bits[irq]) == 0 && irq != 0) + { + printk("PSS: Invalid IRQ %d\n", irq); + return 0; + } + outw(tmp | bits, REG(dev)); + return 1; } static int -set_io_base (pss_confdata * devc, int dev, int base) +set_io_base(pss_confdata * devc, int dev, int base) { - unsigned short tmp = inw (REG (dev)) & 0x003f; - unsigned short bits = (base & 0x0ffc) << 4; + unsigned short tmp = inw(REG(dev)) & 0x003f; + unsigned short bits = (base & 0x0ffc) << 4; - outw (bits | tmp, REG (dev)); + outw(bits | tmp, REG(dev)); - return 1; + return 1; } static int -set_dma (pss_confdata * devc, int dev, int dma) +set_dma(pss_confdata * devc, int dev, int dma) { - static unsigned short dma_bits[8] = - { - 0x0001, 0x0002, 0x0000, 0x0003, - 0x0000, 0x0005, 0x0006, 0x0007 - }; - - unsigned short tmp, bits; + static unsigned short dma_bits[8] = + { + 0x0001, 0x0002, 0x0000, 0x0003, + 0x0000, 0x0005, 0x0006, 0x0007 + }; - if (dma < 0 || dma > 7) - return 0; + unsigned short tmp, bits; - tmp = inw (REG (dev)) & ~0x07; /* Load confreg, mask DMA bits out */ + if (dma < 0 || dma > 7) + return 0; - if ((bits = dma_bits[dma]) == 0 && dma != 4) - { - printk ("PSS: Invalid DMA %d\n", dma); - return 0; - } + tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */ - outw (tmp | bits, REG (dev)); - return 1; + if ((bits = dma_bits[dma]) == 0 && dma != 4) + { + printk("PSS: Invalid DMA %d\n", dma); + return 0; + } + outw(tmp | bits, REG(dev)); + return 1; } static int -pss_reset_dsp (pss_confdata * devc) +pss_reset_dsp(pss_confdata * devc) { - unsigned long i, limit = jiffies + 10; + unsigned long i, limit = jiffies + 10; - outw (0x2000, REG (PSS_CONTROL)); + outw(0x2000, REG(PSS_CONTROL)); - for (i = 0; i < 32768 && jiffies < limit; i++) - inw (REG (PSS_CONTROL)); + for (i = 0; i < 32768 && jiffies < limit; i++) + inw(REG(PSS_CONTROL)); - outw (0x0000, REG (PSS_CONTROL)); + outw(0x0000, REG(PSS_CONTROL)); - return 1; + return 1; } static int -pss_put_dspword (pss_confdata * devc, unsigned short word) +pss_put_dspword(pss_confdata * devc, unsigned short word) { - int i, val; + int i, val; - for (i = 0; i < 327680; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_WRITE_EMPTY) - { - outw (word, REG (PSS_DATA)); - return 1; - } - } - return 0; + for (i = 0; i < 327680; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_WRITE_EMPTY) + { + outw(word, REG(PSS_DATA)); + return 1; + } + } + return 0; } static int -pss_get_dspword (pss_confdata * devc, unsigned short *word) +pss_get_dspword(pss_confdata * devc, unsigned short *word) { - int i, val; + int i, val; - for (i = 0; i < 327680; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_READ_FULL) - { - *word = inw (REG (PSS_DATA)); - return 1; - } - } + for (i = 0; i < 327680; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + { + *word = inw(REG(PSS_DATA)); + return 1; + } + } - return 0; + return 0; } static int -pss_download_boot (pss_confdata * devc, unsigned char *block, int size, int flags) +pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) { - int i, limit, val, count; + int i, limit, val, count; - if (flags & CPF_FIRST) - { + if (flags & CPF_FIRST) + { /*_____ Warn DSP software that a boot is coming */ - outw (0x00fe, REG (PSS_DATA)); + outw(0x00fe, REG(PSS_DATA)); - limit = jiffies + 10; + limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - if (inw (REG (PSS_DATA)) == 0x5500) - break; + for (i = 0; i < 32768 && jiffies < limit; i++) + if (inw(REG(PSS_DATA)) == 0x5500) + break; - outw (*block++, REG (PSS_DATA)); + outw(*block++, REG(PSS_DATA)); - pss_reset_dsp (devc); - } - - count = 1; - while (1) - { - int j; + pss_reset_dsp(devc); + } + count = 1; + while (1) + { + int j; - for (j = 0; j < 327670; j++) - { + for (j = 0; j < 327670; j++) + { /*_____ Wait for BG to appear */ - if (inw (REG (PSS_STATUS)) & PSS_FLAG3) - break; - } - - if (j == 327670) - { - /* It's ok we timed out when the file was empty */ - if (count >= size && flags & CPF_LAST) - break; - else - { - printk ("\nPSS: Download timeout problems, byte %d=%d\n", - count, size); - return 0; - } - } + if (inw(REG(PSS_STATUS)) & PSS_FLAG3) + break; + } + + if (j == 327670) + { + /* It's ok we timed out when the file was empty */ + if (count >= size && flags & CPF_LAST) + break; + else + { + printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size); + return 0; + } + } /*_____ Send the next byte */ - outw (*block++, REG (PSS_DATA)); - count++; - } + outw(*block++, REG(PSS_DATA)); + count++; + } - if (flags & CPF_LAST) - { + if (flags & CPF_LAST) + { /*_____ Why */ - outw (0, REG (PSS_DATA)); - - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - val = inw (REG (PSS_STATUS)); - - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & 0x4000) - break; - } - - /* now read the version */ - for (i = 0; i < 32000; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_READ_FULL) - break; - } - if (i == 32000) - return 0; - - val = inw (REG (PSS_DATA)); - /* printk("<PSS: microcode version %d.%d loaded>", val/16, val % 16); */ - } - - return 1; + outw(0, REG(PSS_DATA)); + + limit = jiffies + 10; + for (i = 0; i < 32768 && jiffies < limit; i++) + val = inw(REG(PSS_STATUS)); + + limit = jiffies + 10; + for (i = 0; i < 32768 && jiffies < limit; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & 0x4000) + break; + } + + /* now read the version */ + for (i = 0; i < 32000; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + break; + } + if (i == 32000) + return 0; + + val = inw(REG(PSS_DATA)); + /* printk( "<PSS: microcode version %d.%d loaded>", val/16, val % 16); */ + } + return 1; } void -attach_pss (struct address_info *hw_config) +attach_pss(struct address_info *hw_config) { - unsigned short id; - char tmp[100]; + unsigned short id; + char tmp[100]; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + devc->osp = hw_config->osp; - if (!probe_pss (hw_config)) - return; + if (!probe_pss(hw_config)) + return; - id = inw (REG (PSS_ID)) & 0x00ff; + id = inw(REG(PSS_ID)) & 0x00ff; - /* - * Disable all emulations. Will be enabled later (if required). - */ - outw (0x0000, REG (CONF_PSS)); /* 0x0400 enables joystick */ - outw (0x0000, REG (CONF_WSS)); - outw (0x0000, REG (CONF_SB)); - outw (0x0000, REG (CONF_MIDI)); - outw (0x0000, REG (CONF_CDROM)); + /* + * Disable all emulations. Will be enabled later (if required). + */ + outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ + outw(0x0000, REG(CONF_WSS)); + outw(0x0000, REG(CONF_SB)); + outw(0x0000, REG(CONF_MIDI)); + outw(0x0000, REG(CONF_CDROM)); #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES - if (sound_alloc_dma (hw_config->dma, "PSS")) - { - printk ("pss.c: Can't allocate DMA channel\n"); - return; - } - - if (!set_irq (devc, CONF_PSS, devc->irq)) - { - printk ("PSS: IRQ error\n"); - return; - } - - if (!set_dma (devc, CONF_PSS, devc->dma)) - { - printk ("PSS: DRQ error\n"); - return; - } + if (sound_alloc_dma(hw_config->dma, "PSS")) + { + printk("pss.c: Can't allocate DMA channel\n"); + return; + } + if (!set_irq(devc, CONF_PSS, devc->irq)) + { + printk("PSS: IRQ error\n"); + return; + } + if (!set_dma(devc, CONF_PSS, devc->dma)) + { + printk("PSS: DRQ error\n"); + return; + } #endif - pss_initialized = 1; - sprintf (tmp, "ECHO-PSS Rev. %d", id); - conf_printf (tmp, hw_config); + pss_initialized = 1; + sprintf(tmp, "ECHO-PSS Rev. %d", id); + conf_printf(tmp, hw_config); } static void -pss_init_speaker (void) +pss_init_speaker(void) { /* Don't ask what are these commands. I really don't know */ - pss_write (0x0010); - pss_write (0x0000 | 252); /* Left master volume */ - pss_write (0x0010); - pss_write (0x0100 | 252); /* Right master volume */ - pss_write (0x0010); - pss_write (0x0200 | 246); /* Bass */ - pss_write (0x0010); - pss_write (0x0300 | 246); /* Treble */ - pss_write (0x0010); - pss_write (0x0800 | 0x00ce); /* Stereo switch? */ + pss_write(0x0010); + pss_write(0x0000 | 252); /* Left master volume */ + pss_write(0x0010); + pss_write(0x0100 | 252); /* Right master volume */ + pss_write(0x0010); + pss_write(0x0200 | 246); /* Bass */ + pss_write(0x0010); + pss_write(0x0300 | 246); /* Treble */ + pss_write(0x0010); + pss_write(0x0800 | 0x00ce); /* Stereo switch? */ } int -probe_pss_mpu (struct address_info *hw_config) +probe_pss_mpu(struct address_info *hw_config) { - int timeout; - - if (!pss_initialized) - return 0; - - if (check_region (hw_config->io_base, 2)) - { - printk ("PSS: MPU I/O port conflict\n"); - return 0; - } - - if (!set_io_base (devc, CONF_MIDI, hw_config->io_base)) - { - printk ("PSS: MIDI base error.\n"); - return 0; - } - - if (!set_irq (devc, CONF_MIDI, hw_config->irq)) - { - printk ("PSS: MIDI IRQ error.\n"); - return 0; - } - - if (!pss_synthLen) - { - printk ("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - return 0; - } - - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return 0; - } - - pss_init_speaker (); + int timeout; + + if (!pss_initialized) + return 0; + + if (check_region(hw_config->io_base, 2)) + { + printk("PSS: MPU I/O port conflict\n"); + return 0; + } + if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) + { + printk("PSS: MIDI base error.\n"); + return 0; + } + if (!set_irq(devc, CONF_MIDI, hw_config->irq)) + { + printk("PSS: MIDI IRQ error.\n"); + return 0; + } + if (!pss_synthLen) + { + printk("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); + return 0; + } + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return 0; + } + pss_init_speaker(); /* * Finally wait until the DSP algorithm has initialized itself and * deactivates receive interrupt. */ - for (timeout = 900000; timeout > 0; timeout--) - { - if ((inb (hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ - inb (hw_config->io_base); /* Discard it */ - else - break; /* No more input */ - } + for (timeout = 900000; timeout > 0; timeout--) + { + if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ + inb(hw_config->io_base); /* Discard it */ + else + break; /* No more input */ + } #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - return probe_mpu401 (hw_config); + return probe_mpu401(hw_config); #else - return 0; + return 0; #endif } static int -pss_coproc_open (void *dev_info, int sub_device) +pss_coproc_open(void *dev_info, int sub_device) { - switch (sub_device) - { - case COPR_MIDI: - - if (pss_synthLen == 0) - { - printk ("PSS: MIDI synth microcode not available.\n"); - return -EIO; - } - - if (nonstandard_microcode) - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + switch (sub_device) { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; + case COPR_MIDI: + + if (pss_synthLen == 0) + { + printk("PSS: MIDI synth microcode not available.\n"); + return -EIO; + } + if (nonstandard_microcode) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return -EIO; + } + nonstandard_microcode = 0; + break; + + default:; } - nonstandard_microcode = 0; - break; - - default:; - } - return 0; + return 0; } static void -pss_coproc_close (void *dev_info, int sub_device) +pss_coproc_close(void *dev_info, int sub_device) { - return; + return; } static void -pss_coproc_reset (void *dev_info) +pss_coproc_reset(void *dev_info) { - if (pss_synthLen) - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - } - nonstandard_microcode = 0; + if (pss_synthLen) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + } + nonstandard_microcode = 0; } static int -download_boot_block (void *dev_info, copr_buffer * buf) +download_boot_block(void *dev_info, copr_buffer * buf) { - if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; - - if (!pss_download_boot (devc, buf->data, buf->len, buf->flags)) - { - printk ("PSS: Unable to load microcode block to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - - return 0; -} + if (buf->len <= 0 || buf->len > sizeof(buf->data)) + return -EINVAL; -static int -pss_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) -{ - /* printk("PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - - switch (cmd) - { - case SNDCTL_COPR_RESET: - pss_coproc_reset (dev_info); - return 0; - break; - - case SNDCTL_COPR_LOAD: - { - copr_buffer *buf; - int err; - - buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); - if (buf == NULL) - return -ENOSPC; - - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - err = download_boot_block (dev_info, buf); - vfree (buf); - return err; - } - break; - - case SNDCTL_COPR_SENDMSG: - { - copr_msg *buf; - unsigned long flags; - unsigned short *data; - int i; - - buf = (copr_msg *) vmalloc (sizeof (copr_msg)); - if (buf == NULL) - return -ENOSPC; - - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - - data = (unsigned short *) (buf->data); - - save_flags (flags); - cli (); - - for (i = 0; i < buf->len; i++) + if (!pss_download_boot(devc, buf->data, buf->len, buf->flags)) { - if (!pss_put_dspword (devc, *data++)) - { - restore_flags (flags); - buf->len = i; /* feed back number of WORDs sent */ - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); - return -EIO; - } + printk("PSS: Unable to load microcode block to DSP.\n"); + return -EIO; } - - restore_flags (flags); - vfree (buf); + nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ return 0; - } - break; - - - case SNDCTL_COPR_RCVMSG: - { - copr_msg *buf; - unsigned long flags; - unsigned short *data; - unsigned int i; - int err = 0; - - buf = (copr_msg *) vmalloc (sizeof (copr_msg)); - if (buf == NULL) - return -ENOSPC; - - - data = (unsigned short *) buf->data; +} - save_flags (flags); - cli (); +static int +pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local) +{ + /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - for (i = 0; i < buf->len; i++) + switch (cmd) { - buf->len = i; /* feed back number of WORDs read */ - if (!pss_get_dspword (devc, data++)) - { - if (i == 0) - err = -EIO; - break; - } + case SNDCTL_COPR_RESET: + pss_coproc_reset(dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + if (buf == NULL) + return -ENOSPC; + + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + err = download_boot_block(dev_info, buf); + vfree(buf); + return err; + } + break; + + case SNDCTL_COPR_SENDMSG: + { + copr_msg *buf; + unsigned long flags; + unsigned short *data; + int i; + + buf = (copr_msg *) vmalloc(sizeof(copr_msg)); + if (buf == NULL) + return -ENOSPC; + + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + + data = (unsigned short *) (buf->data); + + save_flags(flags); + cli(); + + for (i = 0; i < buf->len; i++) + { + if (!pss_put_dspword(devc, *data++)) + { + restore_flags(flags); + buf->len = i; /* feed back number of WORDs sent */ + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); + return -EIO; + } + } + + restore_flags(flags); + vfree(buf); + + return 0; + } + break; + + + case SNDCTL_COPR_RCVMSG: + { + copr_msg *buf; + unsigned long flags; + unsigned short *data; + unsigned int i; + int err = 0; + + buf = (copr_msg *) vmalloc(sizeof(copr_msg)); + if (buf == NULL) + return -ENOSPC; + + + data = (unsigned short *) buf->data; + + save_flags(flags); + cli(); + + for (i = 0; i < buf->len; i++) + { + buf->len = i; /* feed back number of WORDs read */ + if (!pss_get_dspword(devc, data++)) + { + if (i == 0) + err = -EIO; + break; + } + } + + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); + + return err; + } + break; + + + case SNDCTL_COPR_RDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d0)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) + { + restore_flags(flags); + return -EIO; + } + buf.parm1 = tmp; + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf)); + return 0; + } + break; + + case SNDCTL_COPR_WDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d1)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int) buf.parm2 & 0xffff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + restore_flags(flags); + return 0; + } + break; + + case SNDCTL_COPR_WCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d3)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int) buf.parm2 & 0x00ff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + restore_flags(flags); + return 0; + } + break; + + case SNDCTL_COPR_RCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d2)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) /* Read MSB */ + { + restore_flags(flags); + return -EIO; + } + buf.parm1 = tmp << 8; + + if (!pss_get_dspword(devc, &tmp)) /* Read LSB */ + { + restore_flags(flags); + return -EIO; + } + buf.parm1 |= tmp & 0x00ff; + + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf)); + return 0; + } + break; + + default: + return -EINVAL; } - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); - - return err; - } - break; + return -EINVAL; +} +static coproc_operations pss_coproc_operations = +{ + "ADSP-2115", + pss_coproc_open, + pss_coproc_close, + pss_coproc_ioctl, + pss_coproc_reset, + &pss_data +}; - case SNDCTL_COPR_RDATA: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; +void +attach_pss_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + { + attach_mpu401(hw_config); /* Slot 1 */ - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; + } +#endif +} - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d0)) - { - restore_flags (flags); - return -EIO; - } +int +probe_pss_mss(struct address_info *hw_config) +{ + volatile int timeout; - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } + if (!pss_initialized) + return 0; - if (!pss_get_dspword (devc, &tmp)) + if (check_region(hw_config->io_base, 8)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS I/O port conflict\n"); + return 0; } - - buf.parm1 = tmp; - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) &buf, sizeof (buf)); - return 0; - } - break; - - case SNDCTL_COPR_WDATA: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; - - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); - - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d1)) + if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS base error.\n"); + return 0; } - - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + if (!set_irq(devc, CONF_WSS, hw_config->irq)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS IRQ error.\n"); + return 0; } - - tmp = (unsigned int) buf.parm2 & 0xffff; - if (!pss_put_dspword (devc, tmp)) + if (!set_dma(devc, CONF_WSS, hw_config->dma)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS DRQ error\n"); + return 0; } + /* + * For some reason the card returns 0xff in the WSS status register + * immediately after boot. Probably MIDI+SB emulation algorithm + * downloaded to the ADSP2115 spends some time initializing the card. + * Let's try to wait until it finishes this task. + */ + for (timeout = 0; + timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04; + timeout++); + + outb((0x0b), hw_config->io_base + 4); /* Required by some cards */ + + for (timeout = 0; + timeout < 100000; + timeout++); + return probe_ms_sound(hw_config); +} - restore_flags (flags); - return 0; - } - break; +void +attach_pss_mss(struct address_info *hw_config) +{ + attach_ms_sound(hw_config); /* Slot 0 */ - case SNDCTL_COPR_WCODE: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; + if (hw_config->slots[0] != -1) /* The MSS driver installed itself */ + audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; +} - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); +void +unload_pss(struct address_info *hw_config) +{ +} - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d3)) - { - restore_flags (flags); - return -EIO; - } +void +unload_pss_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + unload_mpu401(hw_config); +#endif +} - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } +void +unload_pss_mss(struct address_info *hw_config) +{ + unload_ms_sound(hw_config); +} - tmp = (unsigned int) buf.parm2 & 0x00ff; - if (!pss_put_dspword (devc, tmp)) - { - restore_flags (flags); - return -EIO; - } +#ifdef MODULE - tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; - if (!pss_put_dspword (devc, tmp)) - { - restore_flags (flags); - return -EIO; - } +int io = -1; +int irq = -1; +int dma = -1; - restore_flags (flags); - return 0; - } - break; +int pssmpu, pssmss; +struct address_info cfg; - case SNDCTL_COPR_RCODE: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; +static int fw_load = 0; - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); +/* + * Load a PSS sound card module + */ - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d2)) +int +init_module(void) +{ + if (io == -1 || irq == -1 || dma == -1) { - restore_flags (flags); - return -EIO; + printk("pss: dma, irq and io must be set.\n"); + return -EINVAL; } + cfg.io_base = io; + cfg.irq = irq; - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + if (!pss_synth) { - restore_flags (flags); - return -EIO; + fw_load = 1; + pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); } - - if (!pss_get_dspword (devc, &tmp)) /* Read MSB */ + if (probe_pss(&cfg)) + return -ENODEV; + /* + * Attach stuff + */ + if (probe_pss_mpu(&cfg)) { - restore_flags (flags); - return -EIO; + pssmpu = 1; + attach_pss_mpu(&cfg); } - - buf.parm1 = tmp << 8; - - if (!pss_get_dspword (devc, &tmp)) /* Read LSB */ + if (probe_pss_mss(&cfg)) { - restore_flags (flags); - return -EIO; + pssmss = 1; + attach_pss_mss(&cfg); } - - buf.parm1 |= tmp & 0x00ff; - - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) &buf, sizeof (buf)); + SOUND_LOCK; return 0; - } - break; - - default: - return -EINVAL; - } - - return -EINVAL; -} - -static coproc_operations pss_coproc_operations = -{ - "ADSP-2115", - pss_coproc_open, - pss_coproc_close, - pss_coproc_ioctl, - pss_coproc_reset, - &pss_data -}; - -void -attach_pss_mpu (struct address_info *hw_config) -{ -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - { - int prev_devs; - - prev_devs = num_midis; - attach_mpu401 (hw_config); - - if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ - midi_devs[prev_devs]->coproc = &pss_coproc_operations; - } -#endif -} - -int -probe_pss_mss (struct address_info *hw_config) -{ - volatile int timeout; - - if (!pss_initialized) - return 0; - - if (check_region (hw_config->io_base, 8)) - { - printk ("PSS: WSS I/O port conflict\n"); - return 0; - } - - if (!set_io_base (devc, CONF_WSS, hw_config->io_base)) - { - printk ("PSS: WSS base error.\n"); - return 0; - } - - if (!set_irq (devc, CONF_WSS, hw_config->irq)) - { - printk ("PSS: WSS IRQ error.\n"); - return 0; - } - - if (!set_dma (devc, CONF_WSS, hw_config->dma)) - { - printk ("PSS: WSS DRQ error\n"); - return 0; - } - - /* - * For some reason the card returns 0xff in the WSS status register - * immediately after boot. Probably MIDI+SB emulation algorithm - * downloaded to the ADSP2115 spends some time initializing the card. - * Let's try to wait until it finishes this task. - */ - for (timeout = 0; - timeout < 100000 && (inb (hw_config->io_base + 3) & 0x3f) != 0x04; - timeout++); - - outb ((0x0b), hw_config->io_base + 4); /* Required by some cards */ - - for (timeout = 0; - timeout < 100000; - timeout++); - return probe_ms_sound (hw_config); -} - -void -attach_pss_mss (struct address_info *hw_config) -{ - int prev_devs; - - prev_devs = num_audiodevs; - attach_ms_sound (hw_config); - - if (num_audiodevs == (prev_devs + 1)) /* The MSS driver installed itself */ - audio_devs[prev_devs]->coproc = &pss_coproc_operations; } -void -unload_pss (struct address_info *hw_config) +void +cleanup_module(void) { + if (fw_load && pss_synth) + kfree(pss_synth); + if (pssmss) + unload_pss_mss(&cfg); + if (pssmpu) + unload_pss_mpu(&cfg); + unload_pss(&cfg); + SOUND_LOCK_END; } - -void -unload_pss_mpu (struct address_info *hw_config) -{ -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); #endif -} - -void -unload_pss_mss (struct address_info *hw_config) -{ - unload_ms_sound (hw_config); -} #endif diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index ba2f3be18..861f13c3b 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -1,3 +1,4 @@ +#ifdef CONFIG_SBDSP #define DSP_RESET (devc->base + 0x6) #define DSP_READ (devc->base + 0xA) #define DSP_WRITE (devc->base + 0xC) @@ -124,3 +125,6 @@ void sb_audio_init (sb_devc *devc, char *name); void sb_midi_interrupt (sb_devc *devc); int ess_write (sb_devc *devc, unsigned char reg, unsigned char data); int ess_read (sb_devc *devc, unsigned char reg); + +extern int acer; +#endif diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index a4e29ba8c..13751da3d 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -15,89 +15,88 @@ #include "sound_config.h" -#if defined(CONFIG_SBDSP) +#if defined(CONFIG_SBDSP) || defined(MODULE) #include "sb_mixer.h" #include "sb.h" static int -sb_audio_open (int dev, int mode) +sb_audio_open(int dev, int mode) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - { - printk ("SB: Incomplete initialization\n"); - return -ENXIO; - } - - if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) - { - printk ("SB: Recording is not possible with this device\n"); - return -EPERM; - } - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - return -EBUSY; - } - - if (devc->dma16 != -1 && devc->dma16 != devc->dma8) - { - if (sound_open_dma (devc->dma16, "Sound Blaster 16 bit")) - { - return -EBUSY; - } - } - devc->opened = mode; - restore_flags (flags); - - devc->irq_mode = IMODE_NONE; - sb_dsp_reset (devc); - - return 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + { + printk("SB: Incomplete initialization\n"); + return -ENXIO; + } + if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) + { + printk("Notice: Recording is not possible with /dev/dsp%d\n", dev); + if (mode == OPEN_READ) + return -EPERM; + } + save_flags(flags); + cli(); + if (devc->opened) + { + restore_flags(flags); + return -EBUSY; + } + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + { + if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) + { + restore_flags(flags); + return -EBUSY; + } + } + devc->opened = mode; + restore_flags(flags); + + devc->irq_mode = IMODE_NONE; + sb_dsp_reset(devc); + + return 0; } static void -sb_audio_close (int dev) +sb_audio_close(int dev) { - sb_devc *devc = audio_devs[dev]->devc; + 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_in->dma = + audio_devs[dev]->dmap_out->dma = + devc->dma8; - if (devc->dma16 != -1 && devc->dma16 != devc->dma8) - sound_close_dma (devc->dma16); + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + sound_close_dma(devc->dma16); - devc->opened = 0; + devc->opened = 0; } static void -sb_set_output_parms (int dev, unsigned long buf, int nr_bytes, - int intrflag) +sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - sb_devc *devc = audio_devs[dev]->devc; + 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; + devc->trg_buf = buf; + devc->trg_bytes = nr_bytes; + devc->trg_intrflag = intrflag; + devc->irq_mode = IMODE_OUTPUT; } static void -sb_set_input_parms (int dev, unsigned long buf, int count, int intrflag) +sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; + devc->trg_buf = buf; + devc->trg_bytes = count; + devc->trg_intrflag = intrflag; + devc->irq_mode = IMODE_INPUT; } /* @@ -105,183 +104,180 @@ sb_set_input_parms (int dev, unsigned long buf, int count, int intrflag) */ static void -sb1_audio_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag) +sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x14)) /* 8 bit DAC using DMA */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - } - else - printk ("SB: Unable to start DAC\n"); - restore_flags (flags); - devc->intr_active = 1; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x14)) /* 8 bit DAC using DMA */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + } else + printk("SB: Unable to start DAC\n"); + restore_flags(flags); + devc->intr_active = 1; } static void -sb1_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag) +sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x24)) /* 8 bit ADC using DMA */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - } - else - printk ("SB Error: Unable to start ADC\n"); - restore_flags (flags); - - devc->intr_active = 1; -} + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; -static void -sb1_audio_trigger (int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ - bits &= devc->irq_mode; + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb1_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb1_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; - devc->trigger_bits = bits; + devc->irq_mode = IMODE_INPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x24)) /* 8 bit ADC using DMA */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + } else + printk("SB Error: Unable to start ADC\n"); + restore_flags(flags); + + devc->intr_active = 1; } -static int -sb1_audio_prepare_for_input (int dev, int bsize, int bcount) +static void +sb1_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKOFF); - restore_flags (flags); - - devc->trigger_bits = 0; - return 0; + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } + } + + devc->trigger_bits = bits; } static int -sb1_audio_prepare_for_output (int dev, int bsize, int bcount) +sb1_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKON); - restore_flags (flags); - devc->trigger_bits = 0; - return 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKOFF); + restore_flags(flags); + + devc->trigger_bits = 0; + return 0; } static int -sb1_audio_set_speed (int dev, int speed) +sb1_audio_prepare_for_output(int dev, int bsize, int bcount) { - int max_speed = 23000; - sb_devc *devc = audio_devs[dev]->devc; - int tmp; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKON); + restore_flags(flags); + devc->trigger_bits = 0; + return 0; +} - if (devc->opened & OPEN_READ) - max_speed = 13000; +static int +sb1_audio_set_speed(int dev, int speed) +{ + int max_speed = 23000; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; - if (speed > 0) - { - if (speed < 4000) - speed = 4000; + if (devc->opened & OPEN_READ) + max_speed = 13000; - if (speed > max_speed) - speed = max_speed; + if (speed > 0) + { + if (speed < 4000) + speed = 4000; - devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; + if (speed > max_speed) + speed = max_speed; - tmp = 256 - devc->tconst; - speed = (1000000 + tmp / 2) / tmp; + devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - devc->speed = speed; - } + tmp = 256 - devc->tconst; + speed = (1000000 + tmp / 2) / tmp; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } static short -sb1_audio_set_channels (int dev, short channels) +sb1_audio_set_channels(int dev, short channels) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - return devc->channels = 1; + return devc->channels = 1; } static unsigned int -sb1_audio_set_bits (int dev, unsigned int bits) +sb1_audio_set_bits(int dev, unsigned int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - return devc->bits = 8; + return devc->bits = 8; } static void -sb1_audio_halt_xfer (int dev) +sb1_audio_halt_xfer(int dev) { - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; - save_flags (flags); - cli (); - sb_dsp_reset (devc); - restore_flags (flags); + save_flags(flags); + cli(); + sb_dsp_reset(devc); + restore_flags(flags); } /* @@ -289,112 +285,110 @@ sb1_audio_halt_xfer (int dev) */ static void -sb20_audio_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag) +sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= 23000) - cmd = 0x1c; /* 8 bit PCM output */ - else - cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ - - if (!sb_dsp_command (devc, cmd)) - printk ("SB: Unable to start DAC\n"); - - } - else - printk ("SB: Unable to start DAC\n"); - restore_flags (flags); - devc->intr_active = 1; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= 23000) + cmd = 0x1c; /* 8 bit PCM output */ + else + cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ + + if (!sb_dsp_command(devc, cmd)) + printk("SB: Unable to start DAC\n"); + + } else + printk("SB: Unable to start DAC\n"); + restore_flags(flags); + devc->intr_active = 1; } static void -sb20_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag) +sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) - cmd = 0x2c; /* 8 bit PCM input */ - else - cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ - - if (!sb_dsp_command (devc, cmd)) - printk ("SB: Unable to start ADC\n"); - } - else - printk ("SB Error: Unable to start ADC\n"); - restore_flags (flags); - - devc->intr_active = 1; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) + cmd = 0x2c; /* 8 bit PCM input */ + else + cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ + + if (!sb_dsp_command(devc, cmd)) + printk("SB: Unable to start ADC\n"); + } else + printk("SB Error: Unable to start ADC\n"); + restore_flags(flags); + + devc->intr_active = 1; } static void -sb20_audio_trigger (int dev, int bits) +sb20_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; - - bits &= devc->irq_mode; - - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb20_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb20_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } - - devc->trigger_bits = bits; + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } + } + + devc->trigger_bits = bits; } /* @@ -402,33 +396,32 @@ sb20_audio_trigger (int dev, int bits) */ static int -sb201_audio_set_speed (int dev, int speed) +sb201_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - int s = speed * devc->channels; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + int s = speed * devc->channels; - if (speed > 44100) - speed = 44100; + if (speed > 0) + { + if (speed < 4000) + speed = 4000; - if (devc->opened & OPEN_READ && speed > 15000) - speed = 15000; + if (speed > 44100) + speed = 44100; - devc->tconst = ((65536 - ((256000000 + s / 2) / - s)) >> 8) & 0xff; + if (devc->opened & OPEN_READ && speed > 15000) + speed = 15000; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; - devc->speed = speed; - } + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } /* @@ -436,144 +429,145 @@ sb201_audio_set_speed (int dev, int speed) */ static int -sbpro_audio_prepare_for_input (int dev, int bsize, int bcount) +sbpro_audio_prepare_for_input(int dev, int bsize, int bcount) { /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char bits = 0; - - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; - - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKOFF); - if (devc->channels == 1) - sb_dsp_command (devc, 0xa0 | bits); /* Mono input */ - else - sb_dsp_command (devc, 0xa8 | bits); /* Stereo input */ - restore_flags (flags); - - devc->trigger_bits = 0; - return 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == 16 ? devc->dma16 : devc->dma8; + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKOFF); + if (devc->channels == 1) + sb_dsp_command(devc, 0xa0 | bits); /* Mono input */ + else + sb_dsp_command(devc, 0xa8 | bits); /* Stereo input */ + restore_flags(flags); + + devc->trigger_bits = 0; + return 0; } static int -sbpro_audio_prepare_for_output (int dev, int bsize, int bcount) +sbpro_audio_prepare_for_output(int dev, int bsize, int bcount) { /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char tmp; - unsigned char bits = 0; - - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; - if (devc->model == MDL_SBPRO) - sb_mixer_set_stereo (devc, devc->channels == 2); - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKON); - - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - { - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - if (devc->channels == 1) - sb_dsp_command (devc, 0xa0 | bits); /* Mono output */ - else - sb_dsp_command (devc, 0xa8 | bits); /* Stereo output */ - } - else - { - tmp = sb_getmixer (devc, 0x0e); - if (devc->channels == 1) - tmp &= ~0x02; - else - tmp |= 0x02; - sb_setmixer (devc, 0x0e, tmp); - } - restore_flags (flags); - devc->trigger_bits = 0; - return 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char tmp; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == 16 ? devc->dma16 : devc->dma8; + if (devc->model == MDL_SBPRO) + sb_mixer_set_stereo(devc, devc->channels == 2); + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKON); + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + { + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + if (devc->channels == 1) + sb_dsp_command(devc, 0xa0 | bits); /* Mono output */ + else + sb_dsp_command(devc, 0xa8 | bits); /* Stereo output */ + } else + { + tmp = sb_getmixer(devc, 0x0e); + if (devc->channels == 1) + tmp &= ~0x02; + else + tmp |= 0x02; + sb_setmixer(devc, 0x0e, tmp); + } + restore_flags(flags); + devc->trigger_bits = 0; + return 0; } static int -sbpro_audio_set_speed (int dev, int speed) +sbpro_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; + sb_devc *devc = audio_devs[dev]->devc; - if (speed > 44100) - speed = 44100; + if (speed > 0) + { + if (speed < 4000) + speed = 4000; - if (devc->channels > 1 && speed > 22050) - speed = 22050; + if (speed > 44100) + speed = 44100; - sb201_audio_set_speed (dev, speed); - } + if (devc->channels > 1 && speed > 22050) + speed = 22050; - return devc->speed; + sb201_audio_set_speed(dev, speed); + } + return devc->speed; } static short -sbpro_audio_set_channels (int dev, short channels) +sbpro_audio_set_channels(int dev, short channels) { - sb_devc *devc = audio_devs[dev]->devc; - - if (channels == 1 || channels == 2) - if (channels != devc->channels) - { - devc->channels = channels; - if (devc->model == MDL_SBPRO) - sbpro_audio_set_speed (dev, devc->speed); - } - return devc->channels; + sb_devc *devc = audio_devs[dev]->devc; + + if (channels == 1 || channels == 2) + if (channels != devc->channels) + { + devc->channels = channels; + if (devc->model == MDL_SBPRO && devc->channels == 2) + { + if (devc->speed > 22050) + printk("OSS: Application error. Wrong ioctl call order.\n"); + sbpro_audio_set_speed(dev, devc->speed); + } + } + return devc->channels; } static int -jazz16_audio_set_speed (int dev, int speed) +jazz16_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - int tmp; - int s = speed * devc->channels; + sb_devc *devc = audio_devs[dev]->devc; - if (speed < 5000) - speed = 4000; + if (speed > 0) + { + int tmp; + int s = speed * devc->channels; - if (speed > 44100) - speed = 44100; + if (speed < 5000) + speed = 4000; - devc->tconst = ((65536 - ((256000000 + s / 2) / - s)) >> 8) & 0xff; + if (speed > 44100) + speed = 44100; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; - devc->speed = speed; - } + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } /* @@ -581,620 +575,601 @@ jazz16_audio_set_speed (int dev, int speed) */ static int -ess_audio_set_speed (int dev, int speed) +ess_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - int divider; - - if (speed > 0) - { - if (speed < 5000) - speed = 4000; - - if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - divider = (795500 + speed / 2) / speed; - speed = (795500 + divider / 2) / divider; - } - else - { - divider = (397700 + speed / 2) / speed; - speed = (397700 + divider / 2) / divider; - } - - devc->speed = speed; - } - - return devc->speed; + sb_devc *devc = audio_devs[dev]->devc; + int divider; + + if (speed > 0) + { + if (speed < 5000) + speed = 4000; + + if (speed > 48000) + speed = 48000; + + if (speed > 22000) + { + divider = (795500 + speed / 2) / speed; + speed = (795500 + divider / 2) / divider; + } else + { + divider = (397700 + speed / 2) / speed; + speed = (397700 + divider / 2) / divider; + } + + devc->speed = speed; + } + return devc->speed; } static void -ess_speed (sb_devc * devc) +ess_speed(sb_devc * devc) { - int divider; - unsigned char bits = 0; - int speed = devc->speed; - - if (speed < 4000) - speed = 4000; - else if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - } - else - { - divider = 128 - (397700 + speed / 2) / speed; - } - - bits |= (unsigned char) divider; - ess_write (devc, 0xa1, bits); + int divider; + unsigned char bits = 0; + int speed = devc->speed; + + if (speed < 4000) + speed = 4000; + else if (speed > 48000) + speed = 48000; + + if (speed > 22000) + { + bits = 0x80; + divider = 256 - (795500 + speed / 2) / speed; + } else + { + divider = 128 - (397700 + speed / 2) / speed; + } + + bits |= (unsigned char) divider; + ess_write(devc, 0xa1, bits); /* * Set filter divider register */ - speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ - divider = 256 - 7160000 / (speed * 82); - ess_write (devc, 0xa2, divider); + speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ + divider = 256 - 7160000 / (speed * 82); + ess_write(devc, 0xa2, divider); - return; + return; } static int -ess_audio_prepare_for_input (int dev, int bsize, int bcount) +ess_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - - ess_speed (devc); - sb_dsp_command (devc, DSP_CMD_SPKOFF); - - ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | - (3 - devc->channels)); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ - - if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { /* 8 bit mono */ - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (devc->bits == AFMT_U8) - { /* 8 bit stereo */ - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xbc); - } - } - - ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); - ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); - - devc->trigger_bits = 0; - return 0; + sb_devc *devc = audio_devs[dev]->devc; + + ess_speed(devc); + sb_dsp_command(devc, DSP_CMD_SPKOFF); + + ess_write(devc, 0xb8, 0x0e); /* Auto init DMA mode */ + ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0xd0); + } else + { /* 16 bit mono */ + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xf4); + } + } else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0x98); + } else + { /* 16 bit stereo */ + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xbc); + } + } + + ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); + ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); + + devc->trigger_bits = 0; + return 0; } -static int -ess_audio_prepare_for_output (int dev, int bsize, int bcount) +static int ess_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - - sb_dsp_reset (devc); - ess_speed (devc); - - ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ - ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | - (3 - devc->channels)); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ - - if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { /* 8 bit mono */ - ess_write (devc, 0xb6, 0x80); - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (devc, 0xb6, 0x00); - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (devc->bits == AFMT_U8) - { /* 8 bit stereo */ - ess_write (devc, 0xb6, 0x80); - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0x98); + sb_devc *devc = audio_devs[dev]->devc; + + sb_dsp_reset(devc); + ess_speed(devc); + + ess_write(devc, 0xb8, 4); /* Auto init DMA mode */ + ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write(devc, 0xb6, 0x80); + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0xd0); + } else + { /* 16 bit mono */ + ess_write(devc, 0xb6, 0x00); + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xf4); + } } - else - { /* 16 bit stereo */ - ess_write (devc, 0xb6, 0x00); - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xbc); + else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write(devc, 0xb6, 0x80); + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write(devc, 0xb6, 0x00); + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xbc); + } } - } - ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); - ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); - sb_dsp_command (devc, DSP_CMD_SPKON); + ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); + ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); + sb_dsp_command(devc, DSP_CMD_SPKON); - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static void -ess_audio_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag) +static void ess_audio_output_block(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; - devc->irq_mode = IMODE_OUTPUT; + devc->irq_mode = IMODE_OUTPUT; - ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + ess_write(devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write(devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x05); /* Go */ - devc->intr_active = 1; + ess_write(devc, 0xb8, ess_read(devc, 0xb8) | 0x05); /* Go */ + devc->intr_active = 1; } -static void -ess_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag) +static void ess_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; - devc->irq_mode = IMODE_INPUT; + devc->irq_mode = IMODE_INPUT; - ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + ess_write(devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write(devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x0f); /* Go */ - devc->intr_active = 1; + ess_write(devc, 0xb8, ess_read(devc, 0xb8) | 0x0f); /* Go */ + devc->intr_active = 1; } -static void -ess_audio_trigger (int dev, int bits) +static void ess_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; + bits &= devc->irq_mode; - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else { - case IMODE_INPUT: - ess_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - ess_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; + switch (devc->irq_mode) + { + case IMODE_INPUT: + ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } } - } - devc->trigger_bits = bits; + devc->trigger_bits = bits; } /* * SB16 specific routines */ -static int -sb16_audio_set_speed (int dev, int speed) +static int sb16_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - if (speed < 5000) - speed = 4000; + sb_devc *devc = audio_devs[dev]->devc; - if (speed > 44100) - speed = 44100; + if (speed > 0) + { + if (speed < 5000) + speed = 4000; - devc->speed = speed; - } + if (speed > 44100) + speed = 44100; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } -static unsigned int -sb16_audio_set_bits (int dev, unsigned int bits) +static unsigned int sb16_audio_set_bits(int dev, unsigned int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - if (bits != 0) - if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE) - devc->bits = bits; - else - devc->bits = AFMT_U8; + if (bits != 0) + { + if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE) + devc->bits = bits; + else + devc->bits = AFMT_U8; + } - return devc->bits; + return devc->bits; } -static int -sb16_audio_prepare_for_input (int dev, int bsize, int bcount) +static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + 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; + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static int -sb16_audio_prepare_for_output (int dev, int bsize, int bcount) +static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + 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; + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static void -sb16_audio_output_block (int dev, unsigned long buf, int count, - int intrflag) +static void sb16_audio_output_block(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags, cnt; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; - devc->irq_mode = IMODE_OUTPUT; - devc->intr_active = 1; + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - sb_dsp_command (devc, 0x41); - sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); - sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + sb_dsp_command(devc, 0x41); + sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); - sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); - sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + - (devc->bits == AFMT_S16_LE ? 0x10 : 0))); - sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); - sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); + sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command(devc, (unsigned char) (cnt >> 8)); - restore_flags (flags); + restore_flags(flags); } -static void -sb16_audio_start_input (int dev, unsigned long buf, int count, int intrflag) +static void sb16_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags, cnt; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; - devc->irq_mode = IMODE_INPUT; - devc->intr_active = 1; + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - sb_dsp_command (devc, 0x42); - sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); - sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + sb_dsp_command(devc, 0x42); + sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); - sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); - sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + - (devc->bits == AFMT_S16_LE ? 0x10 : 0))); - sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); - sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); + sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command(devc, (unsigned char) (cnt >> 8)); - restore_flags (flags); + restore_flags(flags); } -static void -sb16_audio_trigger (int dev, int bits) +static void sb16_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; + bits &= devc->irq_mode; - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else { - 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; + } } - } - devc->trigger_bits = bits; + devc->trigger_bits = bits; } -static int -sb_audio_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int sb_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static struct audio_driver sb1_audio_driver = /* SB1.x */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb1_audio_trigger, - sb1_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb1_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels }; static struct audio_driver sb20_audio_driver = /* SB2.0 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sb1_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels }; static struct audio_driver sb201_audio_driver = /* SB2.01 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sb201_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb201_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels }; static struct audio_driver sbpro_audio_driver = /* SB Pro */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sbpro_audio_prepare_for_input, - sbpro_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sbpro_audio_set_speed, - sb1_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sbpro_audio_set_speed, + sb1_audio_set_bits, + sbpro_audio_set_channels }; static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sbpro_audio_prepare_for_input, - sbpro_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - jazz16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + jazz16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels }; static struct audio_driver sb16_audio_driver = /* SB16 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb16_audio_prepare_for_input, - sb16_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb16_audio_trigger, - sb16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb16_audio_prepare_for_input, + sb16_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb16_audio_trigger, + sb16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels }; static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - ess_audio_prepare_for_input, - ess_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - ess_audio_trigger, - ess_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + ess_audio_prepare_for_input, + ess_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + ess_audio_trigger, + ess_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels }; -void -sb_audio_init (sb_devc * devc, char *name) +void sb_audio_init(sb_devc * devc, char *name) { - int audio_flags = 0; - int format_mask = AFMT_U8; - - struct audio_driver *driver = &sb1_audio_driver; - - switch (devc->model) - { - case MDL_SB1: /* SB1.0 or SB 1.5 */ - DDB (printk ("Will use standard SB1.x driver\n")); - audio_flags = DMA_HARDSTOP; - break; - - case MDL_SB2: - DDB (printk ("Will use SB2.0 driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sb20_audio_driver; - break; - - case MDL_SB201: - DDB (printk ("Will use SB2.01 (high speed) driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sb201_audio_driver; - break; - - case MDL_JAZZ: - case MDL_SMW: - DDB (printk ("Will use Jazz16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &jazz16_audio_driver; - break; - - case MDL_ESS: - DDB (printk ("Will use ESS ES688/1688 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &ess_audio_driver; - break; - - case MDL_SB16: - DDB (printk ("Will use SB16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &sb16_audio_driver; - break; - - default: - DDB (printk ("Will use SB Pro driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sbpro_audio_driver; - } - - 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) - { - return; - } - - audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev; - audio_devs[devc->my_dev]->min_fragment = 5; + int audio_flags = 0; + int format_mask = AFMT_U8; + + struct audio_driver *driver = &sb1_audio_driver; + + switch (devc->model) + { + case MDL_SB1: /* SB1.0 or SB 1.5 */ + DDB(printk("Will use standard SB1.x driver\n")); + audio_flags = DMA_HARDSTOP; + break; + + case MDL_SB2: + DDB(printk("Will use SB2.0 driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb20_audio_driver; + break; + + case MDL_SB201: + DDB(printk("Will use SB2.01 (high speed) driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb201_audio_driver; + break; + + case MDL_JAZZ: + case MDL_SMW: + DDB(printk("Will use Jazz16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &jazz16_audio_driver; + break; + + case MDL_ESS: + DDB(printk("Will use ESS ES688/1688 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &ess_audio_driver; + break; + + case MDL_SB16: + DDB(printk("Will use SB16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &sb16_audio_driver; + break; + + default: + DDB(printk("Will use SB Pro driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sbpro_audio_driver; + } + + 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) + { + printk(KERN_ERR "sb: unable to install audio.\n"); + return; + } + audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev; + audio_devs[devc->my_dev]->min_fragment = 5; } #endif diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index d6e4bc67a..57cdc59e3 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -11,40 +11,150 @@ * for more info. */ #include <linux/config.h> +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_SBDSP) +#if defined(CONFIG_SBDSP) || defined (MODULE) #include "sb_mixer.h" #include "sb.h" void -attach_sb_card (struct address_info *hw_config) +attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) - sb_dsp_init (hw_config); + sb_dsp_init(hw_config); #endif } int -probe_sb (struct address_info *hw_config) +probe_sb(struct address_info *hw_config) { - if (check_region (hw_config->io_base, 16)) - { - printk ("\n\nsb_dsp.c: I/O port %x already in use\n\n", - hw_config->io_base); - return 0; - } - - return sb_dsp_detect (hw_config); + if (check_region(hw_config->io_base, 16)) + { + printk("\n\nsb_dsp.c: I/O port %x already in use\n\n", hw_config->io_base); + return 0; + } + return sb_dsp_detect(hw_config); } void -unload_sb (struct address_info *hw_config) +unload_sb(struct address_info *hw_config) { - sb_dsp_unload (hw_config); + sb_dsp_unload(hw_config); } +#ifdef MODULE + +static struct address_info config; +static struct address_info config_mpu; + +/* + * Note DMA2 of -1 has the right meaning in the SB16 driver as well + * as here. It will cause either an error if it is needed or a fallback + * to the 8bit channel. + */ + +int mpu_io = 0; +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int sm_games = 0; /* Mixer - see sb_mixer.c */ +int acer = 0; /* Do acer notebook init */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(mad16, "i"); +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) +{ + printk("Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (mad16 == 0 && trix == 0 && pas2 == 0) + { + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + config.card_subtype = type; + + if (!probe_sb(&config)) + return -ENODEV; + attach_sb_card(&config); +#ifdef CONFIG_MIDI + 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 + } + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (smw_free) + kfree(smw_free); + if (!mad16 && !trix && !pas2) + unload_sb(&config); + if (sbmpu) + unload_sbmpu(&config_mpu); + SOUND_LOCK_END; +} + +#else + +#ifdef SM_GAMES +int sm_games = 1; + +#else +int sm_games = 0; + +#endif +#ifdef SB_ACER +int acer = 1; + +#else +int acer = 0; + #endif +#endif +#endif + +EXPORT_SYMBOL(sb_dsp_init); +EXPORT_SYMBOL(sb_dsp_detect); +EXPORT_SYMBOL(sb_dsp_unload); +EXPORT_SYMBOL(sb_dsp_disable_midi); +EXPORT_SYMBOL(attach_sb_card); +EXPORT_SYMBOL(probe_sb); +EXPORT_SYMBOL(unload_sb); diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index bd9e05704..70f67d75f 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -14,8 +14,9 @@ #include "sound_config.h" +#include "sound_firmware.h" -#if defined(CONFIG_SBDSP) +#if defined(CONFIG_SBDSP) || defined(MODULE) #ifndef CONFIG_AUDIO #error You will need to configure the sound driver with CONFIG_AUDIO option. @@ -52,767 +53,840 @@ static int smw_ucodeLen = 0; #endif + int -sb_dsp_command (sb_devc * devc, unsigned char val) +sb_dsp_command(sb_devc * devc, unsigned char val) { - int i; - unsigned long limit; - - limit = jiffies + HZ / 10; /* Timeout */ - /* - * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb (DSP_STATUS) & 0x80) == 0) - { - outb ((val), DSP_COMMAND); - return 1; - } - } + int i; + unsigned long limit; + + limit = jiffies + HZ / 10; /* Timeout */ + /* + * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 500000 && jiffies < limit; i++) + { + if ((inb(DSP_STATUS) & 0x80) == 0) + { + outb((val), DSP_COMMAND); + return 1; + } + } - printk ("Sound Blaster: DSP Command(%x) Timeout.\n", val); - return 0; + printk("Sound Blaster: DSP Command(%x) Timeout.\n", val); + return 0; } static int -sb_dsp_get_byte (sb_devc * devc) +sb_dsp_get_byte(sb_devc * devc) { - int i; - - for (i = 1000; i; i--) - if (inb (DSP_DATA_AVAIL) & 0x80) - { - return inb (DSP_READ); - } - - return 0xffff; + int i; + + for (i = 1000; i; i--) + if (inb(DSP_DATA_AVAIL) & 0x80) + { + return inb(DSP_READ); + } + return 0xffff; } int -ess_write (sb_devc * devc, unsigned char reg, unsigned char data) +ess_write(sb_devc * devc, unsigned char reg, unsigned char data) { - /* Write a byte to an extended mode register of ES1688 */ + /* Write a byte to an extended mode register of ES1688 */ - if (!sb_dsp_command (devc, reg)) - return 0; + if (!sb_dsp_command(devc, reg)) + return 0; - return sb_dsp_command (devc, data); + return sb_dsp_command(devc, data); } int -ess_read (sb_devc * devc, unsigned char reg) +ess_read(sb_devc * devc, unsigned char reg) { /* Read a byte from an extended mode register of ES1688 */ - if (!sb_dsp_command (devc, 0xc0)) /* Read register command */ - return -1; + if (!sb_dsp_command(devc, 0xc0)) /* Read register command */ + return -1; - if (!sb_dsp_command (devc, reg)) - return -1; + if (!sb_dsp_command(devc, reg)) + return -1; - return sb_dsp_get_byte (devc); + return sb_dsp_get_byte(devc); } static void -sbintr (int irq, void *dev_id, struct pt_regs *dummy) +sbintr(int irq, void *dev_id, struct pt_regs *dummy) { - int status; - unsigned char src = 0xff; - - sb_devc *devc = irq2devc[irq]; + int status; + unsigned char src = 0xff; - if (devc == NULL || devc->irq != irq) - { - DEB (printk ("sbintr: Bogus interrupt IRQ%d\n", irq)); - return; - } + sb_devc *devc = irq2devc[irq]; - devc->irq_ok = 1; + if (devc == NULL || devc->irq != irq) + { + DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq)); + return; + } + devc->irq_ok = 1; - if (devc->model == MDL_SB16) - { + if (devc->model == MDL_SB16) + { - src = sb_getmixer (devc, IRQ_STAT); /* Interrupt source register */ + src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - if (src & 4) - uart401intr (devc->irq, NULL, NULL); /* MPU401 interrupt */ +#if defined(CONFIG_MIDI)&& (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + if (src & 4) + uart401intr(devc->irq, NULL, NULL); /* MPU401 interrupt */ #endif - if (!(src & 3)) - return; /* Not a DSP interrupt */ - } - - if (devc->intr_active) - switch (devc->irq_mode) - { - case IMODE_OUTPUT: - DMAbuf_outputintr (devc->dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr (devc->dev); - break; - - case IMODE_INIT: - break; - - case IMODE_MIDI: -#ifdef CONFIG_MIDI - sb_midi_interrupt (devc); + if (!(src & 3)) + return; /* Not a DSP interrupt */ + } + if (devc->intr_active) + switch (devc->irq_mode) + { + case IMODE_OUTPUT: + DMAbuf_outputintr(devc->dev, 1); + break; + + case IMODE_INPUT: + DMAbuf_inputintr(devc->dev); + break; + + case IMODE_INIT: + break; + + case IMODE_MIDI: +#if defined(CONFIG_MIDI) + sb_midi_interrupt(devc); #endif - break; + break; - default: - /* printk ("Sound Blaster: Unexpected interrupt\n"); */ - ; - } + default: + /* printk( "Sound Blaster: Unexpected interrupt\n"); */ + ; + } /* * Acknowledge interrupts */ - if (src & 0x01) - status = inb (DSP_DATA_AVAIL); + if (src & 0x01) + status = inb(DSP_DATA_AVAIL); - if (devc->model == MDL_SB16 && src & 0x02) - status = inb (DSP_DATA_AVL16); + if (devc->model == MDL_SB16 && src & 0x02) + status = inb(DSP_DATA_AVL16); } + int -sb_dsp_reset (sb_devc * devc) +sb_dsp_reset(sb_devc * devc) { - int loopc; + int loopc; - DDB (printk ("Entered sb_dsp_reset()\n")); + DEB(printk("Entered sb_dsp_reset()\n")); - if (devc->model == MDL_ESS) - outb ((3), DSP_RESET); /* Reset FIFO too */ - else - outb ((1), DSP_RESET); + if (devc->model == MDL_ESS) + outb((3), DSP_RESET); /* Reset FIFO too */ + else + outb((1), DSP_RESET); - tenmicrosec (devc->osp); - outb ((0), DSP_RESET); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); + tenmicrosec(devc->osp); + outb((0), DSP_RESET); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); - for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); + for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++); - if (inb (DSP_READ) != 0xAA) - { - DDB (printk ("sb: No response to RESET\n")); - return 0; /* Sorry */ - } - - if (devc->model == MDL_ESS) - sb_dsp_command (devc, 0xc6); /* Enable extended mode */ + if (inb(DSP_READ) != 0xAA) + { + DDB(printk("sb: No response to RESET\n")); + return 0; /* Sorry */ + } + if (devc->model == MDL_ESS) + sb_dsp_command(devc, 0xc6); /* Enable extended mode */ - DDB (printk ("sb_dsp_reset() OK\n")); - return 1; + DEB(printk("sb_dsp_reset() OK\n")); + return 1; } static void -dsp_get_vers (sb_devc * devc) +dsp_get_vers(sb_devc * devc) { - int i; + int i; - unsigned long flags; + unsigned long flags; - DDB (printk ("Entered dsp_get_vers()\n")); - save_flags (flags); - cli (); - devc->major = devc->minor = 0; - sb_dsp_command (devc, 0xe1); /* Get version */ + DDB(printk("Entered dsp_get_vers()\n")); + save_flags(flags); + cli(); + devc->major = devc->minor = 0; + sb_dsp_command(devc, 0xe1); /* Get version */ - for (i = 100000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { - if (devc->major == 0) - devc->major = inb (DSP_READ); - else - { - devc->minor = inb (DSP_READ); - break; - } - } - } - DDB (printk ("DSP version %d.%d\n", devc->major, devc->minor)); - restore_flags (flags); + for (i = 100000; i; i--) + { + if (inb(DSP_DATA_AVAIL) & 0x80) + { + if (devc->major == 0) + devc->major = inb(DSP_READ); + else + { + devc->minor = inb(DSP_READ); + break; + } + } + } + DDB(printk("DSP version %d.%d\n", devc->major, devc->minor)); + restore_flags(flags); } static int -sb16_set_dma_hw (sb_devc * devc) +sb16_set_dma_hw(sb_devc * devc) { - int bits; - - if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) - { - printk ("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); - return 0; - } + int bits; - bits = (1 << devc->dma8); + if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) + { + printk("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); + return 0; + } + bits = (1 << devc->dma8); - if (devc->dma16 >= 5 && devc->dma16 <= 7) - bits |= (1 << devc->dma16); + if (devc->dma16 >= 5 && devc->dma16 <= 7) + bits |= (1 << devc->dma16); - sb_setmixer (devc, DMA_NR, bits); - return 1; + sb_setmixer(devc, DMA_NR, bits); + return 1; } #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) static void -sb16_set_mpu_port (sb_devc * devc, struct address_info *hw_config) +sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) { /* * This routine initializes new MIDI port setup register of SB Vibra (CT2502). */ - unsigned char bits = sb_getmixer (devc, 0x84) & ~0x06; - - switch (hw_config->io_base) - { - case 0x300: - sb_setmixer (devc, 0x84, bits | 0x04); - break; - - case 0x330: - sb_setmixer (devc, 0x84, bits | 0x00); - break; - - default: - sb_setmixer (devc, 0x84, bits | 0x02); /* Disable MPU */ - printk ("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); - } + unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; + + switch (hw_config->io_base) + { + case 0x300: + sb_setmixer(devc, 0x84, bits | 0x04); + break; + + case 0x330: + sb_setmixer(devc, 0x84, bits | 0x00); + break; + + default: + sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ + printk("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); + } } #endif static int -sb16_set_irq_hw (sb_devc * devc, int level) +sb16_set_irq_hw(sb_devc * devc, int level) { - int ival; - - switch (level) - { - case 5: - ival = 2; - break; - case 7: - ival = 4; - break; - case 9: - ival = 1; - break; - case 10: - ival = 8; - break; - default: - printk ("SB16 IRQ%d is not possible\n", level); - return 0; - } - sb_setmixer (devc, IRQ_NR, ival); - return 1; + int ival; + + switch (level) + { + case 5: + ival = 2; + break; + case 7: + ival = 4; + break; + case 9: + ival = 1; + break; + case 10: + ival = 8; + break; + default: + printk("SB16 IRQ%d is not possible\n", level); + return 0; + } + sb_setmixer(devc, IRQ_NR, ival); + return 1; } static void -relocate_Jazz16 (sb_devc * devc, struct address_info *hw_config) +relocate_Jazz16(sb_devc * devc, struct address_info *hw_config) { - unsigned char bits = 0; - unsigned long flags; - - if (jazz16_base != 0 && jazz16_base != hw_config->io_base) - return; + unsigned char bits = 0; + unsigned long flags; - switch (hw_config->io_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; + if (jazz16_base != 0 && jazz16_base != hw_config->io_base) + return; - default: - return; - } + switch (hw_config->io_base) + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + + default: + return; + } - bits = jazz16_bits = bits << 5; + bits = jazz16_bits = bits << 5; - jazz16_base = hw_config->io_base; + jazz16_base = hw_config->io_base; /* * Magic wake up sequence by writing to 0x201 (aka Joystick port) */ - save_flags (flags); - cli (); - outb ((0xAF), 0x201); - outb ((0x50), 0x201); - outb ((bits), 0x201); - restore_flags (flags); + save_flags(flags); + cli(); + outb((0xAF), 0x201); + outb((0x50), 0x201); + outb((bits), 0x201); + restore_flags(flags); } static int -init_Jazz16 (sb_devc * devc, struct address_info *hw_config) +init_Jazz16(sb_devc * devc, struct address_info *hw_config) { - char name[100]; + char name[100]; /* * First try to check that the card has Jazz16 chip. It identifies itself * by returning 0x12 as response to DSP command 0xfa. */ - if (!sb_dsp_command (devc, 0xfa)) - return 0; + if (!sb_dsp_command(devc, 0xfa)) + return 0; - if (sb_dsp_get_byte (devc) != 0x12) - return 0; + if (sb_dsp_get_byte(devc) != 0x12) + return 0; /* * OK so far. Now configure the IRQ and DMA channel used by the card. */ - if (hw_config->irq < 1 || hw_config->irq > 15 || - jazz_irq_bits[hw_config->irq] == 0) - { - printk ("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); - return 0; - } - - if (hw_config->dma < 0 || hw_config->dma > 3 || - jazz_dma_bits[hw_config->dma] == 0) - { - printk ("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); - return 0; - } - - if (hw_config->dma2 < 0) - { - printk ("Jazz16: No 16 bit DMA channel defined\n"); - return 0; - } - - if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || - jazz_dma_bits[hw_config->dma2] == 0) - { - printk ("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); - return 0; - } - - devc->dma16 = hw_config->dma2; - - if (!sb_dsp_command (devc, 0xfb)) - return 0; - - if (!sb_dsp_command (devc, jazz_dma_bits[hw_config->dma] | - (jazz_dma_bits[hw_config->dma2] << 4))) - return 0; - - if (!sb_dsp_command (devc, jazz_irq_bits[hw_config->irq])) - return 0; + if (hw_config->irq < 1 || hw_config->irq > 15 || + jazz_irq_bits[hw_config->irq] == 0) + { + printk("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); + return 0; + } + if (hw_config->dma < 0 || hw_config->dma > 3 || + jazz_dma_bits[hw_config->dma] == 0) + { + printk("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); + return 0; + } + if (hw_config->dma2 < 0) + { + printk("Jazz16: No 16 bit DMA channel defined\n"); + return 0; + } + if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || + jazz_dma_bits[hw_config->dma2] == 0) + { + printk("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); + return 0; + } + devc->dma16 = hw_config->dma2; + + if (!sb_dsp_command(devc, 0xfb)) + return 0; + + if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] | + (jazz_dma_bits[hw_config->dma2] << 4))) + return 0; + + if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq])) + return 0; /* * Now we have configured a standard Jazz16 device. */ - devc->model = MDL_JAZZ; - strcpy (name, "Jazz16"); - - - hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1))); - sound_mem_sizes[sound_nblocks] = strlen (name + 1); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (hw_config->name != NULL) - strcpy (hw_config->name, name); - devc->caps |= SB_NO_MIDI; - return 1; + devc->model = MDL_JAZZ; + strcpy(name, "Jazz16"); + + + hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc(strlen(name + 1))); + sound_mem_sizes[sound_nblocks] = strlen(name + 1); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy(hw_config->name, name); + devc->caps |= SB_NO_MIDI; + return 1; } +static void +relocate_ess1688(sb_devc * devc) +{ + unsigned char bits; + + switch (devc->base) + { + case 0x220: + bits = 0x04; + break; + case 0x230: + bits = 0x05; + break; + case 0x240: + bits = 0x06; + break; + case 0x250: + bits = 0x07; + break; + default: + return; /* Wrong port */ + } + + DDB(printk("Doing ESS1688 address selection\n")); + +/* + * ES1688 supports two alternative ways for software address config. + * First try the so called Read-Sequence-Key method. + */ + + /* Reset the sequence logic */ + inb(0x229); + inb(0x229); + inb(0x229); + + /* Perform the read sequence */ + inb(0x22b); + inb(0x229); + inb(0x22b); + inb(0x229); + inb(0x229); + inb(0x22b); + inb(0x229); + + /* Select the base address by reading from it. Then probe using the port. */ + inb(devc->base); + if (sb_dsp_reset(devc)) /* Bingo */ + return; + +#if 0 /* This causes system lockups (Nokia 386/25 at least) */ +/* + * The last resort is the system control register method. + */ + + outb((0x00), 0xfb); /* 0xFB is the unlock register */ + outb((0x00), 0xe0); /* Select index 0 */ + outb((bits), 0xe1); /* Write the config bits */ + outb((0x00), 0xf9); /* 0xFB is the lock register */ +#endif +} static int -ess_init (sb_devc * devc, struct address_info *hw_config) +ess_init(sb_devc * devc, struct address_info *hw_config) { - unsigned char cfg, irq_bits = 0, dma_bits = 0; - int ess_major = 0, ess_minor = 0; - int i; - char name[100]; + unsigned char cfg, irq_bits = 0, dma_bits = 0; + int ess_major = 0, ess_minor = 0; + int i; + char name[100]; /* * Try to detect ESS chips. */ - sb_dsp_command (devc, 0xe7); /* Return identification */ + sb_dsp_command(devc, 0xe7); /* Return identification */ - for (i = 1000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { - if (ess_major == 0) - ess_major = inb (DSP_READ); - else - { - ess_minor = inb (DSP_READ); - break; - } - } - } - - if (ess_major == 0) - return 0; - - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) - { - sprintf (name, "ESS ES488 AudioDrive (rev %d)", - ess_minor & 0x0f); - hw_config->name = name; - devc->model = MDL_SBPRO; - return 1; - } - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) - { - char *chip = "ES688"; - - if ((ess_minor & 0x0f) >= 8) - chip = "ES1688"; - - sprintf (name, - "ESS %s AudioDrive (rev %d)", - chip, ess_minor & 0x0f); - } - else - strcpy (name, "Jazz16"); - - devc->model = MDL_ESS; - devc->submodel = ess_minor & 0x0f; - - hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1))); - sound_mem_sizes[sound_nblocks] = strlen (name + 1); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (hw_config->name != NULL) - strcpy (hw_config->name, name); - - - sb_dsp_reset (devc); /* Turn on extended mode */ + for (i = 1000; i; i--) + { + if (inb(DSP_DATA_AVAIL) & 0x80) + { + if (ess_major == 0) + ess_major = inb(DSP_READ); + else + { + ess_minor = inb(DSP_READ); + break; + } + } + } -/* - * Set IRQ configuration register - */ + if (ess_major == 0) + return 0; - cfg = 0x50; /* Enable only DMA counter interrupt */ + if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) + { + sprintf(name, "ESS ES488 AudioDrive (rev %d)", + ess_minor & 0x0f); + hw_config->name = name; + devc->model = MDL_SBPRO; + return 1; + } else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) + { + char *chip = "ES688"; - switch (devc->irq) - { - case 2: - case 9: - irq_bits = 0; - break; + if ((ess_minor & 0x0f) >= 8) + chip = "ES1688"; - case 5: - irq_bits = 1; - break; + sprintf(name, + "ESS %s AudioDrive (rev %d)", + chip, ess_minor & 0x0f); + } else + strcpy(name, "Jazz16"); - case 7: - irq_bits = 2; - break; + devc->model = MDL_ESS; + devc->submodel = ess_minor & 0x0f; - case 10: - irq_bits = 3; - break; + hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc(strlen(name + 1))); + sound_mem_sizes[sound_nblocks] = strlen(name + 1); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy(hw_config->name, name); - default: - irq_bits = 0; - cfg = 0x10; /* Disable all interrupts */ - printk ("\nESS1688: Invalid IRQ %d\n", devc->irq); - return 0; - } - if (!ess_write (devc, 0xb1, cfg | (irq_bits << 2))) - printk ("\nESS1688: Failed to write to IRQ config register\n"); + sb_dsp_reset(devc); /* Turn on extended mode */ + +/* + * Set IRQ configuration register + */ + + cfg = 0x50; /* Enable only DMA counter interrupt */ + + switch (devc->irq) + { + case 2: + case 9: + irq_bits = 0; + break; + + case 5: + irq_bits = 1; + break; + + case 7: + irq_bits = 2; + break; + + case 10: + irq_bits = 3; + break; + + default: + irq_bits = 0; + cfg = 0x10; /* Disable all interrupts */ + printk("\nESS1688: Invalid IRQ %d\n", devc->irq); + return 0; + } + + if (!ess_write(devc, 0xb1, cfg | (irq_bits << 2))) + printk("\nESS1688: Failed to write to IRQ config register\n"); /* * Set DMA configuration register */ - cfg = 0x50; /* Extended mode DMA enable */ - - if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2) - { - dma_bits = 0; - cfg = 0x00; /* Disable all DMA */ - printk ("\nESS1688: Invalid DMA %d\n", devc->dma8); - } - else - { - if (devc->dma8 == 3) - dma_bits = 3; - else - dma_bits = devc->dma8 + 1; - } - - if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) - printk ("\nESS1688: Failed to write to DMA config register\n"); + cfg = 0x50; /* Extended mode DMA enable */ + + if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2) + { + dma_bits = 0; + cfg = 0x00; /* Disable all DMA */ + printk("\nESS1688: Invalid DMA %d\n", devc->dma8); + } else + { + if (devc->dma8 == 3) + dma_bits = 3; + else + dma_bits = devc->dma8 + 1; + } + + if (!ess_write(devc, 0xb2, cfg | (dma_bits << 2))) + printk("\nESS1688: Failed to write to DMA config register\n"); /* * Enable joystick and OPL3 */ - cfg = sb_getmixer (devc, 0x40); - sb_setmixer (devc, 0x40, cfg | 0x03); - if (devc->submodel >= 8) /* ES1688 */ - devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ - sb_dsp_reset (devc); - return 1; + cfg = sb_getmixer(devc, 0x40); + sb_setmixer(devc, 0x40, cfg | 0x03); + if (devc->submodel >= 8) /* ES1688 */ + devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ + sb_dsp_reset(devc); + return 1; } int -sb_dsp_detect (struct address_info *hw_config) +sb_dsp_detect(struct address_info *hw_config) { - sb_devc sb_info; - sb_devc *devc = &sb_info; + sb_devc sb_info; + sb_devc *devc = &sb_info; + sb_info.my_mididev = -1; + sb_info.my_mixerdev = -1; + sb_info.my_dev = -1; /* * Initialize variables */ - DDB (printk ("sb_dsp_detect(%x) entered\n", hw_config->io_base)); - if (check_region (hw_config->io_base, 16)) - return 0; - - memset ((char *) &sb_info, 0, sizeof (sb_info)); /* Zero everything */ + DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base)); + if (check_region(hw_config->io_base, 16)) + { +#ifdef MODULE + printk("sb: I/O region in use.\n"); +#endif + return 0; + } + memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ - devc->type = hw_config->card_subtype; + devc->type = hw_config->card_subtype; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma8 = hw_config->dma; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma8 = hw_config->dma; - devc->dma16 = -1; + devc->dma16 = -1; + if (acer) + { + cli(); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x00); + sti(); + } /* * Detect the device */ - if (sb_dsp_reset (devc)) - dsp_get_vers (devc); - else - devc->major = 0; + if (sb_dsp_reset(devc)) + dsp_get_vers(devc); + else + devc->major = 0; - if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) - if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) - relocate_Jazz16 (devc, hw_config); + if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) + if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) + relocate_Jazz16(devc, hw_config); + if (devc->major == 0 && (devc->type == MDL_ESS || devc->type == 0)) + relocate_ess1688(devc); - if (!sb_dsp_reset (devc)) - { - DDB (printk ("SB reset failed\n")); - return 0; - } - - if (devc->major == 0) - dsp_get_vers (devc); - - if (devc->major == 3 && devc->minor == 1) - { - if (devc->type == MDL_AZTECH) /* SG Washington? */ - { - if (sb_dsp_command (devc, 0x09)) - if (sb_dsp_command (devc, 0x00)) /* Enter WSS mode */ - { - int i; - - /* Have some delay */ - for (i = 0; i < 10000; i++) - inb (DSP_DATA_AVAIL); - devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ - devc->model = MDL_AZTECH; - } - } - } + if (!sb_dsp_reset(devc)) + { + DDB(printk("SB reset failed\n")); +#ifdef MODULE + printk("sb: dsp reset failed.\n"); +#endif + return 0; + } + if (devc->major == 0) + dsp_get_vers(devc); + if (devc->major == 3 && devc->minor == 1) + { + if (devc->type == MDL_AZTECH) /* SG Washington? */ + { + if (sb_dsp_command(devc, 0x09)) + if (sb_dsp_command(devc, 0x00)) /* Enter WSS mode */ + { + int i; + + /* Have some delay */ + for (i = 0; i < 10000; i++) + inb(DSP_DATA_AVAIL); + devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ + devc->model = MDL_AZTECH; + } + } + } /* * Save device information for sb_dsp_init() */ - detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (sb_devc))); - sound_mem_sizes[sound_nblocks] = sizeof (sb_devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - - if (detected_devc == NULL) - { - printk ("sb: Can't allocate memory for device information\n"); - return 0; - } + detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(sb_devc))); + sound_mem_sizes[sound_nblocks] = sizeof(sb_devc); + if (sound_nblocks < 1024) + sound_nblocks++;; - memcpy ((char *) detected_devc, (char *) devc, sizeof (sb_devc)); + if (detected_devc == NULL) + { + printk(KERN_ERR "sb: Can't allocate memory for device information\n"); + return 0; + } + memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc)); - DDB (printk ("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, - hw_config->io_base)); - return 1; + MDB(printk("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); + return 1; } void -sb_dsp_init (struct address_info *hw_config) +sb_dsp_init(struct address_info *hw_config) { - sb_devc *devc; - int n; - char name[100]; - extern int sb_be_quiet; + sb_devc *devc; + char name[100]; + extern int sb_be_quiet; /* * Check if we had detected a SB device earlier */ - DDB (printk ("sb_dsp_init(%x) entered\n", hw_config->io_base)); - name[0] = 0; - - if (detected_devc == NULL) - { - DDB (printk ("No detected device\n")); - return; - } + DDB(printk("sb_dsp_init(%x) entered\n", hw_config->io_base)); + name[0] = 0; - devc = detected_devc; - detected_devc = NULL; - - if (devc->base != hw_config->io_base) - { - DDB (printk ("I/O port mismatch\n")); - return; - } + if (detected_devc == NULL) + { + MDB(printk("No detected device\n")); + return; + } + devc = detected_devc; + detected_devc = NULL; + if (devc->base != hw_config->io_base) + { + DDB(printk("I/O port mismatch\n")); + return; + } /* * Now continue initialization of the device */ - devc->dev = num_audiodevs; - devc->caps = hw_config->driver_use_1; - - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && - hw_config->irq > 0) - { /* IRQ setup */ - if (snd_set_irq_handler (hw_config->irq, - sbintr, "soundblaster", devc->osp) < 0) - { - printk ("SB: Can't allocate IRQ%d\n", hw_config->irq); - return; - } - - irq2devc[hw_config->irq] = devc; - devc->irq_ok = 0; - - if (devc->major == 4) - if (!sb16_set_irq_hw (devc, devc->irq)) /* Unsupported IRQ */ + devc->dev = sound_alloc_audiodev(); + if (devc->dev == -1) { - snd_release_irq (devc->irq); - irq2devc[hw_config->irq] = NULL; - return; + printk(KERN_WARNING "sb: too many audio devices.\n"); + return; } - - if ((devc->type == 0 || devc->type == MDL_ESS) && - devc->major == 3 && devc->minor == 1) - { /* Handle various chipsets which claim they are SB Pro compatible */ - if ((devc->type != 0 && devc->type != MDL_ESS) || - !ess_init (devc, hw_config)) - if ((devc->type != 0 && devc->type != MDL_JAZZ && - devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config)) - { - DDB (printk ("This is a genuine SB Pro\n")); - } - } - -#ifdef __SMP__ - /* Skip IRQ detection if SMP (doesn't work) */ - devc->irq_ok = 1; + devc->caps = hw_config->driver_use_1; + + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && + hw_config->irq > 0) + { /* IRQ setup */ + if (snd_set_irq_handler(hw_config->irq, + sbintr, "soundblaster", devc->osp) < 0) + { + printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); + sound_unload_audiodev(devc->dev); + return; + } + irq2devc[hw_config->irq] = devc; + devc->irq_ok = 0; + + if (devc->major == 4) + if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ + { + snd_release_irq(devc->irq); + sound_unload_audiodev(devc->dev); + irq2devc[hw_config->irq] = NULL; + return; + } + if ((devc->type == 0 || devc->type == MDL_ESS) && + devc->major == 3 && devc->minor == 1) + { /* Handle various chipsets which claim they are SB Pro compatible */ + if ((devc->type != 0 && devc->type != MDL_ESS) || + !ess_init(devc, hw_config)) + if ((devc->type != 0 && devc->type != MDL_JAZZ && + devc->type != MDL_SMW) || !init_Jazz16(devc, hw_config)) + { + DDB(printk("This is a genuine SB Pro\n")); + } + } +#if defined(__SMP__) || defined(__FreeBSD__) + /* Skip IRQ detection if SMP (doesn't work) */ + devc->irq_ok = 1; #else - if (devc->major == 4 && devc->minor <= 11) /* Won't work */ - devc->irq_ok = 1; - else - { - for (n = 0; n < 3 && devc->irq_ok == 0; n++) - if (sb_dsp_command (devc, 0xf2)) /* Cause interrupt immediately */ - { - int i; - - for (i = 0; !devc->irq_ok && i < 10000; i++); - } - - if (!devc->irq_ok) - { - printk ("sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); - } - else - { - DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq)); - } - - } -#endif /* __SMP__ */ - } /* IRQ setup */ - - request_region (hw_config->io_base, 16, "soundblaster"); - - switch (devc->major) - { - case 1: /* SB 1.0 or 1.5 */ - devc->model = hw_config->card_subtype = MDL_SB1; - break; - - case 2: /* SB 2.x */ - if (devc->minor == 0) - devc->model = hw_config->card_subtype = MDL_SB2; - else - devc->model = hw_config->card_subtype = MDL_SB201; - break; - - case 3: /* SB Pro and most clones */ - if (devc->model == 0) - { - devc->model = hw_config->card_subtype = MDL_SBPRO; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; - } - break; - - case 4: - devc->model = hw_config->card_subtype = MDL_SB16; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16"; - - if (hw_config->dma2 == -1) - devc->dma16 = devc->dma8; - else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) - { - printk ("SB16: Bad or missing 16 bit DMA channel\n"); - devc->dma16 = devc->dma8; - } - else - devc->dma16 = hw_config->dma2; - - sb16_set_dma_hw (devc); - devc->caps |= SB_NO_MIDI; - } + if (devc->major == 4 && devc->minor <= 11) /* Won't work */ + devc->irq_ok = 1; + else + { + int n; + + for (n = 0; n < 3 && devc->irq_ok == 0; n++) + if (sb_dsp_command(devc, 0xf2)) /* Cause interrupt immediately */ + { + int i; + + for (i = 0; !devc->irq_ok && i < 10000; i++); + } + if (!devc->irq_ok) + { + printk("sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); + } else + { + DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq)); + } + + } +#endif /* __SMP__ */ + } /* IRQ setup */ + request_region(hw_config->io_base, 16, "soundblaster"); + + switch (devc->major) + { + case 1: /* SB 1.0 or 1.5 */ + devc->model = hw_config->card_subtype = MDL_SB1; + break; + + case 2: /* SB 2.x */ + if (devc->minor == 0) + devc->model = hw_config->card_subtype = MDL_SB2; + else + devc->model = hw_config->card_subtype = MDL_SB201; + break; + + case 3: /* SB Pro and most clones */ + if (devc->model == 0) + { + devc->model = hw_config->card_subtype = MDL_SBPRO; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; + } + break; + + case 4: + devc->model = hw_config->card_subtype = MDL_SB16; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster 16"; + + if (hw_config->dma2 == -1) + devc->dma16 = devc->dma8; + else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) + { + printk("SB16: Bad or missing 16 bit DMA channel\n"); + devc->dma16 = devc->dma8; + } else + devc->dma16 = hw_config->dma2; + + sb16_set_dma_hw(devc); + devc->caps |= SB_NO_MIDI; + } - if (!(devc->caps & SB_NO_MIXER)) - if (devc->major == 3 || devc->major == 4) - sb_mixer_init (devc); + if (!(devc->caps & SB_NO_MIXER)) + if (devc->major == 3 || devc->major == 4) + sb_mixer_init(devc); -#ifdef CONFIG_MIDI - if (!(devc->caps & SB_NO_MIDI)) - sb_dsp_midi_init (devc); +#if defined(CONFIG_MIDI) + if (!(devc->caps & SB_NO_MIDI)) + sb_dsp_midi_init(devc); #endif - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; - sprintf (name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); - conf_printf (name, hw_config); + sprintf(name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); + conf_printf(name, hw_config); /* * Assuming that a soundcard is Sound Blaster (compatible) is the most common @@ -821,84 +895,87 @@ sb_dsp_init (struct address_info *hw_config) * used in Unix. See Readme.cards for more information about configuring OSS/Free * properly. */ - if (devc->model <= MDL_SBPRO) - if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1. */ - { - printk ("This soundcard doesn't seem to be fully Sound Blaster Pro compatible.\n"); - printk ("Almost certainly there is another way to configure OSS so that\n"); - printk ("it works properly with OSS (for example in 16 bit mode).\n"); - } - else if (!sb_be_quiet && devc->model == MDL_SBPRO) - { - printk ("SB DSP version is just %d.%d which means that your card is\n", - devc->major, devc->minor); - printk ("several years old (8 bit only device)\n"); - printk ("or alternatively the sound driver is incorrectly configured.\n"); - } - - hw_config->card_subtype = devc->model; - last_devc = devc; /* For SB MPU detection */ - - if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) - { - if (sound_alloc_dma (devc->dma8, "SoundBlaster8")) - { - printk ("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); - } - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - if (sound_alloc_dma (devc->dma16, "SoundBlaster16")) + if (devc->model <= MDL_SBPRO) + if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1 (rare ones may have 3.2). */ + { + printk("This soundcard may not be fully Sound Blaster Pro compatible.\n"); + printk("In many cases there is another way to configure OSS so that\n"); + printk("it works properly with OSS (for example in 16 bit mode).\n"); + printk("Please ignore this message if you _really_ have a SB Pro.\n"); + } else if (!sb_be_quiet && devc->model == MDL_SBPRO) + { + printk("SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); + printk("several years old (8 bit only device)\n"); + printk("or alternatively the sound driver is incorrectly configured.\n"); + } + hw_config->card_subtype = devc->model; + last_devc = devc; /* For SB MPU detection */ + + if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) + { + if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) + { + printk("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); + } + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) + { + printk("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + } + sb_audio_init(devc, name); + } else { - printk ("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + MDB(printk("sb: No audio devices found.\n")); } - sb_audio_init (devc, name); - } } void -sb_dsp_disable_midi (int io_base) +sb_dsp_disable_midi(int io_base) { } void -sb_dsp_disable_recording (int io_base) +sb_dsp_disable_recording(int io_base) { } void -sb_dsp_unload (struct address_info *hw_config) +sb_dsp_unload(struct address_info *hw_config) { - sb_devc *devc; - int irq = hw_config->irq; + sb_devc *devc; + int irq = hw_config->irq; - if (irq < 0) - irq *= -1; + if (irq < 0) + irq *= -1; - if (irq > 2 && irq < 16) - devc = irq2devc[irq]; - else - devc = NULL; - - if (devc && devc->base == hw_config->io_base) - { - release_region (devc->base, 16); - - if (!(devc->caps & SB_NO_AUDIO)) - { - sound_free_dma (devc->dma8); + if (irq > 2 && irq < 16) + devc = irq2devc[irq]; + else + devc = NULL; - if (devc->dma16 >= 0) - sound_free_dma (devc->dma16); - } + if (devc && devc->base == hw_config->io_base) + { + release_region(devc->base, 16); + + if (!(devc->caps & SB_NO_AUDIO)) + { + sound_free_dma(devc->dma8); + + if (devc->dma16 >= 0) + sound_free_dma(devc->dma16); + } + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && + devc->irq > 0) + { + snd_release_irq(devc->irq); + irq2devc[devc->irq] = NULL; + sound_unload_mixerdev(devc->my_mixerdev); + sound_unload_mididev(devc->my_mididev); + sound_unload_audiodev(devc->my_dev); + } + } else + release_region(hw_config->io_base, 16); - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && - devc->irq > 0) - { - snd_release_irq (devc->irq); - irq2devc[devc->irq] = NULL; - } - } - else - release_region (hw_config->io_base, 16); } /* @@ -906,401 +983,404 @@ sb_dsp_unload (struct address_info *hw_config) */ void -sb_setmixer (sb_devc * devc, unsigned int port, unsigned int value) +sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) { - unsigned long flags; - - save_flags (flags); - cli (); - outb (((unsigned char) (port & 0xff)), MIXER_ADDR); - - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - outb (((unsigned char) (value & 0xff)), MIXER_DATA); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - restore_flags (flags); + unsigned long flags; + + save_flags(flags); + cli(); + outb(((unsigned char) (port & 0xff)), MIXER_ADDR); + + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + outb(((unsigned char) (value & 0xff)), MIXER_DATA); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + restore_flags(flags); } unsigned int -sb_getmixer (sb_devc * devc, unsigned int port) +sb_getmixer(sb_devc * devc, unsigned int port) { - unsigned int val; - unsigned long flags; + unsigned int val; + unsigned long flags; - save_flags (flags); - cli (); - outb (((unsigned char) (port & 0xff)), MIXER_ADDR); + save_flags(flags); + cli(); + outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - val = inb (MIXER_DATA); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - restore_flags (flags); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + val = inb(MIXER_DATA); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + restore_flags(flags); - return val; + return val; } -#ifdef CONFIG_MIDI +#if defined(CONFIG_MIDI) /* * MPU401 MIDI initialization. */ static void -smw_putmem (sb_devc * devc, int base, int addr, unsigned char val) +smw_putmem(sb_devc * devc, int base, int addr, unsigned char val) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((addr & 0xff), base + 1); /* Low address bits */ - outb ((addr >> 8), base + 2); /* High address bits */ - outb ((val), base); /* Data */ + outb((addr & 0xff), base + 1); /* Low address bits */ + outb((addr >> 8), base + 2); /* High address bits */ + outb((val), base); /* Data */ - restore_flags (flags); + restore_flags(flags); } static unsigned char -smw_getmem (sb_devc * devc, int base, int addr) +smw_getmem(sb_devc * devc, int base, int addr) { - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((addr & 0xff), base + 1); /* Low address bits */ - outb ((addr >> 8), base + 2); /* High address bits */ - val = inb (base); /* Data */ + outb((addr & 0xff), base + 1); /* Low address bits */ + outb((addr >> 8), base + 2); /* High address bits */ + val = inb(base); /* Data */ - restore_flags (flags); - return val; + restore_flags(flags); + return val; } static int -smw_midi_init (sb_devc * devc, struct address_info *hw_config) +smw_midi_init(sb_devc * devc, struct address_info *hw_config) { - int mpu_base = hw_config->io_base; - int mp_base = mpu_base + 4; /* Microcontroller base */ - int i; - unsigned char control; - - - /* - * Reset the microcontroller so that the RAM can be accessed - */ + int mpu_base = hw_config->io_base; + int mp_base = mpu_base + 4; /* Microcontroller base */ + int i; + unsigned char control; - control = inb (mpu_base + 7); - outb ((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */ - outb (((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */ - for (i = 0; i < 300; i++) /* Wait at least 1ms */ - tenmicrosec (devc->osp); + /* + * Reset the microcontroller so that the RAM can be accessed + */ - outb ((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ + control = inb(mpu_base + 7); + outb((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */ + outb(((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */ - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem (devc, mp_base, 0, 0x00); - smw_putmem (devc, mp_base, 1, 0xff); - tenmicrosec (devc->osp); + for (i = 0; i < 300; i++) /* Wait at least 1ms */ + tenmicrosec(devc->osp); - if (smw_getmem (devc, mp_base, 0) != 0x00 || smw_getmem (devc, mp_base, 1) != 0xff) - { - DDB (printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", - smw_getmem (devc, mp_base, 0), smw_getmem (devc, mp_base, 1))); - return 0; /* No RAM */ - } + outb((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ - /* - * There is RAM so assume it's really a SM Wave - */ + /* + * Detect microcontroller by probing the 8k RAM area + */ + smw_putmem(devc, mp_base, 0, 0x00); + smw_putmem(devc, mp_base, 1, 0xff); + tenmicrosec(devc->osp); - devc->model = MDL_SMW; - smw_mixer_init (devc); - - if (smw_ucodeLen > 0) - { - if (smw_ucodeLen != 8192) - { - printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); - return 1; - } - - /* - * Download microcode - */ + if (smw_getmem(devc, mp_base, 0) != 0x00 || smw_getmem(devc, mp_base, 1) != 0xff) + { + DDB(printk("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(devc, mp_base, 0), smw_getmem(devc, mp_base, 1))); + return 0; /* No RAM */ + } + /* + * There is RAM so assume it's really a SM Wave + */ - for (i = 0; i < 8192; i++) - smw_putmem (devc, mp_base, i, smw_ucode[i]); + devc->model = MDL_SMW; + smw_mixer_init(devc); - /* - * Verify microcode - */ +#ifdef MODULE + if (!smw_ucode) + { + extern void *smw_free; - for (i = 0; i < 8192; i++) - if (smw_getmem (devc, mp_base, i) != smw_ucode[i]) + smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); + smw_free = smw_ucode; + } +#endif + if (smw_ucodeLen > 0) { - printk ("SM Wave: Microcode verification failed\n"); - return 0; + if (smw_ucodeLen != 8192) + { + printk("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); + return 1; + } + /* + * Download microcode + */ + + for (i = 0; i < 8192; i++) + smw_putmem(devc, mp_base, i, smw_ucode[i]); + + /* + * Verify microcode + */ + + for (i = 0; i < 8192; i++) + if (smw_getmem(devc, mp_base, i) != smw_ucode[i]) + { + printk("SM Wave: Microcode verification failed\n"); + return 0; + } } - } - - control = 0; + control = 0; #ifdef SMW_SCSI_IRQ - /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. - */ - { - static unsigned char scsi_irq_bits[] = - {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; - - control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; - } + /* + * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt + * is disabled by default. + * + * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. + */ + { + static unsigned char scsi_irq_bits[] = + {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; + + control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; + } #endif #ifdef SMW_OPL4_ENABLE - /* - * Make the OPL4 chip visible on the PC bus at 0x380. - * - * There is no need to enable this feature since this driver - * doesn't support OPL4 yet. Also there is no RAM in SM Wave so - * enabling OPL4 is pretty useless. - */ - control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ - /* control |= 0x20; Uncomment this if you want to use IRQ7 */ + /* + * Make the OPL4 chip visible on the PC bus at 0x380. + * + * There is no need to enable this feature since this driver + * doesn't support OPL4 yet. Also there is no RAM in SM Wave so + * enabling OPL4 is pretty useless. + */ + control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ + /* control |= 0x20; Uncomment this if you want to use IRQ7 */ #endif - outb ((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ - hw_config->name = "SoundMan Wave"; - return 1; + outb((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ + hw_config->name = "SoundMan Wave"; + return 1; } static int -ess_midi_init (sb_devc * devc, struct address_info *hw_config) +ess_midi_init(sb_devc * devc, struct address_info *hw_config) { - unsigned char cfg, tmp; - - cfg = sb_getmixer (devc, 0x40) & 0x03; - - if (devc->submodel < 8) - { - sb_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ - return 0; /* ES688 doesn't support MPU401 mode */ - } - - tmp = (hw_config->io_base & 0x0f0) >> 4; - - if (tmp > 3) - { - sb_setmixer (devc, 0x40, cfg); - return 0; - } - - cfg |= tmp << 3; - - tmp = 1; /* MPU enabled without interrupts */ - - switch (hw_config->irq) - { - case 9: - tmp = 0x4; - break; - case 5: - tmp = 0x5; - break; - case 7: - tmp = 0x6; - break; - case 10: - tmp = 0x7; - break; - default: - return 0; - } - - cfg |= tmp << 5; - - sb_setmixer (devc, 0x40, cfg | 0x03); - return 1; + unsigned char cfg, tmp; + + cfg = sb_getmixer(devc, 0x40) & 0x03; + + if (devc->submodel < 8) + { + sb_setmixer(devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ + return 0; /* ES688 doesn't support MPU401 mode */ + } + tmp = (hw_config->io_base & 0x0f0) >> 4; + + if (tmp > 3) + { + sb_setmixer(devc, 0x40, cfg); + return 0; + } + cfg |= tmp << 3; + + tmp = 1; /* MPU enabled without interrupts */ + + switch (hw_config->irq) + { + case 9: + tmp = 0x4; + break; + case 5: + tmp = 0x5; + break; + case 7: + tmp = 0x6; + break; + case 10: + tmp = 0x7; + break; + default: + return 0; + } + + cfg |= tmp << 5; + + sb_setmixer(devc, 0x40, cfg | 0x03); + return 1; } static int -init_Jazz16_midi (sb_devc * devc, struct address_info *hw_config) +init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config) { - int mpu_base = hw_config->io_base; - int sb_base = devc->base; - int irq = hw_config->irq; - - unsigned char bits = 0; - unsigned long flags; - - if (irq < 0) - irq *= -1; - - if (irq < 1 || irq > 15 || - jazz_irq_bits[irq] == 0) - { - printk ("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); - return 0; - } - - switch (sb_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - - default: - return 0; - } - - bits = jazz16_bits = bits << 5; - - switch (mpu_base) - { - case 0x310: - bits |= 1; - break; - case 0x320: - bits |= 2; - break; - case 0x330: - bits |= 3; - break; - - default: - printk ("Jazz16: Invalid MIDI I/O port %x\n", mpu_base); - return 0; - } + int mpu_base = hw_config->io_base; + int sb_base = devc->base; + int irq = hw_config->irq; + + unsigned char bits = 0; + unsigned long flags; + + if (irq < 0) + irq *= -1; + + if (irq < 1 || irq > 15 || + jazz_irq_bits[irq] == 0) + { + printk("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); + return 0; + } + switch (sb_base) + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + + default: + return 0; + } + + bits = jazz16_bits = bits << 5; + + switch (mpu_base) + { + case 0x310: + bits |= 1; + break; + case 0x320: + bits |= 2; + break; + case 0x330: + bits |= 3; + break; + + default: + printk("Jazz16: Invalid MIDI I/O port %x\n", mpu_base); + return 0; + } /* * Magic wake up sequence by writing to 0x201 (aka Joystick port) */ - save_flags (flags); - cli (); - outb ((0xAF), 0x201); - outb ((0x50), 0x201); - outb ((bits), 0x201); - restore_flags (flags); + save_flags(flags); + cli(); + outb((0xAF), 0x201); + outb((0x50), 0x201); + outb((bits), 0x201); + restore_flags(flags); - hw_config->name = "Jazz16"; - smw_midi_init (devc, hw_config); + hw_config->name = "Jazz16"; + smw_midi_init(devc, hw_config); - if (!sb_dsp_command (devc, 0xfb)) - return 0; + if (!sb_dsp_command(devc, 0xfb)) + return 0; - if (!sb_dsp_command (devc, jazz_dma_bits[devc->dma8] | - (jazz_dma_bits[devc->dma16] << 4))) - return 0; + if (!sb_dsp_command(devc, jazz_dma_bits[devc->dma8] | + (jazz_dma_bits[devc->dma16] << 4))) + return 0; - if (!sb_dsp_command (devc, jazz_irq_bits[devc->irq] | - (jazz_irq_bits[irq] << 4))) - return 0; + if (!sb_dsp_command(devc, jazz_irq_bits[devc->irq] | + (jazz_irq_bits[irq] << 4))) + return 0; - return 1; + return 1; } void -attach_sbmpu (struct address_info *hw_config) +attach_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - attach_uart401 (hw_config); +#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + attach_uart401(hw_config); #endif } int -probe_sbmpu (struct address_info *hw_config) +probe_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - sb_devc *devc = last_devc; +#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + sb_devc *devc = last_devc; - if (last_devc == NULL) - return 0; + if (last_devc == NULL) + return 0; - last_devc = 0; + last_devc = 0; - if (hw_config->io_base <= 0) - return 0; + if (hw_config->io_base <= 0) + return 0; - if (check_region (hw_config->io_base, 4)) - { - printk ("sbmpu: I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - switch (devc->model) - { - case MDL_SB16: - if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) - { - printk ("SB16: Invalid MIDI port %x\n", hw_config->irq); - return 0; - } - hw_config->name = "Sound Blaster 16"; - hw_config->irq = -devc->irq; - if (devc->minor > 12) /* What is Vibra's version??? */ - sb16_set_mpu_port (devc, hw_config); - break; - - case MDL_ESS: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!ess_midi_init (devc, hw_config)) - return 0; - hw_config->name = "ESS ES1688"; - break; - - case MDL_JAZZ: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!init_Jazz16_midi (devc, hw_config)) - return 0; - break; - - default: - return 0; - } + if (check_region(hw_config->io_base, 4)) + { + printk("sbmpu: I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + switch (devc->model) + { + case MDL_SB16: + if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) + { + printk("SB16: Invalid MIDI port %x\n", hw_config->irq); + return 0; + } + 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: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!ess_midi_init(devc, hw_config)) + return 0; + hw_config->name = "ESS ES1688"; + break; + + case MDL_JAZZ: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!init_Jazz16_midi(devc, hw_config)) + return 0; + break; + + default: + return 0; + } - return probe_uart401 (hw_config); + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } -void -unload_sbmpu (struct address_info *hw_config) +void +unload_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - unload_uart401 (hw_config); +#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + unload_uart401(hw_config); #endif } -#else /* !CONFIG_MIDI */ +#else /* !CONFIG_MIDI */ -void -unload_sbmpu (struct address_info *hw_config) +void +unload_sbmpu(struct address_info *hw_config) { } int -probe_sbmpu (struct address_info *hw_config) +probe_sbmpu(struct address_info *hw_config) { - return 0; + return 0; } void -attach_sbmpu (struct address_info *hw_config) +attach_sbmpu(struct address_info *hw_config) { } #endif diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index cffaafc7b..06acc19ef 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -15,7 +15,8 @@ #include "sound_config.h" -#if defined(CONFIG_SBDSP) && defined(CONFIG_MIDI) +#ifdef CONFIG_SBDSP +#ifdef CONFIG_MIDI #include "sb.h" #undef SB_TEST_IRQ @@ -30,129 +31,126 @@ static int -sb_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +sb_midi_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return -ENXIO; - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - return -EBUSY; - } - devc->opened = 1; - restore_flags (flags); - - devc->irq_mode = IMODE_MIDI; - devc->midi_broken = 0; - - sb_dsp_reset (devc); - - if (!sb_dsp_command (devc, 0x35)) /* Start MIDI UART mode */ - { - devc->opened = 0; - return -EIO; - } - - devc->intr_active = 1; - - if (mode & OPEN_READ) - { - devc->input_opened = 1; - devc->midi_input_intr = input; - } - - return 0; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + return -ENXIO; + + save_flags(flags); + cli(); + if (devc->opened) + { + restore_flags(flags); + return -EBUSY; + } + devc->opened = 1; + restore_flags(flags); + + devc->irq_mode = IMODE_MIDI; + devc->midi_broken = 0; + + sb_dsp_reset(devc); + + if (!sb_dsp_command(devc, 0x35)) /* Start MIDI UART mode */ + { + devc->opened = 0; + return -EIO; + } + devc->intr_active = 1; + + if (mode & OPEN_READ) + { + devc->input_opened = 1; + devc->midi_input_intr = input; + } + return 0; } static void -sb_midi_close (int dev) +sb_midi_close(int dev) { - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return; - - save_flags (flags); - cli (); - sb_dsp_reset (devc); - devc->intr_active = 0; - devc->input_opened = 0; - devc->opened = 0; - restore_flags (flags); + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + return; + + save_flags(flags); + cli(); + sb_dsp_reset(devc); + devc->intr_active = 0; + devc->input_opened = 0; + devc->opened = 0; + restore_flags(flags); } static int -sb_midi_out (int dev, unsigned char midi_byte) +sb_midi_out(int dev, unsigned char midi_byte) { - sb_devc *devc = midi_devs[dev]->devc; + sb_devc *devc = midi_devs[dev]->devc; - if (devc == NULL) - return 1; + if (devc == NULL) + return 1; - if (devc->midi_broken) - return 1; + if (devc->midi_broken) + return 1; - if (!sb_dsp_command (devc, midi_byte)) - { - devc->midi_broken = 1; - return 1; - } - - return 1; + if (!sb_dsp_command(devc, midi_byte)) + { + devc->midi_broken = 1; + return 1; + } + return 1; } static int -sb_midi_start_read (int dev) +sb_midi_start_read(int dev) { - return 0; + return 0; } static int -sb_midi_end_read (int dev) +sb_midi_end_read(int dev) { - sb_devc *devc = midi_devs[dev]->devc; + sb_devc *devc = midi_devs[dev]->devc; - if (devc == NULL) - return -ENXIO; + if (devc == NULL) + return -ENXIO; - sb_dsp_reset (devc); - devc->intr_active = 0; - return 0; + sb_dsp_reset(devc); + devc->intr_active = 0; + return 0; } static int -sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +sb_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EPERM; + return -EPERM; } void -sb_midi_interrupt (sb_devc * devc) +sb_midi_interrupt(sb_devc * devc) { - unsigned long flags; - unsigned char data; + unsigned long flags; + unsigned char data; - if (devc == NULL) - return; + if (devc == NULL) + return; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - data = inb (DSP_READ); - if (devc->input_opened) - devc->midi_input_intr (devc->my_mididev, data); + data = inb(DSP_READ); + if (devc->input_opened) + devc->midi_input_intr(devc->my_mididev, data); - restore_flags (flags); + restore_flags(flags); } #define MIDI_SYNTH_NAME "Sound Blaster Midi" @@ -161,74 +159,77 @@ sb_midi_interrupt (sb_devc * devc) static struct midi_operations sb_midi_operations = { - {"Sound Blaster", 0, 0, SNDCARD_SB}, - &std_midi_synth, - {0}, - sb_midi_open, - sb_midi_close, - sb_midi_ioctl, - sb_midi_out, - sb_midi_start_read, - sb_midi_end_read, - NULL, - NULL, - NULL, - NULL + {"Sound Blaster", 0, 0, SNDCARD_SB}, + &std_midi_synth, + {0}, + sb_midi_open, + sb_midi_close, + sb_midi_ioctl, + sb_midi_out, + sb_midi_start_read, + sb_midi_end_read, + NULL, + NULL, + NULL, + NULL }; void -sb_dsp_midi_init (sb_devc * devc) +sb_dsp_midi_init(sb_devc * devc) { - if (devc->model < 2) /* No MIDI support for SB 1.x */ - return; - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } + int dev; - std_midi_synth.midi_dev = num_midis; - devc->my_mididev = num_midis; + if (devc->model < 2) /* No MIDI support for SB 1.x */ + return; - std_midi_synth.midi_dev = devc->my_mididev = num_midis; + dev = sound_alloc_mididev(); + if (dev == -1) + { + printk("Sound: Too many midi devices detected\n"); + return; + } + std_midi_synth.midi_dev = dev; + devc->my_mididev = dev; - midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct midi_operations); + std_midi_synth.midi_dev = devc->my_mididev = dev; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (midi_devs[num_midis] == NULL) - { - printk ("sb MIDI: Failed to allocate memory\n"); - return; - } - memcpy ((char *) midi_devs[num_midis], (char *) &sb_midi_operations, - sizeof (struct midi_operations)); + midi_devs[dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations); - midi_devs[num_midis]->devc = devc; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[dev] == NULL) + { + printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n"); + sound_unload_mididev(dev); + return; + } + memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, + sizeof(struct midi_operations)); + midi_devs[dev]->devc = devc; - midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations); - if (sound_nblocks < 1024) - sound_nblocks++;; + midi_devs[dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - if (midi_devs[num_midis]->converter == NULL) - { - printk ("sb MIDI: Failed to allocate memory\n"); - return; - } + if (sound_nblocks < 1024) + sound_nblocks++;; - memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); + if (midi_devs[dev]->converter == NULL) + { + printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n"); + sound_unload_mididev(dev); + return; + } + memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth, + sizeof(struct synth_operations)); - midi_devs[num_midis]->converter->id = "SBMIDI"; - num_midis++; - sequencer_init (); + midi_devs[dev]->converter->id = "SBMIDI"; + sequencer_init(); } #endif +#endif diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 5e6c57899..6a7070e28 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -16,7 +16,7 @@ #include "sound_config.h" -#if defined(CONFIG_SBDSP) +#if defined(CONFIG_SBDSP) || defined(MODULE) #define __SB_MIXER_C__ #include "sb.h" @@ -24,445 +24,432 @@ static int sbmixnum = 1; -static void sb_mixer_reset (sb_devc * devc); +static void sb_mixer_reset(sb_devc * devc); void -sb_mixer_set_stereo (sb_devc * devc, int mode) +sb_mixer_set_stereo(sb_devc * devc, int mode) { - sb_setmixer (devc, OUT_FILTER, ((sb_getmixer (devc, OUT_FILTER) & ~STEREO_DAC) - | (mode ? STEREO_DAC : MONO_DAC))); + sb_setmixer(devc, OUT_FILTER, ((sb_getmixer(devc, OUT_FILTER) & ~STEREO_DAC) + | (mode ? STEREO_DAC : MONO_DAC))); } static int -detect_mixer (sb_devc * devc) +detect_mixer(sb_devc * devc) { - /* - * Detect the mixer by changing parameters of two volume channels. If the - * values read back match with the values written, the mixer is there (is - * it?) - */ - sb_setmixer (devc, FM_VOL, 0xff); - sb_setmixer (devc, VOC_VOL, 0x33); - - if (sb_getmixer (devc, FM_VOL) != 0xff) - return 0; - if (sb_getmixer (devc, VOC_VOL) != 0x33) - return 0; - - return 1; + /* Just trust the mixer is there */ + return 1; } static void -change_bits (sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) +change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) { - unsigned char mask; - int shift; + unsigned char mask; + int shift; - mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* Scale */ + mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; + newval = (int) ((newval * mask) + 50) / 100; /* Scale */ - shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; + shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; - *regval &= ~(mask << shift); /* Mask out previous value */ - *regval |= (newval & mask) << shift; /* Set the new value */ + *regval &= ~(mask << shift); /* Mask out previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ } static int -sb_mixer_get (sb_devc * devc, int dev) +sb_mixer_get(sb_devc * devc, int dev) { - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; + if (!((1 << dev) & devc->supported_devices)) + return -EINVAL; - return devc->levels[dev]; + return devc->levels[dev]; } void -smw_mixer_init (sb_devc * devc) +smw_mixer_init(sb_devc * devc) { - int i; + int i; - sb_setmixer (devc, 0x00, 0x18); /* Mute unused (Telephone) line */ - sb_setmixer (devc, 0x10, 0x38); /* Config register 2 */ + sb_setmixer(devc, 0x00, 0x18); /* Mute unused (Telephone) line */ + sb_setmixer(devc, 0x10, 0x38); /* Config register 2 */ - devc->supported_devices = 0; - for (i = 0; i < sizeof (smw_mix_regs); i++) - if (smw_mix_regs[i] != 0) - devc->supported_devices |= (1 << i); + devc->supported_devices = 0; + for (i = 0; i < sizeof(smw_mix_regs); i++) + if (smw_mix_regs[i] != 0) + devc->supported_devices |= (1 << i); - devc->supported_rec_devices = devc->supported_devices & - ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | - SOUND_MASK_VOLUME); + devc->supported_rec_devices = devc->supported_devices & + ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | + SOUND_MASK_VOLUME); - sb_mixer_reset (devc); + sb_mixer_reset(devc); } static int -smw_mixer_set (sb_devc * devc, int dev, int value) +smw_mixer_set(sb_devc * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int reg, val; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if (dev > 31) - return -EINVAL; - - if (!(devc->supported_devices & (1 << dev))) /* Not supported */ - return -EINVAL; - - switch (dev) - { - case SOUND_MIXER_VOLUME: - sb_setmixer (devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ - sb_setmixer (devc, 0x0c, 96 - (96 * right / 100)); - break; - - case SOUND_MIXER_BASS: - case SOUND_MIXER_TREBLE: - devc->levels[dev] = left | (right << 8); - - /* Set left bass and treble values */ - val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; - val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (devc, 0x0d, val); - - /* Set right bass and treble values */ - val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; - val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (devc, 0x0e, val); - break; - - default: - reg = smw_mix_regs[dev]; - if (reg == 0) - return -EINVAL; - sb_setmixer (devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ - sb_setmixer (devc, reg + 1, (24 - (24 * right / 100)) | 0x40); - } - - devc->levels[dev] = left | (right << 8); - return left | (right << 8); + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int reg, val; + + if (left > 100) + left = 100; + if (right > 100) + right = 100; + + if (dev > 31) + return -EINVAL; + + if (!(devc->supported_devices & (1 << dev))) /* Not supported */ + return -EINVAL; + + switch (dev) + { + case SOUND_MIXER_VOLUME: + sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); + break; + + case SOUND_MIXER_BASS: + case SOUND_MIXER_TREBLE: + devc->levels[dev] = left | (right << 8); + + /* Set left bass and treble values */ + val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; + val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer(devc, 0x0d, val); + + /* Set right bass and treble values */ + val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; + val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer(devc, 0x0e, val); + break; + + default: + reg = smw_mix_regs[dev]; + if (reg == 0) + return -EINVAL; + sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); + } + + devc->levels[dev] = left | (right << 8); + return left | (right << 8); } static int -sb_mixer_set (sb_devc * devc, int dev, int value) +sb_mixer_set(sb_devc * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; - int regoffs; - unsigned char val; + int regoffs; + unsigned char val; - if (devc->model == MDL_SMW) - return smw_mixer_set (devc, dev, value); + if (devc->model == MDL_SMW) + return smw_mixer_set(devc, dev, value); - if (left > 100) - left = 100; - if (right > 100) - right = 100; + if (left > 100) + left = 100; + if (right > 100) + right = 100; - if (dev > 31) - return -EINVAL; + if (dev > 31) + return -EINVAL; - if (!(devc->supported_devices & (1 << dev))) /* - * Not supported - */ - return -EINVAL; + if (!(devc->supported_devices & (1 << dev))) /* + * Not supported + */ + return -EINVAL; - regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; + regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; - if (regoffs == 0) - return -EINVAL; + if (regoffs == 0) + return -EINVAL; - val = sb_getmixer (devc, regoffs); - change_bits (devc, &val, dev, LEFT_CHN, left); + val = sb_getmixer(devc, regoffs); + change_bits(devc, &val, dev, LEFT_CHN, left); - devc->levels[dev] = left | (left << 8); + devc->levels[dev] = left | (left << 8); - if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* - * Change register + if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* + * Change register + */ + { + sb_setmixer(devc, regoffs, val); /* + * Save the old one */ - { - sb_setmixer (devc, regoffs, val); /* - * Save the old one - */ - regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; - - if (regoffs == 0) - return left | (left << 8); /* - * Just left channel present - */ + regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; - val = sb_getmixer (devc, regoffs); /* - * Read the new one - */ - } + if (regoffs == 0) + return left | (left << 8); /* + * Just left channel present + */ - change_bits (devc, &val, dev, RIGHT_CHN, right); + val = sb_getmixer(devc, regoffs); /* + * Read the new one + */ + } + change_bits(devc, &val, dev, RIGHT_CHN, right); - sb_setmixer (devc, regoffs, val); + sb_setmixer(devc, regoffs, val); - devc->levels[dev] = left | (right << 8); - return left | (right << 8); + devc->levels[dev] = left | (right << 8); + return left | (right << 8); } static void -set_recsrc (sb_devc * devc, int src) +set_recsrc(sb_devc * devc, int src) { - sb_setmixer (devc, RECORD_SRC, (sb_getmixer (devc, RECORD_SRC) & ~7) | (src & 0x7)); + sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); } static int -set_recmask (sb_devc * devc, int mask) +set_recmask(sb_devc * devc, int mask) { - int devmask, i; - unsigned char regimageL, regimageR; - - devmask = mask & devc->supported_rec_devices; - - switch (devc->model) - { - case MDL_SBPRO: - case MDL_ESS: - case MDL_JAZZ: - case MDL_SMW: - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* + int devmask, i; + unsigned char regimageL, regimageR; + + devmask = mask & devc->supported_rec_devices; + + switch (devc->model) + { + case MDL_SBPRO: + case MDL_ESS: + case MDL_JAZZ: + case MDL_SMW: + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* * More than one devices selected. Drop the * * previous selection */ - devmask &= ~devc->recmask; - } - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* + devmask &= ~devc->recmask; + } + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* * More than one devices selected. Default to * * mic */ - devmask = SOUND_MASK_MIC; - } - - - if (devmask ^ devc->recmask) /* - * Input source changed - */ - { - switch (devmask) - { - - case SOUND_MASK_MIC: - set_recsrc (devc, SRC__MIC); - break; - - case SOUND_MASK_LINE: - set_recsrc (devc, SRC__LINE); - break; - - case SOUND_MASK_CD: - set_recsrc (devc, SRC__CD); - break; - - default: - set_recsrc (devc, SRC__MIC); - } - } - - break; - - case MDL_SB16: - if (!devmask) - devmask = SOUND_MASK_MIC; - - regimageL = regimageR = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if ((1 << i) & devmask) - { - regimageL |= sb16_recmasks_L[i]; - regimageR |= sb16_recmasks_R[i]; + devmask = SOUND_MASK_MIC; + } + if (devmask ^ devc->recmask) /* + * Input source changed + */ + { + switch (devmask) + { + + case SOUND_MASK_MIC: + set_recsrc(devc, SRC__MIC); + break; + + case SOUND_MASK_LINE: + set_recsrc(devc, SRC__LINE); + break; + + case SOUND_MASK_CD: + set_recsrc(devc, SRC__CD); + break; + + default: + set_recsrc(devc, SRC__MIC); + } + } + break; + + case MDL_SB16: + if (!devmask) + devmask = SOUND_MASK_MIC; + + regimageL = regimageR = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if ((1 << i) & devmask) + { + regimageL |= sb16_recmasks_L[i]; + regimageR |= sb16_recmasks_R[i]; + } + sb_setmixer(devc, SB16_IMASK_L, regimageL); + sb_setmixer(devc, SB16_IMASK_R, regimageR); + break; } - sb_setmixer (devc, SB16_IMASK_L, regimageL); - sb_setmixer (devc, SB16_IMASK_R, regimageR); - break; - } - devc->recmask = devmask; - return devc->recmask; + devc->recmask = devmask; + return devc->recmask; } static int -sb_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - sb_devc *devc = mixer_devs[dev]->devc; - int val; + sb_devc *devc = mixer_devs[dev]->devc; + int val; /* * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). */ - if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) - { - int tmp; - - tmp = *(int *) arg; - - sb_setmixer (devc, 0x43, (~tmp) & 0x01); - return 0; - } - - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - switch (cmd & 0xff) + if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) { - case SOUND_MIXER_RECSRC: - val = *(int *) arg; - return (*(int *) arg = set_recmask (devc, val)); - break; + int tmp; - default: + tmp = *(int *) arg; - val = *(int *) arg; - return (*(int *) arg = sb_mixer_set (devc, cmd & 0xff, val)); + sb_setmixer(devc, 0x43, (~tmp) & 0x01); + return 0; } - else - switch (cmd & 0xff) + if (((cmd >> 8) & 0xff) == 'M') { - - case SOUND_MIXER_RECSRC: - return (*(int *) arg = devc->recmask); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = devc->supported_devices); - break; - - case SOUND_MIXER_STEREODEVS: - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - return (*(int *) arg = devc->supported_devices); - else - return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = devc->supported_rec_devices); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = devc->mixer_caps); - break; - - default: - return (*(int *) arg = sb_mixer_get (devc, cmd & 0xff)); - } - } - else - return -EINVAL; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + val = *(int *) arg; + return (*(int *) arg = set_recmask(devc, val)); + break; + + default: + + val = *(int *) arg; + return (*(int *) arg = sb_mixer_set(devc, cmd & 0xff, val)); + } else + switch (cmd & 0xff) + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = devc->recmask); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = devc->supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + return (*(int *) arg = devc->supported_devices); + else + return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = devc->supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = devc->mixer_caps); + break; + + default: + return (*(int *) arg = sb_mixer_get(devc, cmd & 0xff)); + } + } else + return -EINVAL; } static struct mixer_operations sb_mixer_operations = { - "SB", - "Sound Blaster", - sb_mixer_ioctl + "SB", + "Sound Blaster", + sb_mixer_ioctl }; static void -sb_mixer_reset (sb_devc * devc) +sb_mixer_reset(sb_devc * devc) { - char name[32]; - int i; + char name[32]; + int i; + extern int sm_games; - sprintf (name, "SB_%d", devc->sbmixnum); + sprintf(name, "SB_%d", devc->sbmixnum); - devc->levels = load_mixer_volumes (name, default_levels, 1); + if (sm_games) + devc->levels = load_mixer_volumes(name, smg_default_levels, 1); + else + devc->levels = load_mixer_volumes(name, sb_default_levels, 1); - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - sb_mixer_set (devc, i, devc->levels[i]); + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + sb_mixer_set(devc, i, devc->levels[i]); - set_recmask (devc, SOUND_MASK_MIC); + set_recmask(devc, SOUND_MASK_MIC); } int -sb_mixer_init (sb_devc * devc) +sb_mixer_init(sb_devc * devc) { - int mixer_type = 0; - - devc->sbmixnum = sbmixnum++; - devc->levels = NULL; - - sb_setmixer (devc, 0x00, 0); /* Reset mixer */ - - if (!(mixer_type = detect_mixer (devc))) - return 0; /* No mixer. Why? */ - - switch (devc->model) - { - case MDL_SBPRO: - case MDL_JAZZ: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = SBPRO_MIXER_DEVICES; - devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; - devc->iomap = &sbpro_mix; - break; - - case MDL_ESS: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = ES688_MIXER_DEVICES; - devc->supported_rec_devices = ES688_RECORDING_DEVICES; - devc->iomap = &es688_mix; - break; - - case MDL_SMW: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = 0; - devc->supported_rec_devices = 0; - devc->iomap = &sbpro_mix; - smw_mixer_init (devc); - break; - - case MDL_SB16: - devc->mixer_caps = 0; - devc->supported_devices = SB16_MIXER_DEVICES; - devc->supported_rec_devices = SB16_RECORDING_DEVICES; - devc->iomap = &sb16_mix; - break; - - default: - printk ("SB Warning: Unsupported mixer type %d\n", devc->model); - return 0; - } - - if (num_mixers >= MAX_MIXER_DEV) - return 0; - - - mixer_devs[num_mixers] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct mixer_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - if (mixer_devs[num_mixers] == NULL) - { - printk ("sb_mixer: Can't allocate memory\n"); - return 0; - } - - memcpy ((char *) mixer_devs[num_mixers], (char *) &sb_mixer_operations, - sizeof (struct mixer_operations)); - - mixer_devs[num_mixers]->devc = devc; - - sb_mixer_reset (devc); - devc->my_mixerdev = num_mixers++; - return 1; + int mixer_type = 0; + int m; + + devc->sbmixnum = sbmixnum++; + devc->levels = NULL; + + sb_setmixer(devc, 0x00, 0); /* Reset mixer */ + + if (!(mixer_type = detect_mixer(devc))) + return 0; /* No mixer. Why? */ + + switch (devc->model) + { + case MDL_SBPRO: + case MDL_AZTECH: + case MDL_JAZZ: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = SBPRO_MIXER_DEVICES; + devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; + devc->iomap = &sbpro_mix; + break; + + case MDL_ESS: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = ES688_MIXER_DEVICES; + devc->supported_rec_devices = ES688_RECORDING_DEVICES; + devc->iomap = &es688_mix; + break; + + case MDL_SMW: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = 0; + devc->supported_rec_devices = 0; + devc->iomap = &sbpro_mix; + smw_mixer_init(devc); + break; + + case MDL_SB16: + devc->mixer_caps = 0; + devc->supported_devices = SB16_MIXER_DEVICES; + devc->supported_rec_devices = SB16_RECORDING_DEVICES; + devc->iomap = &sb16_mix; + break; + + default: + printk("SB Warning: Unsupported mixer type %d\n", devc->model); + return 0; + } + + m = sound_alloc_mixerdev(); + if (m == -1) + return 0; + + + mixer_devs[m] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (mixer_devs[m] == NULL) + { + printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); + sound_unload_mixerdev(m); + return 0; + } + memcpy((char *) mixer_devs[m], (char *) &sb_mixer_operations, + sizeof(struct mixer_operations)); + + mixer_devs[m]->devc = devc; + + devc->my_mixerdev = m; + sb_mixer_reset(devc); + return 1; } #endif diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h index 5711b9105..d83c2dbad 100644 --- a/drivers/sound/sb_mixer.h +++ b/drivers/sound/sb_mixer.h @@ -17,6 +17,7 @@ * Added defines for the Sound Galaxy NX Pro mixer. * */ +#ifdef CONFIG_SBDSP #define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) @@ -168,11 +169,11 @@ MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) }; -#ifdef SM_GAMES /* Master volume is lower and PCM & FM volumes +/* SM_GAMES Master volume is lower and PCM & FM volumes higher than with SB Pro. This improves the sound quality */ -static int default_levels[32] = +static int smg_default_levels[32] = { 0x2020, /* Master Volume */ 0x4b4b, /* Bass */ @@ -193,9 +194,7 @@ static int default_levels[32] = 0x1515 /* Line3 */ }; -#else /* If the user selected just plain SB Pro */ - -static int default_levels[32] = +static int sb_default_levels[32] = { 0x5a5a, /* Master Volume */ 0x4b4b, /* Bass */ @@ -215,7 +214,6 @@ static int default_levels[32] = 0x4040, /* Line2 */ 0x1515 /* Line3 */ }; -#endif /* SM_GAMES */ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = { @@ -283,3 +281,4 @@ static char smw_mix_regs[] = /* Left mixer registers */ #define SRC__LINE 7 /* Use Line-in for recording source */ #endif +#endif diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 14d2f24de..8995e0072 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -16,7 +16,9 @@ #define SEQUENCER_C #include "sound_config.h" -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#include "softoss.h" +int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL; #include "midi_ctrl.h" @@ -57,8 +59,8 @@ static int midi_opened[MAX_MIDI_DEV] = static int midi_written[MAX_MIDI_DEV] = {0}; -unsigned long prev_input_time = 0; -int prev_event_time; +static unsigned long prev_input_time = 0; +static int prev_event_time; #include "tuning.h" @@ -75,433 +77,423 @@ static int output_threshold; static int pre_event_timeout; static unsigned synth_open_mask; -static int seq_queue (unsigned char *note, char nonblock); -static void seq_startplay (void); -static int seq_sync (void); -static void seq_reset (void); +static int seq_queue(unsigned char *note, char nonblock); +static void seq_startplay(void); +static int seq_sync(void); +static void seq_reset(void); #if MAX_SYNTH_DEV > 15 #error Too many synthesizer devices enabled. #endif int -sequencer_read (int dev, struct fileinfo *file, char *buf, int count) +sequencer_read(int dev, struct fileinfo *file, char *buf, int count) { - int c = count, p = 0; - int ev_len; - unsigned long flags; - - dev = dev >> 4; - - ev_len = seq_mode == SEQ_1 ? 4 : 8; - - save_flags (flags); - cli (); - if (!iqlen) - { - if ((file->flags & (O_NONBLOCK) ? - 1 : 0)) - { - restore_flags (flags); - return -EAGAIN; - } + int c = count, p = 0; + int ev_len; + unsigned long flags; + dev = dev >> 4; - { - unsigned long tlimit; + ev_len = seq_mode == SEQ_1 ? 4 : 8; - if (pre_event_timeout) - current->timeout = tlimit = jiffies + (pre_event_timeout); - else - tlimit = (unsigned long) -1; - midi_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper); - if (!(midi_sleep_flag.opts & WK_WAKEUP)) + save_flags(flags); + cli(); + if (!iqlen) { - if (jiffies >= tlimit) - midi_sleep_flag.opts |= WK_TIMEOUT; - } - midi_sleep_flag.opts &= ~WK_SLEEP; - }; - - if (!iqlen) - { - restore_flags (flags); - return 0; - } - } + if ((file->flags & (O_NONBLOCK) ? + 1 : 0)) + { + restore_flags(flags); + return -EAGAIN; + } + { + unsigned long tlimit; + + if (pre_event_timeout) + current->timeout = tlimit = jiffies + (pre_event_timeout); + else + tlimit = (unsigned long) -1; + midi_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper); + if (!(midi_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag.opts |= WK_TIMEOUT; + } + midi_sleep_flag.opts &= ~WK_SLEEP; + }; - while (iqlen && c >= ev_len) - { + if (!iqlen) + { + restore_flags(flags); + return 0; + } + } + while (iqlen && c >= ev_len) + { - { - char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; + { + char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; - copy_to_user (&(buf)[p], fixit, ev_len); - }; - p += ev_len; - c -= ev_len; + copy_to_user(&(buf)[p], fixit, ev_len); + }; + p += ev_len; + c -= ev_len; - iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; - iqlen--; - } - restore_flags (flags); + iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; + iqlen--; + } + restore_flags(flags); - return count - c; + return count - c; } static void -sequencer_midi_output (int dev) +sequencer_midi_output(int dev) { - /* - * Currently NOP - */ + /* + * Currently NOP + */ } void -seq_copy_to_input (unsigned char *event_rec, int len) -{ - unsigned long flags; - - /* - * Verify that the len is valid for the current mode. - */ - - if (len != 4 && len != 8) - return; - if ((seq_mode == SEQ_1) != (len == 4)) - return; - - if (iqlen >= (SEQ_MAX_QUEUE - 1)) - return; /* Overflow */ - - save_flags (flags); - cli (); - memcpy (&iqueue[iqtail * IEV_SZ], event_rec, len); - iqlen++; - iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - - if ((midi_sleep_flag.opts & WK_SLEEP)) - { - { - midi_sleep_flag.opts = WK_WAKEUP; - wake_up (&midi_sleeper); - }; - } - restore_flags (flags); -} - -static void -sequencer_midi_input (int dev, unsigned char data) +seq_copy_to_input(unsigned char *event_rec, int len) { - unsigned int tstamp; - unsigned char event_rec[4]; - - if (data == 0xfe) /* Ignore active sensing */ - return; + unsigned long flags; - tstamp = jiffies - seq_time; + /* + * Verify that the len is valid for the current mode. + */ - if (tstamp != prev_input_time) - { - tstamp = (tstamp << 8) | SEQ_WAIT; + if (len != 4 && len != 8) + return; + if ((seq_mode == SEQ_1) != (len == 4)) + return; - seq_copy_to_input ((unsigned char *) &tstamp, 4); - prev_input_time = tstamp; - } + if (iqlen >= (SEQ_MAX_QUEUE - 1)) + return; /* Overflow */ - event_rec[0] = SEQ_MIDIPUTC; - event_rec[1] = data; - event_rec[2] = dev; - event_rec[3] = 0; + save_flags(flags); + cli(); + memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); + iqlen++; + iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - seq_copy_to_input (event_rec, 4); + if ((midi_sleep_flag.opts & WK_SLEEP)) + { + { + midi_sleep_flag.opts = WK_WAKEUP; + wake_up(&midi_sleeper); + }; + } + restore_flags(flags); } -void -seq_input_event (unsigned char *event_rec, int len) +static void +sequencer_midi_input(int dev, unsigned char data) { - unsigned long this_time; + unsigned int tstamp; + unsigned char event_rec[4]; - if (seq_mode == SEQ_2) - this_time = tmr->get_time (tmr_no); - else - this_time = jiffies - seq_time; + if (data == 0xfe) /* Ignore active sensing */ + return; - if (this_time != prev_input_time) - { - unsigned char tmp_event[8]; + if (softsynthp != NULL) + tstamp = softsynthp(SSYN_GETTIME, 0, 0, 0); + else + tstamp = jiffies - seq_time; - tmp_event[0] = EV_TIMING; - tmp_event[1] = TMR_WAIT_ABS; - tmp_event[2] = 0; - tmp_event[3] = 0; - *(unsigned int *) &tmp_event[4] = this_time; + if (tstamp != prev_input_time) + { + tstamp = (tstamp << 8) | SEQ_WAIT; - seq_copy_to_input (tmp_event, 8); - prev_input_time = this_time; - } + seq_copy_to_input((unsigned char *) &tstamp, 4); + prev_input_time = tstamp; + } + event_rec[0] = SEQ_MIDIPUTC; + event_rec[1] = data; + event_rec[2] = dev; + event_rec[3] = 0; - seq_copy_to_input (event_rec, len); + seq_copy_to_input(event_rec, 4); } -int -sequencer_write (int dev, struct fileinfo *file, const char *buf, int count) +void +seq_input_event(unsigned char *event_rec, int len) { - unsigned char event_rec[EV_SZ], ev_code; - int p = 0, c, ev_size; - int err; - int mode = file->mode & O_ACCMODE; - - dev = dev >> 4; - - DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); - - if (mode == OPEN_READ) - return -EIO; - - c = count; - - while (c >= 4) - { - copy_from_user ((char *) event_rec, &(buf)[p], 4); - ev_code = event_rec[0]; - - if (ev_code == SEQ_FULLSIZE) - { - int err, fmt; + unsigned long this_time; - dev = *(unsigned short *) &event_rec[2]; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - - fmt = (*(short *) &event_rec[0]) & 0xffff; - err = synth_devs[dev]->load_patch (dev, fmt, buf, p + 4, c, 0); - if (err < 0) - return err; - - return err; - } - - if (ev_code >= 128) - { - if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) - { - printk ("Sequencer: Invalid level 2 event %x\n", ev_code); - return -EINVAL; - } - - ev_size = 8; - - if (c < ev_size) - { - if (!seq_playing) - seq_startplay (); - return count - c; - } - - copy_from_user ((char *) &event_rec[4], &(buf)[p + 4], 4); - - } - else - { - if (seq_mode == SEQ_2) - { - printk ("Sequencer: 4 byte event in level 2 mode\n"); - return -EINVAL; - } - ev_size = 4; - - if (event_rec[0] != SEQ_MIDIPUTC) - obsolete_api_used = 1; - } - - if (event_rec[0] == SEQ_MIDIPUTC) - { + if (seq_mode == SEQ_2) + this_time = tmr->get_time(tmr_no); + else if (softsynthp != NULL) + this_time = softsynthp(SSYN_GETTIME, 0, 0, 0); + else + this_time = jiffies - seq_time; - if (!midi_opened[event_rec[2]]) - { - int mode; - int dev = event_rec[2]; + if (this_time != prev_input_time) + { + unsigned char tmp_event[8]; - if (dev >= max_mididev) - { - printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); - return -ENXIO; - } + tmp_event[0] = EV_TIMING; + tmp_event[1] = TMR_WAIT_ABS; + tmp_event[2] = 0; + tmp_event[3] = 0; + *(unsigned int *) &tmp_event[4] = this_time; - mode = file->mode & O_ACCMODE; + seq_copy_to_input(tmp_event, 8); + prev_input_time = this_time; + } + seq_copy_to_input(event_rec, len); +} - if ((err = midi_devs[dev]->open (dev, mode, - sequencer_midi_input, sequencer_midi_output)) < 0) - { - seq_reset (); - printk ("Sequencer Error: Unable to open Midi #%d\n", dev); - return err; - } +int +sequencer_write(int dev, struct fileinfo *file, const char *buf, int count) +{ + unsigned char event_rec[EV_SZ], ev_code; + int p = 0, c, ev_size; + int err; + int mode = file->mode & O_ACCMODE; - midi_opened[dev] = 1; - } + dev = dev >> 4; - } + DEB(printk("sequencer_write(dev=%d, count=%d)\n", dev, count)); - if (!seq_queue (event_rec, (file->flags & (O_NONBLOCK) ? - 1 : 0))) - { - int processed = count - c; + if (mode == OPEN_READ) + return -EIO; - if (!seq_playing) - seq_startplay (); + c = count; - if (!processed && (file->flags & (O_NONBLOCK) ? - 1 : 0)) - return -EAGAIN; - else - return processed; - } - - p += ev_size; - c -= ev_size; - } + while (c >= 4) + { + copy_from_user((char *) event_rec, &(buf)[p], 4); + ev_code = event_rec[0]; + + if (ev_code == SEQ_FULLSIZE) + { + int err, fmt; + + dev = *(unsigned short *) &event_rec[2]; + if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) + return -ENXIO; + + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; + + fmt = (*(short *) &event_rec[0]) & 0xffff; + err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); + if (err < 0) + return err; + + return err; + } + if (ev_code >= 128) + { + if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) + { + printk("Sequencer: Invalid level 2 event %x\n", ev_code); + return -EINVAL; + } + ev_size = 8; + + if (c < ev_size) + { + if (!seq_playing) + seq_startplay(); + return count - c; + } + copy_from_user((char *) &event_rec[4], &(buf)[p + 4], 4); + + } else + { + if (seq_mode == SEQ_2) + { + printk("Sequencer: 4 byte event in level 2 mode\n"); + return -EINVAL; + } + ev_size = 4; + + if (event_rec[0] != SEQ_MIDIPUTC) + obsolete_api_used = 1; + } + + if (event_rec[0] == SEQ_MIDIPUTC) + { + + if (!midi_opened[event_rec[2]]) + { + int mode; + int dev = event_rec[2]; + + if (dev >= max_mididev) + { + printk("Sequencer Error: Nonexistent MIDI device %d\n", dev); + return -ENXIO; + } + mode = file->mode & O_ACCMODE; + + if ((err = midi_devs[dev]->open(dev, mode, + sequencer_midi_input, sequencer_midi_output)) < 0) + { + seq_reset(); + printk("Sequencer Error: Unable to open Midi #%d\n", dev); + return err; + } + midi_opened[dev] = 1; + } + } + if (!seq_queue(event_rec, (file->flags & (O_NONBLOCK) ? + 1 : 0))) + { + int processed = count - c; + + if (!seq_playing) + seq_startplay(); + + if (!processed && (file->flags & (O_NONBLOCK) ? + 1 : 0)) + return -EAGAIN; + else + return processed; + } + p += ev_size; + c -= ev_size; + } - if (!seq_playing) - seq_startplay (); + if (!seq_playing) + seq_startplay(); - return count; + return count; } static int -seq_queue (unsigned char *note, char nonblock) +seq_queue(unsigned char *note, char nonblock) { - /* - * Test if there is space in the queue - */ - - if (qlen >= SEQ_MAX_QUEUE) - if (!seq_playing) - seq_startplay (); /* - * Give chance to drain the queue - */ + /* + * Test if there is space in the queue + */ - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP)) - { - /* - * Sleep until there is enough space on the queue - */ + if (qlen >= SEQ_MAX_QUEUE) + if (!seq_playing) + seq_startplay(); /* + * Give chance to drain the queue + */ - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - seq_sleep_flag.opts &= ~WK_SLEEP;; - } + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP)) + { + /* + * Sleep until there is enough space on the queue + */ - if (qlen >= SEQ_MAX_QUEUE) - { - return 0; /* + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + seq_sleep_flag.opts &= ~WK_SLEEP;; + } + if (qlen >= SEQ_MAX_QUEUE) + { + return 0; /* * To be sure */ - } - memcpy (&queue[qtail * EV_SZ], note, EV_SZ); + } + memcpy(&queue[qtail * EV_SZ], note, EV_SZ); - qtail = (qtail + 1) % SEQ_MAX_QUEUE; - qlen++; + qtail = (qtail + 1) % SEQ_MAX_QUEUE; + qlen++; - return 1; + return 1; } static int -extended_event (unsigned char *q) +extended_event(unsigned char *q) { - int dev = q[2]; + int dev = q[2]; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; - switch (q[1]) - { - case SEQ_NOTEOFF: - synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]); - break; + switch (q[1]) + { + case SEQ_NOTEOFF: + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_NOTEON: + if (q[4] > 127 && q[4] != 255) + return 0; + + if (q[5] == 0) + { + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + } + synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_PGMCHANGE: + synth_devs[dev]->set_instr(dev, q[3], q[4]); + break; + + case SEQ_AFTERTOUCH: + synth_devs[dev]->aftertouch(dev, q[3], q[4]); + break; + + case SEQ_BALANCE: + synth_devs[dev]->panning(dev, q[3], (char) q[4]); + break; + + case SEQ_CONTROLLER: + synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); + break; + + case SEQ_VOLMODE: + if (synth_devs[dev]->volume_method != NULL) + synth_devs[dev]->volume_method(dev, q[3]); + break; + + default: + return -EINVAL; + } - case SEQ_NOTEON: - if (q[4] > 127 && q[4] != 255) return 0; - - if (q[5] == 0) - { - synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]); - break; - } - synth_devs[dev]->start_note (dev, q[3], q[4], q[5]); - break; - - case SEQ_PGMCHANGE: - synth_devs[dev]->set_instr (dev, q[3], q[4]); - break; - - case SEQ_AFTERTOUCH: - synth_devs[dev]->aftertouch (dev, q[3], q[4]); - break; - - case SEQ_BALANCE: - synth_devs[dev]->panning (dev, q[3], (char) q[4]); - break; - - case SEQ_CONTROLLER: - synth_devs[dev]->controller (dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); - break; - - case SEQ_VOLMODE: - if (synth_devs[dev]->volume_method != NULL) - synth_devs[dev]->volume_method (dev, q[3]); - break; - - default: - return -EINVAL; - } - - return 0; } static int -find_voice (int dev, int chn, int note) +find_voice(int dev, int chn, int note) { - unsigned short key; - int i; + unsigned short key; + int i; - key = (chn << 8) | (note + 1); + key = (chn << 8) | (note + 1); - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if (synth_devs[dev]->alloc.map[i] == key) - return i; + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if (synth_devs[dev]->alloc.map[i] == key) + return i; - return -1; + return -1; } static int -alloc_voice (int dev, int chn, int note) +alloc_voice(int dev, int chn, int note) { - unsigned short key; - int voice; + unsigned short key; + int voice; - key = (chn << 8) | (note + 1); + key = (chn << 8) | (note + 1); - voice = synth_devs[dev]->alloc_voice (dev, chn, note, - &synth_devs[dev]->alloc); - synth_devs[dev]->alloc.map[voice] = key; - synth_devs[dev]->alloc.alloc_times[voice] = - synth_devs[dev]->alloc.timestamp++; - return voice; + voice = synth_devs[dev]->alloc_voice(dev, chn, note, + &synth_devs[dev]->alloc); + synth_devs[dev]->alloc.map[voice] = key; + synth_devs[dev]->alloc.alloc_times[voice] = + synth_devs[dev]->alloc.timestamp++; + return voice; } static void -seq_chn_voice_event (unsigned char *event_rec) +seq_chn_voice_event(unsigned char *event_rec) { #define dev event_rec[1] #define cmd event_rec[2] @@ -509,73 +501,70 @@ seq_chn_voice_event (unsigned char *event_rec) #define note event_rec[4] #define parm event_rec[5] - int voice = -1; + int voice = -1; - if ((int) dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - if (seq_mode == SEQ_2) - { - if (synth_devs[dev]->alloc_voice) - voice = find_voice (dev, chn, note); + if ((int) dev > max_synthdev || synth_devs[dev] == NULL) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; - if (cmd == MIDI_NOTEON && parm == 0) - { - cmd = MIDI_NOTEOFF; - parm = 64; - } - } - - switch (cmd) - { - case MIDI_NOTEON: - if (note > 127 && note != 255) /* Not a seq2 feature */ - return; - - if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) - { /* Internal synthesizer (FM, GUS, etc) */ - voice = alloc_voice (dev, chn, note); - } - - if (voice == -1) - voice = chn; - - if (seq_mode == SEQ_2 && (int) dev < num_synths) - { - /* - * The MIDI channel 10 is a percussive channel. Use the note - * number to select the proper patch (128 to 255) to play. - */ - - if (chn == 9) - { - synth_devs[dev]->set_instr (dev, voice, 128 + note); - synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; - } - synth_devs[dev]->setup_voice (dev, voice, chn); - } - - synth_devs[dev]->start_note (dev, voice, note, parm); - break; - - case MIDI_NOTEOFF: - if (voice == -1) - voice = chn; - synth_devs[dev]->kill_note (dev, voice, note, parm); - break; - - case MIDI_KEY_PRESSURE: - if (voice == -1) - voice = chn; - synth_devs[dev]->aftertouch (dev, voice, parm); - break; - - default:; - } + if (seq_mode == SEQ_2) + { + if (synth_devs[dev]->alloc_voice) + voice = find_voice(dev, chn, note); + + if (cmd == MIDI_NOTEON && parm == 0) + { + cmd = MIDI_NOTEOFF; + parm = 64; + } + } + switch (cmd) + { + case MIDI_NOTEON: + if (note > 127 && note != 255) /* Not a seq2 feature */ + return; + + if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) + { /* Internal synthesizer (FM, GUS, etc) */ + voice = alloc_voice(dev, chn, note); + } + if (voice == -1) + voice = chn; + + if (seq_mode == SEQ_2 && (int) dev < num_synths) + { + /* + * The MIDI channel 10 is a percussive channel. Use the note + * number to select the proper patch (128 to 255) to play. + */ + + if (chn == 9) + { + synth_devs[dev]->set_instr(dev, voice, 128 + note); + synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; + } + synth_devs[dev]->setup_voice(dev, voice, chn); + } + synth_devs[dev]->start_note(dev, voice, note, parm); + break; + + case MIDI_NOTEOFF: + if (voice == -1) + voice = chn; + synth_devs[dev]->kill_note(dev, voice, note, parm); + break; + + case MIDI_KEY_PRESSURE: + if (voice == -1) + voice = chn; + synth_devs[dev]->aftertouch(dev, voice, parm); + break; + + default:; + } #undef dev #undef cmd #undef chn @@ -585,1422 +574,1422 @@ seq_chn_voice_event (unsigned char *event_rec) static void -seq_chn_common_event (unsigned char *event_rec) +seq_chn_common_event(unsigned char *event_rec) { - unsigned char dev = event_rec[1]; - unsigned char cmd = event_rec[2]; - unsigned char chn = event_rec[3]; - unsigned char p1 = event_rec[4]; - - /* unsigned char p2 = event_rec[5]; */ - unsigned short w14 = *(short *) &event_rec[6]; - - if ((int) dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - switch (cmd) - { - case MIDI_PGM_CHANGE: - if (seq_mode == SEQ_2) - { - synth_devs[dev]->chn_info[chn].pgm_num = p1; - if ((int) dev >= num_synths) - synth_devs[dev]->set_instr (dev, chn, p1); - } - else - synth_devs[dev]->set_instr (dev, chn, p1); + unsigned char dev = event_rec[1]; + unsigned char cmd = event_rec[2]; + unsigned char chn = event_rec[3]; + unsigned char p1 = event_rec[4]; - break; + /* unsigned char p2 = event_rec[5]; */ + unsigned short w14 = *(short *) &event_rec[6]; - case MIDI_CTL_CHANGE: - if (seq_mode == SEQ_2) - { - if (chn > 15 || p1 > 127) - break; - - synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; - - if (p1 < 32) /* Setting MSB should clear LSB to 0 */ - synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; - - if ((int) dev < num_synths) - { - int val = w14 & 0x7f; - int i, key; - - if (p1 < 64) /* Combine MSB and LSB */ - { - val = ((synth_devs[dev]-> - chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) - | (synth_devs[dev]-> - chn_info[chn].controllers[p1 | 32] & 0x7f); - p1 &= ~32; - } - - /* Handle all playing notes on this channel */ - - key = ((int) chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->controller (dev, i, p1, val); - } - else - synth_devs[dev]->controller (dev, chn, p1, w14); - } - else /* Mode 1 */ - synth_devs[dev]->controller (dev, chn, p1, w14); - break; - - case MIDI_PITCH_BEND: - if (seq_mode == SEQ_2) - { - synth_devs[dev]->chn_info[chn].bender_value = w14; - - if ((int) dev < num_synths) - { /* Handle all playing notes on this channel */ - int i, key; - - key = (chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->bender (dev, i, w14); - } - else - synth_devs[dev]->bender (dev, chn, w14); - } - else /* MODE 1 */ - synth_devs[dev]->bender (dev, chn, w14); - break; - - default:; - } + if ((int) dev > max_synthdev || synth_devs[dev] == NULL) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + switch (cmd) + { + case MIDI_PGM_CHANGE: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].pgm_num = p1; + if ((int) dev >= num_synths) + synth_devs[dev]->set_instr(dev, chn, p1); + } else + synth_devs[dev]->set_instr(dev, chn, p1); + + break; + + case MIDI_CTL_CHANGE: + if (seq_mode == SEQ_2) + { + if (chn > 15 || p1 > 127) + break; + + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; + + if (p1 < 32) /* Setting MSB should clear LSB to 0 */ + synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; + + if ((int) dev < num_synths) + { + int val = w14 & 0x7f; + int i, key; + + if (p1 < 64) /* Combine MSB and LSB */ + { + val = ((synth_devs[dev]-> + chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) + | (synth_devs[dev]-> + chn_info[chn].controllers[p1 | 32] & 0x7f); + p1 &= ~32; + } + /* Handle all playing notes on this channel */ + + key = ((int) chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->controller(dev, i, p1, val); + } else + synth_devs[dev]->controller(dev, chn, p1, w14); + } else /* Mode 1 */ + synth_devs[dev]->controller(dev, chn, p1, w14); + break; + + case MIDI_PITCH_BEND: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].bender_value = w14; + + if ((int) dev < num_synths) + { /* Handle all playing notes on this channel */ + int i, key; + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->bender(dev, i, w14); + } else + synth_devs[dev]->bender(dev, chn, w14); + } else /* MODE 1 */ + synth_devs[dev]->bender(dev, chn, w14); + break; + + default:; + } } static int -seq_timing_event (unsigned char *event_rec) +seq_timing_event(unsigned char *event_rec) { - unsigned char cmd = event_rec[1]; - unsigned int parm = *(int *) &event_rec[4]; - - if (seq_mode == SEQ_2) - { - int ret; - - if ((ret = tmr->event (tmr_no, event_rec)) == TIMER_ARMED) - { - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } - } - return ret; - } - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - - /* - * NOTE! No break here. Execution of TMR_WAIT_REL continues in the - * next case (TMR_WAIT_ABS) - */ - - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - time = parm; - prev_event_time = time; - - seq_playing = 1; - request_sound_timer (time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; + unsigned char cmd = event_rec[1]; + unsigned int parm = *(int *) &event_rec[4]; - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } - - return TIMER_ARMED; - } - break; - - case TMR_START: - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - break; - - case TMR_STOP: - break; - - case TMR_CONTINUE: - break; - - case TMR_TEMPO: - break; - - case TMR_ECHO: - if (seq_mode == SEQ_2) - seq_copy_to_input (event_rec, 8); - else - { - parm = (parm << 8 | SEQ_ECHO); - seq_copy_to_input ((unsigned char *) &parm, 4); - } - break; - - default:; - } + if (seq_mode == SEQ_2) + { + int ret; + + if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) + { + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } + } + return ret; + } + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + + /* + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ + + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + time = parm; + prev_event_time = time; + + seq_playing = 1; + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, time, 0, 0); + else + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } + return TIMER_ARMED; + } + break; + + case TMR_START: + if (softsynthp != NULL) + { + softsynthp(SSYN_START, 0, 0, 0); + seq_time = 0; + } else + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + break; + + case TMR_STOP: + break; + + case TMR_CONTINUE: + break; + + case TMR_TEMPO: + break; + + case TMR_ECHO: + if (seq_mode == SEQ_2) + seq_copy_to_input(event_rec, 8); + else + { + parm = (parm << 8 | SEQ_ECHO); + seq_copy_to_input((unsigned char *) &parm, 4); + } + break; + + default:; + } - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static void -seq_local_event (unsigned char *event_rec) +seq_local_event(unsigned char *event_rec) { - unsigned char cmd = event_rec[1]; - unsigned int parm = *((unsigned int *) &event_rec[4]); + unsigned char cmd = event_rec[1]; + unsigned int parm = *((unsigned int *) &event_rec[4]); - switch (cmd) - { - case LOCL_STARTAUDIO: + switch (cmd) + { + case LOCL_STARTAUDIO: #ifdef CONFIG_AUDIO - DMAbuf_start_devices (parm); + DMAbuf_start_devices(parm); #endif - break; + break; - default:; - } + default:; + } } static void -seq_sysex_message (unsigned char *event_rec) +seq_sysex_message(unsigned char *event_rec) { - int dev = event_rec[1]; - int i, l = 0; - unsigned char *buf = &event_rec[2]; - - if ((int) dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - l = 0; - for (i = 0; i < 6 && buf[i] != 0xff; i++) - l = i + 1; - - if (!synth_devs[dev]->send_sysex) - return; - if (l > 0) - synth_devs[dev]->send_sysex (dev, buf, l); + int dev = event_rec[1]; + int i, l = 0; + unsigned char *buf = &event_rec[2]; + + if ((int) dev > max_synthdev) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + l = 0; + for (i = 0; i < 6 && buf[i] != 0xff; i++) + l = i + 1; + + if (!synth_devs[dev]->send_sysex) + return; + if (l > 0) + synth_devs[dev]->send_sysex(dev, buf, l); } static int -play_event (unsigned char *q) +play_event(unsigned char *q) { - /* - * NOTE! This routine returns - * 0 = normal event played. - * 1 = Timer armed. Suspend playback until timer callback. - * 2 = MIDI output buffer full. Restore queue and suspend until timer - */ - unsigned int *delay; - - switch (q[0]) - { - case SEQ_NOTEOFF: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->kill_note (0, q[1], 255, q[3]); - break; - - case SEQ_NOTEON: - if (q[4] < 128 || q[4] == 255) - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->start_note (0, q[1], q[2], q[3]); - break; - - case SEQ_WAIT: - delay = (unsigned int *) q; /* - * Bytes 1 to 3 are containing the * - * delay in 'ticks' - */ - *delay = (*delay >> 8) & 0xffffff; - - if (*delay > 0) - { - long time; - - seq_playing = 1; - time = *delay; - prev_event_time = time; - - request_sound_timer (time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } - /* - * The timer is now active and will reinvoke this function - * after the timer expires. Return to the caller now. - */ - return 1; - } - break; - - case SEQ_PGMCHANGE: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->set_instr (0, q[1], q[2]); - break; - - case SEQ_SYNCTIMER: /* - * Reset timer + /* + * NOTE! This routine returns + * 0 = normal event played. + * 1 = Timer armed. Suspend playback until timer callback. + * 2 = MIDI output buffer full. Restore queue and suspend until timer + */ + unsigned int *delay; + + switch (q[0]) + { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note(0, q[1], 255, q[3]); + break; + + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note(0, q[1], q[2], q[3]); + break; + + case SEQ_WAIT: + delay = (unsigned int *) q; /* + * Bytes 1 to 3 are containing the * + * delay in 'ticks' + */ + *delay = (*delay >> 8) & 0xffffff; + + if (*delay > 0) + { + long time; + + seq_playing = 1; + time = *delay; + prev_event_time = time; + + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, time, 0, 0); + else + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. + */ + return 1; + } + break; + + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr(0, q[1], q[2]); + break; + + case SEQ_SYNCTIMER: /* + * Reset timer */ - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - break; - - case SEQ_MIDIPUTC: /* + if (softsynthp != NULL) + seq_time = 0; + else + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + if (softsynthp != NULL) + softsynthp(SSYN_START, 0, 0, 0); + break; + + case SEQ_MIDIPUTC: /* * Put a midi character */ - if (midi_opened[q[2]]) - { - int dev; - - dev = q[2]; - - if (dev < 0 || dev >= num_midis) - break; - - if (!midi_devs[dev]->outputc (dev, q[1])) - { - /* - * Output FIFO is full. Wait one timer cycle and try again. - */ - - seq_playing = 1; - request_sound_timer (-1); - return 2; - } - else - midi_written[dev] = 1; - } - break; - - case SEQ_ECHO: - seq_copy_to_input (q, 4); /* - * Echo back to the process - */ - break; - - case SEQ_PRIVATE: - if ((int) q[1] < max_synthdev) - synth_devs[q[1]]->hw_control (q[1], q); - break; - - case SEQ_EXTENDED: - extended_event (q); - break; - - case EV_CHN_VOICE: - seq_chn_voice_event (q); - break; - - case EV_CHN_COMMON: - seq_chn_common_event (q); - break; - - case EV_TIMING: - if (seq_timing_event (q) == TIMER_ARMED) - { - return 1; - } - break; - - case EV_SEQ_LOCAL: - seq_local_event (q); - break; - - case EV_SYSEX: - seq_sysex_message (q); - break; - - default:; - } + if (midi_opened[q[2]]) + { + int dev; + + dev = q[2]; + + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + break; + + if (!midi_devs[dev]->outputc(dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ + + seq_playing = 1; + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, -1, 0, 0); + else + request_sound_timer(-1); + return 2; + } else + midi_written[dev] = 1; + } + break; + + case SEQ_ECHO: + seq_copy_to_input(q, 4); /* + * Echo back to the process + */ + break; + + case SEQ_PRIVATE: + if ((int) q[1] < max_synthdev) + synth_devs[q[1]]->hw_control(q[1], q); + break; + + case SEQ_EXTENDED: + extended_event(q); + break; + + case EV_CHN_VOICE: + seq_chn_voice_event(q); + break; + + case EV_CHN_COMMON: + seq_chn_common_event(q); + break; + + case EV_TIMING: + if (seq_timing_event(q) == TIMER_ARMED) + { + return 1; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event(q); + break; + + case EV_SYSEX: + seq_sysex_message(q); + break; + + default:; + } - return 0; + return 0; } static void -seq_startplay (void) +seq_startplay(void) { - unsigned long flags; - int this_one, action; - - while (qlen > 0) - { - - save_flags (flags); - cli (); - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - restore_flags (flags); - - seq_playing = 1; - - if ((action = play_event (&queue[this_one * EV_SZ]))) - { /* Suspend playback. Next timer routine invokes this routine again */ - if (action == 2) - { - qlen++; - qhead = this_one; - } - return; - } + unsigned long flags; + int this_one, action; - } + while (qlen > 0) + { - seq_playing = 0; + save_flags(flags); + cli(); + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + restore_flags(flags); + + seq_playing = 1; + + if ((action = play_event(&queue[this_one * EV_SZ]))) + { /* Suspend playback. Next timer routine invokes this routine again */ + if (action == 2) + { + qlen++; + qhead = this_one; + } + return; + } + } - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; + seq_playing = 0; - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } } static void -reset_controllers (int dev, unsigned char *controller, int update_dev) +reset_controllers(int dev, unsigned char *controller, int update_dev) { - int i; + int i; - for (i = 0; i < 128; i++) - controller[i] = ctrl_def_values[i]; + for (i = 0; i < 128; i++) + controller[i] = ctrl_def_values[i]; } static void -setup_mode2 (void) +setup_mode2(void) { - int dev; - - max_synthdev = num_synths; - - for (dev = 0; dev < num_midis; dev++) - if (midi_devs[dev]->converter != NULL) - { - synth_devs[max_synthdev++] = - midi_devs[dev]->converter; - } + int dev; - for (dev = 0; dev < max_synthdev; dev++) - { - int chn; + max_synthdev = num_synths; - synth_devs[dev]->sysex_ptr = 0; - synth_devs[dev]->emulation = 0; + for (dev = 0; dev < num_midis; dev++) + if (midi_devs[dev] && midi_devs[dev]->converter != NULL) + { + synth_devs[max_synthdev++] = + midi_devs[dev]->converter; + } + for (dev = 0; dev < max_synthdev; dev++) + { + int chn; + + synth_devs[dev]->sysex_ptr = 0; + synth_devs[dev]->emulation = 0; + + for (chn = 0; chn < 16; chn++) + { + synth_devs[dev]->chn_info[chn].pgm_num = 0; + reset_controllers(dev, + synth_devs[dev]->chn_info[chn].controllers, + 0); + synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ + synth_devs[dev]->chn_info[chn].bender_range = 200; + } + } - for (chn = 0; chn < 16; chn++) - { - synth_devs[dev]->chn_info[chn].pgm_num = 0; - reset_controllers (dev, - synth_devs[dev]->chn_info[chn].controllers, - 0); - synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ - synth_devs[dev]->chn_info[chn].bender_range = 200; - } - } - - max_mididev = 0; - seq_mode = SEQ_2; + max_mididev = 0; + seq_mode = SEQ_2; } int -sequencer_open (int dev, struct fileinfo *file) +sequencer_open(int dev, struct fileinfo *file) { - int retval, mode, i; - int level, tmp; - unsigned long flags; + int retval, mode, i; + int level, tmp; + unsigned long flags; - if (!sequencer_ok) - sequencer_init (); + if (!sequencer_ok) + sequencer_init(); - level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; + level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - DEB (printk ("sequencer_open(dev=%d)\n", dev)); + DEB(printk("sequencer_open(dev=%d)\n", dev)); + + if (!sequencer_ok) + { + printk("Soundcard: Sequencer not initialized\n"); + return -ENXIO; + } + if (dev) /* Patch manager device (obsolete) */ + { + return -ENXIO; + } + if (mode == OPEN_READ) + if (!num_midis) + { + printk("Sequencer: No MIDI devices. Input not possible\n"); + sequencer_busy = 0; + return -ENXIO; + } + save_flags(flags); + cli(); + if (sequencer_busy) + { + restore_flags(flags); + return -EBUSY; + } + sequencer_busy = 1; + obsolete_api_used = 0; + restore_flags(flags); - if (!sequencer_ok) - { - printk ("Soundcard: Sequencer not initialized\n"); - return -ENXIO; - } + max_mididev = num_midis; + max_synthdev = num_synths; + pre_event_timeout = 0; + seq_mode = SEQ_1; - if (dev) /* Patch manager device (obsolete) */ - { - return -ENXIO; - } + if (pending_timer != -1) + { + tmr_no = pending_timer; + pending_timer = -1; + } + if (tmr_no == -1) /* Not selected yet */ + { + int i, best; + + best = -1; + for (i = 0; i < num_sound_timers; i++) + if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) + { + tmr_no = i; + best = sound_timer_devs[i]->priority; + } + if (tmr_no == -1) /* Should not be */ + tmr_no = 0; + } + tmr = sound_timer_devs[tmr_no]; - if (mode == OPEN_READ) - if (!num_midis) - { - printk ("Sequencer: No MIDI devices. Input not possible\n"); - sequencer_busy = 0; - return -ENXIO; - } - - save_flags (flags); - cli (); - if (sequencer_busy) - { - restore_flags (flags); - return -EBUSY; - } - sequencer_busy = 1; - obsolete_api_used = 0; - restore_flags (flags); - - max_mididev = num_midis; - max_synthdev = num_synths; - pre_event_timeout = 0; - seq_mode = SEQ_1; - - if (pending_timer != -1) - { - tmr_no = pending_timer; - pending_timer = -1; - } - - if (tmr_no == -1) /* Not selected yet */ - { - int i, best; - - best = -1; - for (i = 0; i < num_sound_timers; i++) - if (sound_timer_devs[i]->priority > best) + if (level == 2) { - tmr_no = i; - best = sound_timer_devs[i]->priority; + if (tmr == NULL) + { + printk("sequencer: No timer for level 2\n"); + sequencer_busy = 0; + return -ENXIO; + } + setup_mode2(); } + if (!max_synthdev && !max_mididev) + return -ENXIO; - if (tmr_no == -1) /* Should not be */ - tmr_no = 0; - } + synth_open_mask = 0; - tmr = sound_timer_devs[tmr_no]; + for (i = 0; i < max_mididev; i++) + { + midi_opened[i] = 0; + midi_written[i] = 0; + } - if (level == 2) - { - if (tmr == NULL) - { - printk ("sequencer: No timer for level 2\n"); - sequencer_busy = 0; - return -ENXIO; - } - setup_mode2 (); - } - - if (!max_synthdev && !max_mididev) - return -ENXIO; - - synth_open_mask = 0; - - for (i = 0; i < max_mididev; i++) - { - midi_opened[i] = 0; - midi_written[i] = 0; - } - - for (i = 0; i < max_synthdev; i++) - { - if ((tmp = synth_devs[i]->open (i, mode)) < 0) - { - printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); - if (synth_devs[i]->midi_dev) - printk ("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); - } - else - { - synth_open_mask |= (1 << i); - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 1; - } - } + for (i = 0; i < max_synthdev; i++) + { + if ((tmp = synth_devs[i]->open(i, mode)) < 0) + { + printk("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); + if (synth_devs[i]->midi_dev) + printk("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); + } else + { + synth_open_mask |= (1 << i); + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 1; + } + } - seq_time = jiffies; + if (softsynthp != NULL) + seq_time = 0; + else + seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; + prev_input_time = 0; + prev_event_time = 0; + if (softsynthp != NULL) + softsynthp(SSYN_START, 0, 0, 0); - if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) - { /* + if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) + { /* * Initialize midi input devices */ - for (i = 0; i < max_mididev; i++) - if (!midi_opened[i]) + for (i = 0; i < max_mididev; i++) + if (!midi_opened[i]) + { + if ((retval = midi_devs[i]->open(i, mode, + sequencer_midi_input, sequencer_midi_output)) >= 0) + midi_opened[i] = 1; + } + } + if (seq_mode == SEQ_2) { - if ((retval = midi_devs[i]->open (i, mode, - sequencer_midi_input, sequencer_midi_output)) >= 0) - midi_opened[i] = 1; + tmr->open(tmr_no, seq_mode); } - } - - if (seq_mode == SEQ_2) - { - tmr->open (tmr_no, seq_mode); - } - - seq_sleep_flag.opts = WK_NONE; - midi_sleep_flag.opts = WK_NONE; - output_threshold = SEQ_MAX_QUEUE / 2; + seq_sleep_flag.opts = WK_NONE; + midi_sleep_flag.opts = WK_NONE; + output_threshold = SEQ_MAX_QUEUE / 2; - return 0; + return 0; } void -seq_drain_midi_queues (void) +seq_drain_midi_queues(void) { - int i, n; - - /* - * Give the Midi drivers time to drain their output queues - */ - - n = 1; + int i, n; - while (!(current->signal & ~current->blocked) && n) - { - n = 0; + /* + * Give the Midi drivers time to drain their output queues + */ - for (i = 0; i < max_mididev; i++) - if (midi_opened[i] && midi_written[i]) - if (midi_devs[i]->buffer_status != NULL) - if (midi_devs[i]->buffer_status (i)) - n++; - - /* - * Let's have a delay - */ - if (n) - { + n = 1; + while (!(current->signal & ~current->blocked) && n) { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - } - } + n = 0; + + for (i = 0; i < max_mididev; i++) + if (midi_opened[i] && midi_written[i]) + if (midi_devs[i]->buffer_status != NULL) + if (midi_devs[i]->buffer_status(i)) + n++; + + /* + * Let's have a delay + */ + if (n) + { + + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + } + } } void -sequencer_release (int dev, struct fileinfo *file) +sequencer_release(int dev, struct fileinfo *file) { - int i; - int mode = file->mode & O_ACCMODE; - - dev = dev >> 4; + int i; + int mode = file->mode & O_ACCMODE; - DEB (printk ("sequencer_release(dev=%d)\n", dev)); + dev = dev >> 4; - /* - * Wait until the queue is empty (if we don't have nonblock) - */ + DEB(printk("sequencer_release(dev=%d)\n", dev)); - if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? - 1 : 0)) - while (!(current->signal & ~current->blocked) && qlen > 0) - { - seq_sync (); + /* + * Wait until the queue is empty (if we don't have nonblock) + */ - { - unsigned long tlimit; - - if (3 * HZ) - current->timeout = tlimit = jiffies + (3 * HZ); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; /* Extra delay */ - } - - if (mode != OPEN_READ) - seq_drain_midi_queues (); /* - * Ensure the output queues are empty - */ - seq_reset (); - if (mode != OPEN_READ) - seq_drain_midi_queues (); /* - * Flush the all notes off messages - */ + if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? + 1 : 0)) + while (!(current->signal & ~current->blocked) && qlen > 0) + { + seq_sync(); + + { + unsigned long tlimit; + + if (3 * HZ) + current->timeout = tlimit = jiffies + (3 * HZ); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; /* Extra delay */ + } + if (mode != OPEN_READ) + seq_drain_midi_queues(); /* + * Ensure the output queues are empty + */ + seq_reset(); + if (mode != OPEN_READ) + seq_drain_midi_queues(); /* + * Flush the all notes off messages + */ - for (i = 0; i < max_synthdev; i++) - { - if (synth_open_mask & (1 << i)) /* - * Actually opened - */ - if (synth_devs[i]) + for (i = 0; i < max_synthdev; i++) { - synth_devs[i]->close (i); - - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 0; + if (synth_open_mask & (1 << i)) /* + * Actually opened + */ + if (synth_devs[i]) + { + synth_devs[i]->close(i); + + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 0; + } } - } - for (i = 0; i < max_mididev; i++) - { - if (midi_opened[i]) - midi_devs[i]->close (i); - } + for (i = 0; i < max_mididev; i++) + { + if (midi_opened[i]) + midi_devs[i]->close(i); + } - if (seq_mode == SEQ_2) - tmr->close (tmr_no); + if (seq_mode == SEQ_2) + tmr->close(tmr_no); - if (obsolete_api_used) - printk ("/dev/music: Obsolete (4 byte) API was used by this program\n"); - sequencer_busy = 0; + if (obsolete_api_used) + printk("/dev/music: Obsolete (4 byte) API was used by this program\n"); + sequencer_busy = 0; } static int -seq_sync (void) +seq_sync(void) { - unsigned long flags; - - if (qlen && !seq_playing && !(current->signal & ~current->blocked)) - seq_startplay (); - - save_flags (flags); - cli (); - if (qlen > 0) - { + unsigned long flags; - { - unsigned long tlimit; + if (qlen && !seq_playing && !(current->signal & ~current->blocked)) + seq_startplay(); - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) + save_flags(flags); + cli(); + if (qlen > 0) { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; + + { + unsigned long tlimit; + + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - } - restore_flags (flags); + restore_flags(flags); - return qlen; + return qlen; } static void -midi_outc (int dev, unsigned char data) +midi_outc(int dev, unsigned char data) { - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ - - int n; - unsigned long flags; - - /* - * This routine sends one byte to the Midi channel. - * If the output FIFO is full, it waits until there - * is space in the queue - */ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ - n = 3 * HZ; /* Timeout */ + int n; + unsigned long flags; - save_flags (flags); - cli (); - while (n && !midi_devs[dev]->outputc (dev, data)) - { + /* + * This routine sends one byte to the Midi channel. + * If the output FIFO is full, it waits until there + * is space in the queue + */ - { - unsigned long tlimit; + n = 3 * HZ; /* Timeout */ - if (4) - current->timeout = tlimit = jiffies + (4); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) + save_flags(flags); + cli(); + while (n && !midi_devs[dev]->outputc(dev, data)) { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; + + { + unsigned long tlimit; + + if (4) + current->timeout = tlimit = jiffies + (4); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + n--; } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - n--; - } - restore_flags (flags); + restore_flags(flags); } static void -seq_reset (void) +seq_reset(void) { - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ - int i; - int chn; - unsigned long flags; + int i; + int chn; + unsigned long flags; - sound_stop_timer (); + if (softsynthp != NULL) + softsynthp(SSYN_STOP, 0, 0, 0); + else + sound_stop_timer(); - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; - qlen = qhead = qtail = 0; - iqlen = iqhead = iqtail = 0; + qlen = qhead = qtail = 0; + iqlen = iqhead = iqtail = 0; - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - synth_devs[i]->reset (i); + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + synth_devs[i]->reset(i); - if (seq_mode == SEQ_2) - { + if (seq_mode == SEQ_2) + { - for (chn = 0; chn < 16; chn++) - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - { - synth_devs[i]->controller (i, chn, 123, 0); /* All notes off */ - synth_devs[i]->controller (i, chn, 121, 0); /* Reset all ctl */ - synth_devs[i]->bender (i, chn, 1 << 13); /* Bender off */ - } - - } - else - /* seq_mode == SEQ_1 */ - { - for (i = 0; i < max_mididev; i++) - if (midi_written[i]) /* - * Midi used. Some notes may still be playing - */ + for (chn = 0; chn < 16; chn++) + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + { + synth_devs[i]->controller(i, chn, 123, 0); /* All notes off */ + synth_devs[i]->controller(i, chn, 121, 0); /* Reset all ctl */ + synth_devs[i]->bender(i, chn, 1 << 13); /* Bender off */ + } + } else + /* seq_mode == SEQ_1 */ + { + for (i = 0; i < max_mididev; i++) + if (midi_written[i]) /* + * Midi used. Some notes may still be playing + */ + { + /* + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ + midi_outc(i, 0xfe); + + for (chn = 0; chn < 16; chn++) + { + midi_outc(i, + (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ + midi_outc(i, 0x7b); /* All notes off */ + midi_outc(i, 0); /* Dummy parameter */ + } + + midi_devs[i]->close(i); + + midi_written[i] = 0; + midi_opened[i] = 0; + } + } + + seq_playing = 0; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) { - /* - * Sending just a ACTIVE SENSING message should be enough to stop all - * playing notes. Since there are devices not recognizing the - * active sensing, we have to send some all notes off messages also. - */ - midi_outc (i, 0xfe); - - for (chn = 0; chn < 16; chn++) - { - midi_outc (i, - (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ - midi_outc (i, 0x7b); /* All notes off */ - midi_outc (i, 0); /* Dummy parameter */ - } - - midi_devs[i]->close (i); - - midi_written[i] = 0; - midi_opened[i] = 0; + /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; } - } - - seq_playing = 0; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - /* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); + restore_flags(flags); } static void -seq_panic (void) +seq_panic(void) { - /* - * This routine is called by the application in case the user - * wants to reset the system to the default state. - */ - - seq_reset (); - - /* - * Since some of the devices don't recognize the active sensing and - * all notes off messages, we have to shut all notes manually. - * - * TO BE IMPLEMENTED LATER - */ - - /* - * Also return the controllers to their default states - */ + /* + * This routine is called by the application in case the user + * wants to reset the system to the default state. + */ + + seq_reset(); + + /* + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER + */ + + /* + * Also return the controllers to their default states + */ } int -sequencer_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +sequencer_ioctl(int dev, struct fileinfo *file, + unsigned int cmd, caddr_t arg) { - int midi_dev, orig_dev, val; - int mode = file->mode & O_ACCMODE; - - orig_dev = dev = dev >> 4; - - switch (cmd) - { - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SOURCE: - - if (seq_mode != SEQ_2) - return -EINVAL; - return tmr->ioctl (tmr_no, cmd, arg); - break; - - case SNDCTL_TMR_SELECT: - - if (seq_mode != SEQ_2) - return -EINVAL; - pending_timer = *(int *) arg; - - if (pending_timer < 0 || pending_timer >= num_sound_timers) - { - pending_timer = -1; - return -EINVAL; - } - - return (*(int *) arg = pending_timer); - break; - - case SNDCTL_SEQ_PANIC: - seq_panic (); - break; - - case SNDCTL_SEQ_SYNC: - - if (mode == OPEN_READ) - return 0; - while (qlen > 0 && !(current->signal & ~current->blocked)) - seq_sync (); - if (qlen) - return -EINTR; - else - return 0; - break; + int midi_dev, orig_dev, val; + int mode = file->mode & O_ACCMODE; - case SNDCTL_SEQ_RESET: + orig_dev = dev = dev >> 4; - seq_reset (); - return 0; - break; - - case SNDCTL_SEQ_TESTMIDI: - midi_dev = *(int *) arg; - if (midi_dev < 0 || midi_dev >= max_mididev) - return -ENXIO; - - if (!midi_opened[midi_dev]) - { - int err, mode; + switch (cmd) + { + case SNDCTL_TMR_TIMEBASE: + case SNDCTL_TMR_TEMPO: + case SNDCTL_TMR_START: + case SNDCTL_TMR_STOP: + case SNDCTL_TMR_CONTINUE: + case SNDCTL_TMR_METRONOME: + case SNDCTL_TMR_SOURCE: + + if (seq_mode != SEQ_2) + return -EINVAL; + return tmr->ioctl(tmr_no, cmd, arg); + break; + + case SNDCTL_TMR_SELECT: + + if (seq_mode != SEQ_2) + return -EINVAL; + pending_timer = *(int *) arg; + + if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) + { + pending_timer = -1; + return -EINVAL; + } + return (*(int *) arg = pending_timer); + break; + + case SNDCTL_SEQ_PANIC: + seq_panic(); + break; + + case SNDCTL_SEQ_SYNC: + + if (mode == OPEN_READ) + return 0; + while (qlen > 0 && !(current->signal & ~current->blocked)) + seq_sync(); + if (qlen) + return -EINTR; + else + return 0; + break; + + case SNDCTL_SEQ_RESET: + + seq_reset(); + return 0; + break; + + case SNDCTL_SEQ_TESTMIDI: + midi_dev = *(int *) arg; + if (midi_dev < 0 || midi_dev >= max_mididev) + return -ENXIO; + + if (!midi_opened[midi_dev]) + { + int err, mode; + + mode = file->mode & O_ACCMODE; + if ((err = midi_devs[midi_dev]->open(midi_dev, mode, + sequencer_midi_input, + sequencer_midi_output)) < 0) + return err; + } + midi_opened[midi_dev] = 1; + + return 0; + break; + + case SNDCTL_SEQ_GETINCOUNT: + if (mode == OPEN_WRITE) + return 0; + return (*(int *) arg = iqlen); + break; + + case SNDCTL_SEQ_GETOUTCOUNT: + + if (mode == OPEN_READ) + return 0; + return (*(int *) arg = SEQ_MAX_QUEUE - qlen); + break; + + case SNDCTL_SEQ_GETTIME: + if (seq_mode == SEQ_2) + return tmr->ioctl(tmr_no, cmd, arg); + + if (softsynthp != NULL) + return (*(int *) arg = softsynthp(SSYN_GETTIME, 0, 0, 0)); + else + return (*(int *) arg = jiffies - seq_time); + break; + + case SNDCTL_SEQ_CTRLRATE: + /* + * If *arg == 0, just return the current rate + */ + if (seq_mode == SEQ_2) + return tmr->ioctl(tmr_no, cmd, arg); + + val = *(int *) arg; + if (val != 0) + return -EINVAL; + + return (*(int *) arg = HZ); + break; + + case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SYNTH_REMOVESAMPLE: + case SNDCTL_SYNTH_CONTROL: + { + int err; + + dev = *(int *) arg; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + { + return -ENXIO; + } + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + { + return -EBUSY; + } + err = synth_devs[dev]->ioctl(dev, cmd, arg); + return err; + } + break; + + case SNDCTL_SEQ_NRSYNTHS: + return (*(int *) arg = max_synthdev); + break; + + case SNDCTL_SEQ_NRMIDIS: + return (*(int *) arg = max_mididev); + break; + + case SNDCTL_SYNTH_MEMAVL: + { + int dev; - mode = file->mode & O_ACCMODE; - if ((err = midi_devs[midi_dev]->open (midi_dev, mode, - sequencer_midi_input, - sequencer_midi_output)) < 0) - return err; - } + dev = *(int *) arg; - midi_opened[midi_dev] = 1; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; - return 0; - break; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; - case SNDCTL_SEQ_GETINCOUNT: - if (mode == OPEN_WRITE) - return 0; - return (*(int *) arg = iqlen); - break; + return (*(int *) arg = synth_devs[dev]->ioctl(dev, cmd, arg)); + } + break; - case SNDCTL_SEQ_GETOUTCOUNT: + case SNDCTL_FM_4OP_ENABLE: + { + int dev; - if (mode == OPEN_READ) - return 0; - return (*(int *) arg = SEQ_MAX_QUEUE - qlen); - break; + dev = *(int *) arg; - case SNDCTL_SEQ_GETTIME: - if (seq_mode == SEQ_2) - return tmr->ioctl (tmr_no, cmd, arg); + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; - return (*(int *) arg = jiffies - seq_time); - break; + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; - case SNDCTL_SEQ_CTRLRATE: - /* - * If *arg == 0, just return the current rate - */ - if (seq_mode == SEQ_2) - return tmr->ioctl (tmr_no, cmd, arg); + synth_devs[dev]->ioctl(dev, cmd, arg); + return 0; + } + break; - val = *(int *) arg; - if (val != 0) - return -EINVAL; + case SNDCTL_SYNTH_INFO: + { + struct synth_info inf; + int dev; - return (*(int *) arg = HZ); - break; + memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf)); + dev = inf.device; - case SNDCTL_SEQ_RESETSAMPLES: - case SNDCTL_SYNTH_REMOVESAMPLE: - case SNDCTL_SYNTH_CONTROL: - { - int err; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; - dev = *(int *) arg; - if (dev < 0 || dev >= num_synths) - { - return -ENXIO; - } + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - { - return -EBUSY; - } + return synth_devs[dev]->ioctl(dev, cmd, arg); + } + break; - err = synth_devs[dev]->ioctl (dev, cmd, arg); - return err; - } - break; - case SNDCTL_SEQ_NRSYNTHS: - return (*(int *) arg = max_synthdev); - break; + /* Like SYNTH_INFO but returns ID in the name field */ + case SNDCTL_SYNTH_ID: + { + struct synth_info inf; + int dev; - case SNDCTL_SEQ_NRMIDIS: - return (*(int *) arg = max_mididev); - break; + memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf)); + dev = inf.device; - case SNDCTL_SYNTH_MEMAVL: - { - int dev; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; - dev = *(int *) arg; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; - if (dev < 0 || dev >= num_synths) - return -ENXIO; + memcpy((char *) &inf, (char *) synth_devs[dev]->info, sizeof(inf)); + strcpy(inf.name, synth_devs[dev]->id); + inf.device = dev; + memcpy((&((char *) arg)[0]), (char *) &inf, sizeof(inf)); + return 0; + } + break; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + case SNDCTL_SEQ_OUTOFBAND: + { + struct seq_event_rec event_rec; + unsigned long flags; - return (*(int *) arg = synth_devs[dev]->ioctl (dev, cmd, arg)); - } - break; + memcpy((char *) &event_rec, (&((char *) arg)[0]), sizeof(event_rec)); - case SNDCTL_FM_4OP_ENABLE: - { - int dev; + save_flags(flags); + cli(); + play_event(event_rec.arr); + restore_flags(flags); - dev = *(int *) arg; + return 0; + } + break; - if (dev < 0 || dev >= num_synths) - return -ENXIO; + case SNDCTL_MIDI_INFO: + { + struct midi_info inf; + int dev; + char *pp; - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf)); + dev = inf.device; - synth_devs[dev]->ioctl (dev, cmd, arg); - return 0; - } - break; + if (dev < 0 || dev >= max_mididev) + return -ENXIO; - case SNDCTL_SYNTH_INFO: - { - struct synth_info inf; - int dev; + midi_devs[dev]->info.device = dev; + pp = (char *) &midi_devs[dev]->info; + memcpy((&((char *) arg)[0]), pp, sizeof(inf)); + return 0; + } + break; - memcpy ((char *) &inf, (&((char *) arg)[0]), sizeof (inf)); - dev = inf.device; + case SNDCTL_SEQ_THRESHOLD: + { + int tmp; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + tmp = *(int *) arg; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + if (tmp < 1) + tmp = 1; + if (tmp >= SEQ_MAX_QUEUE) + tmp = SEQ_MAX_QUEUE - 1; + output_threshold = tmp; + return 0; + } + break; - return synth_devs[dev]->ioctl (dev, cmd, arg); - } - break; + case SNDCTL_MIDI_PRETIME: + { + int val; + val = *(int *) arg; - /* Like SYNTH_INFO but returns ID in the name field */ - case SNDCTL_SYNTH_ID: - { - struct synth_info inf; - int dev; + if (val < 0) + val = 0; - memcpy ((char *) &inf, (&((char *) arg)[0]), sizeof (inf)); - dev = inf.device; + val = (HZ * val) / 10; + pre_event_timeout = val; + return (*(int *) arg = val); + } + break; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + default: + if (mode == OPEN_READ) + return -EIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + if (!synth_devs[0]) + return -ENXIO; + if (!(synth_open_mask & (1 << 0))) + return -ENXIO; + return synth_devs[0]->ioctl(0, cmd, arg); + break; + } - memcpy ((char *) &inf, (char *) synth_devs[dev]->info, sizeof (inf)); - strcpy (inf.name, synth_devs[dev]->id); - memcpy ((&((char *) arg)[0]), (char *) &inf, sizeof (inf)); - return 0; - } - break; + return -EINVAL; +} - case SNDCTL_SEQ_OUTOFBAND: - { - struct seq_event_rec event_rec; +int +sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +{ unsigned long flags; - memcpy ((char *) &event_rec, (&((char *) arg)[0]), sizeof (event_rec)); - - save_flags (flags); - cli (); - play_event (event_rec.arr); - restore_flags (flags); - - return 0; - } - break; - - case SNDCTL_MIDI_INFO: - { - struct midi_info inf; - int dev; - char *pp; + dev = dev >> 4; - memcpy ((char *) &inf, (&((char *) arg)[0]), sizeof (inf)); - dev = inf.device; - - if (dev < 0 || dev >= max_mididev) - return -ENXIO; - - pp = (char *) &midi_devs[dev]->info; - memcpy ((&((char *) arg)[0]), pp, sizeof (inf)); - return 0; - } - break; - - case SNDCTL_SEQ_THRESHOLD: - { - int tmp; - - tmp = *(int *) arg; + switch (sel_type) + { + case SEL_IN: + save_flags(flags); + cli(); + if (!iqlen) + { + + midi_sleep_flag.opts = WK_SLEEP; + poll_wait(&midi_sleeper, wait); + restore_flags(flags); + return 0; + } + restore_flags(flags); + return 1; + break; + + case SEL_OUT: + save_flags(flags); + cli(); + if ((SEQ_MAX_QUEUE - qlen) < output_threshold) + { + + seq_sleep_flag.opts = WK_SLEEP; + poll_wait(&seq_sleeper, wait); + restore_flags(flags); + return 0; + } + restore_flags(flags); + return 1; + break; + + case SEL_EX: + return 0; + } - if (tmp < 1) - tmp = 1; - if (tmp >= SEQ_MAX_QUEUE) - tmp = SEQ_MAX_QUEUE - 1; - output_threshold = tmp; return 0; - } - break; - - case SNDCTL_MIDI_PRETIME: - { - int val; - - val = *(int *) arg; - - if (val < 0) - val = 0; - - val = (HZ * val) / 10; - pre_event_timeout = val; - return (*(int *) arg = val); - } - break; - - default: - if (mode == OPEN_READ) - return -EIO; +} - if (!synth_devs[0]) - return -ENXIO; - if (!(synth_open_mask & (1 << 0))) - return -ENXIO; - return synth_devs[0]->ioctl (0, cmd, arg); - break; - } - return -EINVAL; +void +sequencer_timer(unsigned long dummy) +{ + seq_startplay(); } int -sequencer_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) +note_to_freq(int note_num) { - unsigned long flags; - dev = dev >> 4; + /* + * This routine converts a midi note to a frequency (multiplied by 1000) + */ - switch (sel_type) - { - case SEL_IN: - save_flags (flags); - cli (); - if (!iqlen) + int note, octave, note_freq; + static int notes[] = { + 261632, 277189, 293671, 311132, 329632, 349232, + 369998, 391998, 415306, 440000, 466162, 493880 + }; - midi_sleep_flag.opts = WK_SLEEP; - poll_wait (&midi_sleeper, wait); - restore_flags (flags); - return 0; - } - restore_flags (flags); - return 1; - break; - - case SEL_OUT: - save_flags (flags); - cli (); - if ((SEQ_MAX_QUEUE - qlen) < output_threshold) - { +#define BASE_OCTAVE 5 - seq_sleep_flag.opts = WK_SLEEP; - poll_wait (&seq_sleeper, wait); - restore_flags (flags); - return 0; - } - restore_flags (flags); - return 1; - break; + octave = note_num / 12; + note = note_num % 12; - case SEL_EX: - return 0; - } + note_freq = notes[note]; - return 0; -} + if (octave < BASE_OCTAVE) + note_freq >>= (BASE_OCTAVE - octave); + else if (octave > BASE_OCTAVE) + note_freq <<= (octave - BASE_OCTAVE); + /* + * note_freq >>= 1; + */ -void -sequencer_timer (unsigned long dummy) -{ - seq_startplay (); + return note_freq; } -int -note_to_freq (int note_num) +unsigned long +compute_finetune(unsigned long base_freq, int bend, int range, + int vibrato_cents) { + unsigned long amount; + int negative, semitones, cents, multiplier = 1; - /* - * This routine converts a midi note to a frequency (multiplied by 1000) - */ + if (!bend) + return base_freq; + if (!range) + return base_freq; - int note, octave, note_freq; - static int notes[] = - { - 261632, 277189, 293671, 311132, 329632, 349232, - 369998, 391998, 415306, 440000, 466162, 493880 - }; + if (!base_freq) + return base_freq; -#define BASE_OCTAVE 5 + if (range >= 8192) + range = 8192; - octave = note_num / 12; - note = note_num % 12; + bend = bend * range / 8192; /* Convert to cents */ + bend += vibrato_cents; - note_freq = notes[note]; + if (!bend) + return base_freq; - if (octave < BASE_OCTAVE) - note_freq >>= (BASE_OCTAVE - octave); - else if (octave > BASE_OCTAVE) - note_freq <<= (octave - BASE_OCTAVE); + negative = bend < 0 ? 1 : 0; - /* - * note_freq >>= 1; - */ + if (bend < 0) + bend *= -1; + if (bend > range) + bend = range; - return note_freq; -} + /* + if (bend > 2399) + bend = 2399; + */ + while (bend > 2399) + { + multiplier *= 4; + bend -= 2400; + } -unsigned long -compute_finetune (unsigned long base_freq, int bend, int range, - int vibrato_cents) -{ - unsigned long amount; - int negative, semitones, cents, multiplier = 1; - - if (!bend) - return base_freq; - if (!range) - return base_freq; - - if (!base_freq) - return base_freq; - - if (range >= 8192) - range = 8192; - - bend = bend * range / 8192; /* Convert to cents */ - bend += vibrato_cents; - - if (!bend) - return base_freq; - - negative = bend < 0 ? 1 : 0; - - if (bend < 0) - bend *= -1; - if (bend > range) - bend = range; - - /* - if (bend > 2399) - bend = 2399; - */ - while (bend > 2399) - { - multiplier *= 4; - bend -= 2400; - } - - semitones = bend / 100; - if (semitones > 99) - semitones = 99; - cents = bend % 100; - - amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) - / 10000; - - if (negative) - return (base_freq * 10000) / amount; /* Bend down */ - else - return (base_freq * amount) / 10000; /* Bend up */ + semitones = bend / 100; + if (semitones > 99) + semitones = 99; + cents = bend % 100; + + amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) + / 10000; + + if (negative) + return (base_freq * 10000) / amount; /* Bend down */ + else + return (base_freq * amount) / 10000; /* Bend up */ } void -sequencer_init (void) +sequencer_init(void) { - if (sequencer_ok) - return; + if (sequencer_ok) + return; #ifdef CONFIG_MIDI - MIDIbuf_init (); + MIDIbuf_init(); #endif - queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * EV_SZ)); - sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * EV_SZ; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (queue == NULL) - { - printk ("Sound: Can't allocate memory for sequencer output queue\n"); - return; - } - - - iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * IEV_SZ)); - sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * IEV_SZ; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (iqueue == NULL) - { - printk ("Sound: Can't allocate memory for sequencer input queue\n"); - return; - } - - - sequencer_ok = 1; + queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc(SEQ_MAX_QUEUE * EV_SZ)); + sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * EV_SZ; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (queue == NULL) + { + printk("Sound: Can't allocate memory for sequencer output queue\n"); + return; + } + iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc(SEQ_MAX_QUEUE * IEV_SZ)); + sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * IEV_SZ; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (iqueue == NULL) + { + printk("Sound: Can't allocate memory for sequencer input queue\n"); + return; + } + sequencer_ok = 1; } #endif diff --git a/drivers/sound/softoss.c b/drivers/sound/softoss.c new file mode 100644 index 000000000..a47133a8a --- /dev/null +++ b/drivers/sound/softoss.c @@ -0,0 +1,1580 @@ +/* + * sound/softoss.c + * + * Software based MIDI synthsesizer 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> + +/* + * When POLLED_MODE is defined, the resampling loop is run using a timer + * callback routine. Normally the resampling loop is executed inside + * audio buffer interrupt handler which doesn't work with single mode DMA. + */ +#define SOFTSYN_MAIN +#undef POLLED_MODE +#define HANDLE_LFO + +#define ENVELOPE_SCALE 8 +#define NO_SAMPLE 0xffff + +#include "sound_config.h" +#include "soundmodule.h" + +#if defined(CONFIG_SOFTOSS) || defined(MODULE) +#include "softoss.h" +#include <linux/ultrasound.h> + +int softsynth_disabled = 0; + +static volatile int intr_pending = 0; + +#ifdef POLLED_MODE + +static struct timer_list poll_timer = +{NULL, NULL, 0, 0, softsyn_poll}; + +#else +#endif + +#ifdef HANDLE_LFO +/* + * LFO table. Playback at 128 Hz gives 1 Hz LFO frequency. + */ +static int tremolo_table[128] = +{ + 0, 39, 158, 355, 630, 982, 1411, 1915, + 2494, 3146, 3869, 4662, 5522, 6448, 7438, 8489, + 9598, 10762, 11980, 13248, 14563, 15922, 17321, 18758, + 20228, 21729, 23256, 24806, 26375, 27960, 29556, 31160, + 32768, 34376, 35980, 37576, 39161, 40730, 42280, 43807, + 45308, 46778, 48215, 49614, 50973, 52288, 53556, 54774, + 55938, 57047, 58098, 59088, 60014, 60874, 61667, 62390, + 63042, 63621, 64125, 64554, 64906, 65181, 65378, 65497, + 65536, 65497, 65378, 65181, 64906, 64554, 64125, 63621, + 63042, 62390, 61667, 60874, 60014, 59087, 58098, 57047, + 55938, 54774, 53556, 52288, 50973, 49614, 48215, 46778, + 45308, 43807, 42280, 40730, 39161, 37576, 35980, 34376, + 32768, 31160, 29556, 27960, 26375, 24806, 23256, 21729, + 20228, 18758, 17321, 15922, 14563, 13248, 11980, 10762, + 9598, 8489, 7438, 6448, 5522, 4662, 3869, 3146, + 2494, 1915, 1411, 982, 630, 355, 158, 39 +}; + +static int vibrato_table[128] = +{ + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11039, + 12540, 14010, 15447, 16846, 18205, 19520, 20788, 22006, + 23170, 24279, 25330, 26320, 27246, 28106, 28899, 29622, + 30274, 30853, 31357, 31786, 32138, 32413, 32610, 32729, + 32768, 32729, 32610, 32413, 32138, 31786, 31357, 30853, + 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279, + 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010, + 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, + 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039, + -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006, + -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, + -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729, + -32768, -32729, -32610, -32413, -32138, -31786, -31357, -30853, + -30274, -29622, -28899, -28106, -27246, -26320, -25330, -24279, + -23170, -22006, -20788, -19520, -18205, -16846, -15447, -14010, + -12540, -11039, -9512, -7962, -6393, -4808, -3212, -1608 +}; + +#endif + +static unsigned long last_resample_jiffies; +static unsigned long resample_counter; + +extern int *sound_osp; + +static volatile int is_running = 0; +static int softsynth_loaded = 0; + +static struct synth_info softsyn_info = +{"SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; + +static struct softsyn_devc sdev_info = +{0}; +softsyn_devc *devc = &sdev_info; + +static struct voice_alloc_info *voice_alloc; + +static int softsyn_open(int synthdev, int mode); +static void init_voice(softsyn_devc * devc, int voice); +static void compute_step(int voice); + +static volatile int tmr_running = 0; +static int voice_limit = 24; + +static void +set_max_voices(int nr) +{ + int i; + + if (nr < 4) + nr = 4; + + if (nr > voice_limit) + nr = voice_limit; + + voice_alloc->max_voice = devc->maxvoice = nr; + devc->afterscale = 5; + + for (i = 31; i > 0; i--) + if (nr & (1 << i)) + { + devc->afterscale = i + 1; + return; + } +} + +static void +update_vibrato(int voice) +{ + voice_info *v = &softoss_voices[voice]; + +#ifdef HANDLE_LFO + int x; + + x = vibrato_table[v->vibrato_phase >> 8]; + v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff; + + x = (x * v->vibrato_depth) >> 15; + v->vibrato_level = (x * 600) >> 8; + + compute_step(voice); +#else + v->vibrato_level = 0; +#endif +} + +#ifdef HANDLE_LFO +static void +update_tremolo(int voice) +{ + voice_info *v = &softoss_voices[voice]; + int x; + + x = tremolo_table[v->tremolo_phase >> 8]; + v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff; + + v->tremolo_level = (x * v->tremolo_depth) >> 20; +} +#endif + +static void +start_vibrato(int voice) +{ + voice_info *v = &softoss_voices[voice]; + int rate; + + if (!v->vibrato_depth) + return; + + rate = v->vibrato_rate * 6 * 128; + v->vibrato_step = (rate * devc->control_rate) / devc->speed; + + devc->vibratomap |= (1 << voice); /* Enable vibrato */ +} + +static void +start_tremolo(int voice) +{ + voice_info *v = &softoss_voices[voice]; + int rate; + + if (!v->tremolo_depth) + return; + + rate = v->tremolo_rate * 6 * 128; + v->tremolo_step = (rate * devc->control_rate) / devc->speed; + + devc->tremolomap |= (1 << voice); /* Enable tremolo */ +} + +static void +update_volume(int voice) +{ + voice_info *v = &softoss_voices[voice]; + unsigned int vol; + +/* + * Compute plain volume + */ + + vol = (v->velocity * v->expression_vol * v->main_vol) >> 12; + +#ifdef HANDLE_LFO +/* + * Handle LFO + */ + + if (devc->tremolomap & (1 << voice)) + { + int t; + + t = 32768 - v->tremolo_level; + vol = (vol * t) >> 15; + update_tremolo(voice); + } +#endif +/* + * Envelope + */ + if (v->mode & WAVE_ENVELOPES && !v->percussive_voice) + vol = (vol * (v->envelope_vol >> 16)) >> 19; + else + vol >>= 4; + +/* + * Handle panning + */ + + if (v->panning < 0) /* Pan left */ + v->rightvol = (vol * (128 + v->panning)) / 128; + else + v->rightvol = vol; + + if (v->panning > 0) /* Pan right */ + v->leftvol = (vol * (128 - v->panning)) / 128; + else + v->leftvol = vol; +} + +static void +step_envelope(int voice, int do_release, int velocity) +{ + voice_info *v = &softoss_voices[voice]; + int r, rate, time, dif; + unsigned int vol; + unsigned long flags; + + save_flags(flags); + cli(); + + if (!voice_active[voice] || v->sample == NULL) + { + restore_flags(flags); + return; + } + if (!do_release) + if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2) + { /* Stop envelope until note off */ + v->envelope_volstep = 0; + v->envelope_time = 0x7fffffff; + if (v->mode & WAVE_VIBRATO) + start_vibrato(voice); + if (v->mode & WAVE_TREMOLO) + start_tremolo(voice); + restore_flags(flags); + return; + } + if (do_release) + v->envelope_phase = 3; + else + v->envelope_phase++; + + if (v->envelope_phase >= 5) /* Finished */ + { + init_voice(devc, voice); + restore_flags(flags); + return; + } + vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22; + + + rate = v->sample->env_rate[v->envelope_phase]; + r = 3 - ((rate >> 6) & 0x3); + r *= 3; + r = (int) (rate & 0x3f) << r; + rate = (((r * 44100) / devc->speed) * devc->control_rate) << 8; + + if (rate < (1 << 20)) /* Avoid infinitely "releasing" voices */ + rate = 1 << 20; + + dif = (v->envelope_vol - vol); + if (dif < 0) + dif *= -1; + if (dif < rate * 2) /* Too close */ + { + step_envelope(voice, 0, 60); + restore_flags(flags); + return; + } + if (vol > v->envelope_vol) + { + v->envelope_volstep = rate; + time = (vol - v->envelope_vol) / rate; + } else + { + v->envelope_volstep = -rate; + time = (v->envelope_vol - vol) / rate; + } + + time--; + if (time <= 0) + time = 1; + + v->envelope_time = time; + + + restore_flags(flags); +} + +static void +step_envelope_lfo(int voice) +{ + voice_info *v = &softoss_voices[voice]; + +/* + * Update pitch (vibrato) LFO + */ + + if (devc->vibratomap & (1 << voice)) + update_vibrato(voice); + +/* + * Update envelope + */ + + if (v->mode & WAVE_ENVELOPES) + { + v->envelope_vol += v->envelope_volstep; + /* Overshoot protection */ + if (v->envelope_vol < 0) + { + v->envelope_vol = v->envelope_target; + v->envelope_volstep = 0; + } + if (v->envelope_time-- <= 0) + { + v->envelope_vol = v->envelope_target; + step_envelope(voice, 0, 60); + } + } +} + +static void +compute_step(int voice) +{ + voice_info *v = &softoss_voices[voice]; + + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ + + v->current_freq = compute_finetune(v->orig_freq, + v->bender, + v->bender_range, + v->vibrato_level); + v->step = (((v->current_freq << 9) + (devc->speed >> 1)) / devc->speed); + + if (v->mode & WAVE_LOOP_BACK) + v->step *= -1; /* Reversed playback */ +} + +static void +init_voice(softsyn_devc * devc, int voice) +{ + voice_info *v = &softoss_voices[voice]; + unsigned long flags; + + save_flags(flags); + cli(); + voice_active[voice] = 0; + devc->vibratomap &= ~(1 << voice); + devc->tremolomap &= ~(1 << voice); + v->mode = 0; + v->wave = NULL; + v->sample = NULL; + v->ptr = 0; + v->step = 0; + v->startloop = 0; + v->startbackloop = 0; + v->endloop = 0; + v->looplen = 0; + v->bender = 0; + v->bender_range = 200; + v->panning = 0; + v->main_vol = 127; + v->expression_vol = 127; + v->patch_vol = 127; + v->percussive_voice = 0; + v->sustain_mode = 0; + v->envelope_phase = 1; + v->envelope_vol = 1 << 24; + v->envelope_volstep = 256; + v->envelope_time = 0; + v->vibrato_phase = 0; + v->vibrato_step = 0; + v->vibrato_level = 0; + v->vibrato_rate = 0; + v->vibrato_depth = 0; + v->tremolo_phase = 0; + v->tremolo_step = 0; + v->tremolo_level = 0; + v->tremolo_rate = 0; + v->tremolo_depth = 0; + voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; + restore_flags(flags); +} + +static void +reset_samples(softsyn_devc * devc) +{ + int i; + + for (i = 0; i < MAX_VOICE; i++) + voice_active[i] = 0; + for (i = 0; i < devc->maxvoice; i++) + { + init_voice(devc, i); + softoss_voices[i].instr = 0; + } + + devc->ram_used = 0; + + for (i = 0; i < MAX_PATCH; i++) + devc->programs[i] = NO_SAMPLE; + + for (i = 0; i < devc->nrsamples; i++) + { + vfree(devc->samples[i]); + vfree(devc->wave[i]); + devc->samples[i] = NULL; + devc->wave[i] = NULL; + } + + devc->nrsamples = 0; +} + +static void +init_engine(softsyn_devc * devc) +{ + int i, fz, srate, sz = devc->channels; + + set_max_voices(devc->default_max_voices); + voice_alloc->timestamp = 0; + + if (devc->bits == 16) + sz *= 2; + + fz = devc->fragsize / sz; /* Samples per fragment */ + devc->samples_per_fragment = fz; + + devc->usecs = 0; + devc->usecs_per_frag = (1000000 * fz) / devc->speed; + + for (i = 0; i < devc->maxvoice; i++) + { + init_voice(devc, i); + softoss_voices[i].instr = 0; + } + + devc->engine_state = ES_STOPPED; + +/* + * Initialize delay + */ + + for (i = 0; i < DELAY_SIZE; i++) + left_delay[i] = right_delay[i] = 0; + delayp = 0; + srate = (devc->speed / 10000); /* 1 to 4 */ + if (srate <= 0) + srate = 1; + devc->delay_size = (DELAY_SIZE * srate) / 4; + if (devc->delay_size == 0 || devc->delay_size > DELAY_SIZE) + devc->delay_size = DELAY_SIZE; +} + +void +softsyn_control_loop(void) +{ + int voice; + +/* + * Recompute envlope, LFO, etc. + */ + for (voice = 0; voice < devc->maxvoice; voice++) + if (voice_active[voice]) + { + update_volume(voice); + step_envelope_lfo(voice); + } else + voice_alloc->map[voice] = 0; +} + +static void start_engine(softsyn_devc * devc); + +static void +do_resample(int dummy) +{ + struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; + struct voice_info *vinfo; + unsigned long flags, jif; + + int voice, loops; + short *buf; + + if (softsynth_disabled) + return; + + save_flags(flags); + cli(); + + if (is_running) + { + printk("SoftOSS: Playback overrun\n"); + restore_flags(flags); + return; + } + jif = jiffies; + if (jif == last_resample_jiffies) + { + if (resample_counter++ > 50) + { + for (voice = 0; voice < devc->maxvoice; voice++) + init_voice(devc, voice); + voice_limit--; + resample_counter = 0; + printk("SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit); + + if (voice_limit < 10) + { + voice_limit = 10; + devc->speed = (devc->speed * 2) / 3; + + printk("SoftOSS: Dropping sampling rate and stopping the device.\n"); + softsynth_disabled = 1; + } + } + } else + { + last_resample_jiffies = jif; + resample_counter = 0; + } + + /* is_running = 1; */ + + if (dmap->qlen > devc->max_playahead) + { + printk("SoftOSS: audio buffers full\n"); + is_running = 0; + restore_flags(flags); + return; + } +/* + * First verify that all active voices are valid (do this just once per block). + */ + for (voice = 0; voice < devc->maxvoice; voice++) + if (voice_active[voice]) + { + int ptr; + + vinfo = &softoss_voices[voice]; + ptr = vinfo->ptr >> 9; + + if (vinfo->wave == NULL || + ptr < 0 || + ptr > vinfo->sample->len) + init_voice(devc, voice); + else if (!(vinfo->mode & WAVE_LOOPING) && + (vinfo->ptr + vinfo->step) > vinfo->endloop) + voice_active[voice] = 0; + } +/* + * Start the resampling process + */ + + loops = devc->samples_per_fragment; + buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size)); + + softsynth_resample_loop(buf, loops); /* In Xsoftsynth_rs.c */ + + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + dmap->qlen++; + dmap->user_counter += dmap->fragment_size; + + devc->usecs += devc->usecs_per_frag; + + if (tmr_running) + { + sound_timer_interrupt(); + } +/* + * Execute timer + */ + + if (!tmr_running) + if (devc->usecs >= devc->next_event_usecs) + { + devc->next_event_usecs = ~0; + sequencer_timer(0); + } + is_running = 0; + restore_flags(flags); +} + +static void +delayed_resample(int dummy) +{ + struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; + int n = 0; + + if (is_running) + return; + + while (devc->engine_state != ES_STOPPED && + dmap->qlen < devc->max_playahead && n++ < 2) + do_resample(0); + intr_pending = 0; +} + +#ifdef POLLED_MODE +static void +softsyn_poll(unsigned long dummy) +{ + delayed_resample(0); + + if (devc->engine_state != ES_STOPPED) + + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; +} +#else +static void +softsyn_callback(int dev, int parm) +{ + delayed_resample(0); +} +#endif + +static void +start_engine(softsyn_devc * devc) +{ + struct dma_buffparms *dmap; + + if (!devc->audio_opened) + if (softsyn_open(devc->synthdev, 0) < 0) + return; + + if (devc->audiodev >= num_audiodevs) + return; + + dmap = audio_devs[devc->audiodev]->dmap_out; + + devc->usecs = 0; + devc->next_event_usecs = ~0; + devc->control_rate = 64; + devc->control_counter = 0; + + if (devc->engine_state == ES_STOPPED) + { + int trig, n = 0; + + trig = 0; + dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t) & trig); +#ifdef POLLED_MODE + ; + + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; /* Start polling */ +#else + dmap->audio_callback = softsyn_callback; + dmap->qhead = dmap->qtail = dmap->qlen = 0; +#endif + + while (dmap->qlen < devc->max_playahead && n++ < 2) + do_resample(0); + + devc->engine_state = ES_STARTED; + last_resample_jiffies = jiffies; + resample_counter = 0; + + trig = PCM_ENABLE_OUTPUT; + if (dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, + (caddr_t) & trig) < 0) + { + printk("SoftOSS: Trigger failed\n"); + } + } +} + +static void +stop_engine(softsyn_devc * devc) +{ +} + +static void +request_engine(softsyn_devc * devc, int ticks) +{ + if (ticks < 0) /* Relative time */ + devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ); + else + devc->next_event_usecs = ticks * (1000000 / HZ); +} + +/* + * Softsync hook serves mode1 (timing) calls made by sequencer.c + */ +static int +softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3) +{ + switch (cmd) + { + case SSYN_START: + start_engine(devc); + break; + + case SSYN_STOP: + stop_engine(devc); + break; + + case SSYN_REQUEST: + request_engine(devc, parm1); + break; + + case SSYN_GETTIME: + return devc->usecs / (1000000 / HZ); + break; + + default: + printk("SoftOSS: Unknown request %d\n", cmd); + } + + return 0; +} + +static int +softsyn_ioctl(int dev, + unsigned int cmd, caddr_t arg) +{ + switch (cmd) + { + + case SNDCTL_SYNTH_INFO: + softsyn_info.nr_voices = devc->maxvoice; + + memcpy((&((char *) arg)[0]), (char *) &softsyn_info, sizeof(softsyn_info)); + return 0; + break; + + case SNDCTL_SEQ_RESETSAMPLES: + stop_engine(devc); + reset_samples(devc); + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return devc->ram_size - devc->ram_used; + break; + + default: + return -EINVAL; + } + +} + +static int +softsyn_kill_note(int devno, int voice, int note, int velocity) +{ + if (voice < 0 || voice > devc->maxvoice) + return 0; + voice_alloc->map[voice] = 0xffff; /* Releasing */ + + if (softoss_voices[voice].sustain_mode & 1) /* Sustain controller on */ + { + softoss_voices[voice].sustain_mode = 3; /* Note off pending */ + return 0; + } + if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE) + { + init_voice(devc, voice); /* Mark it inactive */ + return 0; + } + if (softoss_voices[voice].mode & WAVE_ENVELOPES) + step_envelope(voice, 1, velocity); /* Enter sustain phase */ + else + init_voice(devc, voice); /* Mark it inactive */ + return 0; +} + +static int +softsyn_set_instr(int dev, int voice, int instr) +{ + if (voice < 0 || voice > devc->maxvoice) + return 0; + + if (instr < 0 || instr > MAX_PATCH) + { + printk("SoftOSS: Invalid instrument number %d\n", instr); + return 0; + } + softoss_voices[voice].instr = instr; + + return 0; +} + +static int +softsyn_start_note(int dev, int voice, int note, int volume) +{ + int instr = 0; + int best_sample, best_delta, delta_freq, selected; + unsigned long note_freq, freq, base_note, flags; + voice_info *v = &softoss_voices[voice]; + + struct patch_info *sample; + + if (voice < 0 || voice > devc->maxvoice) + return 0; + + if (volume == 0) /* Actually note off */ + softsyn_kill_note(dev, voice, note, volume); + + save_flags(flags); + cli(); + + if (note == 255) + { /* Just volume update */ + v->velocity = volume; + if (voice_active[voice]) + update_volume(voice); + restore_flags(flags); + return 0; + } + voice_active[voice] = 0; /* Stop the voice for a while */ + devc->vibratomap &= ~(1 << voice); + devc->tremolomap &= ~(1 << voice); + + instr = v->instr; + if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE) + { + printk("SoftOSS: Undefined MIDI instrument %d\n", instr); + restore_flags(flags); + return 0; + } + instr = devc->programs[instr]; + + if (instr < 0 || instr >= devc->nrsamples) + { + printk("SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr); + restore_flags(flags); + return 0; + } + note_freq = note_to_freq(note); + + selected = -1; + + best_sample = instr; + best_delta = 1000000; + + while (instr != NO_SAMPLE && instr >= 0 && selected == -1) + { + delta_freq = note_freq - devc->samples[instr]->base_note; + + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = instr; + best_delta = delta_freq; + } + if (devc->samples[instr]->low_note <= note_freq && + note_freq <= devc->samples[instr]->high_note) + selected = instr; + else + instr = devc->samples[instr]->key; /* Link to next sample */ + + if (instr < 0 || instr >= devc->nrsamples) + instr = NO_SAMPLE; + } + + if (selected == -1) + instr = best_sample; + else + instr = selected; + + if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples) + { + printk("SoftOSS: Unresolved MIDI instrument %d\n", v->instr); + restore_flags(flags); + return 0; + } + sample = devc->samples[instr]; + v->sample = sample; + + if (v->percussive_voice) /* No key tracking */ + { + v->orig_freq = sample->base_freq; /* Fixed pitch */ + } else + { + base_note = sample->base_note / 100; + note_freq /= 100; + + freq = sample->base_freq * note_freq / base_note; + v->orig_freq = freq; + } + + if (!(sample->mode & WAVE_LOOPING)) + { + sample->loop_end = sample->len; + } + v->wave = devc->wave[instr]; + + if (volume < 0) + volume = 0; + else if (volume > 127) + volume = 127; + + v->ptr = 0; + v->startloop = sample->loop_start * 512; + v->startbackloop = 0; + v->endloop = sample->loop_end * 512; + v->looplen = (sample->loop_end - sample->loop_start) * 512; + v->leftvol = 64; + v->rightvol = 64; + v->patch_vol = sample->volume; + v->velocity = volume; + v->mode = sample->mode; + v->vibrato_phase = 0; + v->vibrato_step = 0; + v->vibrato_level = 0; + v->vibrato_rate = 0; + v->vibrato_depth = 0; + v->tremolo_phase = 0; + v->tremolo_step = 0; + v->tremolo_level = 0; + v->tremolo_rate = 0; + v->tremolo_depth = 0; + + if (!(v->mode & WAVE_LOOPING)) + v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK); + else if (v->mode & WAVE_LOOP_BACK) + { + v->ptr = sample->len; + v->startbackloop = v->startloop; + } + if (v->mode & WAVE_VIBRATO) + { + v->vibrato_rate = sample->vibrato_rate; + v->vibrato_depth = sample->vibrato_depth; + } + if (v->mode & WAVE_TREMOLO) + { + v->tremolo_rate = sample->tremolo_rate; + v->tremolo_depth = sample->tremolo_depth; + } + if (v->mode & WAVE_ENVELOPES) + { + v->envelope_phase = -1; + v->envelope_vol = 0; + step_envelope(voice, 0, 60); + } + update_volume(voice); + compute_step(voice); + + voice_active[voice] = 1; /* Mark it active */ + + restore_flags(flags); + return 0; +} + +static int +softsyn_open(int synthdev, int mode) +{ + int err; + extern int softoss_dev; + int frags = 0x7fff0007; /* fragment size of 128 bytes */ + + if (devc->audio_opened) /* Already opened */ + return 0; + + softsynth_disabled = 0; + devc->finfo.mode = OPEN_WRITE; + devc->finfo.flags = 0; + + if (softoss_dev >= num_audiodevs) + softoss_dev = num_audiodevs - 1; + + if (softoss_dev < 0) + softoss_dev = 0; + if (softoss_dev >= num_audiodevs) + return -ENXIO; + devc->audiodev = softoss_dev; + + if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE)) + { + printk("SoftOSS: The audio device doesn't support 16 bits\n"); + return -ENXIO; + } + if ((err = audio_open((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0) + return err; + + devc->speed = audio_devs[devc->audiodev]->d->set_speed( + devc->audiodev, devc->speed); + devc->channels = audio_devs[devc->audiodev]->d->set_channels( + devc->audiodev, devc->channels); + devc->bits = audio_devs[devc->audiodev]->d->set_bits( + devc->audiodev, devc->bits); + + + DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels)); + + dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags); + dma_ioctl(devc->audiodev, SNDCTL_DSP_GETBLKSIZE, (caddr_t) & devc->fragsize); + + if (devc->bits != 16 || devc->channels != 2) + { + audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); + printk("SoftOSS: A 16 bit stereo soundcard is required\n"); + return 0; + } + if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs) + devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs; + + DDB(printk("SoftOSS: Using %d fragments of %d bytes\n", devc->max_playahead, devc->fragsize)); + + init_engine(devc); + devc->audio_opened = 1; + devc->sequencer_mode = mode; + return 0; +} + +static void +softsyn_close(int synthdev) +{ + devc->engine_state = ES_STOPPED; +#ifdef POLLED_MODE + del_timer(&poll_timer);; +#endif + dma_ioctl(devc->audiodev, SNDCTL_DSP_RESET, 0); + if (devc->audio_opened) + audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); + devc->audio_opened = 0; +} + +static void +softsyn_hw_control(int dev, unsigned char *event_rec) +{ + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; + + cmd = event_rec[2]; + voice = event_rec[3]; + p1 = *(unsigned short *) &event_rec[4]; + p2 = *(unsigned short *) &event_rec[6]; + plong = *(unsigned int *) &event_rec[4]; + + switch (cmd) + { + + case _GUS_NUMVOICES: + set_max_voices(p1); + break; + + + default:; + } +} + +static int +softsyn_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) +{ + struct patch_info *patch = NULL; + + int i, p, instr; + long sizeof_patch; + int memlen, adj; + unsigned short data; + short *wave = NULL; + + sizeof_patch = (long) &patch->data[0] - (long) patch; /* Header size */ + + if (format != GUS_PATCH) + { + printk("SoftOSS: Invalid patch format (key) 0x%x\n", format); + return -EINVAL; + } + if (count < sizeof_patch) + { + printk("SoftOSS: Patch header too short\n"); + return -EINVAL; + } + count -= sizeof_patch; + + if (devc->nrsamples >= MAX_SAMPLE) + { + printk("SoftOSS: Sample table full\n"); + return -ENOSPC; + } + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ + + patch = vmalloc(sizeof(*patch)); + + if (patch == NULL) + { + printk("SoftOSS: Out of memory\n"); + return -ENOSPC; + } + copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs); + + if (patch->mode & WAVE_ROM) + { + vfree(patch); + return -EINVAL; + } + instr = patch->instr_no; + + if (instr < 0 || instr > MAX_PATCH) + { + printk("SoftOSS: Invalid patch number %d\n", instr); + vfree(patch); + return -EINVAL; + } + if (count < patch->len) + { + printk("SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len); + patch->len = count; + } + if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used)) + { + printk("SoftOSS: Invalid sample length %d\n", (int) patch->len); + vfree(patch); + return -EINVAL; + } + if (patch->mode & WAVE_LOOPING) + { + if (patch->loop_start < 0 || patch->loop_start >= patch->len) + { + printk("SoftOSS: Invalid loop start %d\n", patch->loop_start); + vfree(patch); + return -EINVAL; + } + if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len) + { + printk("SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end); + vfree(patch); + return -EINVAL; + } + } +/* + * Next load the wave data to memory + */ + + memlen = patch->len; + adj = 1; + + if (!(patch->mode & WAVE_16_BITS)) + memlen *= 2; + else + adj = 2; + + wave = vmalloc(memlen); + + if (wave == NULL) + { + printk("SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen); + vfree(patch); + return -ENOSPC; + } + p = 0; + for (i = 0; i < memlen / 2; i++) /* Handle words */ + { + unsigned char tmp; + + data = 0; + + if (patch->mode & WAVE_16_BITS) + { + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */ + data = tmp; + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */ + if (patch->mode & WAVE_UNSIGNED) + tmp ^= 0x80; /* Convert to signed */ + data |= (tmp << 8); + } else + { + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); + if (patch->mode & WAVE_UNSIGNED) + tmp ^= 0x80; /* Convert to signed */ + data = (tmp << 8); /* Convert to 16 bits */ + } + + wave[i] = (short) data; + } + + devc->ram_used += patch->len; +/* + * Convert pointers to 16 bit indexes + */ + patch->len /= adj; + patch->loop_start /= adj; + patch->loop_end /= adj; + +/* + * Finally link the loaded patch to the chain + */ + + patch->key = devc->programs[instr]; + devc->programs[instr] = devc->nrsamples; + devc->wave[devc->nrsamples] = (short *) wave; + devc->samples[devc->nrsamples++] = patch; + + return 0; +} + +static void +softsyn_panning(int dev, int voice, int pan) +{ + if (voice < 0 || voice > devc->maxvoice) + return; + + if (pan < -128) + pan = -128; + if (pan > 127) + pan = 127; + + softoss_voices[voice].panning = pan; + if (voice_active[voice]) + update_volume(voice); +} + +static void +softsyn_volume_method(int dev, int mode) +{ +} + +static void +softsyn_aftertouch(int dev, int voice, int pressure) +{ + if (voice < 0 || voice > devc->maxvoice) + return; + + if (voice_active[voice]) + update_volume(voice); +} + +static void +softsyn_controller(int dev, int voice, int ctrl_num, int value) +{ + unsigned long flags; + + if (voice < 0 || voice > devc->maxvoice) + return; + save_flags(flags); + cli(); + + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + softoss_voices[voice].bender = value; + + if (voice_active[voice]) + compute_step(voice); /* Update pitch */ + break; + + + case CTRL_PITCH_BENDER_RANGE: + softoss_voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + softoss_voices[voice].expression_vol = value; + if (voice_active[voice]) + update_volume(voice); + break; + + case CTL_PAN: + softsyn_panning(dev, voice, (value * 2) - 128); + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + softoss_voices[voice].main_vol = value; + if (voice_active[voice]) + update_volume(voice); + break; + + default: + break; + } + + restore_flags(flags); +} + +static void +softsyn_bender(int dev, int voice, int value) +{ + if (voice < 0 || voice > devc->maxvoice) + return; + + softoss_voices[voice].bender = value - 8192; + if (voice_active[voice]) + compute_step(voice); /* Update pitch */ +} + +static int +softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) +{ + int i, p, best = -1, best_time = 0x7fffffff; + + p = alloc->ptr; + /* + * First look for a completely stopped voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + voice_active[p] = 0; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } + + /* + * Then look for a releasing voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + voice_active[p] = 0; + return p; + } + p = (p + 1) % alloc->max_voice; + } + + if (best >= 0) + p = best; + + alloc->ptr = p; + voice_active[p] = 0; + return p; +} + +static void +softsyn_setup_voice(int dev, int voice, int chn) +{ + unsigned long flags; + + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + save_flags(flags); + cli(); + /* init_voice(devc, voice); */ + softsyn_set_instr(dev, voice, info->pgm_num); + + softoss_voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just MSB */ + softoss_voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + softsyn_panning(dev, voice, (info->controllers[CTL_PAN] * 2) - 128); + softoss_voices[voice].bender = 0; /* info->bender_value; */ + softoss_voices[voice].bender_range = info->bender_range; + + if (chn == 9) + softoss_voices[voice].percussive_voice = 1; + restore_flags(flags); +} + +static void +softsyn_reset(int devno) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + for (i = 0; i < devc->maxvoice; i++) + init_voice(devc, i); + restore_flags(flags); +} + +static struct synth_operations softsyn_operations = +{ + "SoftOSS", + &softsyn_info, + 0, + SYNTH_TYPE_SAMPLE, + 0, + softsyn_open, + softsyn_close, + softsyn_ioctl, + softsyn_kill_note, + softsyn_start_note, + softsyn_set_instr, + softsyn_reset, + softsyn_hw_control, + softsyn_load_patch, + softsyn_aftertouch, + softsyn_controller, + softsyn_panning, + softsyn_volume_method, + softsyn_bender, + softsyn_alloc_voice, + softsyn_setup_voice +}; + +/* + * Timer stuff (for /dev/music). + */ + +static unsigned int +soft_tmr_start(int dev, unsigned int usecs) +{ + tmr_running = 1; + start_engine(devc); + return devc->usecs_per_frag; +} + +static void +soft_tmr_disable(int dev) +{ + stop_engine(devc); + tmr_running = 0; +} + +static void +soft_tmr_restart(int dev) +{ + tmr_running = 1; +} + +static struct sound_lowlev_timer soft_tmr = +{ + 0, + 9999, + soft_tmr_start, + soft_tmr_disable, + soft_tmr_restart +}; + +int +probe_softsyn(struct address_info *hw_config) +{ + int i; + + if (softsynth_loaded) + return 0; + + devc->ram_size = 8 * 1024 * 1024; + devc->ram_used = 0; + devc->nrsamples = 0; + for (i = 0; i < MAX_PATCH; i++) + { + devc->programs[i] = NO_SAMPLE; + devc->wave[i] = NULL; + } + + devc->maxvoice = DEFAULT_VOICES; + + devc->audiodev = 0; + devc->audio_opened = 0; + devc->channels = 2; + devc->bits = 16; + devc->max_playahead = 32; + +#ifdef SOFTOSS_RATE + devc->speed = SOFTOSS_RATE; +#else + devc->speed = 32000; +#endif + +#ifdef SOFTOSS_VOICES + devc->default_max_voices = SOFTOSS_VOICES; +#else + devc->default_max_voices = 32; +#endif + + softsynth_loaded = 1; + return 1; +} + +void +attach_softsyn_card(struct address_info *hw_config) +{ + + voice_alloc = &softsyn_operations.alloc; + synth_devs[devc->synthdev = num_synths++] = &softsyn_operations; + sequencer_init(); + sound_timer_init(&soft_tmr, "SoftOSS"); + devc->timerdev = num_sound_timers; + softsynthp = softsynth_hook; + +#ifndef POLLED_MODE +#endif +} + +void +unload_softsyn(struct address_info *hw_config) +{ + if (!softsynth_loaded) + return; +#ifndef POLLED_MODE +#endif + + softsynthp = NULL; + softsynth_loaded = 0; + reset_samples(devc); +} + +#ifdef MODULE + +static struct address_info config; + +int +init_module(void) +{ + printk("SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n"); + if (!probe_softsyn(&config)) + return -ENODEV; + attach_softsyn_card(&config); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + unload_softsyn(&config); + sound_unload_synthdev(devc->synthdev); + sound_unload_timerdev(devc->timerdev); + SOUND_LOCK_END; +} +#endif +#endif diff --git a/drivers/sound/softoss.h b/drivers/sound/softoss.h new file mode 100644 index 000000000..f0b07e8d0 --- /dev/null +++ b/drivers/sound/softoss.h @@ -0,0 +1,161 @@ +/* + * softoss.h - Definitions for Software MIDI Synthesizer. + */ +/* + * 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. + */ + + +/* + * Sequencer mode1 timer calls made by sequencer.c + */ +extern int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3); + +#define SSYN_START 1 +#define SSYN_REQUEST 2 /* parm1 = time */ +#define SSYN_STOP 3 +#define SSYN_GETTIME 4 /* Returns number of ticks since reset */ + +#define MAX_PATCH 256 +#define MAX_SAMPLE 512 +#define MAX_VOICE 32 +#define DEFAULT_VOICES 16 + +typedef struct voice_info +{ +/* + * Don't change anything in the beginning of this struct. These fields are used + * by the resampling loop which may have been written in assembly for some + * architectures. Any change may make the resampling code incompatible + */ + int instr; + short *wave; + struct patch_info *sample; + + unsigned int ptr; int step; /* Pointer to the wave data and pointer increment */ + + int mode; + int startloop, startbackloop, endloop, looplen; + + unsigned int leftvol, rightvol; +/***** Don't change anything above this */ + + volatile unsigned long orig_freq, current_freq; + volatile int bender, bender_range, panning; + volatile int main_vol, expression_vol, patch_vol, velocity; + +/* Envelope parameters */ + + int envelope_phase; + volatile int envelope_vol; + volatile int envelope_volstep; + int envelope_time; /* Number of remaining envelope steps */ + unsigned int envelope_target; + int percussive_voice; + int sustain_mode; /* 0=off, 1=sustain on, 2=sustain on+key released */ + +/* Vibrato */ + int vibrato_rate; + int vibrato_depth; + int vibrato_phase; + int vibrato_step; + int vibrato_level; + +/* Tremolo */ + int tremolo_rate; + int tremolo_depth; + int tremolo_phase; + int tremolo_step; + int tremolo_level; +} voice_info; + +extern voice_info softoss_voices[MAX_VOICE]; /* Voice spesific info */ + +typedef struct softsyn_devc +{ +/* + * Don't change anything in the beginning of this struct. These fields are used + * by the resampling loop which may have been written in assembly for some + * architectures. Any change may make the resampling code incompatible + */ + int maxvoice; /* # of voices to be processed */ + int afterscale; + int delay_size; + int control_rate, control_counter; +/***** Don't change anything above this */ + + int ram_size; + int ram_used; + + int synthdev; + int timerdev; + int sequencer_mode; +/* + * Audio parameters + */ + + int audiodev; + int audio_opened; + int speed; + int channels; + int bits; + int default_max_voices; + int max_playahead; + struct fileinfo finfo; + int fragsize; + int samples_per_fragment; + +/* + * Sample storage + */ + int nrsamples; + struct patch_info *samples[MAX_SAMPLE]; + short *wave[MAX_SAMPLE]; + +/* + * Programs + */ + int programs[MAX_SAMPLE]; + +/* + * Timer parameters + */ + volatile unsigned long usecs; + volatile unsigned long usecs_per_frag; + volatile unsigned long next_event_usecs; + +/* + * Engine state + */ + + volatile int engine_state; +#define ES_STOPPED 0 +#define ES_STARTED 1 + + /* Voice spesific bitmaps */ + volatile int tremolomap; + volatile int vibratomap; + +} softsyn_devc; + +void softsynth_resample_loop(short *buf, int loops); +extern void softsyn_control_loop(void); + +#define DELAY_SIZE 4096 + +#ifdef SOFTSYN_MAIN + short voice_active[MAX_VOICE] = {0}; + voice_info softoss_voices[MAX_VOICE] = {{0}}; /* Voice spesific info */ + int left_delay[DELAY_SIZE]={0}, right_delay[DELAY_SIZE]={0}; + int delayp=0; +#else + extern softsyn_devc *devc; + + extern int left_delay[DELAY_SIZE], right_delay[DELAY_SIZE]; + extern int delayp; + extern short voice_active[MAX_VOICE]; +#endif diff --git a/drivers/sound/softoss_rs.c b/drivers/sound/softoss_rs.c new file mode 100644 index 000000000..f8dac8ed5 --- /dev/null +++ b/drivers/sound/softoss_rs.c @@ -0,0 +1,136 @@ + +/* + * sound/softoss_rs.c + * + * Software based MIDI synthsesizer driver, the actual mixing loop. + * Keep the loop as simple as possible to make it easier to rewrite this + * routine in assembly. + */ +/* + * 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 "sound_config.h" + +#if defined(CONFIG_SOFTOSS) || defined(MODULE) +#include "softoss.h" + +void +softsynth_resample_loop(short *buf, int loops) +{ + int iloop, voice; + volatile voice_info *v; + +#ifdef OSS_BIG_ENDIAN + unsigned char *cbuf = (unsigned char *) buf; + +#endif + + for (iloop = 0; iloop < loops; iloop++) + { /* Mix one sample */ + + int accum, left = 0, right = 0; + int ix, position; + + for (voice = 0; voice < devc->maxvoice; voice++) + if (voice_active[voice]) + { /* Compute voice */ + + v = &softoss_voices[voice]; +#ifdef SOFTOSS_TEST + ix = iloop << 3; + position = v->ptr; +#else + ix = (position = v->ptr) >> 9; +#endif + /* Interpolation (resolution of 512 steps) */ + { + int fract = v->ptr & 0x1f; /* 9 bits */ + + /* This method works with less arithmetic operations */ + register int v1 = v->wave[ix]; + + accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9); + } + + left += (accum * v->leftvol); + right += (accum * v->rightvol); + + /* Update sample pointer */ + + position += v->step; + if (position <= v->endloop) + v->ptr = position; + else if (v->mode & WAVE_LOOPING) + { + if (v->mode & WAVE_BIDIR_LOOP) + { + v->mode ^= WAVE_LOOP_BACK; /* Turn around */ + v->step *= -1; + } else + { + position -= v->looplen; + v->ptr = position; + } + } + /* else leave the voice looping the current sample */ + + if (v->mode & WAVE_LOOP_BACK && position < v->startloop) + { + if (v->mode & WAVE_BIDIR_LOOP) + { + v->mode ^= WAVE_LOOP_BACK; /* Turn around */ + v->step *= -1; + } else + { + position += v->looplen; + v->ptr = position; + } + } + } /* Compute voice */ +#if 1 /* Delay */ + left += left_delay[delayp]; + right += right_delay[delayp]; + + left_delay[delayp] = right >> 2; + right_delay[delayp] = left >> 2; + delayp = (delayp + 1) % devc->delay_size; +#endif + +#define AFTERSCALE devc->afterscale; + + left >>= AFTERSCALE; + right >>= AFTERSCALE; + + if (left > 32767) + left = 32767; + if (left < -32768) + left = -32768; + if (right > 32767) + right = 32767; + if (right < -32768) + right = -32768; + +#ifdef OSS_BIG_ENDIAN + *cbuf++ = left & 0xff; + *cbuf++ = (left >> 8) & 0xff; + *cbuf++ = right & 0xff; + *cbuf++ = (right >> 8) & 0xff; +#else + *buf++ = left; + *buf++ = right; +#endif + if (devc->control_counter++ >= devc->control_rate) + { + devc->control_counter = 0; + softsyn_control_loop(); + } + } /* Mix one sample */ +} +#endif diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h index 8bb54fa9d..829cfcf91 100644 --- a/drivers/sound/sound_calls.h +++ b/drivers/sound/sound_calls.h @@ -41,6 +41,7 @@ void audio_init_devices (void); int audio_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); void reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording); +int dma_ioctl (int dev, unsigned int cmd, caddr_t arg); /* * System calls for the /dev/sequencer @@ -83,7 +84,7 @@ void MIDIbuf_init(void); */ /* From soundcard.c */ -#ifndef __bsdi__ +#if !defined(__bsdi__) && !defined(__NjetBSD__) void tenmicrosec(int *osp); #endif void request_sound_timer (int count); @@ -107,7 +108,7 @@ int sound_ioctl_sw (int dev, struct fileinfo *file, /* From opl3.c */ int opl3_detect (int ioaddr, int *osp); -void opl3_init(int ioaddr, int *osp); +int opl3_init(int ioaddr, int *osp); /* From sb_card.c */ void attach_sb_card(struct address_info *hw_config); @@ -160,7 +161,7 @@ int probe_gus_db16(struct address_info *hw_config); /* From gus_wave.c */ int gus_wave_detect(int baseaddr); void gus_wave_init(struct address_info *hw_config); -void gus_wave_unload (void); +void gus_wave_unload (struct address_info *hw_config); void gus_voice_irq(void); void gus_write8(int reg, unsigned int data); void guswave_dma_irq(void); @@ -169,7 +170,7 @@ int gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg); void gus_timer_command (unsigned int addr, unsigned int val); /* From gus_midi.c */ -void gus_midi_init(void); +void gus_midi_init(struct address_info *hw_config); void gus_midi_interrupt(int dummy); /* From mpu401.c */ @@ -185,14 +186,14 @@ int probe_uart6850(struct address_info *hw_config); void enable_opl3_mode(int left, int right, int both); /* From ics2101.c */ -void ics2101_mixer_init(void); +int ics2101_mixer_init(void); /* From sound_timer.c */ void sound_timer_interrupt(void); void sound_timer_syncinterval(unsigned int new_usecs); /* From ad1848.c */ -void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp); +int ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp); void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); int ad1848_detect (int io_base, int *flags, int *osp); diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index baa04be61..9ca2f3d8a 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -11,7 +11,8 @@ */ -#include "local.h" +#include "local.h.master" + #include "os.h" #include "soundvers.h" @@ -115,7 +116,9 @@ struct address_info { int driver_use_1; /* Driver defined field 1 */ int driver_use_2; /* Driver defined field 2 */ int *osp; /* OS specific info */ - int card_subtype; /* Driver spesific. Usually 0 */ + int card_subtype; /* Driver specific. Usually 0 */ + void *memptr; /* Module memory chainer */ + int slots[6]; /* To remember driver slot ids */ }; #define SYNTH_MAX_VOICES 32 @@ -145,6 +148,7 @@ struct channel_info { #define WK_SIGNAL 0x04 #define WK_SLEEP 0x08 #define WK_SELECT 0x10 +#define WK_ABORT 0x20 #define OPEN_READ PCM_ENABLE_INPUT #define OPEN_WRITE PCM_ENABLE_OUTPUT @@ -161,5 +165,17 @@ struct channel_info { #define DDB(x) {} #endif +#ifndef MDB +#ifdef MODULE +#define MDB(x) x +#else +#define MDB(x) +#endif +#endif + #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 + + + + diff --git a/drivers/sound/sound_firmware.c b/drivers/sound/sound_firmware.c new file mode 100644 index 000000000..4dedda0d9 --- /dev/null +++ b/drivers/sound/sound_firmware.c @@ -0,0 +1,58 @@ +#define __KERNEL_SYSCALLS__ +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/unistd.h> +#include <asm/uaccess.h> + +static int errno; + +static int do_mod_firmware_load(const char *fn, char **fp) +{ + int fd; + long l; + char *dp; + + fd = open(fn, 0, 0); + if (fd == -1) + { + printk(KERN_INFO "Unable to load '%s'.\n", fn); + return 0; + } + l = lseek(fd, 0L, 2); + if (l <= 0 || l > 65535) + { + printk(KERN_INFO "Invalid firmware '%s'\n", fn); + sys_close(fd); + return 0; + } + lseek(fd, 0L, 0); + dp = kmalloc(l, GFP_KERNEL); + if (dp == NULL) + { + printk(KERN_INFO "Out of memory loading '%s'.\n", fn); + sys_close(fd); + return 0; + } + if (read(fd, dp, l) != l) + { + printk(KERN_INFO "Failed to read '%s'.\n", fn); + kfree(dp); + sys_close(fd); + return 0; + } + close(fd); + *fp = dp; + return (int) l; +} + +int mod_firmware_load(const char *fn, char **fp) +{ + int r; + unsigned long fs = get_fs(); + + set_fs(get_ds()); + r = do_mod_firmware_load(fn, fp); + set_fs(fs); + return r; +} diff --git a/drivers/sound/sound_firmware.h b/drivers/sound/sound_firmware.h new file mode 100644 index 000000000..0a0cbfdfb --- /dev/null +++ b/drivers/sound/sound_firmware.h @@ -0,0 +1,2 @@ +extern int mod_firmware_load(const char *fn, char **fp); + diff --git a/drivers/sound/sound_pnp.c b/drivers/sound/sound_pnp.c deleted file mode 100644 index ffaa5b644..000000000 --- a/drivers/sound/sound_pnp.c +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * sound/sound_pnp.c - * - * PnP soundcard support (Linux spesific) - */ -/* - * 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 "sound_config.h" - -#if defined(CONFIG_SPNP) - - -static struct wait_queue *maui_sleeper = NULL; -static volatile struct snd_wait maui_sleep_flag = -{0}; - -extern unsigned long init_pnp (unsigned long, int *); - -#include "pnp.h" -extern int *sound_osp; - -extern int (*pnp_ioctl) (unsigned int cmd, caddr_t arg); - -extern int sound_pnp_port; -static int disabled_devices[] = -{ - PNP_DEVID ('G', 'R', 'V', 0x0003), /* GUS SB emulation */ - PNP_DEVID ('G', 'R', 'V', 0x0004), /* GUS MPU emulation */ - 0 -}; - -static int special_devices[] = -{ - PNP_DEVID ('C', 'S', 'C', 0x0010), /* CS4232/6 control port */ - PNP_DEVID ('C', 'S', 'C', 0x0002), /* CS4232/6 control port */ - 0 -}; - -static int pnp_sig = 0; - -static void -pnp_delay (long t) -{ - t = (t * HZ) / 1000000; /* Convert to jiffies */ - - - { - unsigned long tlimit; - - if (t) - current->timeout = tlimit = jiffies + (t); - else - tlimit = (unsigned long) -1; - maui_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&maui_sleeper); - if (!(maui_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - maui_sleep_flag.opts |= WK_TIMEOUT; - } - maui_sleep_flag.opts &= ~WK_SLEEP; - }; -} - -void -cs4232_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - int old_num_mixers = num_mixers; - int is_4232 = 0; /* CS4232 (not CS4236 or something better) */ - - int portmask = 0xff; - int irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver; - - - if (pnp_trace) - printk ("CS4232/6 driver waking up\n"); - - if (dev->card->key == (PNP_DEVID ('C', 'S', 'C', 0x4232))) - is_4232 = 1; - -#ifndef USE_HOT_PNP_INIT - if (is_4232) /* CS4232 may cause lockups */ - if (pnp_get_port (dev, 0) == NO_PORT || - pnp_get_port (dev, 1) == NO_PORT || - pnp_get_irq (dev, 0) == NO_IRQ || - pnp_get_dma (dev, 0) == NO_DMA - ) - { - printk ("Sound: CS4232 in PnP mode requires prior initialization by PnP BIOS\n"); - return; - } -#endif - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x02; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!is_4232) - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - { - printk ("sound_pnp: Failed to find free resources\n"); - return; - } - - { - struct address_info hw_config; - int wss_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 0); - opl3_base = pnp_get_port (dev, 1); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - - if (num_mixers > old_num_mixers) - { /* Assume the mixer map is as suggested in the CS4232 spec */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM */ - } - } - } -} - -void -opti82C924_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver; - - if (pnp_trace) - printk ("OPTi 82C924 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x02; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int wss_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 1); - opl3_base = pnp_get_port (dev, 2); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (2000000); - - if (pnp_trace) - { - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base + 8; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base + 4; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - } - } -} - -void -opl3sa2_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver, mpu_driver; - - if (pnp_trace) - printk ("OPL3-SA2 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x02; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x04; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x08; /* OPL3 */ - else - printk ("Sound: PnP UART401 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int wss_base, opl3_base, mpu_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 1); - opl3_base = pnp_get_port (dev, 2); - mpu_base = pnp_get_port (dev, 3); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("I/O3 %03x\n", mpu_base); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base + 4; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -static unsigned char -C931_read (int base, int reg) -{ - unsigned char data; - unsigned long flags; - - save_flags (flags); - cli (); - outb ((0xE4), base); - outb ((reg), base + 2); - data = inb (base + 3); - restore_flags (flags); - return data; -} - -static void -C931_write (int base, int reg, unsigned char data) -{ - unsigned long flags; - - save_flags (flags); - cli (); - outb ((0xE4), base); - outb ((reg), base + 2); - outb ((data), base + 3); - restore_flags (flags); -} - -void -opti82C931_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver; - - if (pnp_trace) - printk ("OPTi 82C931 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x02; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int wss_base, opl3_base, master_ctl; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 0); - opl3_base = pnp_get_port (dev, 1); - master_ctl = pnp_get_port (dev, 3); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - if (pnp_trace) - { - int i; - - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("Master control port %x\n", master_ctl); - for (i = 0; i < 4; i++) - printk ("Port %x = %x\n", master_ctl + i, inb (master_ctl + i)); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - { - unsigned char tmp; - - tmp = C931_read (master_ctl, 5) | 0x20; /* Enable codec registers I16 to I31 */ - C931_write (master_ctl, 5, tmp); - - tmp = 0x82; /* MPU and WSS enabled, SB disabled */ - C931_write (master_ctl, 6, tmp); - } - - pnp_delay (2000000); - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base + 8; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - ad1848_control (AD1848_SET_C930_PWD, master_ctl); - } - } -} - -void -opti82C924mpu_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int mpu_driver; - - if (pnp_trace) - printk ("OPTi 82C924/C925/C931 MPU driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP MPU"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; /* MPU401 */ - else - printk ("Sound: PnP MPU device detected but no driver enabled\n"); - - /* printk ("MPU driver %d\n", mpu_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - irq = pnp_get_irq (dev, 0); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O %03x\n", mpu_base); - printk ("IRQ %d\n", irq); - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -void -cs4236mpu_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int mpu_driver; - - if (dev->card->key == (PNP_DEVID ('C', 'S', 'C', 0x4232))) /* CS4232 */ - return; - - if (pnp_trace) - printk ("CS4236 MPU driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP MPU"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; /* MPU401 */ - else - printk ("Sound: CS4236 PnP MPU device detected but no driver enabled\n"); - - /* printk ("MPU driver %d\n", mpu_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - irq = pnp_get_irq (dev, 0); - - pnp_delay (1500000); - - if (pnp_trace) - { - printk ("I/O %03x\n", mpu_base); - printk ("IRQ %d\n", irq); - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -void -soundscape_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x03, dmamask = 0x01; - int sscape_driver, wss_driver; - - if (pnp_trace) - printk ("Soundscape PnP driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SoundScape PnP"; - - if ((sscape_driver = sndtable_identify_card ("SSCAPE"))) - portmask |= 0x01; /* MPU401 */ - else - printk ("Sound: Soundscape PnP device detected but no driver enabled\n"); - - /* printk ("Soundscape driver %d\n", sscape_driver); */ - - if ((wss_driver = sndtable_identify_card ("SSCAPEMSS"))) - portmask |= 0x01; - else - printk ("Sound: Soundscape codec device detected but no driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sscape_base; - int irq, irq2, dma, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sscape_base = pnp_get_port (dev, 0); - irq = pnp_get_irq (dev, 0); - irq2 = pnp_get_irq (dev, 1); - dma = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O %03x\n", sscape_base); - printk ("IRQ %d\n", irq); - printk ("IRQ2 %d\n", irq2); - printk ("DMA %d\n", dma); - printk ("DMA2 %d\n", dma2); - } - - if (sscape_base && sscape_driver) - { - hw_config.io_base = sscape_base; - hw_config.irq = irq; - hw_config.dma = dma; - hw_config.dma2 = dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0x12345678; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (sscape_driver, &hw_config); - } - - if (sscape_base && wss_driver) - { - hw_config.io_base = sscape_base + 8; /* The codec base */ - hw_config.irq = irq2; - hw_config.dma = dma; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - ad1848_control (AD1848_SET_XTAL, 1); /* 14.3 MHz is used */ - } - } -} - -void -soundscape_vivo (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x07, irqmask = 0x03, dmamask = 0x03; - int mpu_driver, wss_driver, vivo_driver; - int is_vivo_classic = 0; - - if (pnp_trace) - printk ("Soundscape VIVO driver waking up\n"); - - if (dev->card->key == (PNP_DEVID ('E', 'N', 'S', 0x4080))) - is_vivo_classic = 1; - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SoundScape VIVO"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; /* MPU401 */ - - /* printk ("MPU driver %d\n", mpu_driver); */ - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x02; - else - printk ("Sound: Soundscape codec device detected but no driver enabled\n"); - - if ((vivo_driver = sndtable_identify_card ("VIVO"))) - portmask |= 0x07; - else - printk ("Sound: Soundscape VIVO/OTTO device detected but no driver installed\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base, mss_base, otto_base; - int irq, irq2, dma, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - mss_base = pnp_get_port (dev, 1); - otto_base = pnp_get_port (dev, 2); - irq = pnp_get_irq (dev, 0); - irq2 = pnp_get_irq (dev, 1); - dma = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - if (dma2 == NO_DMA) - dma2 = dma; - - if (pnp_trace) - { - printk ("I/O %03x\n", mpu_base); - printk ("MSS I/O %03x\n", mss_base); - printk ("OTTO I/O %03x\n", otto_base); - printk ("IRQ %d\n", irq); - printk ("IRQ2 %d\n", irq2); - printk ("DMA %d\n", dma); - printk ("DMA2 %d\n", dma2); - } - - - if (mss_base && wss_driver) - { - hw_config.io_base = mss_base + 4; /* The codec base */ - hw_config.irq = irq; - hw_config.dma = dma; - hw_config.dma2 = dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - } - - if (otto_base && vivo_driver) - { - hw_config.io_base = otto_base; - hw_config.irq = irq2; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = mpu_base; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (vivo_driver, &hw_config); - - if (is_vivo_classic) - { - /* - * The original VIVO uses XCTL0 pin of AD1845 as a synth (un)mute bit. Turn it - * on _after_ the synth is initialized. Btw, XCTL1 controls 30 dB mic boost - * circuit. - */ - - ad1848_control (AD1848_SET_XCTL0, 1); /* Unmute */ - } - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); /* AUX1 is OTTO input */ - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE); /* Line in */ - - } - } -} - -void -gus_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int gus_driver, wss_driver; - - if (pnp_trace) - printk ("GUS PnP driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "Ultrasound PnP"; - - if ((gus_driver = sndtable_identify_card ("GUSPNP"))) - portmask |= 0x07; - else - printk ("Sound: GUS PnP device detected but no driver enabled\n"); - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MAX */ - else - printk ("Sound: GUS PnP codec device detected but no driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int gus_base; - int irq; - int dma1, dma2; - - gus_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - if (pnp_trace) - printk ("Device activation OK (P%x I%d D%d d%d)\n", - gus_base, irq, dma1, dma2); - - if (gus_base && gus_driver) - { - - hw_config.io_base = gus_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (gus_driver, &hw_config); - } - } -} - -void -sb_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int sb_driver, mpu_driver, opl3_driver; - - if (pnp_trace) - printk ("SB PnP driver waking up\n"); - pnp_delay (1000000); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SoundBlaster PnP"; - - if ((sb_driver = sndtable_identify_card ("SBPNP"))) - portmask |= 0x01; - else - printk ("Sound: SB PnP device detected but no driver enabled\n"); - - if ((mpu_driver = sndtable_identify_card ("SBMPU"))) - portmask |= 0x02; - else - printk ("Sound: SB PnP device detected but SB MPU driver not enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x04; - else - printk ("Sound: SB PnP device detected but OPL3 driver not enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sb_base, mpu_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sb_base = pnp_get_port (dev, 0); - mpu_base = pnp_get_port (dev, 1); - opl3_base = pnp_get_port (dev, 2); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - if (sb_base && sb_driver) - { - hw_config.io_base = sb_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (sb_driver, &hw_config); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -void -als_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int sb_driver; - - if (pnp_trace) - printk ("ALS### PnP driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SB16 clone"; - - if ((sb_driver = sndtable_identify_card ("SBPNP"))) - portmask |= 0x01; - else - printk ("Sound: ALS PnP device detected but no driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sb_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sb_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 1); - dma2 = pnp_get_dma (dev, 0); - - if (sb_base && sb_driver) - { - hw_config.io_base = sb_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (sb_driver, &hw_config); - } - } -} - -void -als_pnp_mpu (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int mpu_driver; - - if (pnp_trace) - printk ("ALS### PnP MPU driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SB16 clone"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; - else - printk ("Sound: ALS PnP device detected but no MPU driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - } - } -} - -void -als_pnp_opl (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int opl3_driver; - - if (pnp_trace) - printk ("ALS### PnP OPL3 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SB16 clone"; - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x01; - else - printk ("Sound: ALS PnP device detected but no OPL3 driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int opl3_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - opl3_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - } - } -} - -void -ess_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x03, irqmask = 0x01, dmamask = 0x03; - int sb_driver, mpu_driver, opl3_driver; - - if (pnp_trace) - printk ("ESS PnP driver waking up\n"); - - if (pnp_trace) - { - printk ("ESS1868: IRQB,IRQA = %x\n", pnp_readreg (dev, 0x20)); - printk ("ESS1868: IRQD,IRQC = %x\n", pnp_readreg (dev, 0x21)); - printk ("ESS1868: IRQF,IRQE = %x\n", pnp_readreg (dev, 0x22)); - printk ("ESS1868: DRQB,DRQA = %x\n", pnp_readreg (dev, 0x23)); - printk ("ESS1868: DRQD,DRQC = %x\n", pnp_readreg (dev, 0x24)); - printk ("ESS1868: Configuration ROM Header 0 = %x\n", pnp_readreg (dev, 0x25)); - printk ("ESS1868: Configuration ROM Header 1 = %x\n", pnp_readreg (dev, 0x26)); - printk ("ESS1868: HW Volume IRQ = %x\n", pnp_readreg (dev, 0x27)); - printk ("ESS1868: MPU401 IRQ = %x\n", pnp_readreg (dev, 0x28)); - } - - if (pnp_readreg (dev, 0x27) & 0x01) /* MPU401 is at logical device #3 */ - printk ("Nonstandard ESS1868 implementation - contact support@4front-tech.com\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "ESS AudioDrive PnP"; - - if ((sb_driver = sndtable_identify_card ("SBLAST"))) - portmask |= 0x01; - else - printk ("Sound: SB PnP device detected but no driver enabled\n"); - - if ((mpu_driver = sndtable_identify_card ("SBMPU"))) - portmask |= 0x02; - else - printk ("Sound: SB PnP device detected but SB MPU driver not enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x04; - else - printk ("Sound: SB PnP device detected but OPL3 driver not enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sb_base, mpu_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sb_base = pnp_get_port (dev, 0); - opl3_base = pnp_get_port (dev, 1); - mpu_base = pnp_get_port (dev, 2); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - /* dma2 = pnp_get_dma (dev, 1); */ dma2 = -1; - - if (pnp_trace) - { - printk ("ESS PnP at %x/%x/%x, %d, %d/%d\n", - sb_base, mpu_base, opl3_base, - irq, dma1, dma2); - } - - if (sb_base && sb_driver) - { - hw_config.io_base = sb_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = NULL; - hw_config.card_subtype = 0; - - sndtable_start_card (sb_driver, &hw_config); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = NULL; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = -irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = NULL; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -static struct pnp_sounddev pnp_devs[] = -{ - {PNP_DEVID ('C', 'S', 'C', 0x0000), cs4232_pnp, "CS4232"}, - {PNP_DEVID ('C', 'S', 'C', 0x0003), cs4236mpu_pnp, "CS4236MPU"}, - {PNP_DEVID ('G', 'R', 'V', 0x0000), gus_pnp, "GUS"}, - {PNP_DEVID ('R', 'V', 'L', 0x0010), gus_pnp, "WAVXTREME"}, - {PNP_DEVID ('A', 'D', 'V', 0x0010), gus_pnp, "IWAVE"}, - {PNP_DEVID ('D', 'X', 'P', 0x0010), gus_pnp, "IWAVE"}, - {PNP_DEVID ('Y', 'M', 'H', 0x0021), opl3sa2_pnp, "OPL3SA2"}, - {PNP_DEVID ('O', 'P', 'T', 0x0000), opti82C924_pnp, "82C924"}, - {PNP_DEVID ('O', 'P', 'T', 0x9250), opti82C924_pnp, "82C925"}, - {PNP_DEVID ('O', 'P', 'T', 0x9310), opti82C931_pnp, "82C931"}, - {PNP_DEVID ('O', 'P', 'T', 0x0002), opti82C924mpu_pnp, "82C924MPU"}, - {PNP_DEVID ('E', 'N', 'S', 0x0000), soundscape_pnp, "SSCAPE"}, - {PNP_DEVID ('N', 'E', 'C', 0x0000), soundscape_pnp, "NEC"}, - {PNP_DEVID ('E', 'N', 'S', 0x1010), soundscape_vivo, "SSCAPE"}, - {PNP_DEVID ('E', 'N', 'S', 0x1011), soundscape_vivo, "SSCAPE"}, - {PNP_DEVID ('C', 'T', 'L', 0x0031), sb_pnp, "SB"}, - {PNP_DEVID ('C', 'T', 'L', 0x0001), sb_pnp, "SB"}, - {PNP_DEVID ('C', 'T', 'L', 0x0041), sb_pnp, "SB"}, /* SB32 (new revision) */ - {PNP_DEVID ('C', 'T', 'L', 0x0042), sb_pnp, "SB"}, /* SB64 */ - {PNP_DEVID ('C', 'T', 'L', 0x0044), sb_pnp, "SB"}, /* SB64 Gold */ - {PNP_DEVID ('@', '@', '@', 0x0001), als_pnp, "SB"}, - {PNP_DEVID ('@', 'X', '@', 0x0001), als_pnp_mpu, "SB"}, - {PNP_DEVID ('@', 'H', '@', 0x0001), als_pnp_opl, "SB"}, - {PNP_DEVID ('E', 'S', 'S', 0x1868), ess_pnp, "ESS"} -}; - -static int nr_pnpdevs = sizeof (pnp_devs) / sizeof (struct pnp_sounddev); - -static int -pnp_activate (int id, struct pnp_dev *dev) -{ - int i; - - for (i = 0; i < nr_pnpdevs; i++) - if (pnp_devs[i].id == id) - { - - if (pnp_trace) - printk ("PnP dev: %08x, %s\n", id, - pnp_devid2asc (id)); - - pnp_devs[i].setup ((void *) dev); - return 1; - } - - return 0; -} - -void -cs423x_special (struct pnp_dev *dev) -{ -} - -void -sound_pnp_init (int *osp) -{ - - struct pnp_dev *dev; - - if (pnp_sig == 0) - init_pnp (0, osp); - - if (pnp_sig == 0) - if ((pnp_sig = pnp_connect ("sound")) == -1) - { - printk ("Sound: Can't connect to kernel PnP services.\n"); - return; - } - -/* - * First handle some special configuration ports. - */ - dev = NULL; - while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) - { - int i; - - for (i = 0; special_devices[i] != 0; i++) - if (special_devices[i] == dev->key) - switch (i) - { - case 0: - case 1: - cs423x_special (dev); - break; - } - } - -/* - * Next disable some unused sound devices so that they don't consume - * valuable IRQ and DMA resources. - */ - dev = NULL; - while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) - { - int i; - - for (i = 0; disabled_devices[i] != 0; i++) - if (disabled_devices[i] == dev->key) - pnp_enable_device (dev, 0); /* Disable it */ - } - -/* - * Then initialize drivers for known PnP devices. - */ - dev = NULL; - while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) - { - if (!pnp_activate (dev->key, dev)) - { - /* Scan all compatible devices */ - - int i; - - for (i = 0; i < dev->ncompat; i++) - if (pnp_activate (dev->compat_keys[i], dev)) - break; - } - } -} - -void -sound_pnp_disconnect (void) -{ - pnp_disconnect (pnp_sig); -} - - -#endif diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index bacdccb66..8e8c553bf 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -33,696 +33,702 @@ static int status_busy = 0; int * -load_mixer_volumes (char *name, int *levels, int present) +load_mixer_volumes(char *name, int *levels, int present) { - int i, n; - - for (i = 0; i < num_mixer_volumes; i++) - if (strcmp (name, mixer_vols[i].name) == 0) - { - if (present) - mixer_vols[i].num = i; - return mixer_vols[i].levels; - } - - if (num_mixer_volumes >= MAX_MIXER_DEV) - { - printk ("Sound: Too many mixers (%s)\n", name); - return levels; - } - - n = num_mixer_volumes++; + int i, n; + + for (i = 0; i < num_mixer_volumes; i++) + if (strcmp(name, mixer_vols[i].name) == 0) + { + if (present) + mixer_vols[i].num = i; + return mixer_vols[i].levels; + } + if (num_mixer_volumes >= MAX_MIXER_DEV) + { + printk("Sound: Too many mixers (%s)\n", name); + return levels; + } + n = num_mixer_volumes++; - strcpy (mixer_vols[n].name, name); + strcpy(mixer_vols[n].name, name); - if (present) - mixer_vols[n].num = n; - else - mixer_vols[n].num = -1; + if (present) + mixer_vols[n].num = n; + else + mixer_vols[n].num = -1; - for (i = 0; i < 32; i++) - mixer_vols[n].levels[i] = levels[i]; - return mixer_vols[n].levels; + for (i = 0; i < 32; i++) + mixer_vols[n].levels[i] = levels[i]; + return mixer_vols[n].levels; } static int -set_mixer_levels (caddr_t arg) +set_mixer_levels(caddr_t arg) { - mixer_vol_table *buf = NULL; - int err = 0; + mixer_vol_table *buf = NULL; + int err = 0; - if ((buf = (mixer_vol_table *) vmalloc (sizeof (mixer_vol_table))) == NULL) - return -ENOSPC; + if ((buf = (mixer_vol_table *) vmalloc(sizeof(mixer_vol_table))) == NULL) + return -ENOSPC; - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); - load_mixer_volumes (buf->name, buf->levels, 0); + load_mixer_volumes(buf->name, buf->levels, 0); - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); - return err; + return err; } static int -get_mixer_levels (caddr_t arg) +get_mixer_levels(caddr_t arg) { - mixer_vol_table *buf = NULL; - int n, err = 0; + mixer_vol_table *buf = NULL; + int n, err = 0; - if ((buf = (mixer_vol_table *) vmalloc (sizeof (mixer_vol_table))) == NULL) - return -ENOSPC; + if ((buf = (mixer_vol_table *) vmalloc(sizeof(mixer_vol_table))) == NULL) + return -ENOSPC; - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); - n = buf->num; - if (n < 0 || n >= num_mixer_volumes) - err = -EINVAL; - else - { - memcpy ((char *) buf, (char *) &mixer_vols[n], sizeof (*buf)); - } + n = buf->num; + if (n < 0 || n >= num_mixer_volumes) + err = -EINVAL; + else + { + memcpy((char *) buf, (char *) &mixer_vols[n], sizeof(*buf)); + } - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); - return err; + return err; } static int -put_status (char *s) +put_status(char *s) { - int l = strlen (s); + int l = strlen(s); - if (status_len + l >= 4000) - return 0; + if (status_len + l >= 4000) + return 0; - memcpy (&status_buf[status_len], s, l); - status_len += l; + memcpy(&status_buf[status_len], s, l); + status_len += l; - return 1; + return 1; } static int -put_status_int (unsigned int val, int radix) +put_status_int(unsigned int val, int radix) { - int l, v; + int l, v; - static char hx[] = "0123456789abcdef"; - char buf[11]; + static char hx[] = "0123456789abcdef"; + char buf[11]; - if (!val) - return put_status ("0"); + if (!val) + return put_status("0"); - l = 0; - buf[10] = 0; + l = 0; + buf[10] = 0; - while (val) - { - v = val % radix; - val = val / radix; + while (val) + { + v = val % radix; + val = val / radix; - buf[9 - l] = hx[v]; - l++; - } + buf[9 - l] = hx[v]; + l++; + } - if (status_len + l >= 4000) - return 0; + if (status_len + l >= 4000) + return 0; - memcpy (&status_buf[status_len], &buf[10 - l], l); - status_len += l; + memcpy(&status_buf[status_len], &buf[10 - l], l); + status_len += l; - return 1; + return 1; } static void -init_status (void) +init_status(void) { - /* - * Write the status information to the status_buf and update status_len. - * There is a limit of 4000 bytes for the data. - */ + /* + * Write the status information to the status_buf and update status_len. + * There is a limit of 4000 bytes for the data. + */ - int i; + int i; - status_ptr = 0; + status_ptr = 0; #ifdef SOUND_UNAME_A - put_status ("OSS/Free" SOUND_VERSION_STRING - " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n" - SOUND_UNAME_A ")" - "\n"); + put_status("OSS/Free" SOUND_VERSION_STRING + " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n" + SOUND_UNAME_A ")" + "\n"); #else - put_status ("OSS/Free:" SOUND_VERSION_STRING - " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" - SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" - "\n"); + put_status("OSS/Free:" SOUND_VERSION_STRING +#if 0 + " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" + SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" +#endif + "\n"); #endif #ifdef MODULE - put_status ("Load type: Driver loaded as a module.\n"); + put_status("Load type: Driver loaded as a module.\n"); #else - put_status ("Load type: Driver compiled into kernel\n"); -#endif - put_status ("Kernel: "); - put_status (system_utsname.sysname); - put_status (" "); - put_status (system_utsname.nodename); - put_status (" "); - put_status (system_utsname.release); - put_status (" "); - put_status (system_utsname.version); - put_status (" "); - put_status (system_utsname.machine); - put_status ("\n"); -#ifdef MODULE - put_status ("Driver loaded as a module\n"); + put_status("Load type: Driver compiled into kernel\n"); #endif - - - if (!put_status ("Config options: ")) - return; - if (!put_status_int (SELECTED_SOUND_OPTIONS, 16)) - return; - - if (!put_status ("\n\nInstalled drivers: \n")) - return; - - for (i = 0; i < num_sound_drivers; i++) - if (sound_drivers[i].card_type != 0) - { - if (!put_status ("Type ")) - return; - if (!put_status_int (sound_drivers[i].card_type, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (sound_drivers[i].name)) - return; - - if (!put_status ("\n")) - return; - } - - - if (!put_status ("\nCard config: \n")) - return; - - for (i = 0; i < num_sound_cards; i++) - if (snd_installed_cards[i].card_type != 0) - { - int drv, tmp; - - if (!snd_installed_cards[i].enabled) - if (!put_status ("(")) - return; - - /* - * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return; - * if (!put_status (": ")) return; - */ - - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) - if (!put_status (sound_drivers[drv].name)) - return; - - if (snd_installed_cards[i].config.io_base) - { - if (!put_status (" at 0x")) - return; - if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) - return; - } - - tmp = snd_installed_cards[i].config.irq; - if (tmp != 0) - { - if (!put_status (" irq ")) - return; - if (tmp < 0) - tmp = -tmp; - if (!put_status_int (tmp, 10)) - return; - } - - if (snd_installed_cards[i].config.dma != -1) + put_status("Kernel: "); + put_status(system_utsname.sysname); + put_status(" "); + put_status(system_utsname.nodename); + put_status(" "); + put_status(system_utsname.release); + put_status(" "); + put_status(system_utsname.version); + put_status(" "); + put_status(system_utsname.machine); + put_status("\n"); + + + if (!put_status("Config options: ")) + return; + if (!put_status_int(SELECTED_SOUND_OPTIONS, 16)) + return; + + if (!put_status("\n\nInstalled drivers: \n")) + return; + + for (i = 0; i < num_sound_drivers; i++) + if (sound_drivers[i].card_type != 0) + { + if (!put_status("Type ")) + return; + if (!put_status_int(sound_drivers[i].card_type, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(sound_drivers[i].name)) + return; + + if (!put_status("\n")) + return; + } + if (!put_status("\nCard config: \n")) + return; + + for (i = 0; i < num_sound_cards; i++) + if (snd_installed_cards[i].card_type != 0) + { + int drv, tmp; + + if (!snd_installed_cards[i].enabled) + if (!put_status("(")) + return; + + /* + * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return; + * if (!put_status (": ")) return; + */ + + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1) + if (!put_status(sound_drivers[drv].name)) + return; + + if (snd_installed_cards[i].config.io_base) + { + if (!put_status(" at 0x")) + return; + if (!put_status_int(snd_installed_cards[i].config.io_base, 16)) + return; + } + tmp = snd_installed_cards[i].config.irq; + if (tmp != 0) + { + if (!put_status(" irq ")) + return; + if (tmp < 0) + tmp = -tmp; + if (!put_status_int(tmp, 10)) + return; + } + if (snd_installed_cards[i].config.dma != -1) + { + if (!put_status(" drq ")) + return; + if (!put_status_int(snd_installed_cards[i].config.dma, 10)) + return; + if (snd_installed_cards[i].config.dma2 != -1) + { + if (!put_status(",")) + return; + if (!put_status_int(snd_installed_cards[i].config.dma2, 10)) + return; + } + } + if (!snd_installed_cards[i].enabled) + if (!put_status(")")) + return; + + if (!put_status("\n")) + return; + } + if (!sound_started) { - if (!put_status (" drq ")) - return; - if (!put_status_int (snd_installed_cards[i].config.dma, 10)) - return; - if (snd_installed_cards[i].config.dma2 != -1) - { - if (!put_status (",")) + put_status("\n\n***** Sound driver not started *****\n\n"); return; - if (!put_status_int (snd_installed_cards[i].config.dma2, 10)) - return; - } } - - if (!snd_installed_cards[i].enabled) - if (!put_status (")")) - return; - - if (!put_status ("\n")) - return; - } - - if (!sound_started) - { - put_status ("\n\n***** Sound driver not started *****\n\n"); - return; - } - #ifndef CONFIG_AUDIO - if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n")) - return; + if (!put_status("\nAudio devices: NOT ENABLED IN CONFIG\n")) + return; #else - if (!put_status ("\nAudio devices:\n")) - return; - - for (i = 0; i < num_audiodevs; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (audio_devs[i]->name)) - return; - - if (audio_devs[i]->flags & DMA_DUPLEX) - if (!put_status (" (DUPLEX)")) - return; - - if (!put_status ("\n")) - return; - } + if (!put_status("\nAudio devices:\n")) + return; + + for (i = 0; i < num_audiodevs; i++) + { + if (audio_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(audio_devs[i]->name)) + return; + + if (audio_devs[i]->flags & DMA_DUPLEX) + if (!put_status(" (DUPLEX)")) + return; + + if (!put_status("\n")) + return; + } #endif #ifndef CONFIG_SEQUENCER - if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n")) - return; + if (!put_status("\nSynth devices: NOT ENABLED IN CONFIG\n")) + return; #else - if (!put_status ("\nSynth devices:\n")) - return; - - for (i = 0; i < num_synths; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (synth_devs[i]->info->name)) - return; - if (!put_status ("\n")) - return; - } + if (!put_status("\nSynth devices:\n")) + return; + + for (i = 0; i < num_synths; i++) + { + if (synth_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(synth_devs[i]->info->name)) + return; + if (!put_status("\n")) + return; + } #endif #ifndef CONFIG_MIDI - if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n")) - return; + if (!put_status("\nMidi devices: NOT ENABLED IN CONFIG\n")) + return; #else - if (!put_status ("\nMidi devices:\n")) - return; - - for (i = 0; i < num_midis; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (midi_devs[i]->info.name)) - return; - if (!put_status ("\n")) - return; - } + if (!put_status("\nMidi devices:\n")) + return; + + for (i = 0; i < num_midis; i++) + { + if (midi_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(midi_devs[i]->info.name)) + return; + if (!put_status("\n")) + return; + } #endif #ifdef CONFIG_SEQUENCER - if (!put_status ("\nTimers:\n")) - return; - - for (i = 0; i < num_sound_timers; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (sound_timer_devs[i]->info.name)) - return; - if (!put_status ("\n")) - return; - } + if (!put_status("\nTimers:\n")) + return; + + for (i = 0; i < num_sound_timers; i++) + { + if (sound_timer_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(sound_timer_devs[i]->info.name)) + return; + if (!put_status("\n")) + return; + } #endif - if (!put_status ("\nMixers:\n")) - return; - - for (i = 0; i < num_mixers; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (mixer_devs[i]->name)) - return; - if (!put_status ("\n")) - return; - } + if (!put_status("\nMixers:\n")) + return; + + for (i = 0; i < num_mixers; i++) + { + if (mixer_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(mixer_devs[i]->name)) + return; + if (!put_status("\n")) + return; + } } static int -read_status (char *buf, int count) +read_status(char *buf, int count) { - /* - * Return at most 'count' bytes from the status_buf. - */ - int l, c; + /* + * Return at most 'count' bytes from the status_buf. + */ + int l, c; - l = count; - c = status_len - status_ptr; + l = count; + c = status_len - status_ptr; - if (l > c) - l = c; - if (l <= 0) - return 0; + if (l > c) + l = c; + if (l <= 0) + return 0; - { - char *fixit = &status_buf[status_ptr]; + { + char *fixit = &status_buf[status_ptr]; - copy_to_user (&(buf)[0], fixit, l); - }; - status_ptr += l; + copy_to_user(&(buf)[0], fixit, l); + }; + status_ptr += l; - return l; + return l; } int -sound_read_sw (int dev, struct fileinfo *file, char *buf, int count) +sound_read_sw(int dev, struct fileinfo *file, char *buf, int count) { - DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count)); + DEB(printk("sound_read_sw(dev=%d, count=%d)\n", dev, count)); - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - return read_status (buf, count); - break; + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return read_status(buf, count); + break; #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return audio_read (dev, file, buf, count); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_read(dev, file, buf, count); + break; #endif #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_read (dev, file, buf, count); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_read(dev, file, buf, count); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_read (dev, file, buf, count); + case SND_DEV_MIDIN: + return MIDIbuf_read(dev, file, buf, count); #endif - default:; - } + default:; + } - return -EINVAL; + return -EINVAL; } int -sound_write_sw (int dev, struct fileinfo *file, const char *buf, int count) +sound_write_sw(int dev, struct fileinfo *file, const char *buf, int count) { - DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count)); + DEB(printk("sound_write_sw(dev=%d, count=%d)\n", dev, count)); - switch (dev & 0x0f) - { + switch (dev & 0x0f) + { #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_write (dev, file, buf, count); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_write(dev, file, buf, count); + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return audio_write (dev, file, buf, count); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_write(dev, file, buf, count); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_write (dev, file, buf, count); + case SND_DEV_MIDIN: + return MIDIbuf_write(dev, file, buf, count); #endif - } + } - return -EINVAL; + return -EINVAL; } int -sound_open_sw (int dev, struct fileinfo *file) +sound_open_sw(int dev, struct fileinfo *file) { - int retval; - - DEB (printk ("sound_open_sw(dev=%d)\n", dev)); - - if ((dev >= SND_NDEVS) || (dev < 0)) - { - printk ("Invalid minor device %d\n", dev); - return -ENXIO; - } - - - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - if (status_busy) - return -EBUSY; - status_busy = 1; - if ((status_buf = (char *) vmalloc (4000)) == NULL) - return -EIO; - status_len = status_ptr = 0; - init_status (); - break; - - case SND_DEV_CTL: - if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) - return -ENXIO; - return 0; - break; + int retval; + + DEB(printk("sound_open_sw(dev=%d)\n", dev)); + + if ((dev >= SND_NDEVS) || (dev < 0)) + { + printk("Invalid minor device %d\n", dev); + return -ENXIO; + } + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_busy) + return -EBUSY; + status_busy = 1; + if ((status_buf = (char *) vmalloc(4000)) == NULL) + { + status_busy = 0; + return -EIO; + } + status_len = status_ptr = 0; + init_status(); + break; + + case SND_DEV_CTL: + if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) + return -ENXIO; + return 0; + break; #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - if ((retval = sequencer_open (dev, file)) < 0) - return retval; - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + if ((retval = sequencer_open(dev, file)) < 0) + return retval; + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - if ((retval = MIDIbuf_open (dev, file)) < 0) - return retval; - break; + case SND_DEV_MIDIN: + if ((retval = MIDIbuf_open(dev, file)) < 0) + return retval; + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - if ((retval = audio_open (dev, file)) < 0) - return retval; - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + if ((retval = audio_open(dev, file)) < 0) + return retval; + break; #endif - default: - printk ("Invalid minor device %d\n", dev); - return -ENXIO; - } + default: + printk("Invalid minor device %d\n", dev); + return -ENXIO; + } - in_use++; + in_use++; - return 0; + return 0; } void -sound_release_sw (int dev, struct fileinfo *file) +sound_release_sw(int dev, struct fileinfo *file) { - DEB (printk ("sound_release_sw(dev=%d)\n", dev)); + DEB(printk("sound_release_sw(dev=%d)\n", dev)); - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - if (status_buf) - vfree (status_buf); - status_buf = NULL; - status_busy = 0; - break; + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_buf) + vfree(status_buf); + status_buf = NULL; + status_busy = 0; + break; - case SND_DEV_CTL: - break; + case SND_DEV_CTL: + break; #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - sequencer_release (dev, file); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + sequencer_release(dev, file); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - MIDIbuf_release (dev, file); - break; + case SND_DEV_MIDIN: + MIDIbuf_release(dev, file); + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - audio_release (dev, file); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + audio_release(dev, file); + break; #endif - default: - printk ("Sound error: Releasing unknown device 0x%02x\n", dev); - } - in_use--; + default: + printk("Sound error: Releasing unknown device 0x%02x\n", dev); + } + in_use--; } static int -get_mixer_info (int dev, caddr_t arg) +get_mixer_info(int dev, caddr_t arg) { - mixer_info info; + mixer_info info; + int i; - if (dev < 0 || dev >= num_mixers) - return -ENXIO; + if (dev < 0 || dev >= num_mixers) + return -ENXIO; - strcpy (info.id, mixer_devs[dev]->id); - strcpy (info.name, mixer_devs[dev]->name); - info.modify_counter = mixer_devs[dev]->modify_counter; + strcpy(info.id, mixer_devs[dev]->id); + for (i = 0; i < 32 && mixer_devs[dev]->name; i++) + info.name[i] = mixer_devs[dev]->name[i]; + info.name[i] = 0; + info.modify_counter = mixer_devs[dev]->modify_counter; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; } static int -get_old_mixer_info (int dev, caddr_t arg) +get_old_mixer_info(int dev, caddr_t arg) { - _old_mixer_info info; + _old_mixer_info info; + int i; - if (dev < 0 || dev >= num_mixers) - return -ENXIO; + if (dev < 0 || dev >= num_mixers) + return -ENXIO; - strcpy (info.id, mixer_devs[dev]->id); - strcpy (info.name, mixer_devs[dev]->name); + strcpy(info.id, mixer_devs[dev]->id); + for (i = 0; i < 32 && mixer_devs[dev]->name; i++) + info.name[i] = mixer_devs[dev]->name[i]; + info.name[i] = 0; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; } static int -sound_mixer_ioctl (int mixdev, - unsigned int cmd, caddr_t arg) +sound_mixer_ioctl(int mixdev, + unsigned int cmd, caddr_t arg) { - if (cmd == SOUND_MIXER_INFO) - return get_mixer_info (mixdev, arg); - if (cmd == SOUND_OLD_MIXER_INFO) - return get_old_mixer_info (mixdev, arg); + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info(mixdev, arg); + if (cmd == SOUND_OLD_MIXER_INFO) + return get_old_mixer_info(mixdev, arg); - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - mixer_devs[mixdev]->modify_counter++; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + mixer_devs[mixdev]->modify_counter++; - return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); + return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); } int -sound_ioctl_sw (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +sound_ioctl_sw(int dev, struct fileinfo *file, + unsigned int cmd, caddr_t arg) { - DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); + DEB(printk("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - if (cmd == OSS_GETVERSION) - return (*(int *) arg = SOUND_VERSION); + if (cmd == OSS_GETVERSION) + return (*(int *) arg = SOUND_VERSION); - if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ - if ((dev & 0x0f) != SND_DEV_CTL) - { - int dtype = dev & 0x0f; - int mixdev; + if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ + if ((dev & 0x0f) != SND_DEV_CTL) + { + int dtype = dev & 0x0f; + int mixdev; - switch (dtype) - { + switch (dtype) + { #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - mixdev = audio_devs[dev >> 4]->mixer_dev; - if (mixdev < 0 || mixdev >= num_mixers) - return -ENXIO; - return sound_mixer_ioctl (mixdev, cmd, arg); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + mixdev = audio_devs[dev >> 4]->mixer_dev; + if (mixdev < 0 || mixdev >= num_mixers) + return -ENXIO; + return sound_mixer_ioctl(mixdev, cmd, arg); + break; #endif - default: - return sound_mixer_ioctl (dev, cmd, arg); - } - } - - switch (dev & 0x0f) - { + default: + return sound_mixer_ioctl(dev, cmd, arg); + } + } + switch (dev & 0x0f) + { - case SND_DEV_CTL: - if (cmd == SOUND_MIXER_GETLEVELS) - return get_mixer_levels (arg); - if (cmd == SOUND_MIXER_SETLEVELS) - return set_mixer_levels (arg); + case SND_DEV_CTL: + if (cmd == SOUND_MIXER_GETLEVELS) + return get_mixer_levels(arg); + if (cmd == SOUND_MIXER_SETLEVELS) + return set_mixer_levels(arg); - if (!num_mixers) - return -ENXIO; + if (!num_mixers) + return -ENXIO; - dev = dev >> 4; + dev = dev >> 4; - if (dev >= num_mixers) - return -ENXIO; + if (dev >= num_mixers) + return -ENXIO; - return sound_mixer_ioctl (dev, cmd, arg); - break; + return sound_mixer_ioctl(dev, cmd, arg); + break; #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_ioctl (dev, file, cmd, arg); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_ioctl(dev, file, cmd, arg); + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return audio_ioctl (dev, file, cmd, arg); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_ioctl(dev, file, cmd, arg); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_ioctl (dev, file, cmd, arg); - break; + case SND_DEV_MIDIN: + return MIDIbuf_ioctl(dev, file, cmd, arg); + break; #endif - } + } - return -EINVAL; + return -EINVAL; } diff --git a/drivers/sound/sound_syms.c b/drivers/sound/sound_syms.c new file mode 100644 index 000000000..2b80bd165 --- /dev/null +++ b/drivers/sound/sound_syms.c @@ -0,0 +1,78 @@ +/* + * The sound core exports the following symbols to the rest of + * modulespace. + * + * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL + */ + +#include <linux/config.h> +#include <linux/module.h> +#include "sound_config.h" +#define _MIDI_SYNTH_C_ +#include "midi_synth.h" +#include <linux/notifier.h> +#include "sound_firmware.h" + +extern struct notifier_block *sound_locker; + +EXPORT_SYMBOL(mixer_devs); +EXPORT_SYMBOL(audio_devs); +EXPORT_SYMBOL(num_audiodevs); + +EXPORT_SYMBOL(note_to_freq); +EXPORT_SYMBOL(compute_finetune); +EXPORT_SYMBOL(seq_copy_to_input); +EXPORT_SYMBOL(sequencer_timer); + +EXPORT_SYMBOL(sound_install_audiodrv); +EXPORT_SYMBOL(sound_install_mixer); +EXPORT_SYMBOL(sound_alloc_dma); +EXPORT_SYMBOL(sound_free_dma); +EXPORT_SYMBOL(snd_set_irq_handler); +EXPORT_SYMBOL(snd_release_irq); +EXPORT_SYMBOL(sound_alloc_audiodev); +EXPORT_SYMBOL(sound_alloc_mididev); +EXPORT_SYMBOL(sound_alloc_mixerdev); +EXPORT_SYMBOL(sound_alloc_timerdev); +EXPORT_SYMBOL(sound_alloc_synthdev); +EXPORT_SYMBOL(sound_unload_audiodev); +EXPORT_SYMBOL(sound_unload_mididev); +EXPORT_SYMBOL(sound_unload_mixerdev); +EXPORT_SYMBOL(sound_unload_timerdev); +EXPORT_SYMBOL(sound_unload_synthdev); + +EXPORT_SYMBOL(DMAbuf_start_dma); +EXPORT_SYMBOL(DMAbuf_inputintr); +EXPORT_SYMBOL(DMAbuf_outputintr); +EXPORT_SYMBOL(dma_ioctl); + +EXPORT_SYMBOL(conf_printf2); + +EXPORT_SYMBOL(sound_timer_init); +EXPORT_SYMBOL(sound_timer_interrupt); +EXPORT_SYMBOL(sound_timer_syncinterval); + +/* Locking */ +EXPORT_SYMBOL(sound_locker); + +/* MIDI symbols */ +EXPORT_SYMBOL(midi_devs); +EXPORT_SYMBOL(num_midis); +EXPORT_SYMBOL(synth_devs); +EXPORT_SYMBOL(num_synths); + +EXPORT_SYMBOL(do_midi_msg); +EXPORT_SYMBOL(midi_synth_open); +EXPORT_SYMBOL(midi_synth_close); +EXPORT_SYMBOL(midi_synth_ioctl); +EXPORT_SYMBOL(midi_synth_kill_note); +EXPORT_SYMBOL(midi_synth_start_note); +EXPORT_SYMBOL(midi_synth_set_instr); +EXPORT_SYMBOL(midi_synth_reset); +EXPORT_SYMBOL(midi_synth_hw_control); +EXPORT_SYMBOL(midi_synth_aftertouch); +EXPORT_SYMBOL(midi_synth_controller); +EXPORT_SYMBOL(midi_synth_panning); +EXPORT_SYMBOL(midi_synth_setup_voice); +EXPORT_SYMBOL(midi_synth_send_sysex); +EXPORT_SYMBOL(midi_synth_bender); diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c index e72fef192..5fafccc42 100644 --- a/drivers/sound/sound_timer.c +++ b/drivers/sound/sound_timer.c @@ -1,3 +1,5 @@ + + /* * sound/sound_timer.c */ @@ -13,7 +15,7 @@ #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) +#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) static volatile int initialized = 0, opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; @@ -27,320 +29,315 @@ static volatile unsigned long usecs_per_tmr; /* Length of the current interval * static struct sound_lowlev_timer *tmr = NULL; static unsigned long -tmr2ticks (int tmr_value) +tmr2ticks(int tmr_value) { - /* - * Convert timer ticks to MIDI ticks - */ + /* + * Convert timer ticks to MIDI ticks + */ - unsigned long tmp; - unsigned long scale; + unsigned long tmp; + unsigned long scale; - tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ + tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ - scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ + scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ - return (tmp + (scale / 2)) / scale; + return (tmp + (scale / 2)) / scale; } static void -reprogram_timer (void) +reprogram_timer(void) { - unsigned long usecs_per_tick; + unsigned long usecs_per_tick; - usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); + usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); - /* - * Don't kill the system by setting too high timer rate - */ - if (usecs_per_tick < 2000) - usecs_per_tick = 2000; + /* + * Don't kill the system by setting too high timer rate + */ + if (usecs_per_tick < 2000) + usecs_per_tick = 2000; - usecs_per_tmr = tmr->tmr_start (tmr->dev, usecs_per_tick); + usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick); } void -sound_timer_syncinterval (unsigned int new_usecs) +sound_timer_syncinterval(unsigned int new_usecs) { /* * This routine is called by the hardware level if * the clock frequency has changed for some reason. */ - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; - usecs_per_tmr = new_usecs; + usecs_per_tmr = new_usecs; } static void -tmr_reset (void) +tmr_reset(void) { - unsigned long flags; - - save_flags (flags); - cli (); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - restore_flags (flags); + unsigned long flags; + + save_flags(flags); + cli(); + tmr_offs = 0; + ticks_offs = 0; + tmr_ctr = 0; + next_event_time = (unsigned long) -1; + prev_event_time = 0; + curr_ticks = 0; + restore_flags(flags); } static int -timer_open (int dev, int mode) +timer_open(int dev, int mode) { - if (opened) - return -EBUSY; + if (opened) + return -EBUSY; - tmr_reset (); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - reprogram_timer (); + tmr_reset(); + curr_tempo = 60; + curr_timebase = 100; + opened = 1; + reprogram_timer(); - return 0; + return 0; } static void -timer_close (int dev) +timer_close(int dev) { - opened = tmr_running = 0; - tmr->tmr_disable (tmr->dev); + opened = tmr_running = 0; + tmr->tmr_disable(tmr->dev); } static int -timer_event (int dev, unsigned char *event) +timer_event(int dev, unsigned char *event) { - unsigned char cmd = event[1]; - unsigned long parm = *(int *) &event[4]; - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - tmr_reset (); - tmr_running = 1; - reprogram_timer (); - break; - - case TMR_STOP: - tmr_running = 0; - break; - - case TMR_CONTINUE: - tmr_running = 1; - reprogram_timer (); - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = parm; - reprogram_timer (); - } - break; - - case TMR_ECHO: - seq_copy_to_input (event, 8); - break; - - default:; - } - - return TIMER_NOT_ARMED; + unsigned char cmd = event[1]; + unsigned long parm = *(int *) &event[4]; + + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + tmr_reset(); + tmr_running = 1; + reprogram_timer(); + break; + + case TMR_STOP: + tmr_running = 0; + break; + + case TMR_CONTINUE: + tmr_running = 1; + reprogram_timer(); + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = parm; + reprogram_timer(); + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; + + default:; + } + + return TIMER_NOT_ARMED; } static unsigned long -timer_get_time (int dev) +timer_get_time(int dev) { - if (!opened) - return 0; + if (!opened) + return 0; - return curr_ticks; + return curr_ticks; } static int -timer_ioctl (int dev, - unsigned int cmd, caddr_t arg) +timer_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - int val; - - switch (cmd) - { - case SNDCTL_TMR_SOURCE: - return (*(int *) arg = TMR_INTERNAL); - break; - - case SNDCTL_TMR_START: - tmr_reset (); - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - val = *(int *) arg; - - if (val) - { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - - return (*(int *) arg = curr_timebase); - break; - - case SNDCTL_TMR_TEMPO: - val = *(int *) arg; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = val; - reprogram_timer (); - } - - return (*(int *) arg = curr_tempo); - break; - - case SNDCTL_SEQ_CTRLRATE: - val = *(int *) arg; - - if (val != 0) /* Can't change */ - return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - - default:; - } + int val; + + switch (cmd) + { + case SNDCTL_TMR_SOURCE: + return (*(int *) arg = TMR_INTERNAL); + break; + + case SNDCTL_TMR_START: + tmr_reset(); + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + val = *(int *) arg; + + if (val) + { + if (val < 1) + val = 1; + if (val > 1000) + val = 1000; + curr_timebase = val; + } + return (*(int *) arg = curr_timebase); + break; + + case SNDCTL_TMR_TEMPO: + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = val; + reprogram_timer(); + } + return (*(int *) arg = curr_tempo); + break; + + case SNDCTL_SEQ_CTRLRATE: + val = *(int *) arg; + + if (val != 0) /* Can't change */ + return -EINVAL; + + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + break; + + case SNDCTL_TMR_METRONOME: + /* NOP */ + break; + + default:; + } - return -EINVAL; + return -EINVAL; } static void -timer_arm (int dev, long time) +timer_arm(int dev, long time) { - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; - next_event_time = prev_event_time = time; + next_event_time = prev_event_time = time; - return; + return; } static struct sound_timer_operations sound_timer = { - {"Sound Timer", 0}, - 1, /* Priority */ - 0, /* Local device link */ - timer_open, - timer_close, - timer_event, - timer_get_time, - timer_ioctl, - timer_arm + {"Sound Timer", 0}, + 1, /* Priority */ + 0, /* Local device link */ + timer_open, + timer_close, + timer_event, + timer_get_time, + timer_ioctl, + timer_arm }; void -sound_timer_interrupt (void) +sound_timer_interrupt(void) { - if (!opened) - return; + if (!opened) + return; - tmr->tmr_restart (tmr->dev); + tmr->tmr_restart(tmr->dev); - if (!tmr_running) - return; + if (!tmr_running) + return; - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks (tmr_ctr); + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer (0); - } + if (curr_ticks >= next_event_time) + { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } } -void -sound_timer_init (struct sound_lowlev_timer *t, char *name) +void +sound_timer_init(struct sound_lowlev_timer *t, char *name) { - int n; - - if (initialized) - { - if (t->priority <= tmr->priority) - return; /* There is already a similar or better timer */ - tmr = t; - return; - } - initialized = 1; - - tmr = t; - - if (num_sound_timers >= MAX_TIMER_DEV) - n = 0; /* Overwrite the system timer */ - else - n = num_sound_timers++; - - strcpy (sound_timer.info.name, name); - - sound_timer_devs[n] = &sound_timer; + int n; + + if (initialized) + { + if (t->priority <= tmr->priority) + return; /* There is already a similar or better timer */ + tmr = t; + return; + } + initialized = 1; + + tmr = t; + + n = sound_alloc_timerdev(); + if (n == -1) + n = 0; /* Overwrite the system timer */ + strcpy(sound_timer.info.name, name); + sound_timer_devs[n] = &sound_timer; } #endif diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 450197a34..f6d17e4e8 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -25,11 +25,19 @@ #include <linux/wait.h> #include <linux/malloc.h> #include <linux/ioport.h> -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ #include <linux/delay.h> -#include <linux/major.h> +#define SOUND_CORE + +#include "soundmodule.h" +#include <linux/major.h> +#ifdef MODULE +#define modular 1 +#else +#define modular 0 +#endif static int chrdev_registered = 0; static int sound_major = SOUND_MAJOR; @@ -56,296 +64,270 @@ static char dma_alloc_map[8] = -static long -sound_read (struct inode *inode, struct file *file, char *buf, unsigned long count) +static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - int dev; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - return sound_read_sw (dev, &files[dev], buf, count); + return sound_read_sw(dev, &files[dev], buf, count); } -static long -sound_write (struct inode *inode, struct file *file, const char *buf, unsigned long count) +static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int dev; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - return sound_write_sw (dev, &files[dev], buf, count); + return sound_write_sw(dev, &files[dev], buf, count); } -static long long sound_lseek (struct file *file, long long offset, int orig) +static long long sound_lseek(struct file *file, long long offset, int orig) { - return -EPERM; + return -ESPIPE; } -static int -sound_open (struct inode *inode, struct file *file) +static int sound_open(struct inode *inode, struct file *file) { - int dev, retval; - struct fileinfo tmp_file; - - if (is_unloading) - { - printk ("Sound: Driver partially removed. Can't open device\n"); - return -EBUSY; - } - - dev = MINOR (inode->i_rdev); + int dev, retval; + struct fileinfo tmp_file; - if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) - { - printk ("SoundCard Error: The soundcard system has not been configured\n"); - return -ENXIO; - } + if (is_unloading) + { +/* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/ + return -EBUSY; + } + dev = MINOR(inode->i_rdev); - tmp_file.mode = 0; - tmp_file.flags = file->f_flags; + if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) + { +/* printk("SoundCard Error: The soundcard system has not been configured\n");*/ + return -ENXIO; + } + tmp_file.mode = 0; + tmp_file.flags = file->f_flags; - if ((tmp_file.flags & O_ACCMODE) == O_RDWR) - tmp_file.mode = OPEN_READWRITE; - if ((tmp_file.flags & O_ACCMODE) == O_RDONLY) - tmp_file.mode = OPEN_READ; - if ((tmp_file.flags & O_ACCMODE) == O_WRONLY) - tmp_file.mode = OPEN_WRITE; + if ((tmp_file.flags & O_ACCMODE) == O_RDWR) + tmp_file.mode = OPEN_READWRITE; + if ((tmp_file.flags & O_ACCMODE) == O_RDONLY) + tmp_file.mode = OPEN_READ; + if ((tmp_file.flags & O_ACCMODE) == O_WRONLY) + tmp_file.mode = OPEN_WRITE; - if ((retval = sound_open_sw (dev, &tmp_file)) < 0) - return retval; + if ((retval = sound_open_sw(dev, &tmp_file)) < 0) + return retval; #ifdef MODULE - MOD_INC_USE_COUNT; + SOUND_INC_USE_COUNT; #endif - memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file)); - return retval; + memcpy((char *) &files[dev], (char *) &tmp_file, sizeof(tmp_file)); + return retval; } -static int -sound_release (struct inode *inode, struct file *file) +static int sound_release(struct inode *inode, struct file *file) { - int dev; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - sound_release_sw (dev, &files[dev]); + sound_release_sw(dev, &files[dev]); #ifdef MODULE - MOD_DEC_USE_COUNT; + SOUND_DEC_USE_COUNT; #endif - return 0; + return 0; } -static int -sound_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int sound_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - int dev, err; - int len = 0; - int alloced = 0; - char *ptr = (char *) arg; - - dev = MINOR (inode->i_rdev); - - files[dev].flags = file->f_flags; - - if (_SIOC_DIR (cmd) != _SIOC_NONE && _SIOC_DIR (cmd) != 0) - { - /* - * Have to validate the address given by the process. - */ + int dev, err; + int len = 0; + int alloced = 0; + char *ptr = (char *) arg; - len = _SIOC_SIZE (cmd); - if (len < 1 || len > 65536 || arg == 0) - return -EFAULT; + dev = MINOR(inode->i_rdev); - ptr = vmalloc (len); - alloced = 1; - if (ptr == NULL) - return -EFAULT; + files[dev].flags = file->f_flags; - if (_SIOC_DIR (cmd) & _SIOC_WRITE) + if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { - if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0) - return err; - copy_from_user (ptr, (char *) arg, len); + /* + * Have to validate the address given by the process. + */ + + len = _SIOC_SIZE(cmd); + if (len < 1 || len > 65536 || arg == 0) + return -EFAULT; + + ptr = vmalloc(len); + alloced = 1; + if (ptr == NULL) + return -EFAULT; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { + if ((err = verify_area(VERIFY_READ, (void *) arg, len)) < 0) + return err; + copy_from_user(ptr, (char *) arg, len); + } + if (_SIOC_DIR(cmd) & _SIOC_READ) + { + if ((err = verify_area(VERIFY_WRITE, (void *) arg, len)) < 0) + return err; + } } + err = sound_ioctl_sw(dev, &files[dev], cmd, (caddr_t) ptr); - if (_SIOC_DIR (cmd) & _SIOC_READ) - { - if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0) - return err; - } - - } - - err = sound_ioctl_sw (dev, &files[dev], cmd, (caddr_t) ptr); + if (_SIOC_DIR(cmd) & _SIOC_READ) + copy_to_user((char *) arg, ptr, len); - if (_SIOC_DIR (cmd) & _SIOC_READ) - { - copy_to_user ((char *) arg, ptr, len); - } + if (ptr != NULL && alloced) + vfree(ptr); - if (ptr != NULL && alloced) - vfree (ptr); - - return ((err < 0) ? err : 0); + return ((err < 0) ? err : 0); } -static int -sound_select (struct inode *inode, struct file *file, int sel_type, poll_table * wait) +static int sound_select(struct inode *inode, struct file *file, int sel_type, poll_table * wait) { - int dev; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); + DEB(printk("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); - switch (dev & 0x0f) - { -#ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_select (dev, &files[dev], sel_type, wait); - break; + switch (dev & 0x0f) + { +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_select(dev, &files[dev], sel_type, wait); + break; #endif -#ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_select (dev, &files[dev], sel_type, wait); - break; +#if defined(CONFIG_MIDI) + case SND_DEV_MIDIN: + return MIDIbuf_select(dev, &files[dev], sel_type, wait); + break; #endif -#ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return DMAbuf_select (dev >> 4, &files[dev], sel_type, wait); - break; +#if defined(CONFIG_AUDIO) || defined(MODULE) + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait); + break; #endif - default: - return 0; - } + default: + return 0; + } - return 0; + return 0; } -static unsigned int -sound_poll (struct file *file, poll_table * wait) +static unsigned int sound_poll(struct file *file, poll_table * wait) { - struct inode *inode; - int ret = 0; + struct inode *inode; + int ret = 0; - inode = file->f_dentry->d_inode; + inode = file->f_dentry->d_inode; - if (sound_select (inode, file, SEL_IN, wait)) - ret |= POLLIN; - if (sound_select (inode, file, SEL_OUT, wait)) - ret |= POLLOUT; - return ret; + if (sound_select(inode, file, SEL_IN, wait)) + ret |= POLLIN; + if (sound_select(inode, file, SEL_OUT, wait)) + ret |= POLLOUT; + return ret; } -static int -sound_mmap (struct file *file, struct vm_area_struct *vma) +static int sound_mmap(struct file *file, struct vm_area_struct *vma) { - int dev, dev_class; - unsigned long size; - struct dma_buffparms *dmap = NULL; - - dev = MINOR (file->f_dentry->d_inode->i_rdev); - - files[dev].flags = file->f_flags; - - dev_class = dev & 0x0f; - dev >>= 4; - - if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) - { - printk ("Sound: mmap() not supported for other than audio devices\n"); - return -EINVAL; - } - - if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ - { - dmap = audio_devs[dev]->dmap_out; - } - else if (vma->vm_flags & VM_READ) - { - dmap = audio_devs[dev]->dmap_in; - } - else - { - printk ("Sound: Undefined mmap() access\n"); - return -EINVAL; - } - - if (dmap == NULL) - { - printk ("Sound: mmap() error. dmap == NULL\n"); - return -EIO; - } - - if (dmap->raw_buf == NULL) - { - printk ("Sound: mmap() called when raw_buf == NULL\n"); - return -EIO; - } - - if (dmap->mapping_flags) - { - printk ("Sound: mmap() called twice for the same DMA buffer\n"); - return -EIO; - } - - if (vma->vm_offset != 0) - { - printk ("Sound: mmap() offset must be 0.\n"); - return -EINVAL; - } - - size = vma->vm_end - vma->vm_start; - - if (size != dmap->bytes_in_use) - { - printk ("Sound: mmap() size = %ld. Should be %d\n", - size, dmap->bytes_in_use); - } - - if (remap_page_range (vma->vm_start, virt_to_phys (dmap->raw_buf), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - vma->vm_dentry = dget(file->f_dentry); - - dmap->mapping_flags |= DMA_MAP_MAPPED; - - memset (dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); - return 0; + int dev, dev_class; + unsigned long size; + struct dma_buffparms *dmap = NULL; + + dev = MINOR(file->f_dentry->d_inode->i_rdev); + + files[dev].flags = file->f_flags; + + dev_class = dev & 0x0f; + dev >>= 4; + + if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) + { +/* printk("Sound: mmap() not supported for other than audio devices\n");*/ + return -EINVAL; + } + if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ + dmap = audio_devs[dev]->dmap_out; + else if (vma->vm_flags & VM_READ) + dmap = audio_devs[dev]->dmap_in; + else + { +/* printk("Sound: Undefined mmap() access\n");*/ + return -EINVAL; + } + + if (dmap == NULL) + { +/* printk("Sound: mmap() error. dmap == NULL\n");*/ + return -EIO; + } + if (dmap->raw_buf == NULL) + { +/* printk("Sound: mmap() called when raw_buf == NULL\n");*/ + return -EIO; + } + if (dmap->mapping_flags) + { +/* printk("Sound: mmap() called twice for the same DMA buffer\n");*/ + return -EIO; + } + if (vma->vm_offset != 0) + { +/* printk("Sound: mmap() offset must be 0.\n");*/ + return -EINVAL; + } + size = vma->vm_end - vma->vm_start; + + if (size != dmap->bytes_in_use) + { + printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); + } + if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + vma->vm_dentry = dget(file->f_dentry); + + dmap->mapping_flags |= DMA_MAP_MAPPED; + + memset(dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); + return 0; } static struct file_operations sound_fops = { - sound_lseek, - sound_read, - sound_write, - NULL, /* sound_readdir */ - sound_poll, - sound_ioctl, - sound_mmap, - sound_open, - sound_release + sound_lseek, + sound_read, + sound_write, + NULL, /* sound_readdir */ + sound_poll, + sound_ioctl, + sound_mmap, + sound_open, + sound_release }; #ifdef MODULE @@ -353,26 +335,28 @@ static void #else void #endif -soundcard_init (void) +soundcard_init(void) { #ifndef MODULE - register_chrdev (sound_major, "sound", &sound_fops); - chrdev_registered = 1; + register_chrdev(sound_major, "sound", &sound_fops); + chrdev_registered = 1; #endif - soundcard_configured = 1; + soundcard_configured = 1; - sndtable_init (); /* Initialize call tables and detect cards */ + sndtable_init(); /* Initialize call tables and detect cards */ - if (sndtable_get_cardcount () == 0) - return; /* No cards detected */ +#ifdef FIXME + if (sndtable_get_cardcount() == 0) + return; /* No cards detected */ +#endif -#ifdef CONFIG_AUDIO - if (num_audiodevs) /* Audio devices present */ - { - audio_init_devices (); - } +#if defined(CONFIG_AUDIO) + if (num_audiodevs || modular) /* Audio devices present */ + { + audio_init_devices(); + } #endif @@ -382,17 +366,19 @@ static unsigned int irqs = 0; #ifdef MODULE static void -free_all_irqs (void) +free_all_irqs(void) { - int i; - - for (i = 0; i < 31; i++) - if (irqs & (1ul << i)) - { - printk ("Sound warning: IRQ%d was left allocated - fixed.\n", i); - snd_release_irq (i); - } - irqs = 0; + int i; + + for (i = 0; i < 31; i++) + { + if (irqs & (1ul << i)) + { + printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i); + snd_release_irq(i); + } + } + irqs = 0; } char kernel_version[] = UTS_RELEASE; @@ -404,277 +390,249 @@ static int debugmem = 0; /* switched off by default */ static int sound[20] = {0}; -int -init_module (void) +int init_module(void) { - int err; - int ints[21]; - int i; - - if (0 < 0) - { - printk ("Sound: Incompatible kernel (wrapper) version\n"); - return -EINVAL; - } - - /* - * "sound=" command line handling by Harald Milz. - */ - i = 0; - while (i < 20 && sound[i]) - ints[i + 1] = sound[i++]; - ints[0] = i; - - if (i) - sound_setup ("sound=", ints); - - err = register_chrdev (sound_major, "sound", &sound_fops); - if (err) - { - printk ("sound: driver already loaded/included in kernel\n"); - return err; - } - - chrdev_registered = 1; - soundcard_init (); - - if (sound_nblocks >= 1024) - printk ("Sound warning: Deallocation table was too small.\n"); - - return 0; + int err; + int ints[21]; + int i; + + /* + * "sound=" command line handling by Harald Milz. + */ + i = 0; + while (i < 20 && sound[i]) + ints[i + 1] = sound[i++]; + ints[0] = i; + + if (i) + sound_setup("sound=", ints); + + err = register_chrdev(sound_major, "sound", &sound_fops); + if (err) + { + printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); + return err; + } + chrdev_registered = 1; + soundcard_init(); + + if (sound_nblocks >= 1024) + printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); + + return 0; } #ifdef MODULE -void -cleanup_module (void) +void cleanup_module(void) { - int i; - - if (MOD_IN_USE) - { - return; - } + int i; - if (chrdev_registered) - unregister_chrdev (sound_major, "sound"); + if (MOD_IN_USE) + { + return; + } + if (chrdev_registered) + unregister_chrdev(sound_major, "sound"); -#ifdef CONFIG_SEQUENCER - sound_stop_timer (); +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + sound_stop_timer(); #endif #ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_unload_lowlevel_drivers (void); + { + extern void sound_unload_lowlevel_drivers(void); - sound_unload_lowlevel_drivers (); - } + sound_unload_lowlevel_drivers(); + } #endif - sound_unload_drivers (); + sound_unload_drivers(); - free_all_irqs (); /* If something was left allocated by accident */ + free_all_irqs(); /* If something was left allocated by accident */ - for (i = 0; i < 8; i++) - if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) - { - printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i); - sound_free_dma (i); - } - - - for (i = 0; i < sound_nblocks; i++) - { - vfree (sound_mem_blocks[i]); - } + for (i = 0; i < 8; i++) + { + if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) + { + printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i); + sound_free_dma(i); + } + } + for (i = 0; i < sound_nblocks; i++) + { + vfree(sound_mem_blocks[i]); + } } #endif -void -tenmicrosec (int *osp) +void tenmicrosec(int *osp) { - udelay (10); + udelay(10); } -int -snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) +int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) { - int retcode; - unsigned long flags; - - save_flags (flags); - cli (); - retcode = request_irq (interrupt_level, iproc, 0, name, NULL); - if (retcode < 0) - { - printk ("Sound: IRQ%d already in use\n", interrupt_level); - } - else - irqs |= (1ul << interrupt_level); - - restore_flags (flags); - return retcode; + int retcode; + unsigned long flags; + + save_flags(flags); + cli(); + retcode = request_irq(interrupt_level, iproc, 0, name, NULL); + + if (retcode < 0) + { + printk(KERN_ERR "Sound: IRQ%d already in use\n", interrupt_level); + } + else + irqs |= (1ul << interrupt_level); + + restore_flags(flags); + return retcode; } -void -snd_release_irq (int vect) +void snd_release_irq(int vect) { - if (!(irqs & (1ul << vect))) - return; + if (!(irqs & (1ul << vect))) + return; - irqs &= ~(1ul << vect); - free_irq (vect, NULL); + irqs &= ~(1ul << vect); + free_irq(vect, NULL); } -int -sound_alloc_dma (int chn, char *deviceID) +int sound_alloc_dma(int chn, char *deviceID) { - int err; + int err; - if ((err = request_dma (chn, deviceID)) != 0) - return err; + if ((err = request_dma(chn, deviceID)) != 0) + return err; - dma_alloc_map[chn] = DMA_MAP_FREE; + dma_alloc_map[chn] = DMA_MAP_FREE; - return 0; + return 0; } -int -sound_open_dma (int chn, char *deviceID) +int sound_open_dma(int chn, char *deviceID) { - unsigned long flags; - - if (chn < 0 || chn > 7 || chn == 4) - { - printk ("sound_open_dma: Invalid DMA channel %d\n", chn); - return 1; - } - - save_flags (flags); - cli (); - - if (dma_alloc_map[chn] != DMA_MAP_FREE) - { - printk ("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); - restore_flags (flags); - return 1; - } - - dma_alloc_map[chn] = DMA_MAP_BUSY; - restore_flags (flags); - return 0; + unsigned long flags; + + if (chn < 0 || chn > 7 || chn == 4) + { + printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); + return 1; + } + save_flags(flags); + cli(); + + if (dma_alloc_map[chn] != DMA_MAP_FREE) + { + printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); + restore_flags(flags); + return 1; + } + dma_alloc_map[chn] = DMA_MAP_BUSY; + restore_flags(flags); + return 0; } -void -sound_free_dma (int chn) +void sound_free_dma(int chn) { - if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) - { - /* printk ("sound_free_dma: Bad access to DMA channel %d\n", chn); */ - return; - } - free_dma (chn); - dma_alloc_map[chn] = DMA_MAP_UNAVAIL; + if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) + { + /* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */ + return; + } + free_dma(chn); + dma_alloc_map[chn] = DMA_MAP_UNAVAIL; } -void -sound_close_dma (int chn) +void sound_close_dma(int chn) { - unsigned long flags; - - save_flags (flags); - cli (); - - if (dma_alloc_map[chn] != DMA_MAP_BUSY) - { - printk ("sound_close_dma: Bad access to DMA channel %d\n", chn); - restore_flags (flags); - return; - } - dma_alloc_map[chn] = DMA_MAP_FREE; - restore_flags (flags); + unsigned long flags; + + save_flags(flags); + cli(); + + if (dma_alloc_map[chn] != DMA_MAP_BUSY) + { + printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); + restore_flags(flags); + return; + } + dma_alloc_map[chn] = DMA_MAP_FREE; + restore_flags(flags); } -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) -static void -do_sequencer_timer (unsigned long dummy) +static void do_sequencer_timer(unsigned long dummy) { - sequencer_timer (0); + sequencer_timer(0); } static struct timer_list seq_timer = {NULL, NULL, 0, 0, do_sequencer_timer}; -void -request_sound_timer (int count) +void request_sound_timer(int count) { - extern unsigned long seq_time; + extern unsigned long seq_time; - if (count < 0) - { - - { - seq_timer.expires = (-count) + jiffies; - add_timer (&seq_timer); - }; - return; - } - - count += seq_time; - - count -= jiffies; + if (count < 0) + { + seq_timer.expires = (-count) + jiffies; + add_timer(&seq_timer); + return; + } + count += seq_time; - if (count < 1) - count = 1; + count -= jiffies; + if (count < 1) + count = 1; - { - seq_timer.expires = (count) + jiffies; - add_timer (&seq_timer); - }; + seq_timer.expires = (count) + jiffies; + add_timer(&seq_timer); } -void -sound_stop_timer (void) +void sound_stop_timer(void) { - del_timer (&seq_timer);; + del_timer(&seq_timer);; } #endif #ifdef CONFIG_AUDIO -static int dma_buffsize = DSP_BUFFSIZE; +static int dma_buffsize = DSP_BUFFSIZE; int -sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) +sound_alloc_dmap(int dev, struct dma_buffparms *dmap, int chan) { - char *start_addr, *end_addr; - int i, dma_pagesize; + char *start_addr, *end_addr; + int i, dma_pagesize; - dmap->mapping_flags &= ~DMA_MAP_MAPPED; + dmap->mapping_flags &= ~DMA_MAP_MAPPED; - if (dmap->raw_buf != NULL) - return 0; /* Already done */ + if (dmap->raw_buf != NULL) + return 0; /* Already done */ - if (dma_buffsize < 4096) - dma_buffsize = 4096; + if (dma_buffsize < 4096) + dma_buffsize = 4096; - if (chan < 4) - dma_pagesize = 64 * 1024; - else - dma_pagesize = 128 * 1024; + if (chan < 4) + dma_pagesize = 64 * 1024; + else + dma_pagesize = 128 * 1024; - dmap->raw_buf = NULL; + dmap->raw_buf = NULL; - dmap->buffsize = dma_buffsize; + dmap->buffsize = dma_buffsize; - if (dmap->buffsize > dma_pagesize) - dmap->buffsize = dma_pagesize; + if (dmap->buffsize > dma_pagesize) + dmap->buffsize = dma_pagesize; - start_addr = NULL; + start_addr = NULL; /* * Now loop until we get a free buffer. Try to get smaller buffer if @@ -682,151 +640,142 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) * reasons. */ - while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) - { - int sz, size; + while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) + { + int sz, size; - for (sz = 0, size = PAGE_SIZE; - size < dmap->buffsize; - sz++, size <<= 1); + for (sz = 0, size = PAGE_SIZE; + size < dmap->buffsize; + sz++, size <<= 1); - dmap->buffsize = PAGE_SIZE * (1 << sz); + dmap->buffsize = PAGE_SIZE * (1 << sz); - if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL) - dmap->buffsize /= 2; - } + if ((start_addr = (char *) __get_free_pages(GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL) + dmap->buffsize /= 2; + } + + if (start_addr == NULL) + { + printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n"); + return -ENOMEM; + } + else + { + /* make some checks */ + end_addr = start_addr + dmap->buffsize - 1; - if (start_addr == NULL) - { - printk ("Sound error: Couldn't allocate DMA buffer\n"); - return -ENOMEM; - } - else - { - /* make some checks */ - end_addr = start_addr + dmap->buffsize - 1; + if (debugmem) + printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); - if (debugmem) - printk ("sound: start 0x%lx, end 0x%lx\n", - (long) start_addr, (long) end_addr); + /* now check if it fits into the same dma-pagesize */ - /* now check if it fits into the same dma-pagesize */ + if (((long) start_addr & ~(dma_pagesize - 1)) + != ((long) end_addr & ~(dma_pagesize - 1)) + || end_addr >= (char *) (MAX_DMA_ADDRESS)) + { + printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); + return -EFAULT; + } + } + dmap->raw_buf = start_addr; + dmap->raw_buf_phys = virt_to_bus(start_addr); - if (((long) start_addr & ~(dma_pagesize - 1)) - != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) { - printk ( - "sound: Got invalid address 0x%lx for %db DMA-buffer\n", - (long) start_addr, - dmap->buffsize); - return -EFAULT; + set_bit(PG_reserved, &mem_map[i].flags);; } - } - dmap->raw_buf = start_addr; - dmap->raw_buf_phys = virt_to_bus (start_addr); - for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) - { - set_bit (PG_reserved, &mem_map[i].flags);; - } - - return 0; + return 0; } -void -sound_free_dmap (int dev, struct dma_buffparms *dmap, int chan) +void sound_free_dmap(int dev, struct dma_buffparms *dmap, int chan) { - int sz, size, i; - unsigned long start_addr, end_addr; + int sz, size, i; + unsigned long start_addr, end_addr; - if (dmap->raw_buf == NULL) - return; + if (dmap->raw_buf == NULL) + return; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return; /* Don't free mmapped buffer. Will use it next time */ + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return; /* Don't free mmapped buffer. Will use it next time */ - for (sz = 0, size = PAGE_SIZE; - size < dmap->buffsize; - sz++, size <<= 1); + for (sz = 0, size = PAGE_SIZE; + size < dmap->buffsize; + sz++, size <<= 1); - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + dmap->buffsize; + start_addr = (unsigned long) dmap->raw_buf; + end_addr = start_addr + dmap->buffsize; - for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) - { - clear_bit (PG_reserved, &mem_map[i].flags);; - } + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + { + clear_bit(PG_reserved, &mem_map[i].flags);; + } - free_pages ((unsigned long) dmap->raw_buf, sz); - dmap->raw_buf = NULL; + free_pages((unsigned long) dmap->raw_buf, sz); + dmap->raw_buf = NULL; } /* Intel version !!!!!!!!! */ -int -sound_start_dma (int dev, struct dma_buffparms *dmap, int chan, - unsigned long physaddr, - int count, int dma_mode, int autoinit) + +int sound_start_dma(int dev, struct dma_buffparms *dmap, int chan, + unsigned long physaddr, + int count, int dma_mode, int autoinit) { - unsigned long flags; - - /* printk("Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - if (autoinit) - dma_mode |= DMA_AUTOINIT; - save_flags (flags); - cli (); - 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); - - return 0; + unsigned long flags; + + /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ + if (autoinit) + dma_mode |= DMA_AUTOINIT; + save_flags(flags); + cli(); + 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); + + return 0; } #endif -void -conf_printf (char *name, struct address_info *hw_config) +void conf_printf(char *name, struct address_info *hw_config) { - if (!trace_init) - return; + if (!trace_init) + return; - printk ("<%s> at 0x%03x", name, hw_config->io_base); + printk("<%s> at 0x%03x", name, hw_config->io_base); - if (hw_config->irq) - printk (" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); + if (hw_config->irq) + printk(" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); - if (hw_config->dma != -1 || hw_config->dma2 != -1) - { - printk (" dma %d", hw_config->dma); - if (hw_config->dma2 != -1) - printk (",%d", hw_config->dma2); - } - - printk ("\n"); + if (hw_config->dma != -1 || hw_config->dma2 != -1) + { + printk(" dma %d", hw_config->dma); + if (hw_config->dma2 != -1) + printk(",%d", hw_config->dma2); + } + printk("\n"); } -void -conf_printf2 (char *name, int base, int irq, int dma, int dma2) +void conf_printf2(char *name, int base, int irq, int dma, int dma2) { - if (!trace_init) - return; + if (!trace_init) + return; - printk ("<%s> at 0x%03x", name, base); + printk("<%s> at 0x%03x", name, base); - if (irq) - printk (" irq %d", (irq > 0) ? irq : -irq); + if (irq) + printk(" irq %d", (irq > 0) ? irq : -irq); - if (dma != -1 || dma2 != -1) - { - printk (" dma %d", dma); - if (dma2 != -1) - printk (",%d", dma2); - } - - printk ("\n"); + if (dma != -1 || dma2 != -1) + { + printk(" dma %d", dma); + if (dma2 != -1) + printk(",%d", dma2); + } + printk("\n"); } diff --git a/drivers/sound/soundmodule.h b/drivers/sound/soundmodule.h new file mode 100644 index 000000000..d590acc0b --- /dev/null +++ b/drivers/sound/soundmodule.h @@ -0,0 +1,41 @@ +#ifndef _SOUNDMODULE_H +#define _SOUNDMODULE_H + +#ifdef MODULE + +#include <linux/notifier.h> + +#ifdef SOUND_CORE + +struct notifier_block *sound_locker=(struct notifier_block *)0; + +#define SOUND_INC_USE_COUNT notifier_call_chain(&sound_locker, 1, 0) +#define SOUND_DEC_USE_COUNT notifier_call_chain(&sound_locker, 0, 0) + +#else + +#define SOUND_LOCK notifier_chain_register(&sound_locker, &sound_notifier) +#define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier) + +extern struct notifier_block *sound_locker; + + +static int my_notifier_call(struct notifier_block *b, unsigned long foo, void *bar) +{ + if(foo) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; + return NOTIFY_DONE; +} + +static struct notifier_block sound_notifier= +{ + my_notifier_call, + (void *)0, + 0 +}; + +#endif +#endif +#endif diff --git a/drivers/sound/soundvers.h b/drivers/sound/soundvers.h index 5b9b6a5c6..b3a8356c2 100644 --- a/drivers/sound/soundvers.h +++ b/drivers/sound/soundvers.h @@ -1,2 +1,2 @@ -#define SOUND_VERSION_STRING "3.8a" +#define SOUND_VERSION_STRING "3.8s-971110" #define SOUND_INTERNAL_VERSION 0x030804 diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index c5cf7de3f..befd924d0 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -11,11 +11,12 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_SSCAPEHW) +#if defined(CONFIG_SSCAPEHW) || defined(MODULE) #include "coproc.h" @@ -73,25 +74,28 @@ #define CMD_ACK 0x80 typedef struct sscape_info - { - int base, irq, dma; - int ok; /* Properly detected */ - int failed; - int dma_allocated; - int codec_audiodev; - int opened; - int *osp; - } -sscape_info; - -static struct sscape_info adev_info = -{0}; +{ + int base, irq, dma; + int ok; /* Properly detected */ + int failed; + int dma_allocated; + int codec_audiodev; + int opened; + int *osp; + int my_audiodev; +} sscape_info; + +static struct sscape_info adev_info = { + 0 +}; + static struct sscape_info *devc = &adev_info; static int sscape_mididev = -1; static struct wait_queue *sscape_sleeper = NULL; -static volatile struct snd_wait sscape_sleep_flag = -{0}; +static volatile struct snd_wait sscape_sleep_flag = { + 0 +}; /* Some older cards have assigned interrupt bits differently than new ones */ static char valid_interrupts_old[] = @@ -110,165 +114,153 @@ static char old_hardware = 0; #endif -static unsigned char -sscape_read (struct sscape_info *devc, int reg) +static unsigned char sscape_read(struct sscape_info *devc, int reg) { - unsigned long flags; - unsigned char val; - - save_flags (flags); - cli (); - outb ((reg), PORT (ODIE_ADDR)); - val = inb (PORT (ODIE_DATA)); - restore_flags (flags); - return val; + unsigned long flags; + unsigned char val; + + save_flags(flags); + cli(); + outb((reg), PORT(ODIE_ADDR)); + val = inb(PORT(ODIE_DATA)); + restore_flags(flags); + return val; } static void -sscape_write (struct sscape_info *devc, int reg, int data) +sscape_write(struct sscape_info *devc, int reg, int data) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - outb ((reg), PORT (ODIE_ADDR)); - outb ((data), PORT (ODIE_DATA)); - restore_flags (flags); + save_flags(flags); + cli(); + outb((reg), PORT(ODIE_ADDR)); + outb((data), PORT(ODIE_DATA)); + restore_flags(flags); } static void -host_open (struct sscape_info *devc) +host_open(struct sscape_info *devc) { - outb ((0x00), PORT (HOST_CTRL)); /* Put the board to the host mode */ + outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */ } static void -host_close (struct sscape_info *devc) +host_close(struct sscape_info *devc) { - outb ((0x03), PORT (HOST_CTRL)); /* Put the board to the MIDI mode */ + outb((0x03), PORT(HOST_CTRL)); /* Put the board to the MIDI mode */ } static int -host_write (struct sscape_info *devc, unsigned char *data, int count) +host_write(struct sscape_info *devc, unsigned char *data, int count) { - unsigned long flags; - int i, timeout_val; - - save_flags (flags); - cli (); + unsigned long flags; + int i, timeout_val; - /* - * Send the command and data bytes - */ + save_flags(flags); + cli(); - for (i = 0; i < count; i++) - { - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb (PORT (HOST_CTRL)) & TX_READY) - break; + /* + * Send the command and data bytes + */ - if (timeout_val <= 0) - { - restore_flags (flags); - return 0; - } - - outb ((data[i]), PORT (HOST_DATA)); - } + for (i = 0; i < count; i++) + { + for (timeout_val = 10000; timeout_val > 0; timeout_val--) + if (inb(PORT(HOST_CTRL)) & TX_READY) + break; + + if (timeout_val <= 0) + { + restore_flags(flags); + return 0; + } + outb((data[i]), PORT(HOST_DATA)); + } - restore_flags (flags); + restore_flags(flags); - return 1; + return 1; } static int -host_read (struct sscape_info *devc) +host_read(struct sscape_info *devc) { - unsigned long flags; - int timeout_val; - unsigned char data; - - save_flags (flags); - cli (); + unsigned long flags; + int timeout_val; + unsigned char data; - /* - * Read a byte - */ + save_flags(flags); + cli(); - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb (PORT (HOST_CTRL)) & RX_READY) - break; + /* + * Read a byte + */ - if (timeout_val <= 0) - { - restore_flags (flags); - return -1; - } + for (timeout_val = 10000; timeout_val > 0; timeout_val--) + if (inb(PORT(HOST_CTRL)) & RX_READY) + break; - data = inb (PORT (HOST_DATA)); + if (timeout_val <= 0) + { + restore_flags(flags); + return -1; + } + data = inb(PORT(HOST_DATA)); - restore_flags (flags); + restore_flags(flags); - return data; + return data; } -static int -host_command1 (struct sscape_info *devc, int cmd) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - - return host_write (devc, buf, 1); -} static int -host_command2 (struct sscape_info *devc, int cmd, int parm1) +host_command2(struct sscape_info *devc, int cmd, int parm1) { - unsigned char buf[10]; + unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); - return host_write (devc, buf, 2); + return host_write(devc, buf, 2); } static int -host_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2) +host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2) { - unsigned char buf[10]; + unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - buf[2] = (unsigned char) (parm2 & 0xff); + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + buf[2] = (unsigned char) (parm2 & 0xff); - return host_write (devc, buf, 3); + return host_write(devc, buf, 3); } static void -set_mt32 (struct sscape_info *devc, int value) +set_mt32(struct sscape_info *devc, int value) { - host_open (devc); - host_command2 (devc, CMD_SET_MT32, - value ? 1 : 0); - if (host_read (devc) != CMD_ACK) - { - /* printk ("SNDSCAPE: Setting MT32 mode failed\n"); */ - } - host_close (devc); + host_open(devc); + host_command2(devc, CMD_SET_MT32, + value ? 1 : 0); + if (host_read(devc) != CMD_ACK) + { + /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */ + } + host_close(devc); } static void -set_control (struct sscape_info *devc, int ctrl, int value) +set_control(struct sscape_info *devc, int ctrl, int value) { - host_open (devc); - host_command3 (devc, CMD_SET_CONTROL, ctrl, value); - if (host_read (devc) != CMD_ACK) - { - /* printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl); */ - } - host_close (devc); + host_open(devc); + host_command3(devc, CMD_SET_CONTROL, ctrl, value); + if (host_read(devc) != CMD_ACK) + { + /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */ + } + host_close(devc); } @@ -276,378 +268,370 @@ set_control (struct sscape_info *devc, int ctrl, int value) static void -do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) +do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) { - unsigned char temp; - - if (dma_chan != SSCAPE_DMA_A) - { - printk ("SSCAPE: Tried to use DMA channel != A. Why?\n"); - return; - } - - audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; - DMAbuf_start_dma (devc->codec_audiodev, - buf, - blk_size, mode); - audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; - - temp = devc->dma << 4; /* Setup DMA channel select bits */ - if (devc->dma <= 3) - temp |= 0x80; /* 8 bit DMA channel */ - - temp |= 1; /* Trigger DMA */ - sscape_write (devc, GA_DMAA_REG, temp); - temp &= 0xfe; /* Clear DMA trigger */ - sscape_write (devc, GA_DMAA_REG, temp); + unsigned char temp; + + if (dma_chan != SSCAPE_DMA_A) + { + printk("SSCAPE: Tried to use DMA channel != A. Why?\n"); + return; + } + audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; + DMAbuf_start_dma(devc->codec_audiodev, + buf, + blk_size, mode); + audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; + + temp = devc->dma << 4; /* Setup DMA channel select bits */ + if (devc->dma <= 3) + temp |= 0x80; /* 8 bit DMA channel */ + + temp |= 1; /* Trigger DMA */ + sscape_write(devc, GA_DMAA_REG, temp); + temp &= 0xfe; /* Clear DMA trigger */ + sscape_write(devc, GA_DMAA_REG, temp); } static int -verify_mpu (struct sscape_info *devc) +verify_mpu(struct sscape_info *devc) { - /* - * The SoundScape board could be in three modes (MPU, 8250 and host). - * If the card is not in the MPU mode, enabling the MPU driver will - * cause infinite loop (the driver believes that there is always some - * received data in the buffer. - * - * Detect this by looking if there are more than 10 received MIDI bytes - * (0x00) in the buffer. - */ - - int i; - - for (i = 0; i < 10; i++) - { - if (inb (devc->base + HOST_CTRL) & 0x80) - return 1; + /* + * The SoundScape board could be in three modes (MPU, 8250 and host). + * If the card is not in the MPU mode, enabling the MPU driver will + * cause infinite loop (the driver believes that there is always some + * received data in the buffer. + * + * Detect this by looking if there are more than 10 received MIDI bytes + * (0x00) in the buffer. + */ - if (inb (devc->base) != 0x00) - return 1; - } + int i; + + for (i = 0; i < 10; i++) + { + if (inb(devc->base + HOST_CTRL) & 0x80) + return 1; + + if (inb(devc->base) != 0x00) + return 1; + } - printk ("SoundScape: The device is not in the MPU-401 mode\n"); - return 0; + printk("SoundScape: The device is not in the MPU-401 mode\n"); + return 0; } static int -sscape_coproc_open (void *dev_info, int sub_device) +sscape_coproc_open(void *dev_info, int sub_device) { - if (sub_device == COPR_MIDI) - { - set_mt32 (devc, 0); - if (!verify_mpu (devc)) - return -EIO; - } - - sscape_sleep_flag.opts = WK_NONE; - return 0; + if (sub_device == COPR_MIDI) + { + set_mt32(devc, 0); + if (!verify_mpu(devc)) + return -EIO; + } + sscape_sleep_flag.opts = WK_NONE; + return 0; } static void -sscape_coproc_close (void *dev_info, int sub_device) +sscape_coproc_close(void *dev_info, int sub_device) { - struct sscape_info *devc = dev_info; - unsigned long flags; - - save_flags (flags); - cli (); - if (devc->dma_allocated) - { - sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ - devc->dma_allocated = 0; - } - sscape_sleep_flag.opts = WK_NONE; - restore_flags (flags); - - return; + struct sscape_info *devc = dev_info; + unsigned long flags; + + save_flags(flags); + cli(); + if (devc->dma_allocated) + { + sscape_write(devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ + devc->dma_allocated = 0; + } + sscape_sleep_flag.opts = WK_NONE; + restore_flags(flags); + + return; } static void -sscape_coproc_reset (void *dev_info) +sscape_coproc_reset(void *dev_info) { } static int -sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag) +sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag) { - unsigned long flags; - unsigned char temp; - volatile int done, timeout_val; - static unsigned char codec_dma_bits = 0; - - if (flag & CPF_FIRST) - { - /* - * First block. Have to allocate DMA and to reset the board - * before continuing. - */ - - save_flags (flags); - cli (); - codec_dma_bits = sscape_read (devc, GA_CDCFG_REG); - - if (devc->dma_allocated == 0) - { - devc->dma_allocated = 1; - } - restore_flags (flags); - - sscape_write (devc, GA_HMCTL_REG, - (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - sscape_read (devc, GA_HMCTL_REG); /* Delay */ + unsigned long flags; + unsigned char temp; + volatile int done, timeout_val; + static unsigned char codec_dma_bits = 0; - /* Take board out of reset */ - sscape_write (devc, GA_HMCTL_REG, - (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80); - } - - /* - * Transfer one code block using DMA - */ - if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) - { - printk ("SSCAPE: Error: DMA buffer not available\n"); - return 0; - } - - memcpy (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); + if (flag & CPF_FIRST) + { + /* + * First block. Have to allocate DMA and to reset the board + * before continuing. + */ + + save_flags(flags); + cli(); + codec_dma_bits = sscape_read(devc, GA_CDCFG_REG); + + if (devc->dma_allocated == 0) + { + devc->dma_allocated = 1; + } + restore_flags(flags); + + sscape_write(devc, GA_HMCTL_REG, + (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ + + for (timeout_val = 10000; timeout_val > 0; timeout_val--) + sscape_read(devc, GA_HMCTL_REG); /* Delay */ + + /* Take board out of reset */ + sscape_write(devc, GA_HMCTL_REG, + (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80); + } + /* + * Transfer one code block using DMA + */ + if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) + { + printk("SSCAPE: Error: DMA buffer not available\n"); + return 0; + } + memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); - save_flags (flags); - cli (); + save_flags(flags); + cli(); /******** INTERRUPTS DISABLED NOW ********/ - do_dma (devc, SSCAPE_DMA_A, - audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, - size, DMA_MODE_WRITE); - - /* - * Wait until transfer completes. - */ - sscape_sleep_flag.opts = WK_NONE; - done = 0; - timeout_val = 30; - while (!done && timeout_val-- > 0) - { - int resid; - - { - unsigned long tlimit; - - if (HZ / 50) - current->timeout = tlimit = jiffies + (HZ / 50); - else - tlimit = (unsigned long) -1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + do_dma(devc, SSCAPE_DMA_A, + audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, + size, DMA_MODE_WRITE); + + /* + * Wait until transfer completes. + */ + sscape_sleep_flag.opts = WK_NONE; + done = 0; + timeout_val = 30; + while (!done && timeout_val-- > 0) { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; + int resid; + + { + unsigned long tlimit; + + if (HZ / 50) + current->timeout = tlimit = jiffies + (HZ / 50); + else + tlimit = (unsigned long) -1; + sscape_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sscape_sleeper); + if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sscape_sleep_flag.opts |= WK_TIMEOUT; + } + sscape_sleep_flag.opts &= ~WK_SLEEP; + }; + clear_dma_ff(devc->dma); + if ((resid = get_dma_residue(devc->dma)) == 0) + { + done = 1; + } } - sscape_sleep_flag.opts &= ~WK_SLEEP; - }; - clear_dma_ff (devc->dma); - if ((resid = get_dma_residue (devc->dma)) == 0) - { - done = 1; - } - } - - restore_flags (flags); - if (!done) - return 0; - - if (flag & CPF_LAST) - { - /* - * Take the board out of reset - */ - outb ((0x00), PORT (HOST_CTRL)); - outb ((0x00), PORT (MIDI_CTRL)); - - temp = sscape_read (devc, GA_HMCTL_REG); - temp |= 0x40; - sscape_write (devc, GA_HMCTL_REG, temp); /* Kickstart the board */ - - /* - * Wait until the ODB wakes up - */ - - save_flags (flags); - cli (); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; + restore_flags(flags); + if (!done) + return 0; + if (flag & CPF_LAST) { - unsigned long tlimit; - - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; - }; - x = inb (PORT (HOST_DATA)); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - DDB (printk ("Soundscape: Acknowledge = %x\n", x)); - done = 1; - } - } - sscape_write (devc, GA_CDCFG_REG, codec_dma_bits); - - restore_flags (flags); - if (!done) - { - printk ("SoundScape: The OBP didn't respond after code download\n"); - return 0; - } - - save_flags (flags); - cli (); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - - { - unsigned long tlimit; - - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; - }; - if (inb (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ - done = 1; - } - restore_flags (flags); - if (!done) - { - printk ("SoundScape: OBP Initialization failed.\n"); - return 0; - } - - printk ("SoundScape board initialized OK\n"); - set_control (devc, CTL_MASTER_VOL, 100); - set_control (devc, CTL_SYNTH_VOL, 100); + /* + * Take the board out of reset + */ + outb((0x00), PORT(HOST_CTRL)); + outb((0x00), PORT(MIDI_CTRL)); + + temp = sscape_read(devc, GA_HMCTL_REG); + temp |= 0x40; + sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */ + + /* + * Wait until the ODB wakes up + */ + + save_flags(flags); + cli(); + done = 0; + timeout_val = 5 * HZ; + while (!done && timeout_val-- > 0) + { + unsigned char x; + + + { + unsigned long tlimit; + + if (1) + current->timeout = tlimit = jiffies + (1); + else + tlimit = (unsigned long) -1; + sscape_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sscape_sleeper); + if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sscape_sleep_flag.opts |= WK_TIMEOUT; + } + sscape_sleep_flag.opts &= ~WK_SLEEP; + }; + x = inb(PORT(HOST_DATA)); + if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ + { + DDB(printk("Soundscape: Acknowledge = %x\n", x)); + done = 1; + } + } + sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); + + restore_flags(flags); + if (!done) + { + printk("SoundScape: The OBP didn't respond after code download\n"); + return 0; + } + save_flags(flags); + cli(); + done = 0; + timeout_val = 5 * HZ; + while (!done && timeout_val-- > 0) + { + + { + unsigned long tlimit; + + if (1) + current->timeout = tlimit = jiffies + (1); + else + tlimit = (unsigned long) -1; + sscape_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sscape_sleeper); + if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sscape_sleep_flag.opts |= WK_TIMEOUT; + } + sscape_sleep_flag.opts &= ~WK_SLEEP; + }; + if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ + done = 1; + } + restore_flags(flags); + if (!done) + { + printk("SoundScape: OBP Initialization failed.\n"); + return 0; + } + printk("SoundScape board initialized OK\n"); + set_control(devc, CTL_MASTER_VOL, 100); + set_control(devc, CTL_SYNTH_VOL, 100); #ifdef SSCAPE_DEBUG3 - /* - * Temporary debugging aid. Print contents of the registers after - * downloading the code. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); - } + /* + * Temporary debugging aid. Print contents of the registers after + * downloading the code. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); + } #endif - } - - return 1; + } + return 1; } static int -download_boot_block (void *dev_info, copr_buffer * buf) +download_boot_block(void *dev_info, copr_buffer * buf) { - if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; + if (buf->len <= 0 || buf->len > sizeof(buf->data)) + return -EINVAL; - if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) - { - printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); - return -EIO; - } - - return 0; + if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) + { + printk("SSCAPE: Unable to load microcode block to the OBP.\n"); + return -EIO; + } + return 0; } static int -sscape_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) +sscape_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local) { - switch (cmd) - { - case SNDCTL_COPR_RESET: - sscape_coproc_reset (dev_info); - return 0; - break; - - case SNDCTL_COPR_LOAD: - { - copr_buffer *buf; - int err; - - buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); - if (buf == NULL) - return -ENOSPC; - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - err = download_boot_block (dev_info, buf); - vfree (buf); - return err; - } - break; - - default: - return -EINVAL; - } + switch (cmd) + { + case SNDCTL_COPR_RESET: + sscape_coproc_reset(dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + if (buf == NULL) + return -ENOSPC; + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + err = download_boot_block(dev_info, buf); + vfree(buf); + return err; + } + break; + + default: + return -EINVAL; + } } static coproc_operations sscape_coproc_operations = { - "SoundScape M68K", - sscape_coproc_open, - sscape_coproc_close, - sscape_coproc_ioctl, - sscape_coproc_reset, - &adev_info + "SoundScape M68K", + sscape_coproc_open, + sscape_coproc_close, + sscape_coproc_ioctl, + sscape_coproc_reset, + &adev_info }; static int sscape_detected = 0; void -attach_sscape (struct address_info *hw_config) +attach_sscape(struct address_info *hw_config) { #ifndef SSCAPE_REGS - /* - * Config register values for Spea/V7 Media FX and Ensoniq S-2000. - * These values are card - * dependent. If you have another SoundScape based card, you have to - * find the correct values. Do the following: - * - Compile this driver with SSCAPE_DEBUG1 defined. - * - Shut down and power off your machine. - * - Boot with DOS so that the SSINIT.EXE program is run. - * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed - * when detecting the SoundScape. - * - Modify the following list to use the values printed during boot. - * Undefine the SSCAPE_DEBUG1 - */ + /* + * Config register values for Spea/V7 Media FX and Ensoniq S-2000. + * These values are card + * dependent. If you have another SoundScape based card, you have to + * find the correct values. Do the following: + * - Compile this driver with SSCAPE_DEBUG1 defined. + * - Shut down and power off your machine. + * - Boot with DOS so that the SSINIT.EXE program is run. + * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed + * when detecting the SoundScape. + * - Modify the following list to use the values printed during boot. + * Undefine the SSCAPE_DEBUG1 + */ #define SSCAPE_REGS { \ /* I0 */ 0x00, \ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ @@ -662,356 +646,400 @@ attach_sscape (struct address_info *hw_config) } #endif - unsigned long flags; - static unsigned char regs[10] = SSCAPE_REGS; - - int i, irq_bits = 0xff; - - if (sscape_detected != hw_config->io_base) - return; - - request_region (devc->base + 2, 6, "SoundScape"); - if (old_hardware) - { - valid_interrupts = valid_interrupts_old; - conf_printf ("Ensoniq SoundScape (old)", hw_config); - } - else - conf_printf ("Ensoniq SoundScape", hw_config); - - for (i = 0; i < sizeof (valid_interrupts); i++) - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - - if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) - { - printk ("Invalid IRQ%d\n", hw_config->irq); - return; - } - - save_flags (flags); - cli (); - - for (i = 1; i < 10; i++) - switch (i) - { - case 1: /* Host interrupt enable */ - sscape_write (devc, i, 0xf0); /* All interrupts enabled */ - break; - - case 2: /* DMA A status/trigger register */ - case 3: /* DMA B status/trigger register */ - sscape_write (devc, i, 0x20); /* DMA channel disabled */ - break; - - case 4: /* Host interrupt config reg */ - sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits); - break; - - case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ - sscape_write (devc, i, (regs[i] & 0x3f) | - (sscape_read (devc, i) & 0xc0)); - break; - - case 6: /* CD-ROM config (WSS codec actually) */ - sscape_write (devc, i, regs[i]); - break; - - case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ - sscape_write (devc, i, - (sscape_read (devc, i) & 0xf0) | 0x08); - break; - - default: - sscape_write (devc, i, regs[i]); - } - - restore_flags (flags); + unsigned long flags; + static unsigned char regs[10] = SSCAPE_REGS; + + int i, irq_bits = 0xff; + + if (sscape_detected != hw_config->io_base) + return; + + request_region(devc->base + 2, 6, "SoundScape"); + if (old_hardware) + { + valid_interrupts = valid_interrupts_old; + conf_printf("Ensoniq SoundScape (old)", hw_config); + } else + conf_printf("Ensoniq SoundScape", hw_config); + + for (i = 0; i < sizeof(valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) + { + printk("Invalid IRQ%d\n", hw_config->irq); + return; + } + save_flags(flags); + cli(); + + for (i = 1; i < 10; i++) + switch (i) + { + case 1: /* Host interrupt enable */ + sscape_write(devc, i, 0xf0); /* All interrupts enabled */ + break; + + case 2: /* DMA A status/trigger register */ + case 3: /* DMA B status/trigger register */ + sscape_write(devc, i, 0x20); /* DMA channel disabled */ + break; + + case 4: /* Host interrupt config reg */ + sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits); + break; + + case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ + sscape_write(devc, i, (regs[i] & 0x3f) | + (sscape_read(devc, i) & 0xc0)); + break; + + case 6: /* CD-ROM config (WSS codec actually) */ + sscape_write(devc, i, regs[i]); + break; + + case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ + sscape_write(devc, i, + (sscape_read(devc, i) & 0xf0) | 0x08); + break; + + default: + sscape_write(devc, i, regs[i]); + } + + restore_flags(flags); #ifdef SSCAPE_DEBUG2 - /* - * Temporary debugging aid. Print contents of the registers after - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); - } + /* + * Temporary debugging aid. Print contents of the registers after + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); + } #endif #if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) - if (probe_mpu401 (hw_config)) - hw_config->always_detect = 1; - { - int prev_devs; - - prev_devs = num_midis; - hw_config->name = "SoundScape"; - - hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401 (hw_config); - hw_config->irq *= -1; /* Restore it */ - - if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ - { - sscape_mididev = prev_devs; - midi_devs[prev_devs]->coproc = &sscape_coproc_operations; - } - } + if (probe_mpu401(hw_config)) + hw_config->always_detect = 1; + { + hw_config->name = "SoundScape"; + + hw_config->irq *= -1; /* Negative value signals IRQ sharing */ + attach_mpu401(hw_config); + hw_config->irq *= -1; /* Restore it */ + + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + { + sscape_mididev = hw_config->slots[1]; + midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; + } + } #endif - sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - devc->ok = 1; - devc->failed = 0; + sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ + devc->ok = 1; + devc->failed = 0; } static int -detect_ga (sscape_info * devc) +detect_ga(sscape_info * devc) { - unsigned char save; - - DDB (printk ("Entered Soundscape detect_ga(%x)\n", devc->base)); - - if (check_region (devc->base, 8)) - return 0; - - /* - * First check that the address register of "ODIE" is - * there and that it has exactly 4 writable bits. - * First 4 bits - */ - if ((save = inb (PORT (ODIE_ADDR))) & 0xf0) - { - DDB (printk ("soundscape: Detect error A\n")); - return 0; - } - - outb ((0x00), PORT (ODIE_ADDR)); - if (inb (PORT (ODIE_ADDR)) != 0x00) - { - DDB (printk ("soundscape: Detect error B\n")); - return 0; - } - - outb ((0xff), PORT (ODIE_ADDR)); - if (inb (PORT (ODIE_ADDR)) != 0x0f) - { - DDB (printk ("soundscape: Detect error C\n")); - return 0; - } - - outb ((save), PORT (ODIE_ADDR)); - - /* - * Now verify that some indirect registers return zero on some bits. - * This may break the driver with some future revisions of "ODIE" but... - */ - - if (sscape_read (devc, 0) & 0x0c) - { - DDB (printk ("soundscape: Detect error D (%x)\n", sscape_read (devc, 0))); - return 0; - } - - if (sscape_read (devc, 1) & 0x0f) - { - DDB (printk ("soundscape: Detect error E\n")); - return 0; - } - - if (sscape_read (devc, 5) & 0x0f) - { - DDB (printk ("soundscape: Detect error F\n")); - return 0; - } - - return 1; -} + unsigned char save; -int -probe_sscape (struct address_info *hw_config) -{ + DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base)); - if (sscape_detected != 0 && sscape_detected != hw_config->io_base) - return 0; + if (check_region(devc->base, 8)) + return 0; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; + /* + * First check that the address register of "ODIE" is + * there and that it has exactly 4 writable bits. + * First 4 bits + */ + if ((save = inb(PORT(ODIE_ADDR))) & 0xf0) + { + DDB(printk("soundscape: Detect error A\n")); + return 0; + } + outb((0x00), PORT(ODIE_ADDR)); + if (inb(PORT(ODIE_ADDR)) != 0x00) + { + DDB(printk("soundscape: Detect error B\n")); + return 0; + } + outb((0xff), PORT(ODIE_ADDR)); + if (inb(PORT(ODIE_ADDR)) != 0x0f) + { + DDB(printk("soundscape: Detect error C\n")); + return 0; + } + outb((save), PORT(ODIE_ADDR)); -#ifdef SSCAPE_DEBUG1 - /* - * Temporary debugging aid. Print contents of the registers before - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i)); - } -#endif + /* + * Now verify that some indirect registers return zero on some bits. + * This may break the driver with some future revisions of "ODIE" but... + */ + if (sscape_read(devc, 0) & 0x0c) + { + DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0))); + return 0; + } + if (sscape_read(devc, 1) & 0x0f) + { + DDB(printk("soundscape: Detect error E\n")); + return 0; + } + if (sscape_read(devc, 5) & 0x0f) + { + DDB(printk("soundscape: Detect error F\n")); + return 0; + } + return 1; +} - devc->failed = 1; +int +probe_sscape(struct address_info *hw_config) +{ - if (!detect_ga (devc)) - return 0; + if (sscape_detected != 0 && sscape_detected != hw_config->io_base) + return 0; - if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ - { - unsigned char tmp; - int cc; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + devc->osp = hw_config->osp; - if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0)) +#ifdef SSCAPE_DEBUG1 + /* + * Temporary debugging aid. Print contents of the registers before + * changing them. + */ { - sscape_write (devc, GA_HMCTL_REG, tmp | 0x80); - for (cc = 0; cc < 200000; ++cc) - inb (devc->base + ODIE_ADDR); + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x (old value)\n", i, sscape_read(devc, i)); } - } +#endif + + devc->failed = 1; - sscape_detected = hw_config->io_base; + if (!detect_ga(devc)) + return 0; - return 1; + if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ + { + unsigned char tmp; + int cc; + + if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0)) + { + sscape_write(devc, GA_HMCTL_REG, tmp | 0x80); + for (cc = 0; cc < 200000; ++cc) + inb(devc->base + ODIE_ADDR); + } + } + sscape_detected = hw_config->io_base; + + return 1; } int -probe_ss_ms_sound (struct address_info *hw_config) +probe_ss_ms_sound(struct address_info *hw_config) { - int i, irq_bits = 0xff; - int ad_flags = 0; - - if (devc->failed) - { - printk ("Soundscape: Card not detected\n"); - return 0; - } - - if (devc->ok == 0) - { - printk ("SoundScape: Invalid initialization order.\n"); - return 0; - } - - for (i = 0; i < sizeof (valid_interrupts); i++) - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - if (hw_config->irq > 15 || irq_bits == 0xff) - { - printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); - return 0; - } - - - if (old_hardware) - ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ - return ad1848_detect (hw_config->io_base, &ad_flags, hw_config->osp); + int i, irq_bits = 0xff; + int ad_flags = 0; + + if (devc->failed) + { + printk("Soundscape: Card not detected\n"); + return 0; + } + if (devc->ok == 0) + { + printk("SoundScape: Invalid initialization order.\n"); + return 0; + } + for (i = 0; i < sizeof(valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + if (hw_config->irq > 15 || irq_bits == 0xff) + { + printk("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); + return 0; + } + if (old_hardware) + ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ + return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp); } void -attach_ss_ms_sound (struct address_info *hw_config) +attach_ss_ms_sound(struct address_info *hw_config) { - /* - * This routine configures the SoundScape card for use with the - * Win Sound System driver. The AD1848 codec interface uses the CD-ROM - * config registers of the "ODIE". - */ + /* + * This routine configures the SoundScape card for use with the + * Win Sound System driver. The AD1848 codec interface uses the CD-ROM + * config registers of the "ODIE". + */ + + int i, irq_bits = 0xff; + + hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ + + /* + * Setup the DMA polarity. + */ + sscape_write(devc, GA_DMACFG_REG, 0x50); + + /* + * Take the gate-array off of the DMA channel. + */ + sscape_write(devc, GA_DMAB_REG, 0x20); + + /* + * Init the AD1848 (CD-ROM) config reg. + */ + + for (i = 0; i < sizeof(valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | + (irq_bits << 1)); + + if (hw_config->irq == devc->irq) + printk("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); + + hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, + 0, + devc->osp); + + if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ + { + audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations; + devc->codec_audiodev = hw_config->slots[0]; + devc->my_audiodev = hw_config->slots[0]; - int i, irq_bits = 0xff; + /* Set proper routings here (what are they) */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + } +#ifdef SSCAPE_DEBUG5 + /* + * Temporary debugging aid. Print contents of the registers + * after the AD1848 device has been initialized. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x\n", i, sscape_read(devc, i)); + } +#endif - int prev_devs = num_audiodevs; +} - hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ +void +unload_sscape(struct address_info *hw_config) +{ + release_region(devc->base + 2, 6); +#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) + unload_mpu401(hw_config); +#endif +} - /* - * Setup the DMA polarity. - */ - sscape_write (devc, GA_DMACFG_REG, 0x50); +void +unload_ss_ms_sound(struct address_info *hw_config) +{ + ad1848_unload(hw_config->io_base, + hw_config->irq, + devc->dma, + devc->dma, + 0); + sound_unload_audiodev(hw_config->slots[0]); +} - /* - * Take the gate-array off of the DMA channel. - */ - sscape_write (devc, GA_DMAB_REG, 0x20); +#ifdef MODULE - /* - * Init the AD1848 (CD-ROM) config reg. - */ +int dma = -1; +int irq = -1; +int io = -1; - for (i = 0; i < sizeof (valid_interrupts); i++) - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } +int mpu_irq = -1; +int mpu_io = -1; - sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | - (irq_bits << 1)); +static int mss = 0; - if (hw_config->irq == devc->irq) - printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); +MODULE_PARM(dma, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(mpu_irq, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(mss, "i"); - ad1848_init ("SoundScape", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); +struct address_info config; +struct address_info mpu_config; - if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ - { - audio_devs[prev_devs]->coproc = &sscape_coproc_operations; - devc->codec_audiodev = prev_devs; +int +init_module(void) +{ + printk("Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + if (dma == -1 || irq == -1 || io == -1) + { + printk("DMA, IRQ, and IO port must be specified.\n"); + return -EINVAL; + } + if (mpu_irq == -1 && mpu_io != -1) + { + printk("MPU_IRQ must be specified if MPU_IO is set.\n"); + return -EINVAL; + } + config.irq = irq; + config.dma = dma; + config.io_base = io; - /* Set proper routings here (what are they) */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - } + mpu_config.irq = mpu_irq; + mpu_config.io_base = mpu_io; -#ifdef SSCAPE_DEBUG5 - /* - * Temporary debugging aid. Print contents of the registers - * after the AD1848 device has been initialized. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x\n", i, sscape_read (devc, i)); - } -#endif + if (probe_sscape(&mpu_config) == 0) + return -ENODEV; -} + attach_sscape(&mpu_config); + + mss = probe_ss_ms_sound(&config); -void -unload_sscape (struct address_info *hw_config) -{ - release_region (devc->base + 2, 6); -#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); -#endif + if (mss) + attach_ss_ms_sound(&config); + SOUND_LOCK; + return 0; } -void -unload_ss_ms_sound (struct address_info *hw_config) +void +cleanup_module(void) { - ad1848_unload (hw_config->io_base, - hw_config->irq, - devc->dma, - devc->dma, - 0); + if (mss) + unload_ss_ms_sound(&config); + SOUND_LOCK_END; + unload_sscape(&config); } - +#endif #endif diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c index ca21cfa60..8097d1872 100644 --- a/drivers/sound/sys_timer.c +++ b/drivers/sound/sys_timer.c @@ -16,7 +16,7 @@ #include "sound_config.h" -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) static volatile int opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; @@ -26,281 +26,279 @@ static volatile unsigned long curr_ticks; static volatile unsigned long next_event_time; static unsigned long prev_event_time; -static void poll_def_tmr (unsigned long dummy); +static void poll_def_tmr(unsigned long dummy); static struct timer_list def_tmr = {NULL, NULL, 0, 0, poll_def_tmr}; static unsigned long -tmr2ticks (int tmr_value) +tmr2ticks(int tmr_value) { - /* - * Convert system timer ticks (HZ) to MIDI ticks - * (divide # of MIDI ticks/minute by # of system ticks/minute). - */ + /* + * Convert system timer ticks (HZ) to MIDI ticks + * (divide # of MIDI ticks/minute by # of system ticks/minute). + */ - return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ); + return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ); } static void -poll_def_tmr (unsigned long dummy) +poll_def_tmr(unsigned long dummy) { - if (opened) - { - - { - def_tmr.expires = (1) + jiffies; - add_timer (&def_tmr); - }; + if (opened) + { - if (tmr_running) - { - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks (tmr_ctr); - - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer (0); - } - } - } + { + def_tmr.expires = (1) + jiffies; + add_timer(&def_tmr); + }; + + if (tmr_running) + { + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); + + if (curr_ticks >= next_event_time) + { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } + } + } } static void -tmr_reset (void) +tmr_reset(void) { - unsigned long flags; - - save_flags (flags); - cli (); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - restore_flags (flags); + unsigned long flags; + + save_flags(flags); + cli(); + tmr_offs = 0; + ticks_offs = 0; + tmr_ctr = 0; + next_event_time = (unsigned long) -1; + prev_event_time = 0; + curr_ticks = 0; + restore_flags(flags); } static int -def_tmr_open (int dev, int mode) +def_tmr_open(int dev, int mode) { - if (opened) - return -EBUSY; + if (opened) + return -EBUSY; - tmr_reset (); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; + tmr_reset(); + curr_tempo = 60; + curr_timebase = 100; + opened = 1; - ; + ; - { - def_tmr.expires = (1) + jiffies; - add_timer (&def_tmr); - }; + { + def_tmr.expires = (1) + jiffies; + add_timer(&def_tmr); + }; - return 0; + return 0; } static void -def_tmr_close (int dev) +def_tmr_close(int dev) { - opened = tmr_running = 0; - del_timer (&def_tmr);; + opened = tmr_running = 0; + del_timer(&def_tmr);; } static int -def_tmr_event (int dev, unsigned char *event) +def_tmr_event(int dev, unsigned char *event) { - unsigned char cmd = event[1]; - unsigned long parm = *(int *) &event[4]; - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; + unsigned char cmd = event[1]; + unsigned long parm = *(int *) &event[4]; - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - tmr_reset (); - tmr_running = 1; - break; - - case TMR_STOP: - tmr_running = 0; - break; - - case TMR_CONTINUE: - tmr_running = 1; - break; + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + tmr_reset(); + tmr_running = 1; + break; + + case TMR_STOP: + tmr_running = 0; + break; + + case TMR_CONTINUE: + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 360) + parm = 360; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; + + default:; + } - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 360) - parm = 360; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = parm; - } - break; - - case TMR_ECHO: - seq_copy_to_input (event, 8); - break; - - default:; - } - - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static unsigned long -def_tmr_get_time (int dev) +def_tmr_get_time(int dev) { - if (!opened) - return 0; + if (!opened) + return 0; - return curr_ticks; + return curr_ticks; } static int -def_tmr_ioctl (int dev, - unsigned int cmd, caddr_t arg) +def_tmr_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - switch (cmd) - { - case SNDCTL_TMR_SOURCE: - return (*(int *) arg = TMR_INTERNAL); - break; - - case SNDCTL_TMR_START: - tmr_reset (); - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - - val = *(int *) arg; - - if (val) + switch (cmd) { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; + case SNDCTL_TMR_SOURCE: + return (*(int *) arg = TMR_INTERNAL); + break; + + case SNDCTL_TMR_START: + tmr_reset(); + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val; + + val = *(int *) arg; + + if (val) + { + if (val < 1) + val = 1; + if (val > 1000) + val = 1000; + curr_timebase = val; + } + return (*(int *) arg = curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val; + + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = val; + } + return (*(int *) arg = curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + { + int val; + + val = *(int *) arg; + if (val != 0) /* Can't change */ + return -EINVAL; + + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + } + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + break; + + case SNDCTL_TMR_METRONOME: + /* NOP */ + break; + + default:; } - return (*(int *) arg = curr_timebase); - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - - val = *(int *) arg; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = val; - } - - return (*(int *) arg = curr_tempo); - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - - val = *(int *) arg; - if (val != 0) /* Can't change */ - return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - } - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - - default:; - } - - return -EINVAL; + return -EINVAL; } static void -def_tmr_arm (int dev, long time) +def_tmr_arm(int dev, long time) { - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; - next_event_time = prev_event_time = time; + next_event_time = prev_event_time = time; - return; + return; } struct sound_timer_operations default_sound_timer = { - {"System clock", 0}, - 0, /* Priority */ - 0, /* Local device link */ - def_tmr_open, - def_tmr_close, - def_tmr_event, - def_tmr_get_time, - def_tmr_ioctl, - def_tmr_arm + {"System clock", 0}, + 0, /* Priority */ + 0, /* Local device link */ + def_tmr_open, + def_tmr_close, + def_tmr_event, + def_tmr_get_time, + def_tmr_ioctl, + def_tmr_arm }; #endif diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 5bb60ea6a..4c3d0fb2c 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -12,12 +12,20 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" #include "sb.h" +#include "sound_firmware.h" -#if defined(CONFIG_TRIX) +#if defined(CONFIG_TRIX) || defined (MODULE) + +#if defined(CONFIG_UART401) || defined(CONFIG_UART401_MODULE) +#if defined(CONFIG_MIDI) +#define DO_MIDI +#endif +#endif #ifdef INCLUDE_TRIX_BOOT #include "trix_boot.h" @@ -35,100 +43,98 @@ static int mpu_initialized = 0; static int *trix_osp = NULL; static unsigned char -trix_read (int addr) +trix_read(int addr) { - outb (((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ - return inb (0x391); /* MT-0002-PC ASIC data */ + outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ + return inb(0x391); /* MT-0002-PC ASIC data */ } static void -trix_write (int addr, int data) +trix_write(int addr, int data) { - outb (((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ - outb (((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ + outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ + outb(((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ } static void -download_boot (int base) +download_boot(int base) { - int i = 0, n = trix_boot_len; + int i = 0, n = trix_boot_len; - if (trix_boot_len == 0) - return; + if (trix_boot_len == 0) + return; - trix_write (0xf8, 0x00); /* ??????? */ - outb ((0x01), base + 6); /* Clear the internal data pointer */ - outb ((0x00), base + 6); /* Restart */ + trix_write(0xf8, 0x00); /* ??????? */ + outb((0x01), base + 6); /* Clear the internal data pointer */ + outb((0x00), base + 6); /* Restart */ - /* - * Write the boot code to the RAM upload/download register. - * Each write increments the internal data pointer. - */ - outb ((0x01), base + 6); /* Clear the internal data pointer */ - outb ((0x1A), 0x390); /* Select RAM download/upload port */ + /* + * Write the boot code to the RAM upload/download register. + * Each write increments the internal data pointer. + */ + outb((0x01), base + 6); /* Clear the internal data pointer */ + outb((0x1A), 0x390); /* Select RAM download/upload port */ - for (i = 0; i < n; i++) - outb ((trix_boot[i]), 0x391); - for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ - outb ((0x00), 0x391); - outb ((0x00), base + 6); /* Reset */ - outb ((0x50), 0x390); /* ?????? */ + for (i = 0; i < n; i++) + outb((trix_boot[i]), 0x391); + for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ + outb((0x00), 0x391); + outb((0x00), base + 6); /* Reset */ + outb((0x50), 0x390); /* ?????? */ } static int -trix_set_wss_port (struct address_info *hw_config) +trix_set_wss_port(struct address_info *hw_config) { - unsigned char addr_bits; - - if (check_region (0x390, 2)) - { - printk ("AudioTrix: Config port I/O conflict\n"); - return 0; - } - - if (kilroy_was_here) /* Already initialized */ - return 0; - - if (trix_read (0x15) != 0x71) /* No ASIC signature */ - { - DDB (printk ("No AudioTrix ASIC signature found\n")); - return 0; - } - - kilroy_was_here = 1; - - /* - * Reset some registers. - */ - - trix_write (0x13, 0); - trix_write (0x14, 0); - - /* - * Configure the ASIC to place the codec to the proper I/O location - */ - - switch (hw_config->io_base) - { - case 0x530: - addr_bits = 0; - break; - case 0x604: - addr_bits = 1; - break; - case 0xE80: - addr_bits = 2; - break; - case 0xF40: - addr_bits = 3; - break; - default: - return 0; - } - - trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits); - return 1; + unsigned char addr_bits; + + if (check_region(0x390, 2)) + { + printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); + return 0; + } + if (kilroy_was_here) /* Already initialized */ + return 0; + + if (trix_read(0x15) != 0x71) /* No ASIC signature */ + { + MDB(printk("No AudioTrix ASIC signature found\n")); + return 0; + } + kilroy_was_here = 1; + + /* + * Reset some registers. + */ + + trix_write(0x13, 0); + trix_write(0x14, 0); + + /* + * Configure the ASIC to place the codec to the proper I/O location + */ + + switch (hw_config->io_base) + { + case 0x530: + addr_bits = 0; + break; + case 0x604: + addr_bits = 1; + break; + case 0xE80: + addr_bits = 2; + break; + case 0xF40: + addr_bits = 3; + break; + default: + return 0; + } + + trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits); + return 1; } /* @@ -137,339 +143,421 @@ trix_set_wss_port (struct address_info *hw_config) */ int -probe_trix_wss (struct address_info *hw_config) +probe_trix_wss(struct address_info *hw_config) { - int ret; - - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. - */ - if (check_region (hw_config->io_base, 8)) - { - printk ("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - trix_osp = hw_config->osp; - - if (!trix_set_wss_port (hw_config)) - return 0; - - if ((inb (hw_config->io_base + 3) & 0x3f) != 0x00) - { - DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base)); - return 0; - } - - if (hw_config->irq > 11) - { - printk ("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); - return 0; - } - - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk ("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); - return 0; - } - - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) - { - printk ("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); - return 0; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("AudioTrix: Can't use DMA0 with a 8 bit card\n"); - return 0; - } - - if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("AudioTrix: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); - return 0; - } - - ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); - - if (ret) - { + int ret; + + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00. + */ + if (check_region(hw_config->io_base, 8)) + { + printk("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + trix_osp = hw_config->osp; + + if (!trix_set_wss_port(hw_config)) + return 0; + + if ((inb(hw_config->io_base + 3) & 0x3f) != 0x00) + { + MDB(printk("No MSS signature detected on port 0x%x\n", hw_config->io_base)); + return 0; + } + if (hw_config->irq > 11) + { + printk("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); + return 0; + } + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); + return 0; + } + if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) + if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) + { + printk("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); + return 0; + } + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) + { + printk("AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); + return 0; + } + if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) + { + printk("AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); + return 0; + } + ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); + + if (ret) + { #ifdef TRIX_ENABLE_JOYSTICK - trix_write (0x15, 0x80); + trix_write(0x15, 0x80); #endif - request_region (0x390, 2, "AudioTrix"); - } - - return ret; + request_region(0x390, 2, "AudioTrix"); + } + return ret; } void -attach_trix_wss (struct address_info *hw_config) +attach_trix_wss(struct address_info *hw_config) { - static unsigned char interrupt_bits[12] = - {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; - char bits; - - static unsigned char dma_bits[4] = - {1, 2, 0, 3}; - - int config_port = hw_config->io_base + 0; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; - - trix_osp = hw_config->osp; - - if (!kilroy_was_here) - { - DDB (printk ("AudioTrix: Attach called but not probed yet???\n")); - return; - } - - /* - * Set the IRQ and DMA addresses. - */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == 0) - { - printk ("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); - return; - } - - outb ((bits | 0x40), config_port); - - if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) - { - bits |= dma_bits[dma1]; - dma2 = dma1; - } - else - { - unsigned char tmp; - - tmp = trix_read (0x13) & ~30; - trix_write (0x13, tmp | 0x80 | (dma1 << 4)); - - tmp = trix_read (0x14) & ~30; - trix_write (0x14, tmp | 0x80 | (dma2 << 4)); - } - - outb ((bits), config_port); /* Write IRQ+DMA setup */ - - ad1848_init ("AudioTrix Pro", hw_config->io_base + 4, - hw_config->irq, - dma1, - dma2, - 0, - hw_config->osp); - request_region (hw_config->io_base, 4, "MSS config"); - - if (num_mixers > old_num_mixers) /* Mixer got installed */ - { - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ - AD1848_REROUTE (SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ - } + static unsigned char interrupt_bits[12] = + {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; + char bits; + + static unsigned char dma_bits[4] = + {1, 2, 0, 3}; + + int config_port = hw_config->io_base + 0; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int old_num_mixers = num_mixers; + + trix_osp = hw_config->osp; + + if (!kilroy_was_here) + { + DDB(printk("AudioTrix: Attach called but not probed yet???\n")); + return; + } + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == 0) + { + printk("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); + return; + } + outb((bits | 0x40), config_port); + + if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) + { + bits |= dma_bits[dma1]; + dma2 = dma1; + } else + { + unsigned char tmp; + + tmp = trix_read(0x13) & ~30; + trix_write(0x13, tmp | 0x80 | (dma1 << 4)); + + tmp = trix_read(0x14) & ~30; + trix_write(0x14, tmp | 0x80 | (dma2 << 4)); + } + + outb((bits), config_port); /* Write IRQ+DMA setup */ + + hw_config->slots[0] = ad1848_init("AudioTrix Pro", hw_config->io_base + 4, + hw_config->irq, + dma1, + dma2, + 0, + hw_config->osp); + request_region(hw_config->io_base, 4, "MSS config"); + + if (num_mixers > old_num_mixers) /* Mixer got installed */ + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ + AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ + } } int -probe_trix_sb (struct address_info *hw_config) +probe_trix_sb(struct address_info *hw_config) { - int tmp; - unsigned char conf; - static char irq_translate[] = - {-1, -1, -1, 0, 1, 2, -1, 3}; - - if (trix_boot_len == 0) - return 0; /* No boot code -> no fun */ - - if (!kilroy_was_here) - return 0; /* AudioTrix Pro has not been detected earlier */ - - if (sb_initialized) - return 0; - - if (check_region (hw_config->io_base, 16)) - { - printk ("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if ((hw_config->io_base & 0xffffff8f) != 0x200) - return 0; - - tmp = hw_config->irq; - if (tmp > 7) - return 0; - if (irq_translate[tmp] == -1) - return 0; - - tmp = hw_config->dma; - if (tmp != 1 && tmp != 3) - return 0; - - conf = 0x84; /* DMA and IRQ enable */ - conf |= hw_config->io_base & 0x70; /* I/O address bits */ - conf |= irq_translate[hw_config->irq]; - if (hw_config->dma == 3) - conf |= 0x08; - trix_write (0x1b, conf); - - download_boot (hw_config->io_base); - sb_initialized = 1; - - hw_config->name = "AudioTrix SB"; + int tmp; + unsigned char conf; + static char irq_translate[] = + {-1, -1, -1, 0, 1, 2, -1, 3}; + + if (trix_boot_len == 0) + return 0; /* No boot code -> no fun */ + + if (!kilroy_was_here) + return 0; /* AudioTrix Pro has not been detected earlier */ + + if (sb_initialized) + return 0; + + if (check_region(hw_config->io_base, 16)) + { + printk("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + if ((hw_config->io_base & 0xffffff8f) != 0x200) + return 0; + + tmp = hw_config->irq; + if (tmp > 7) + return 0; + if (irq_translate[tmp] == -1) + return 0; + + tmp = hw_config->dma; + if (tmp != 1 && tmp != 3) + return 0; + + conf = 0x84; /* DMA and IRQ enable */ + conf |= hw_config->io_base & 0x70; /* I/O address bits */ + conf |= irq_translate[hw_config->irq]; + if (hw_config->dma == 3) + conf |= 0x08; + trix_write(0x1b, conf); + + download_boot(hw_config->io_base); + sb_initialized = 1; + + hw_config->name = "AudioTrix SB"; #ifdef CONFIG_SBDSP - return sb_dsp_detect (hw_config); + return sb_dsp_detect(hw_config); #else - return 0; + return 0; #endif } void -attach_trix_sb (struct address_info *hw_config) +attach_trix_sb(struct address_info *hw_config) { - extern int sb_be_quiet; - int old_quiet; + extern int sb_be_quiet; + int old_quiet; #ifdef CONFIG_SBDSP - hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; + hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; - /* Prevent false alarms */ - old_quiet = sb_be_quiet; - sb_be_quiet = 1; + /* Prevent false alarms */ + old_quiet = sb_be_quiet; + sb_be_quiet = 1; - sb_dsp_init (hw_config); + sb_dsp_init(hw_config); - sb_be_quiet = old_quiet; + sb_be_quiet = old_quiet; #endif } void -attach_trix_mpu (struct address_info *hw_config) +attach_trix_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - hw_config->name = "AudioTrix Pro"; - attach_uart401 (hw_config); + hw_config->name = "AudioTrix Pro"; + attach_uart401(hw_config); #endif } int -probe_trix_mpu (struct address_info *hw_config) +probe_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unsigned char conf; - static char irq_bits[] = - {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; - - if (!kilroy_was_here) - { - DDB (printk ("Trix: WSS and SB modes must be initialized before MPU\n")); - return 0; /* AudioTrix Pro has not been detected earlier */ - } - - if (!sb_initialized) - { - DDB (printk ("Trix: SB mode must be initialized before MPU\n")); - return 0; - } - - if (mpu_initialized) - { - DDB (printk ("Trix: MPU mode already initialized\n")); - return 0; - } - - if (check_region (hw_config->io_base, 4)) - { - printk ("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if (hw_config->irq > 9) - { - printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - - if (irq_bits[hw_config->irq] == -1) - { - printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - - switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x370: - conf = 0x04; - break; - case 0x3b0: - conf = 0x08; - break; - case 0x3f0: - conf = 0x0c; - break; - default: - return 0; /* Invalid port */ - } - - conf |= irq_bits[hw_config->irq] << 4; - - trix_write (0x19, (trix_read (0x19) & 0x83) | conf); - - mpu_initialized = 1; - - return probe_uart401 (hw_config); +#ifdef DO_MIDI + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; + + if (!kilroy_was_here) + { + DDB(printk("Trix: WSS and SB modes must be initialized before MPU\n")); + return 0; /* AudioTrix Pro has not been detected earlier */ + } + if (!sb_initialized) + { + DDB(printk("Trix: SB mode must be initialized before MPU\n")); + return 0; + } + if (mpu_initialized) + { + DDB(printk("Trix: MPU mode already initialized\n")); + return 0; + } + if (check_region(hw_config->io_base, 4)) + { + printk("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + if (hw_config->irq > 9) + { + printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + if (irq_bits[hw_config->irq] == -1) + { + printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x370: + conf = 0x04; + break; + case 0x3b0: + conf = 0x08; + break; + case 0x3f0: + conf = 0x0c; + break; + default: + return 0; /* Invalid port */ + } + + conf |= irq_bits[hw_config->irq] << 4; + + trix_write(0x19, (trix_read(0x19) & 0x83) | conf); + + mpu_initialized = 1; + + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } void -unload_trix_wss (struct address_info *hw_config) +unload_trix_wss(struct address_info *hw_config) { - int dma2 = hw_config->dma2; + int dma2 = hw_config->dma2; - if (dma2 == -1) - dma2 = hw_config->dma; + if (dma2 == -1) + dma2 = hw_config->dma; - release_region (0x390, 2); - release_region (hw_config->io_base, 4); + release_region(0x390, 2); + release_region(hw_config->io_base, 4); - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - dma2, - 0); + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + dma2, + 0); + sound_unload_audiodev(hw_config->slots[0]); } void -unload_trix_mpu (struct address_info *hw_config) +unload_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unload_uart401 (hw_config); +#ifdef DO_MIDI + unload_uart401(hw_config); #endif } void -unload_trix_sb (struct address_info *hw_config) +unload_trix_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP - sb_dsp_unload (hw_config); + sb_dsp_unload(hw_config); #endif } +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; /* Set this for modules that need it */ + +int sb_io = -1; +int sb_dma = -1; +int sb_irq = -1; + +int mpu_io = -1; +int mpu_irq = -1; + +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; + +int +init_module(void) +{ + printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma2; + + sb_config.io_base = sb_io; + sb_config.irq = sb_irq; + sb_config.dma = sb_dma; + + mpu_config.io_base = mpu_io; + mpu_config.irq = mpu_irq; + + if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1)) + { + printk(KERN_INFO "SB_IRQ and SB_DMA must be specified if SB_IO is set.\n"); + return -EINVAL; + } + if (mpu_io != -1 && mpu_irq == -1) + { + printk(KERN_INFO "MPU_IRQ must be specified if MPU_IO is set.\n"); + return -EINVAL; + } + if (!trix_boot) + { + fw_load = 1; + trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", + (char **) &trix_boot); + } + if (!probe_trix_wss(&config)) + return -ENODEV; + attach_trix_wss(&config); + + /* + * We must attach in the right order to get the firmware + * loaded up in time. + */ + + if (sb_io != -1) + { + sb = probe_trix_sb(&sb_config); + if (sb) + attach_trix_sb(&sb_config); + } + if (mpu_io != -1) + { + mpu = probe_trix_mpu(&mpu_config); + if (mpu) + attach_trix_mpu(&mpu_config); + } + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (fw_load && trix_boot) + kfree(trix_boot); + if (sb) + unload_trix_sb(&sb_config); + if (mpu) + unload_trix_mpu(&mpu_config); + unload_trix_wss(&config); + SOUND_LOCK_END; +} + +#endif #endif diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c index e8a399cb6..22e4fe8f9 100644 --- a/drivers/sound/uart401.c +++ b/drivers/sound/uart401.c @@ -11,22 +11,23 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "soundmodule.h" -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) +#if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE) typedef struct uart401_devc { - int base; - int irq; - int *osp; - void (*midi_input_intr) (int dev, unsigned char data); - int opened, disabled; - volatile unsigned char input_byte; - int my_dev; - int share_irq; + int base; + int irq; + int *osp; + void (*midi_input_intr) (int dev, unsigned char data); + int opened, disabled; + volatile unsigned char input_byte; + int my_dev; + int share_irq; } uart401_devc; @@ -38,27 +39,27 @@ static uart401_devc *irq2devc[16] = #define COMDPORT (devc->base+1) #define STATPORT (devc->base+1) -static int -uart401_status (uart401_devc * devc) +static int +uart401_status(uart401_devc * devc) { - return inb (STATPORT); + return inb(STATPORT); } #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) -static void -uart401_cmd (uart401_devc * devc, unsigned char cmd) +static void +uart401_cmd(uart401_devc * devc, unsigned char cmd) { - outb ((cmd), COMDPORT); + outb((cmd), COMDPORT); } -static int -uart401_read (uart401_devc * devc) +static int +uart401_read(uart401_devc * devc) { - return inb (DATAPORT); + return inb(DATAPORT); } -static void -uart401_write (uart401_devc * devc, unsigned char byte) +static void +uart401_write(uart401_devc * devc, unsigned char byte) { - outb ((byte), DATAPORT); + outb((byte), DATAPORT); } #define OUTPUT_READY 0x40 @@ -67,141 +68,139 @@ uart401_write (uart401_devc * devc, unsigned char byte) #define MPU_RESET 0xFF #define UART_MODE_ON 0x3F -static int reset_uart401 (uart401_devc * devc); -static void enter_uart_mode (uart401_devc * devc); +static int reset_uart401(uart401_devc * devc); +static void enter_uart_mode(uart401_devc * devc); static void -uart401_input_loop (uart401_devc * devc) +uart401_input_loop(uart401_devc * devc) { - while (input_avail (devc)) - { - unsigned char c = uart401_read (devc); - - if (c == MPU_ACK) - devc->input_byte = c; - else if (devc->opened & OPEN_READ && devc->midi_input_intr) - devc->midi_input_intr (devc->my_dev, c); - } + while (input_avail(devc)) + { + unsigned char c = uart401_read(devc); + + if (c == MPU_ACK) + devc->input_byte = c; + else if (devc->opened & OPEN_READ && devc->midi_input_intr) + devc->midi_input_intr(devc->my_dev, c); + } } void -uart401intr (int irq, void *dev_id, struct pt_regs *dummy) +uart401intr(int irq, void *dev_id, struct pt_regs *dummy) { - uart401_devc *devc; + uart401_devc *devc; - if (irq < 1 || irq > 15) - return; + if (irq < 1 || irq > 15) + return; - devc = irq2devc[irq]; + devc = irq2devc[irq]; - if (devc == NULL) - return; + if (devc == NULL) + return; - if (input_avail (devc)) - uart401_input_loop (devc); + if (input_avail(devc)) + uart401_input_loop(devc); } static int -uart401_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +uart401_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; - if (devc->opened) - { - return -EBUSY; - } + if (devc->opened) + { + return -EBUSY; + } + while (input_avail(devc)) + uart401_read(devc); - while (input_avail (devc)) - uart401_read (devc); + devc->midi_input_intr = input; + devc->opened = mode; + enter_uart_mode(devc); + devc->disabled = 0; - devc->midi_input_intr = input; - devc->opened = mode; - enter_uart_mode (devc); - devc->disabled = 0; - - return 0; + return 0; } static void -uart401_close (int dev) +uart401_close(int dev) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; - reset_uart401 (devc); - devc->opened = 0; + reset_uart401(devc); + devc->opened = 0; } static int -uart401_out (int dev, unsigned char midi_byte) +uart401_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; - - if (devc->disabled) - return 1; - /* - * Test for input since pending input seems to block the output. - */ - - save_flags (flags); - cli (); - - if (input_avail (devc)) - uart401_input_loop (devc); - - restore_flags (flags); - - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); - - if (!output_ready (devc)) - { - printk ("MPU-401: Timeout - Device not responding\n"); - devc->disabled = 1; - reset_uart401 (devc); - enter_uart_mode (devc); - return 1; - } - - uart401_write (devc, midi_byte); - return 1; + int timeout; + unsigned long flags; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + if (devc->disabled) + return 1; + /* + * Test for input since pending input seems to block the output. + */ + + save_flags(flags); + cli(); + + if (input_avail(devc)) + uart401_input_loop(devc); + + restore_flags(flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); + + if (!output_ready(devc)) + { + printk("MPU-401: Timeout - Device not responding\n"); + devc->disabled = 1; + reset_uart401(devc); + enter_uart_mode(devc); + return 1; + } + uart401_write(devc, midi_byte); + return 1; } static int -uart401_start_read (int dev) +uart401_start_read(int dev) { - return 0; + return 0; } static int -uart401_end_read (int dev) +uart401_end_read(int dev) { - return 0; + return 0; } static int -uart401_ioctl (int dev, unsigned cmd, caddr_t arg) +uart401_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -uart401_kick (int dev) +uart401_kick(int dev) { } static int -uart401_buffer_status (int dev) +uart401_buffer_status(int dev) { - return 0; + return 0; } #define MIDI_SYNTH_NAME "MPU-401 UART" @@ -210,253 +209,300 @@ uart401_buffer_status (int dev) static struct midi_operations uart401_operations = { - {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, - &std_midi_synth, - {0}, - uart401_open, - uart401_close, - uart401_ioctl, - uart401_out, - uart401_start_read, - uart401_end_read, - uart401_kick, - NULL, - uart401_buffer_status, - NULL + {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + &std_midi_synth, + {0}, + uart401_open, + uart401_close, + uart401_ioctl, + uart401_out, + uart401_start_read, + uart401_end_read, + uart401_kick, + NULL, + uart401_buffer_status, + NULL }; static void -enter_uart_mode (uart401_devc * devc) +enter_uart_mode(uart401_devc * devc) { - int ok, timeout; - unsigned long flags; + int ok, timeout; + unsigned long flags; - save_flags (flags); - cli (); - for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--); + save_flags(flags); + cli(); + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - devc->input_byte = 0; - uart401_cmd (devc, UART_MODE_ON); + devc->input_byte = 0; + uart401_cmd(devc, UART_MODE_ON); - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) - ok = 1; - else if (input_avail (devc)) - if (uart401_read (devc) == MPU_ACK) - ok = 1; + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) + ok = 1; + else if (input_avail(devc)) + if (uart401_read(devc) == MPU_ACK) + ok = 1; - restore_flags (flags); + restore_flags(flags); } void -attach_uart401 (struct address_info *hw_config) +attach_uart401(struct address_info *hw_config) { - uart401_devc *devc; - char *name = "MPU-401 (UART) MIDI"; - - if (hw_config->name) - name = hw_config->name; - - if (detected_devc == NULL) - return; - - - devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (uart401_devc))); - sound_mem_sizes[sound_nblocks] = sizeof (uart401_devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (devc == NULL) - { - printk ("uart401: Can't allocate memory\n"); - return; - } - - memcpy ((char *) devc, (char *) detected_devc, sizeof (uart401_devc)); - detected_devc = NULL; - - devc->irq = hw_config->irq; - if (devc->irq < 0) - { - devc->share_irq = 1; - devc->irq *= -1; - } - else - devc->share_irq = 0; - - if (devc->irq < 1 || devc->irq > 15) - return; - - if (!devc->share_irq) - if (snd_set_irq_handler (devc->irq, uart401intr, "uart401", devc->osp) < 0) - { - printk ("uart401: Failed to allocate IRQ%d\n", devc->irq); - devc->share_irq = 1; - } - - irq2devc[devc->irq] = devc; - devc->my_dev = num_midis; - - request_region (hw_config->io_base, 4, "SB MIDI"); - enter_uart_mode (devc); - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - conf_printf (name, hw_config); + uart401_devc *devc; + char *name = "MPU-401 (UART) MIDI"; + + if (hw_config->name) + name = hw_config->name; + + if (detected_devc == NULL) + return; + + + devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(uart401_devc))); + sound_mem_sizes[sound_nblocks] = sizeof(uart401_devc); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (devc == NULL) + { + printk(KERN_WARNING "uart401: Can't allocate memory\n"); + return; + } + memcpy((char *) devc, (char *) detected_devc, sizeof(uart401_devc)); + detected_devc = NULL; + + devc->irq = hw_config->irq; + if (devc->irq < 0) + { + devc->share_irq = 1; + devc->irq *= -1; + } else + devc->share_irq = 0; + + if (devc->irq < 1 || devc->irq > 15) + return; + + if (!devc->share_irq) + if (snd_set_irq_handler(devc->irq, uart401intr, "MPU-401 UART", devc->osp) < 0) + { + printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); + devc->share_irq = 1; + } + irq2devc[devc->irq] = devc; + devc->my_dev = sound_alloc_mididev(); + + request_region(hw_config->io_base, 4, "MPU-401 UART"); + enter_uart_mode(devc); + + if (devc->my_dev == -1) + { + printk(KERN_INFO "uart401: Too many midi devices detected\n"); + return; + } + conf_printf(name, hw_config); + + std_midi_synth.midi_dev = devc->my_dev; + + + midi_devs[devc->my_dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[devc->my_dev] == NULL) + { + printk("uart401: Failed to allocate memory\n"); + sound_unload_mididev(devc->my_dev); + return; + } + memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations, + sizeof(struct midi_operations)); + + midi_devs[devc->my_dev]->devc = devc; + + + midi_devs[devc->my_dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); + + if (sound_nblocks < 1024) + sound_nblocks++; + + if (midi_devs[devc->my_dev]->converter == NULL) + { + printk(KERN_WARNING "uart401: Failed to allocate memory\n"); + sound_unload_mididev(devc->my_dev); + return; + } + memcpy((char *) midi_devs[devc->my_dev]->converter, (char *) &std_midi_synth, + sizeof(struct synth_operations)); + + strcpy(midi_devs[devc->my_dev]->info.name, name); + midi_devs[devc->my_dev]->converter->id = "UART401"; + hw_config->slots[4] = devc->my_dev; + sequencer_init(); + devc->opened = 0; +} - std_midi_synth.midi_dev = devc->my_dev = num_midis; +static int +reset_uart401(uart401_devc * devc) +{ + int ok, timeout, n; + /* + * Send the RESET command. Try again if no success at the first time. + */ - midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct midi_operations); + ok = 0; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (midi_devs[num_midis] == NULL) - { - printk ("uart401: Failed to allocate memory\n"); - return; - } + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - memcpy ((char *) midi_devs[num_midis], (char *) &uart401_operations, - sizeof (struct midi_operations)); + devc->input_byte = 0; + uart401_cmd(devc, MPU_RESET); - midi_devs[num_midis]->devc = devc; + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) /* Interrupt */ + ok = 1; + else if (input_avail(devc)) + if (uart401_read(devc) == MPU_ACK) + ok = 1; - midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations); + } - if (sound_nblocks < 1024) - sound_nblocks++;; - if (midi_devs[num_midis]->converter == NULL) - { - printk ("uart401: Failed to allocate memory\n"); - return; - } + if (ok) + { + DEB(printk("Reset UART401 OK\n")); + } else + DDB(printk("Reset UART401 failed - No hardware detected.\n")); - memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); + if (ok) + uart401_input_loop(devc); /* + * Flush input before enabling interrupts + */ - strcpy (midi_devs[num_midis]->info.name, name); - midi_devs[num_midis]->converter->id = "UART401"; - num_midis++; - sequencer_init (); - devc->opened = 0; + return ok; } -static int -reset_uart401 (uart401_devc * devc) +int +probe_uart401(struct address_info *hw_config) { - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; + int ok = 0; + unsigned long flags; - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--); + static uart401_devc hw_info; + uart401_devc *devc = &hw_info; - devc->input_byte = 0; - uart401_cmd (devc, MPU_RESET); + DDB(printk("Entered probe_uart401()\n")); - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ + detected_devc = NULL; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail (devc)) - if (uart401_read (devc) == MPU_ACK) - ok = 1; + if (check_region(hw_config->io_base, 4)) + return 0; - } + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->osp = hw_config->osp; + devc->midi_input_intr = NULL; + devc->opened = 0; + devc->input_byte = 0; + devc->my_dev = 0; + devc->share_irq = 0; + save_flags(flags); + cli(); + ok = reset_uart401(devc); + restore_flags(flags); - if (ok) - { - DDB (printk ("Reset UART401 OK\n")); - } - else - DDB (printk ("Reset UART401 failed - No hardware detected.\n")); + if (ok) + detected_devc = devc; - if (ok) - uart401_input_loop (devc); /* - * Flush input before enabling interrupts - */ - - return ok; + return ok; } -int -probe_uart401 (struct address_info *hw_config) +void +unload_uart401(struct address_info *hw_config) { - int ok = 0; - unsigned long flags; - - static uart401_devc hw_info; - uart401_devc *devc = &hw_info; - - DDB (printk ("Entered probe_uart401()\n")); + uart401_devc *devc; - detected_devc = NULL; + int irq = hw_config->irq; - if (check_region (hw_config->io_base, 4)) - return 0; + if (irq < 0) + { + irq *= -1; + } + if (irq < 1 || irq > 15) + return; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->osp = hw_config->osp; - devc->midi_input_intr = NULL; - devc->opened = 0; - devc->input_byte = 0; - devc->my_dev = 0; - devc->share_irq = 0; + devc = irq2devc[irq]; + if (devc == NULL) + return; - save_flags (flags); - cli (); - ok = reset_uart401 (devc); - restore_flags (flags); + reset_uart401(devc); + release_region(hw_config->io_base, 4); - if (ok) - detected_devc = devc; + if (!devc->share_irq) + snd_release_irq(devc->irq); - return ok; + /* Free device too !! - AC FIXME: CHECK THIS IS RIGHT */ + if (devc) + vfree(devc); + sound_unload_mididev(hw_config->slots[4]); } -void -unload_uart401 (struct address_info *hw_config) -{ - uart401_devc *devc; - - int irq = hw_config->irq; +#ifdef MODULE - if (irq < 0) - irq *= -1; +int io = -1; +int irq = -1; - if (irq < 1 || irq > 15) - return; +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +struct address_info hw; - devc = irq2devc[irq]; - if (devc == NULL) - return; - - reset_uart401 (devc); - release_region (hw_config->io_base, 4); +int +init_module(void) +{ + /* Can be loaded either for module use or to provide functions + to others */ + if (io != -1 && irq != -1) + { + printk("MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); + hw.irq = irq; + hw.io_base = io; + if (probe_uart401(&hw) == 0) + return -ENODEV; + attach_uart401(&hw); + } + SOUND_LOCK; + return 0; +} - if (!devc->share_irq) - snd_release_irq (devc->irq); +void +cleanup_module(void) +{ + if (io != -1 && irq != -1) + { + unload_uart401(&hw); + } + /* FREE SYMTAB */ + SOUND_LOCK_END; } +#else #endif + +#endif + +EXPORT_SYMBOL(attach_uart401); +EXPORT_SYMBOL(probe_uart401); +EXPORT_SYMBOL(unload_uart401); +EXPORT_SYMBOL(uart401intr); diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index 547cbba92..9285e40b1 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -1,3 +1,6 @@ + + + /* * sound/uart6850.c */ @@ -7,16 +10,20 @@ * 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. + * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver. + * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2. + * */ #include <linux/config.h> +#include <linux/module.h> /* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: * added 6850 support, used with COVOX SoundMaster II and custom cards. */ #include "sound_config.h" - -#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) +#include "soundmodule.h" +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) || defined(MODULE) static int uart6850_base = 0x330; @@ -26,27 +33,27 @@ static int *uart6850_osp; #define COMDPORT (uart6850_base+1) #define STATPORT (uart6850_base+1) -static int -uart6850_status (void) +static int +uart6850_status(void) { - return inb (STATPORT); + return inb(STATPORT); } #define input_avail() (uart6850_status()&INPUT_AVAIL) #define output_ready() (uart6850_status()&OUTPUT_READY) -static void -uart6850_cmd (unsigned char cmd) +static void +uart6850_cmd(unsigned char cmd) { - outb ((cmd), COMDPORT); + outb((cmd), COMDPORT); } -static int -uart6850_read (void) +static int +uart6850_read(void) { - return inb (DATAPORT); + return inb(DATAPORT); } -static void -uart6850_write (unsigned char byte) +static void +uart6850_write(unsigned char byte) { - outb ((byte), DATAPORT); + outb((byte), DATAPORT); } #define OUTPUT_READY 0x02 /* Mask for data ready Bit */ @@ -60,43 +67,42 @@ static int uart6850_irq; static int uart6850_detected = 0; static int my_dev; -static int reset_uart6850 (void); +static int reset_uart6850(void); static void (*midi_input_intr) (int dev, unsigned char data); -static void poll_uart6850 (unsigned long dummy); +static void poll_uart6850(unsigned long dummy); static struct timer_list uart6850_timer = {NULL, NULL, 0, 0, poll_uart6850}; static void -uart6850_input_loop (void) +uart6850_input_loop(void) { - int count; + int count; - count = 10; + count = 10; - while (count) /* + while (count) /* * Not timed out */ - if (input_avail ()) - { - unsigned char c = uart6850_read (); - - count = 100; - - if (uart6850_opened & OPEN_READ) - midi_input_intr (my_dev, c); - } - else - while (!input_avail () && count) - count--; + if (input_avail()) + { + unsigned char c = uart6850_read(); + + count = 100; + + if (uart6850_opened & OPEN_READ) + midi_input_intr(my_dev, c); + } else + while (!input_avail() && count) + count--; } void -m6850intr (int irq, void *dev_id, struct pt_regs *dummy) +m6850intr(int irq, void *dev_id, struct pt_regs *dummy) { - if (input_avail ()) - uart6850_input_loop (); + if (input_avail()) + uart6850_input_loop(); } /* @@ -105,135 +111,136 @@ m6850intr (int irq, void *dev_id, struct pt_regs *dummy) */ static void -poll_uart6850 (unsigned long dummy) +poll_uart6850(unsigned long dummy) { - unsigned long flags; + unsigned long flags; - if (!(uart6850_opened & OPEN_READ)) - return; /* Device has been closed */ + if (!(uart6850_opened & OPEN_READ)) + return; /* Device has been closed */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - if (input_avail ()) - uart6850_input_loop (); + if (input_avail()) + uart6850_input_loop(); - { - uart6850_timer.expires = (1) + jiffies; - add_timer (&uart6850_timer); - }; /* + { + uart6850_timer.expires = (1) + jiffies; + add_timer(&uart6850_timer); + }; /* * Come back later */ - restore_flags (flags); + restore_flags(flags); } static int -uart6850_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +uart6850_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - if (uart6850_opened) - { - printk ("Midi6850: Midi busy\n"); - return -EBUSY; - } + if (uart6850_opened) + { + printk("Midi6850: Midi busy\n"); + return -EBUSY; + }; - ; - uart6850_cmd (UART_RESET); + MOD_INC_USE_COUNT; + uart6850_cmd(UART_RESET); - uart6850_input_loop (); + uart6850_input_loop(); - midi_input_intr = input; - uart6850_opened = mode; - poll_uart6850 (0); /* + midi_input_intr = input; + uart6850_opened = mode; + poll_uart6850(0); /* * Enable input polling */ - return 0; + return 0; } static void -uart6850_close (int dev) +uart6850_close(int dev) { - uart6850_cmd (UART_MODE_ON); + uart6850_cmd(UART_MODE_ON); + + del_timer(&uart6850_timer);; + uart6850_opened = 0; - del_timer (&uart6850_timer);; - uart6850_opened = 0; + MOD_DEC_USE_COUNT; } static int -uart6850_out (int dev, unsigned char midi_byte) +uart6850_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; + int timeout; + unsigned long flags; - /* - * Test for input since pending input seems to block the output. - */ + /* + * Test for input since pending input seems to block the output. + */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - if (input_avail ()) - uart6850_input_loop (); + if (input_avail()) + uart6850_input_loop(); - restore_flags (flags); + restore_flags(flags); - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* - * Wait - */ + for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* + * Wait + */ - if (!output_ready ()) - { - printk ("Midi6850: Timeout\n"); - return 0; - } - - uart6850_write (midi_byte); - return 1; + if (!output_ready()) + { + printk("Midi6850: Timeout\n"); + return 0; + } + uart6850_write(midi_byte); + return 1; } static int -uart6850_command (int dev, unsigned char *midi_byte) +uart6850_command(int dev, unsigned char *midi_byte) { - return 1; + return 1; } static int -uart6850_start_read (int dev) +uart6850_start_read(int dev) { - return 0; + return 0; } static int -uart6850_end_read (int dev) +uart6850_end_read(int dev) { - return 0; + return 0; } static int -uart6850_ioctl (int dev, unsigned cmd, caddr_t arg) +uart6850_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -uart6850_kick (int dev) +uart6850_kick(int dev) { } static int -uart6850_buffer_status (int dev) +uart6850_buffer_status(int dev) { - return 0; /* + return 0; /* * No data in buffers */ } @@ -244,91 +251,127 @@ uart6850_buffer_status (int dev) static struct midi_operations uart6850_operations = { - {"6850 UART", 0, 0, SNDCARD_UART6850}, - &std_midi_synth, - {0}, - uart6850_open, - uart6850_close, - uart6850_ioctl, - uart6850_out, - uart6850_start_read, - uart6850_end_read, - uart6850_kick, - uart6850_command, - uart6850_buffer_status + {"6850 UART", 0, 0, SNDCARD_UART6850}, + &std_midi_synth, + {0}, + uart6850_open, + uart6850_close, + uart6850_ioctl, + uart6850_out, + uart6850_start_read, + uart6850_end_read, + uart6850_kick, + uart6850_command, + uart6850_buffer_status }; void -attach_uart6850 (struct address_info *hw_config) +attach_uart6850(struct address_info *hw_config) { - int ok, timeout; - unsigned long flags; - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - uart6850_base = hw_config->io_base; - uart6850_osp = hw_config->osp; - uart6850_irq = hw_config->irq; - - if (!uart6850_detected) - return; - - save_flags (flags); - cli (); - - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* - * Wait - */ - uart6850_cmd (UART_MODE_ON); - - ok = 1; - - restore_flags (flags); - - conf_printf ("6850 Midi Interface", hw_config); - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &uart6850_operations; - sequencer_init (); + int ok, timeout; + unsigned long flags; + + if ((my_dev = sound_alloc_mididev()) == -1) + { + printk(KERN_INFO "uart6850: Too many midi devices detected\n"); + return; + } + uart6850_base = hw_config->io_base; + uart6850_osp = hw_config->osp; + uart6850_irq = hw_config->irq; + + if (!uart6850_detected) + { + sound_unload_mididev(my_dev); + return; + } + save_flags(flags); + cli(); + + for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* + * Wait + */ + uart6850_cmd(UART_MODE_ON); + + ok = 1; + + restore_flags(flags); + + conf_printf("6850 Midi Interface", hw_config); + + std_midi_synth.midi_dev = my_dev; + hw_config->slots[4] = my_dev; + midi_devs[my_dev] = &uart6850_operations; + sequencer_init(); } static int -reset_uart6850 (void) +reset_uart6850(void) { - uart6850_read (); - return 1; /* + uart6850_read(); + return 1; /* * OK */ } int -probe_uart6850 (struct address_info *hw_config) +probe_uart6850(struct address_info *hw_config) { - int ok = 0; + int ok = 0; - uart6850_osp = hw_config->osp; - uart6850_base = hw_config->io_base; - uart6850_irq = hw_config->irq; + uart6850_osp = hw_config->osp; + uart6850_base = hw_config->io_base; + uart6850_irq = hw_config->irq; - if (snd_set_irq_handler (uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0) - return 0; + if (snd_set_irq_handler(uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0) + return 0; - ok = reset_uart6850 (); + ok = reset_uart6850(); - uart6850_detected = ok; - return ok; + uart6850_detected = ok; + return ok; } void -unload_uart6850 (struct address_info *hw_config) +unload_uart6850(struct address_info *hw_config) +{ + snd_release_irq(hw_config->irq); + sound_unload_mididev(hw_config->slots[4]); +} + + +#ifdef MODULE + +int io = -1; +int irq = -1; + +struct address_info cfg; + +int +init_module(void) { - snd_release_irq (hw_config->irq); + if (io == -1 || irq == -1) + { + printk("uart6850: irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + + if (probe_uart6850(&cfg)) + return -ENODEV; + + SOUND_LOCK; + return 0; } +void +cleanup_module(void) +{ + unload_uart6850(&cfg); + SOUND_LOCK_END; +} +#endif #endif |