diff options
author | Takashi Iwai <tiwai@suse.de> | 2017-10-24 09:15:23 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2017-10-31 11:06:39 +0100 |
commit | 727dede0ba8afbd8d19116d39f2ae8d19d00033d (patch) | |
tree | 45e476bd259b8d5e7851f1adf31fe5e3f21fd27b | |
parent | 3f1185d6c9d3fe91aa85ec8d3f4d71207452c458 (diff) | |
download | blackbird-op-linux-727dede0ba8afbd8d19116d39f2ae8d19d00033d.tar.gz blackbird-op-linux-727dede0ba8afbd8d19116d39f2ae8d19d00033d.zip |
sound: Retire OSS
Since no complaints have been raised after disabling the build of OSS
(Open Sound System) by the commit 31cbee6a5611 ("sound: Disable the
build of OSS drivers"), let's finally drop the whole code and
documentation.
Some glue codes are still left intact since sound/oss/dmasound stuff
remains -- which is an independent implementation solely for m68k, and
it's not covered by ALSA yet.
Also, a couple of API header files (linux/sound.h and
linux/soundcard.h) are kept remaining as well, since the OSS API
itself is still supported by ALSA OSS emulation, and applications can
refer to these.
Where we're at it, some help texts in the top-level Kconfig are
adjusted, too (who still needs to specify I/O port in kbuild
nowadays?).
Reviewed-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
96 files changed, 2 insertions, 41225 deletions
diff --git a/Documentation/sound/oss/ALS b/Documentation/sound/oss/ALS deleted file mode 100644 index bf10bed4574b..000000000000 --- a/Documentation/sound/oss/ALS +++ /dev/null @@ -1,66 +0,0 @@ -ALS-007/ALS-100/ALS-200 based sound cards -========================================= - -Support for sound cards based around the Avance Logic -ALS-007/ALS-100/ALS-200 chip is included. These chips are a single -chip PnP sound solution which is mostly hardware compatible with the -Sound Blaster 16 card, with most differences occurring in the use of -the mixer registers. For this reason the ALS code is integrated -as part of the Sound Blaster 16 driver (adding only 800 bytes to the -SB16 driver). - -To use an ALS sound card under Linux, enable the following options as -modules in the sound configuration section of the kernel config: - - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support - - FM synthesizer (YM3812/OPL-3) support - - standalone MPU401 support may be required for some cards; for the - ALS-007, when using isapnptools, it is required -Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be -compiled in. If kernel level PnP support is not included, isapnptools will -be required to configure the card before the sound modules are loaded. - -When using kernel level ISAPnP, the kernel should correctly identify and -configure all resources required by the card when the "sb" module is -inserted. Note that the ALS-007 does not have a 16 bit DMA channel and that -the MPU401 interface on this card uses a different interrupt to the audio -section. This should all be correctly configured by the kernel; if problems -with the MPU401 interface surface, try using the standalone MPU401 module, -passing "0" as the "sb" module's "mpu_io" module parameter to prevent the -soundblaster driver attempting to register the MPU401 itself. The onboard -synth device can be accessed using the "opl3" module. - -If isapnptools is used to wake up the sound card (as in 2.2.x), the settings -of the card's resources should be passed to the kernel modules ("sb", "opl3" -and "mpu401") using the module parameters. When configuring an ALS-007, be -sure to specify different IRQs for the audio and MPU401 sections - this card -requires they be different. For "sb", "io", "irq" and "dma" should be set -to the same values used to configure the audio section of the card with -isapnp. "dma16" should be explicitly set to "-1" for an ALS-007 since this -card does not have a 16 bit dma channel; if not specified the kernel will -default to using channel 5 anyway which will cause audio not to work. -"mpu_io" should be set to 0. The "io" parameter of the "opl3" module should -also agree with the setting used by isapnp. To get the MPU401 interface -working on an ALS-007 card, the "mpu401" module will be required since this -card uses separate IRQs for the audio and MPU401 sections and there is no -parameter available to pass a different IRQ to the "sb" driver (whose -inbuilt MPU401 driver would otherwise be fine). Insert the mpu401 module -passing appropriate values using the "io" and "irq" parameters. - -The resulting sound driver will provide the following capabilities: - - 8 and 16 bit audio playback - - 8 and 16 bit audio recording - - Software selection of record source (line in, CD, FM, mic, master) - - Record and playback of midi data via the external MPU-401 - - Playback of midi data using inbuilt FM synthesizer - - Control of the ALS-007 mixer via any OSS-compatible mixer programs. - Controls available are Master (L&R), Line in (L&R), CD (L&R), - DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono). - -Jonathan Woithe -jwoithe@just42.net -30 March 1998 - -Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200 -Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info. -Modified 2000-11-19 by Jonathan Woithe, jwoithe@just42.net - - updated information for kernel 2.4.x. diff --git a/Documentation/sound/oss/AudioExcelDSP16 b/Documentation/sound/oss/AudioExcelDSP16 deleted file mode 100644 index ea8549faede9..000000000000 --- a/Documentation/sound/oss/AudioExcelDSP16 +++ /dev/null @@ -1,101 +0,0 @@ -Driver ------- - -Information about Audio Excel DSP 16 driver can be found in the source -file aedsp16.c -Please, read the head of the source before using it. It contain useful -information. - -Configuration -------------- - -The Audio Excel configuration, is now done with the standard Linux setup. -You have to configure the sound card (Sound Blaster or Microsoft Sound System) -and, if you want it, the Roland MPU-401 (do not use the Sound Blaster MPU-401, -SB-MPU401) in the main driver menu. Activate the lowlevel drivers then select -the Audio Excel hardware that you want to initialize. Check the IRQ/DMA/MIRQ -of the Audio Excel initialization: it must be the same as the SBPRO (or MSS) -setup. If the parameters are different, correct it. -I you own a Gallant's audio card based on SC-6600, activate the SC-6600 support. -If you want to change the configuration of the sound board, be sure to -check off all the configuration items before re-configure it. - -Module parameters ------------------ -To use this driver as a module, you must configure some module parameters, to -set up I/O addresses, IRQ lines and DMA channels. Some parameters are -mandatory while some others are optional. Here a list of parameters you can -use with this module: - -Name Description -==== =========== -MANDATORY -io I/O base address (0x220 or 0x240) -irq irq line (5, 7, 9, 10 or 11) -dma dma channel (0, 1 or 3) - -OPTIONAL -mss_base I/O base address for activate MSS mode (default SBPRO) - (0x530 or 0xE80) -mpu_base I/O base address for activate MPU-401 mode - (0x300, 0x310, 0x320 or 0x330) -mpu_irq MPU-401 irq line (5, 7, 9, 10 or 0) - -A configuration file in /etc/modprobe.d/ directory will have lines like this: - -options opl3 io=0x388 -options ad1848 io=0x530 irq=11 dma=3 -options aedsp16 io=0x220 irq=11 dma=3 mss_base=0x530 - -Where the aedsp16 options are the options for this driver while opl3 and -ad1848 are the corresponding options for the MSS and OPL3 modules. - -Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly -the sound card. Installation dependencies must be written in configuration -files under /etc/modprobe.d/ directory: - -softdep ad1848 pre: aedsp16 -softdep opl3 pre: aedsp16 - -Then you must load the sound modules stack in this order: -sound -> aedsp16 -> [ ad1848, opl3 ] - -With the above configuration, loading ad1848 or opl3 modules, will -automatically load all the sound stack. - -Sound cards supported ---------------------- -This driver supports the SC-6000 and SC-6600 based Gallant's sound card. -It don't support the Audio Excel DSP 16 III (try the SC-6600 code). -I'm working on the III version of the card: if someone have useful -information about it, please let me know. -For all the non-supported audio cards, you have to boot MS-DOS (or WIN95) -activating the audio card with the MS-DOS device driver, then you have to -<ctrl>-<alt>-<del> and boot Linux. -Follow these steps: - -1) Compile Linux kernel with standard sound driver, using the emulation - you want, with the parameters of your audio card, - e.g. Microsoft Sound System irq10 dma3 -2) Install your new kernel as the default boot kernel. -3) Boot MS-DOS and configure the audio card with the boot time device - driver, for MSS irq10 dma3 in our example. -4) <ctrl>-<alt>-<del> and boot Linux. This will maintain the DOS configuration - and will boot the new kernel with sound driver. The sound driver will find - the audio card and will recognize and attach it. - -Reports on User successes -------------------------- - -> Date: Mon, 29 Jul 1996 08:35:40 +0100 -> From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk> -> To: riccardo@cdc8g5.cdc.polimi.it (Riccardo Facchetti) -> Subject: Re: Audio Excel DSP 16 initialization code -> -> Just to let you know got my Audio Excel (emulating a MSS) working -> with my original SB16, thanks for the driver! - - -Last revised: 20 August 1998 -Riccardo Facchetti -fizban@tin.it diff --git a/Documentation/sound/oss/CMI8330 b/Documentation/sound/oss/CMI8330 deleted file mode 100644 index 8a5fd1611c6f..000000000000 --- a/Documentation/sound/oss/CMI8330 +++ /dev/null @@ -1,152 +0,0 @@ -Documentation for CMI 8330 (SoundPRO) -------------------------------------- -Alessandro Zummo <azummo@ita.flashnet.it> - -( Be sure to read Documentation/sound/oss/SoundPro too ) - - -This adapter is now directly supported by the sb driver. - - The only thing you have to do is to compile the kernel sound -support as a module and to enable kernel ISAPnP support, -as shown below. - - -CONFIG_SOUND=m -CONFIG_SOUND_SB=m - -CONFIG_PNP=y -CONFIG_ISAPNP=y - - -and optionally: - - -CONFIG_SOUND_MPU401=m - - for MPU401 support. - - -(I suggest you to use "make menuconfig" or "make xconfig" - for a more comfortable configuration editing) - - - -Then you can do - - modprobe sb - -and everything will be (hopefully) configured. - -You should get something similar in syslog: - -sb: CMI8330 detected. -sb: CMI8330 sb base located at 0x220 -sb: CMI8330 mpu base located at 0x330 -sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it> -sb: ISAPnP reports CMI 8330 SoundPRO at i/o 0x220, irq 7, dma 1,5 - - - - -The old documentation file follows for reference -purposes. - - -How to enable CMI 8330 (SOUNDPRO) soundchip on Linux ------------------------------------------- -Stefan Laudat <Stefan.Laudat@asit.ro> - -[Note: The CMI 8338 is unrelated and is supported by cmpci.o] - - - In order to use CMI8330 under Linux you just have to use a proper isapnp.conf, a good isapnp and a little bit of patience. I use isapnp 1.17, but -you may get a better one I guess at http://www.roestock.demon.co.uk/isapnptools/. - - Of course you will have to compile kernel sound support as module, as shown below: - -CONFIG_SOUND=m -CONFIG_SOUND_OSS=m -CONFIG_SOUND_SB=m -CONFIG_SOUND_ADLIB=m -CONFIG_SOUND_MPU401=m -# Mikro$chaft sound system (kinda useful here ;)) -CONFIG_SOUND_MSS=m - - The /etc/isapnp.conf file will be: - -<snip below> - - -(READPORT 0x0203) -(ISOLATE PRESERVE) -(IDENTIFY *) -(VERBOSITY 2) -(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING -(VERIFYLD N) - - -# WSS - -(CONFIGURE CMI0001/16777472 (LD 0 -(IO 0 (SIZE 8) (BASE 0x0530)) -(IO 1 (SIZE 8) (BASE 0x0388)) -(INT 0 (IRQ 7 (MODE +E))) -(DMA 0 (CHANNEL 0)) -(NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}") -(ACT Y) -)) - -# MPU - -(CONFIGURE CMI0001/16777472 (LD 1 -(IO 0 (SIZE 2) (BASE 0x0330)) -(INT 0 (IRQ 11 (MODE +E))) -(NAME "CMI0001/16777472[1]{CMI8330/C3D Audio Adapter}") -(ACT Y) -)) - -# Joystick - -(CONFIGURE CMI0001/16777472 (LD 2 -(IO 0 (SIZE 8) (BASE 0x0200)) -(NAME "CMI0001/16777472[2]{CMI8330/C3D Audio Adapter}") -(ACT Y) -)) - -# SoundBlaster - -(CONFIGURE CMI0001/16777472 (LD 3 -(IO 0 (SIZE 16) (BASE 0x0220)) -(INT 0 (IRQ 5 (MODE +E))) -(DMA 0 (CHANNEL 1)) -(DMA 1 (CHANNEL 5)) -(NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}") -(ACT Y) -)) - - -(WAITFORKEY) - -<end of snip> - - The module sequence is trivial: - -/sbin/insmod soundcore -/sbin/insmod sound -/sbin/insmod uart401 -# insert this first -/sbin/insmod ad1848 io=0x530 irq=7 dma=0 soundpro=1 -# The sb module is an alternative to the ad1848 (Microsoft Sound System) -# Anyhow, this is full duplex and has MIDI -/sbin/insmod sb io=0x220 dma=1 dma16=5 irq=5 mpu_io=0x330 - - - -Alma Chao <elysian@ethereal.torsion.org> suggests the following in -a /etc/modprobe.d/*conf file: - -alias sound ad1848 -alias synth0 opl3 -options ad1848 io=0x530 irq=7 dma=0 soundpro=1 -options opl3 io=0x388 diff --git a/Documentation/sound/oss/ESS b/Documentation/sound/oss/ESS deleted file mode 100644 index bba93b4d2def..000000000000 --- a/Documentation/sound/oss/ESS +++ /dev/null @@ -1,34 +0,0 @@ -Documentation for the ESS AudioDrive chips - -In 2.4 kernels the SoundBlaster driver not only tries to detect an ESS chip, it -tries to detect the type of ESS chip too. The correct detection of the chip -doesn't always succeed however, so unless you use the kernel isapnp facilities -(and you chip is pnp capable) the default behaviour is 2.0 behaviour which -means: only detect ES688 and ES1688. - -All ESS chips now have a recording level setting. This is a need-to-have for -people who want to use their ESS for recording sound. - -Every chip that's detected as a later-than-es1688 chip has a 6 bits logarithmic -master volume control. - -Every chip that's detected as a ES1887 now has Full Duplex support. Made a -little testprogram that shows that is works, haven't seen a real program that -needs this however. - -For ESS chips an additional parameter "esstype" can be specified. This controls -the (auto) detection of the ESS chips. It can have 3 kinds of values: - --1 Act like 2.0 kernels: only detect ES688 or ES1688. -0 Try to auto-detect the chip (may fail for ES1688) -688 The chip will be treated as ES688 -1688 ,, ,, ,, ,, ,, ,, ES1688 -1868 ,, ,, ,, ,, ,, ,, ES1868 -1869 ,, ,, ,, ,, ,, ,, ES1869 -1788 ,, ,, ,, ,, ,, ,, ES1788 -1887 ,, ,, ,, ,, ,, ,, ES1887 -1888 ,, ,, ,, ,, ,, ,, ES1888 - -Because Full Duplex is supported for ES1887 you can specify a second DMA -channel by specifying module parameter dma16. It can be one of: 0, 1, 3 or 5. - diff --git a/Documentation/sound/oss/ESS1868 b/Documentation/sound/oss/ESS1868 deleted file mode 100644 index 55e922f21bc0..000000000000 --- a/Documentation/sound/oss/ESS1868 +++ /dev/null @@ -1,55 +0,0 @@ -Documentation for the ESS1868F AudioDrive PnP sound card - -The ESS1868 sound card is a PnP ESS1688-compatible 16-bit sound card. - -It should be automatically detected by the Linux Kernel isapnp support when you -load the sb.o module. Otherwise you should take care of: - - * The ESS1868 does not allow use of a 16-bit DMA, thus DMA 0, 1, 2, and 3 - may only be used. - - * isapnptools version 1.14 does work with ESS1868. Earlier versions might - not. - - * Sound support MUST be compiled as MODULES, not statically linked - into the kernel. - - -NOTE: this is only needed when not using the kernel isapnp support! - -For configuring the sound card's I/O addresses, IRQ and DMA, here is a -sample copy of the isapnp.conf directives regarding the ESS1868: - -(CONFIGURE ESS1868/-1 (LD 1 -(IO 0 (BASE 0x0220)) -(IO 1 (BASE 0x0388)) -(IO 2 (BASE 0x0330)) -(DMA 0 (CHANNEL 1)) -(INT 0 (IRQ 5 (MODE +E))) -(ACT Y) -)) - -(for a full working isapnp.conf file, remember the -(ISOLATE) -(IDENTIFY *) -at the beginning and the -(WAITFORKEY) -at the end.) - -In this setup, the main card I/O is 0x0220, FM synthesizer is 0x0388, and -the MPU-401 MIDI port is located at 0x0330. IRQ is IRQ 5, DMA is channel 1. - -After configuring the sound card via isapnp, to use the card you must load -the sound modules with the proper I/O information. Here is my setup: - -# ESS1868F AudioDrive initialization - -/sbin/modprobe sound -/sbin/insmod uart401 -/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1 -/sbin/insmod mpu401 io=0x330 -/sbin/insmod opl3 io=0x388 -/sbin/insmod v_midi - -opl3 is the FM synthesizer -/sbin/insmod opl3 io=0x388 diff --git a/Documentation/sound/oss/Introduction b/Documentation/sound/oss/Introduction deleted file mode 100644 index 42da2d8fa372..000000000000 --- a/Documentation/sound/oss/Introduction +++ /dev/null @@ -1,459 +0,0 @@ -Introduction Notes on Modular Sound Drivers and Soundcore -Wade Hampton -2/14/2001 - -Purpose: -======== -This document provides some general notes on the modular -sound drivers and their configuration, along with the -support modules sound.o and soundcore.o. - -Note, some of this probably should be added to the Sound-HOWTO! - -Note, soundlow.o was present with 2.2 kernels but is not -required for 2.4.x kernels. References have been removed -to this. - - -Copying: -======== -none - - -History: -======== -0.1.0 11/20/1998 First version, draft -1.0.0 11/1998 Alan Cox changes, incorporation in 2.2.0 - as Documentation/sound/oss/Introduction -1.1.0 6/30/1999 Second version, added notes on making the drivers, - added info on multiple sound cards of similar types,] - added more diagnostics info, added info about esd. - added info on OSS and ALSA. -1.1.1 19991031 Added notes on sound-slot- and sound-service. - (Alan Cox) -1.1.2 20000920 Modified for Kernel 2.4 (Christoph Hellwig) -1.1.3 20010214 Minor notes and corrections (Wade Hampton) - Added examples of sound-slot-0, etc. - - -Modular Sound Drivers: -====================== - -Thanks to the GREAT work by Alan Cox (alan@lxorguk.ukuu.org.uk), - -[And Oleg Drokin, Thomas Sailer, Andrew Veliath and more than a few - others - not to mention Hannu's original code being designed well - enough to cope with that kind of chopping up](Alan) - -the standard Linux kernels support a modular sound driver. From -Alan's comments in linux/drivers/sound/README.FIRST: - - The modular sound driver patches were 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. - -The modular sound drivers may be loaded via insmod or modprobe. -To support all the various sound modules, there are two general -support modules that must be loaded first: - - soundcore.o: Top level handler for the sound system, provides - a set of functions for registration of devices - by type. - - sound.o: Common sound functions required by all modules. - -For the specific sound modules (e.g., sb.o for the Soundblaster), -read the documentation on that module to determine what options -are available, for example IRQ, address, DMA. - -Warning, the options for different cards sometime use different names -for the same or a similar feature (dma1= versus dma16=). As a last -resort, inspect the code (search for module_param). - -Notes: - -1. There is a new OpenSource sound driver called ALSA which is - currently under development: http://www.alsa-project.org/ - The ALSA drivers support some newer hardware that may not - be supported by this sound driver and also provide some - additional features. - -2. The commercial OSS driver may be obtained from the site: - http://www.opensound.com. This may be used for cards that - are unsupported by the kernel driver, or may be used - by other operating systems. - -3. The enlightenment sound daemon may be used for playing - multiple sounds at the same time via a single card, eliminating - some of the requirements for multiple sound card systems. For - more information, see: http://www.tux.org/~ricdude/EsounD.html - The "esd" program may be used with the real-player and mpeg - players like mpg123 and x11amp. The newer real-player - and some games even include built-in support for ESD! - - -Building the Modules: -===================== - -This document does not provide full details on building the -kernel, etc. The notes below apply only to making the kernel -sound modules. If this conflicts with the kernel's README, -the README takes precedence. - -1. To make the kernel sound modules, cd to your /usr/src/linux - directory (typically) and type make config, make menuconfig, - or make xconfig (to start the command line, dialog, or x-based - configuration tool). - -2. Select the Sound option and a dialog will be displayed. - -3. Select M (module) for "Sound card support". - -4. Select your sound driver(s) as a module. For ProAudio, Sound - Blaster, etc., select M (module) for OSS sound modules. - [thanks to Marvin Stodolsky <stodolsk@erols.com>]A - -5. Make the kernel (e.g., make bzImage), and install the kernel. - -6. Make the modules and install them (make modules; make modules_install). - -Note, for 2.5.x kernels, make sure you have the newer module-init-tools -installed or modules will not be loaded properly. 2.5.x requires an -updated module-init-tools. - - -Plug and Play (PnP: -=================== - -If the sound card is an ISA PnP card, isapnp may be used -to configure the card. See the file isapnp.txt in the -directory one level up (e.g., /usr/src/linux/Documentation). - -Also the 2.4.x kernels provide PnP capabilities, see the -file NEWS in this directory. - -PCI sound cards are highly recommended, as they are far -easier to configure and from what I have read, they use -less resources and are more CPU efficient. - - -INSMOD: -======= - -If loading via insmod, the common modules must be loaded in the -order below BEFORE loading the other sound modules. The card-specific -modules may then be loaded (most require parameters). For example, -I use the following via a shell script to load my SoundBlaster: - -SB_BASE=0x240 -SB_IRQ=9 -SB_DMA=3 -SB_DMA2=5 -SB_MPU=0x300 -# -echo Starting sound -/sbin/insmod soundcore -/sbin/insmod sound -# -echo Starting sound blaster.... -/sbin/insmod uart401 -/sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP - -When using sound as a module, I typically put these commands -in a file such as /root/soundon.sh. - - -MODPROBE: -========= - -If loading via modprobe, these common files are automatically loaded when -requested by modprobe. For example, my /etc/modprobe.d/oss.conf contains: - -alias sound sb -options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300 - -All you need to do to load the module is: - - /sbin/modprobe sb - - -Sound Status: -============= - -The status of sound may be read/checked by: - cat (anyfile).au >/dev/audio - -[WWH: This may not work properly for SoundBlaster PCI 128 cards -such as the es1370/1 (see the es1370/1 files in this directory) -as they do not automatically support uLaw on /dev/audio.] - -The status of the modules and which modules depend on -which other modules may be checked by: - /sbin/lsmod - -/sbin/lsmod should show something like the following: - sb 26280 0 - uart401 5640 0 [sb] - sound 57112 0 [sb uart401] - soundcore 1968 8 [sb sound] - - -Removing Sound: -=============== - -Sound may be removed by using /sbin/rmmod in the reverse order -in which you load the modules. Note, if a program has a sound device -open (e.g., xmixer), that module (and the modules on which it -depends) may not be unloaded. - -For example, I use the following to remove my Soundblaster (rmmod -in the reverse order in which I loaded the modules): - -/sbin/rmmod sb -/sbin/rmmod uart401 -/sbin/rmmod sound -/sbin/rmmod soundcore - -When using sound as a module, I typically put these commands -in a script such as /root/soundoff.sh. - - -Removing Sound for use with OSS: -================================ - -If you get really stuck or have a card that the kernel modules -will not support, you can get a commercial sound driver from -http://www.opensound.com. Before loading the commercial sound -driver, you should do the following: - -1. remove sound modules (detailed above) -2. remove the sound modules from /etc/modprobe.d/*.conf -3. move the sound modules from /lib/modules/<kernel>/misc - (for example, I make a /lib/modules/<kernel>/misc/tmp - directory and copy the sound module files to that - directory). - - -Multiple Sound Cards: -===================== - -The sound drivers will support multiple sound cards and there -are some great applications like multitrack that support them. -Typically, you need two sound cards of different types. Note, this -uses more precious interrupts and DMA channels and sometimes -can be a configuration nightmare. I have heard reports of 3-4 -sound cards (typically I only use 2). You can sometimes use -multiple PCI sound cards of the same type. - -On my machine I have two sound cards (cs4232 and Soundblaster Vibra -16). By loading sound as modules, I can control which is the first -sound device (/dev/dsp, /dev/audio, /dev/mixer) and which is -the second. Normally, the cs4232 (Dell sound on the motherboard) -would be the first sound device, but I prefer the Soundblaster. -All you have to do is to load the one you want as /dev/dsp -first (in my case "sb") and then load the other one -(in my case "cs4232"). - -If you have two cards of the same type that are jumpered -cards or different PnP revisions, you may load the same -module twice. For example, I have a SoundBlaster vibra 16 -and an older SoundBlaster 16 (jumpers). To load the module -twice, you need to do the following: - -1. Copy the sound modules to a new name. For example - sb.o could be copied (or symlinked) to sb1.o for the - second SoundBlaster. - -2. Make a second entry in /etc/modprobe.d/*conf, for example, - sound1 or sb1. This second entry should refer to the - new module names for example sb1, and should include - the I/O, etc. for the second sound card. - -3. Update your soundon.sh script, etc. - -Warning: I have never been able to get two PnP sound cards of the -same type to load at the same time. I have tried this several times -with the Soundblaster Vibra 16 cards. OSS has indicated that this -is a PnP problem.... If anyone has any luck doing this, please -send me an E-MAIL. PCI sound cards should not have this problem.a -Since this was originally release, I have received a couple of -mails from people who have accomplished this! - -NOTE: In Linux 2.4 the Sound Blaster driver (and only this one yet) -supports multiple cards with one module by default. -Read the file 'Soundblaster' in this directory for details. - - -Sound Problems: -=============== - -First RTFM (including the troubleshooting section -in the Sound-HOWTO). - -1) If you are having problems loading the modules (for - example, if you get device conflict errors) try the - following: - - A) If you have Win95 or NT on the same computer, - write down what addresses, IRQ, and DMA channels - those were using for the same hardware. You probably - can use these addresses, IRQs, and DMA channels. - You should really do this BEFORE attempting to get - sound working! - - B) Check (cat) /proc/interrupts, /proc/ioports, - and /proc/dma. Are you trying to use an address, - IRQ or DMA port that another device is using? - - C) Check (cat) /proc/isapnp - - D) Inspect your /var/log/messages file. Often that will - indicate what IRQ or IO port could not be obtained. - - E) Try another port or IRQ. Note this may involve - using the PnP tools to move the sound card to - another location. Sometimes this is the only way - and it is more or less trial and error. - -2) If you get motor-boating (the same sound or part of a - sound clip repeated), you probably have either an IRQ - or DMA conflict. Move the card to another IRQ or DMA - port. This has happened to me when playing long files - when I had an IRQ conflict. - -3. If you get dropouts or pauses when playing high sample - rate files such as using mpg123 or x11amp/xmms, you may - have too slow of a CPU and may have to use the options to - play the files at 1/2 speed. For example, you may use - the -2 or -4 option on mpg123. You may also get this - when trying to play mpeg files stored on a CD-ROM - (my Toshiba T8000 PII/366 sometimes has this problem). - -4. If you get "cannot access device" errors, your /dev/dsp - files, etc. may be set to owner root, mode 600. You - may have to use the command: - chmod 666 /dev/dsp /dev/mixer /dev/audio - -5. If you get "device busy" errors, another program has the - sound device open. For example, if using the Enlightenment - sound daemon "esd", the "esd" program has the sound device. - If using "esd", please RTFM the docs on ESD. For example, - esddsp <program> may be used to play files via a non-esd - aware program. - -6) Ask for help on the sound list or send E-MAIL to the - sound driver author/maintainer. - -7) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). - -8) If the system reports insufficient DMA memory then you may want to - load sound with the "dmabufs=1" option. Or in /etc/conf.modules add - - preinstall sound dmabufs=1 - - This makes the sound system allocate its buffers and hang onto them. - - You may also set persistent DMA when building a 2.4.x kernel. - - -Configuring Sound: -================== - -There are several ways of configuring your sound: - -1) On the kernel command line (when using the sound driver(s) - compiled in the kernel). Check the driver source and - documentation for details. - -2) On the command line when using insmod or in a bash script - using command line calls to load sound. - -3) In /etc/modprobe.d/*conf when using modprobe. - -4) Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based). - -5) Via the OSS soundconf program (with the commercial version - of the OSS driver. - -6) By just loading the module and let isapnp do everything relevant - for you. This works only with a few drivers yet and - of course - - only with isapnp hardware. - -And I am sure, several other ways. - -Anyone want to write a linuxconf module for configuring sound? - - -Module Loading: -=============== - -When a sound card is first referenced and sound is modular, the sound system -will ask for the sound devices to be loaded. Initially it requests that -the driver for the sound system is loaded. It then will ask for -sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and -so on). Thus you can do - -alias sound-slot-0 sb - -To load a soundblaster at this point. If the slot loading does not provide -the desired device - for example a soundblaster does not directly provide -a midi synth in all cases then it will request "sound-service-0-n" where n -is - - 0 Mixer - - 2 MIDI - - 3, 4 DSP audio - - -For example, I use the following to load my Soundblaster PCI 128 -(ES 1371) card first, followed by my SoundBlaster Vibra 16 card, -then by my TV card: - -# Load the Soundblaster PCI 128 as /dev/dsp, /dev/dsp1, /dev/mixer -alias sound-slot-0 es1371 - -# Load the Soundblaster Vibra 16 as /dev/dsp2, /dev/mixer1 -alias sound-slot-1 sb -options sb io=0x240 irq=5 dma=1 dma16=5 mpu_io=0x330 - -# Load the BTTV (TV card) as /dev/mixer2 -alias sound-slot-2 bttv -alias sound-service-2-0 tvmixer - -pre-install bttv modprobe tuner ; modprobe tvmixer -pre-install tvmixer modprobe msp3400; modprobe tvaudio -options tuner debug=0 type=8 -options bttv card=0 radio=0 pll=0 - - -For More Information (RTFM): -============================ -1) Information on kernel modules: manual pages for insmod and modprobe. - -2) Information on PnP, RTFM manual pages for isapnp. - -3) Sound-HOWTO and Sound-Playing-HOWTO. - -4) OSS's WWW site at http://www.opensound.com. - -5) All the files in Documentation/sound. - -6) The comments and code in linux/drivers/sound. - -7) The sndconfig and rhsound documentation from Red Hat. - -8) The Linux-sound mailing list: sound-list@redhat.com. - -9) Enlightenment documentation (for info on esd) - http://www.tux.org/~ricdude/EsounD.html. - -10) ALSA home page: http://www.alsa-project.org/ - - -Contact Information: -==================== -Wade Hampton: (whampton@staffnet.com) - diff --git a/Documentation/sound/oss/MultiSound b/Documentation/sound/oss/MultiSound deleted file mode 100644 index e4a18bb7f73a..000000000000 --- a/Documentation/sound/oss/MultiSound +++ /dev/null @@ -1,1137 +0,0 @@ -#! /bin/sh -# -# Turtle Beach MultiSound Driver Notes -# -- Andrew Veliath <andrewtv@usa.net> -# -# Last update: September 10, 1998 -# Corresponding msnd driver: 0.8.3 -# -# ** This file is a README (top part) and shell archive (bottom part). -# The corresponding archived utility sources can be unpacked by -# running `sh MultiSound' (the utilities are only needed for the -# Pinnacle and Fiji cards). ** -# -# -# -=-=- Getting Firmware -=-=- -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# See the section `Obtaining and Creating Firmware Files' in this -# document for instructions on obtaining the necessary firmware -# files. -# -# -# Supported Features -# ~~~~~~~~~~~~~~~~~~ -# -# Currently, full-duplex digital audio (/dev/dsp only, /dev/audio is -# not currently available) and mixer functionality (/dev/mixer) are -# supported (memory mapped digital audio is not yet supported). -# Digital transfers and monitoring can be done as well if you have -# the digital daughterboard (see the section on using the S/PDIF port -# for more information). -# -# Support for the Turtle Beach MultiSound Hurricane architecture is -# composed of the following modules (these can also operate compiled -# into the kernel): -# -# msnd - MultiSound base (requires soundcore) -# -# msnd_classic - Base audio/mixer support for Classic, Monetery and -# Tahiti cards -# -# msnd_pinnacle - Base audio/mixer support for Pinnacle and Fiji cards -# -# -# Important Notes - Read Before Using -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# The firmware files are not included (may change in future). You -# must obtain these images from Turtle Beach (they are included in -# the MultiSound Development Kits), and place them in /etc/sound for -# example, and give the full paths in the Linux configuration. If -# you are compiling in support for the MultiSound driver rather than -# using it as a module, these firmware files must be accessible -# during kernel compilation. -# -# Please note these files must be binary files, not assembler. See -# the section later in this document for instructions to obtain these -# files. -# -# -# Configuring Card Resources -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# ** This section is very important, as your card may not work at all -# or your machine may crash if you do not do this correctly. ** -# -# * Classic/Monterey/Tahiti -# -# These cards are configured through the driver msnd_classic. You must -# know the io port, then the driver will select the irq and memory resources -# on the card. It is up to you to know if these are free locations or now, -# a conflict can lock the machine up. -# -# * Pinnacle/Fiji -# -# The Pinnacle and Fiji cards have an extra config port, either -# 0x250, 0x260 or 0x270. This port can be disabled to have the card -# configured strictly through PnP, however you lose the ability to -# access the IDE controller and joystick devices on this card when -# using PnP. The included pinnaclecfg program in this shell archive -# can be used to configure the card in non-PnP mode, and in PnP mode -# you can use isapnptools. These are described briefly here. -# -# pinnaclecfg is not required; you can use the msnd_pinnacle module -# to fully configure the card as well. However, pinnaclecfg can be -# used to change the resource values of a particular device after the -# msnd_pinnacle module has been loaded. If you are compiling the -# driver into the kernel, you must set these values during compile -# time, however other peripheral resource values can be changed with -# the pinnaclecfg program after the kernel is loaded. -# -# -# *** PnP mode -# -# Use pnpdump to obtain a sample configuration if you can; I was able -# to obtain one with the command `pnpdump 1 0x203' -- this may vary -# for you (running pnpdump by itself did not work for me). Then, -# edit this file and use isapnp to uncomment and set the card values. -# Use these values when inserting the msnd_pinnacle module. Using -# this method, you can set the resources for the DSP and the Kurzweil -# synth (Pinnacle). Since Linux does not directly support PnP -# devices, you may have difficulty when using the card in PnP mode -# when it the driver is compiled into the kernel. Using non-PnP mode -# is preferable in this case. -# -# Here is an example mypinnacle.conf for isapnp that sets the card to -# io base 0x210, irq 5 and mem 0xd8000, and also sets the Kurzweil -# synth to 0x330 and irq 9 (may need editing for your system): -# -# (READPORT 0x0203) -# (CSN 2) -# (IDENTIFY *) -# -# # DSP -# (CONFIGURE BVJ0440/-1 (LD 0 -# (INT 0 (IRQ 5 (MODE +E))) (IO 0 (BASE 0x0210)) (MEM 0 (BASE 0x0d8000)) -# (ACT Y))) -# -# # Kurzweil Synth (Pinnacle Only) -# (CONFIGURE BVJ0440/-1 (LD 1 -# (IO 0 (BASE 0x0330)) (INT 0 (IRQ 9 (MODE +E))) -# (ACT Y))) -# -# (WAITFORKEY) -# -# -# *** Non-PnP mode -# -# The second way is by running the card in non-PnP mode. This -# actually has some advantages in that you can access some other -# devices on the card, such as the joystick and IDE controller. To -# configure the card, unpack this shell archive and build the -# pinnaclecfg program. Using this program, you can assign the -# resource values to the card's devices, or disable the devices. As -# an alternative to using pinnaclecfg, you can specify many of the -# configuration values when loading the msnd_pinnacle module (or -# during kernel configuration when compiling the driver into the -# kernel). -# -# If you specify cfg=0x250 for the msnd_pinnacle module, it -# automatically configure the card to the given io, irq and memory -# values using that config port (the config port is jumper selectable -# on the card to 0x250, 0x260 or 0x270). -# -# See the `msnd_pinnacle Additional Options' section below for more -# information on these parameters (also, if you compile the driver -# directly into the kernel, these extra parameters can be useful -# here). -# -# -# ** It is very easy to cause problems in your machine if you choose a -# resource value which is incorrect. ** -# -# -# Examples -# ~~~~~~~~ -# -# * MultiSound Classic/Monterey/Tahiti: -# -# modprobe soundcore -# insmod msnd -# insmod msnd_classic io=0x290 irq=7 mem=0xd0000 -# -# * MultiSound Pinnacle in PnP mode: -# -# modprobe soundcore -# insmod msnd -# isapnp mypinnacle.conf -# insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values -# -# * MultiSound Pinnacle in non-PnP mode (replace 0x250 with your configuration port, -# one of 0x250, 0x260 or 0x270): -# -# insmod soundcore -# insmod msnd -# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 -# -# * To use the MPU-compatible Kurzweil synth on the Pinnacle in PnP -# mode, add the following (assumes you did `isapnp mypinnacle.conf'): -# -# insmod sound -# insmod mpu401 io=0x330 irq=9 <-- match mypinnacle.conf values -# -# * To use the MPU-compatible Kurzweil synth on the Pinnacle in non-PnP -# mode, add the following. Note how we first configure the peripheral's -# resources, _then_ install a Linux driver for it: -# -# insmod sound -# pinnaclecfg 0x250 mpu 0x330 9 -# insmod mpu401 io=0x330 irq=9 -# -# -- OR you can use the following sequence without pinnaclecfg in non-PnP mode: -# -# insmod soundcore -# insmod msnd -# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 mpu_io=0x330 mpu_irq=9 -# insmod sound -# insmod mpu401 io=0x330 irq=9 -# -# * To setup the joystick port on the Pinnacle in non-PnP mode (though -# you have to find the actual Linux joystick driver elsewhere), you -# can use pinnaclecfg: -# -# pinnaclecfg 0x250 joystick 0x200 -# -# -- OR you can configure this using msnd_pinnacle with the following: -# -# insmod soundcore -# insmod msnd -# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 joystick_io=0x200 -# -# -# msnd_classic, msnd_pinnacle Required Options -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# If the following options are not given, the module will not load. -# Examine the kernel message log for informative error messages. -# WARNING--probing isn't supported so try to make sure you have the -# correct shared memory area, otherwise you may experience problems. -# -# io I/O base of DSP, e.g. io=0x210 -# irq IRQ number, e.g. irq=5 -# mem Shared memory area, e.g. mem=0xd8000 -# -# -# msnd_classic, msnd_pinnacle Additional Options -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# fifosize The digital audio FIFOs, in kilobytes. If not -# specified, the default will be used. Increasing -# this value will reduce the chance of a FIFO -# underflow at the expense of increasing overall -# latency. For example, fifosize=512 will -# allocate 512kB read and write FIFOs (1MB total). -# While this may reduce dropouts, a heavy machine -# load will undoubtedly starve the FIFO of data -# and you will eventually get dropouts. One -# option is to alter the scheduling priority of -# the playback process, using `nice' or some form -# of POSIX soft real-time scheduling. -# -# calibrate_signal Setting this to one calibrates the ADCs to the -# signal, zero calibrates to the card (defaults -# to zero). -# -# -# msnd_pinnacle Additional Options -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# digital Specify digital=1 to enable the S/PDIF input -# if you have the digital daughterboard -# adapter. This will enable access to the -# DIGITAL1 input for the soundcard in the mixer. -# Some mixer programs might have trouble setting -# the DIGITAL1 source as an input. If you have -# trouble, you can try the setdigital.c program -# at the bottom of this document. -# -# cfg Non-PnP configuration port for the Pinnacle -# and Fiji (typically 0x250, 0x260 or 0x270, -# depending on the jumper configuration). If -# this option is omitted, then it is assumed -# that the card is in PnP mode, and that the -# specified DSP resource values are already -# configured with PnP (i.e. it won't attempt to -# do any sort of configuration). -# -# When the Pinnacle is in non-PnP mode, you can use the following -# options to configure particular devices. If a full specification -# for a device is not given, then the device is not configured. Note -# that you still must use a Linux driver for any of these devices -# once their resources are setup (such as the Linux joystick driver, -# or the MPU401 driver from OSS for the Kurzweil synth). -# -# mpu_io I/O port of MPU (on-board Kurzweil synth) -# mpu_irq IRQ of MPU (on-board Kurzweil synth) -# ide_io0 First I/O port of IDE controller -# ide_io1 Second I/O port of IDE controller -# ide_irq IRQ IDE controller -# joystick_io I/O port of joystick -# -# -# Obtaining and Creating Firmware Files -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# For the Classic/Tahiti/Monterey -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# Download to /tmp and unzip the following file from Turtle Beach: -# -# ftp://ftp.voyetra.com/pub/tbs/msndcl/msndvkit.zip -# -# When unzipped, unzip the file named MsndFiles.zip. Then copy the -# following firmware files to /etc/sound (note the file renaming): -# -# cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin -# cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin -# -# When configuring the Linux kernel, specify /etc/sound/msndinit.bin and -# /etc/sound/msndperm.bin for the two firmware files (Linux kernel -# versions older than 2.2 do not ask for firmware paths, and are -# hardcoded to /etc/sound). -# -# If you are compiling the driver into the kernel, these files must -# be accessible during compilation, but will not be needed later. -# The files must remain, however, if the driver is used as a module. -# -# -# For the Pinnacle/Fiji -# ~~~~~~~~~~~~~~~~~~~~~ -# -# Download to /tmp and unzip the following file from Turtle Beach (be -# sure to use the entire URL; some have had trouble navigating to the -# URL): -# -# ftp://ftp.voyetra.com/pub/tbs/pinn/pnddk100.zip -# -# Unpack this shell archive, and run make in the created directory -# (you need a C compiler and flex to build the utilities). This -# should give you the executables conv, pinnaclecfg and setdigital. -# conv is only used temporarily here to create the firmware files, -# while pinnaclecfg is used to configure the Pinnacle or Fiji card in -# non-PnP mode, and setdigital can be used to set the S/PDIF input on -# the mixer (pinnaclecfg and setdigital should be copied to a -# convenient place, possibly run during system initialization). -# -# To generating the firmware files with the `conv' program, we create -# the binary firmware files by doing the following conversion -# (assuming the archive unpacked into a directory named PINNDDK): -# -# ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin -# ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin -# -# The conv (and conv.l) program is not needed after conversion and can -# be safely deleted. Then, when configuring the Linux kernel, specify -# /etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two -# firmware files (Linux kernel versions older than 2.2 do not ask for -# firmware paths, and are hardcoded to /etc/sound). -# -# If you are compiling the driver into the kernel, these files must -# be accessible during compilation, but will not be needed later. -# The files must remain, however, if the driver is used as a module. -# -# -# Using Digital I/O with the S/PDIF Port -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# If you have a Pinnacle or Fiji with the digital daughterboard and -# want to set it as the input source, you can use this program if you -# have trouble trying to do it with a mixer program (be sure to -# insert the module with the digital=1 option, or say Y to the option -# during compiled-in kernel operation). Upon selection of the S/PDIF -# port, you should be able monitor and record from it. -# -# There is something to note about using the S/PDIF port. Digital -# timing is taken from the digital signal, so if a signal is not -# connected to the port and it is selected as recording input, you -# will find PCM playback to be distorted in playback rate. Also, -# attempting to record at a sampling rate other than the DAT rate may -# be problematic (i.e. trying to record at 8000Hz when the DAT signal -# is 44100Hz). If you have a problem with this, set the recording -# input to analog if you need to record at a rate other than that of -# the DAT rate. -# -# -# -- Shell archive attached below, just run `sh MultiSound' to extract. -# Contains Pinnacle/Fiji utilities to convert firmware, configure -# in non-PnP mode, and select the DIGITAL1 input for the mixer. -# -# -#!/bin/sh -# This is a shell archive (produced by GNU sharutils 4.2). -# To extract the files from this archive, save it to some FILE, remove -# everything before the `!/bin/sh' line above, then type `sh FILE'. -# -# Made on 1998-12-04 10:07 EST by <andrewtv@ztransform.velsoft.com>. -# Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'. -# -# Existing files will *not* be overwritten unless `-c' is specified. -# -# This shar contains: -# length mode name -# ------ ---------- ------------------------------------------ -# 2046 -rw-rw-r-- MultiSound.d/setdigital.c -# 10235 -rw-rw-r-- MultiSound.d/pinnaclecfg.c -# 106 -rw-rw-r-- MultiSound.d/Makefile -# 141 -rw-rw-r-- MultiSound.d/conv.l -# 1472 -rw-rw-r-- MultiSound.d/msndreset.c -# -save_IFS="${IFS}" -IFS="${IFS}:" -gettext_dir=FAILED -locale_dir=FAILED -first_param="$1" -for dir in $PATH -do - if test "$gettext_dir" = FAILED && test -f $dir/gettext \ - && ($dir/gettext --version >/dev/null 2>&1) - then - set `$dir/gettext --version 2>&1` - if test "$3" = GNU - then - gettext_dir=$dir - fi - fi - if test "$locale_dir" = FAILED && test -f $dir/shar \ - && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) - then - locale_dir=`$dir/shar --print-text-domain-dir` - fi -done -IFS="$save_IFS" -if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED -then - echo=echo -else - TEXTDOMAINDIR=$locale_dir - export TEXTDOMAINDIR - TEXTDOMAIN=sharutils - export TEXTDOMAIN - echo="$gettext_dir/gettext -s" -fi -touch -am 1231235999 $$.touch >/dev/null 2>&1 -if test ! -f 1231235999 && test -f $$.touch; then - shar_touch=touch -else - shar_touch=: - echo - $echo 'WARNING: not restoring timestamps. Consider getting and' - $echo "installing GNU \`touch', distributed in GNU File Utilities..." - echo -fi -rm -f 1231235999 $$.touch -# -if mkdir _sh01426; then - $echo 'x -' 'creating lock directory' -else - $echo 'failed to create lock directory' - exit 1 -fi -# ============= MultiSound.d/setdigital.c ============== -if test ! -d 'MultiSound.d'; then - $echo 'x -' 'creating directory' 'MultiSound.d' - mkdir 'MultiSound.d' -fi -if test -f 'MultiSound.d/setdigital.c' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'MultiSound.d/setdigital.c' '(file already exists)' -else - $echo 'x -' extracting 'MultiSound.d/setdigital.c' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/setdigital.c' && -/********************************************************************* -X * -X * setdigital.c - sets the DIGITAL1 input for a mixer -X * -X * Copyright (C) 1998 Andrew Veliath -X * -X * This program is free software; you can redistribute it and/or modify -X * it under the terms of the GNU General Public License as published by -X * the Free Software Foundation; either version 2 of the License, or -X * (at your option) any later version. -X * -X * This program is distributed in the hope that it will be useful, -X * but WITHOUT ANY WARRANTY; without even the implied warranty of -X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -X * GNU General Public License for more details. -X * -X * You should have received a copy of the GNU General Public License -X * along with this program; if not, write to the Free Software -X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -X * -X ********************************************************************/ -X -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/soundcard.h> -X -int main(int argc, char *argv[]) -{ -X int fd; -X unsigned long recmask, recsrc; -X -X if (argc != 2) { -X fprintf(stderr, "usage: setdigital <mixer device>\n"); -X exit(1); -X } -X -X if ((fd = open(argv[1], O_RDWR)) < 0) { -X perror(argv[1]); -X exit(1); -X } -X -X if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) { -X fprintf(stderr, "error: ioctl read recording mask failed\n"); -X perror("ioctl"); -X close(fd); -X exit(1); -X } -X -X if (!(recmask & SOUND_MASK_DIGITAL1)) { -X fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n"); -X close(fd); -X exit(1); -X } -X -X if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) { -X fprintf(stderr, "error: ioctl read recording source failed\n"); -X perror("ioctl"); -X close(fd); -X exit(1); -X } -X -X recsrc |= SOUND_MASK_DIGITAL1; -X -X if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) { -X fprintf(stderr, "error: ioctl write recording source failed\n"); -X perror("ioctl"); -X close(fd); -X exit(1); -X } -X -X close(fd); -X -X return 0; -} -SHAR_EOF - $shar_touch -am 1204092598 'MultiSound.d/setdigital.c' && - chmod 0664 'MultiSound.d/setdigital.c' || - $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed' -e87217fc3e71288102ba41fd81f71ec4 MultiSound.d/setdigital.c -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`" - test 2046 -eq "$shar_count" || - $echo 'MultiSound.d/setdigital.c:' 'original size' '2046,' 'current size' "$shar_count!" - fi -fi -# ============= MultiSound.d/pinnaclecfg.c ============== -if test -f 'MultiSound.d/pinnaclecfg.c' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'MultiSound.d/pinnaclecfg.c' '(file already exists)' -else - $echo 'x -' extracting 'MultiSound.d/pinnaclecfg.c' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/pinnaclecfg.c' && -/********************************************************************* -X * -X * pinnaclecfg.c - Pinnacle/Fiji Device Configuration Program -X * -X * This is for NON-PnP mode only. For PnP mode, use isapnptools. -X * -X * This is Linux-specific, and must be run with root permissions. -X * -X * Part of the Turtle Beach MultiSound Sound Card Driver for Linux -X * -X * Copyright (C) 1998 Andrew Veliath -X * -X * This program is free software; you can redistribute it and/or modify -X * it under the terms of the GNU General Public License as published by -X * the Free Software Foundation; either version 2 of the License, or -X * (at your option) any later version. -X * -X * This program is distributed in the hope that it will be useful, -X * but WITHOUT ANY WARRANTY; without even the implied warranty of -X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -X * GNU General Public License for more details. -X * -X * You should have received a copy of the GNU General Public License -X * along with this program; if not, write to the Free Software -X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -X * -X ********************************************************************/ -X -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <asm/io.h> -#include <asm/types.h> -X -#define IREG_LOGDEVICE 0x07 -#define IREG_ACTIVATE 0x30 -#define LD_ACTIVATE 0x01 -#define LD_DISACTIVATE 0x00 -#define IREG_EECONTROL 0x3F -#define IREG_MEMBASEHI 0x40 -#define IREG_MEMBASELO 0x41 -#define IREG_MEMCONTROL 0x42 -#define IREG_MEMRANGEHI 0x43 -#define IREG_MEMRANGELO 0x44 -#define MEMTYPE_8BIT 0x00 -#define MEMTYPE_16BIT 0x02 -#define MEMTYPE_RANGE 0x00 -#define MEMTYPE_HIADDR 0x01 -#define IREG_IO0_BASEHI 0x60 -#define IREG_IO0_BASELO 0x61 -#define IREG_IO1_BASEHI 0x62 -#define IREG_IO1_BASELO 0x63 -#define IREG_IRQ_NUMBER 0x70 -#define IREG_IRQ_TYPE 0x71 -#define IRQTYPE_HIGH 0x02 -#define IRQTYPE_LOW 0x00 -#define IRQTYPE_LEVEL 0x01 -#define IRQTYPE_EDGE 0x00 -X -#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) -#define LOBYTE(w) ((BYTE)(w)) -#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8))) -X -typedef __u8 BYTE; -typedef __u16 USHORT; -typedef __u16 WORD; -X -static int config_port = -1; -X -static int msnd_write_cfg(int cfg, int reg, int value) -{ -X outb(reg, cfg); -X outb(value, cfg + 1); -X if (value != inb(cfg + 1)) { -X fprintf(stderr, "error: msnd_write_cfg: I/O error\n"); -X return -EIO; -X } -X return 0; -} -X -static int msnd_read_cfg(int cfg, int reg) -{ -X outb(reg, cfg); -X return inb(cfg + 1); -} -X -static int msnd_write_cfg_io0(int cfg, int num, WORD io) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io))) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io))) -X return -EIO; -X return 0; -} -X -static int msnd_read_cfg_io0(int cfg, int num, WORD *io) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X -X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO0_BASELO), -X msnd_read_cfg(cfg, IREG_IO0_BASEHI)); -X -X return 0; -} -X -static int msnd_write_cfg_io1(int cfg, int num, WORD io) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io))) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io))) -X return -EIO; -X return 0; -} -X -static int msnd_read_cfg_io1(int cfg, int num, WORD *io) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X -X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO1_BASELO), -X msnd_read_cfg(cfg, IREG_IO1_BASEHI)); -X -X return 0; -} -X -static int msnd_write_cfg_irq(int cfg, int num, WORD irq) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq))) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE)) -X return -EIO; -X return 0; -} -X -static int msnd_read_cfg_irq(int cfg, int num, WORD *irq) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X -X *irq = msnd_read_cfg(cfg, IREG_IRQ_NUMBER); -X -X return 0; -} -X -static int msnd_write_cfg_mem(int cfg, int num, int mem) -{ -X WORD wmem; -X -X mem >>= 8; -X mem &= 0xfff; -X wmem = (WORD)mem; -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem))) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem))) -X return -EIO; -X if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT))) -X return -EIO; -X return 0; -} -X -static int msnd_read_cfg_mem(int cfg, int num, int *mem) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X -X *mem = MAKEWORD(msnd_read_cfg(cfg, IREG_MEMBASELO), -X msnd_read_cfg(cfg, IREG_MEMBASEHI)); -X *mem <<= 8; -X -X return 0; -} -X -static int msnd_activate_logical(int cfg, int num) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE)) -X return -EIO; -X return 0; -} -X -static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_write_cfg_io0(cfg, num, io0)) -X return -EIO; -X if (msnd_write_cfg_io1(cfg, num, io1)) -X return -EIO; -X if (msnd_write_cfg_irq(cfg, num, irq)) -X return -EIO; -X if (msnd_write_cfg_mem(cfg, num, mem)) -X return -EIO; -X if (msnd_activate_logical(cfg, num)) -X return -EIO; -X return 0; -} -X -static int msnd_read_cfg_logical(int cfg, int num, WORD *io0, WORD *io1, WORD *irq, int *mem) -{ -X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) -X return -EIO; -X if (msnd_read_cfg_io0(cfg, num, io0)) -X return -EIO; -X if (msnd_read_cfg_io1(cfg, num, io1)) -X return -EIO; -X if (msnd_read_cfg_irq(cfg, num, irq)) -X return -EIO; -X if (msnd_read_cfg_mem(cfg, num, mem)) -X return -EIO; -X return 0; -} -X -static void usage(void) -{ -X fprintf(stderr, -X "\n" -X "pinnaclecfg 1.0\n" -X "\n" -X "usage: pinnaclecfg <config port> [device config]\n" -X "\n" -X "This is for use with the card in NON-PnP mode only.\n" -X "\n" -X "Available devices (not all available for Fiji):\n" -X "\n" -X " Device Description\n" -X " -------------------------------------------------------------------\n" -X " reset Reset all devices (i.e. disable)\n" -X " show Display current device configurations\n" -X "\n" -X " dsp <io> <irq> <mem> Audio device\n" -X " mpu <io> <irq> Internal Kurzweil synth\n" -X " ide <io0> <io1> <irq> On-board IDE controller\n" -X " joystick <io> Joystick port\n" -X "\n"); -X exit(1); -} -X -static int cfg_reset(void) -{ -X int i; -X -X for (i = 0; i < 4; ++i) -X msnd_write_cfg_logical(config_port, i, 0, 0, 0, 0); -X -X return 0; -} -X -static int cfg_show(void) -{ -X int i; -X int count = 0; -X -X for (i = 0; i < 4; ++i) { -X WORD io0, io1, irq; -X int mem; -X msnd_read_cfg_logical(config_port, i, &io0, &io1, &irq, &mem); -X switch (i) { -X case 0: -X if (io0 || irq || mem) { -X printf("dsp 0x%x %d 0x%x\n", io0, irq, mem); -X ++count; -X } -X break; -X case 1: -X if (io0 || irq) { -X printf("mpu 0x%x %d\n", io0, irq); -X ++count; -X } -X break; -X case 2: -X if (io0 || io1 || irq) { -X printf("ide 0x%x 0x%x %d\n", io0, io1, irq); -X ++count; -X } -X break; -X case 3: -X if (io0) { -X printf("joystick 0x%x\n", io0); -X ++count; -X } -X break; -X } -X } -X -X if (count == 0) -X fprintf(stderr, "no devices configured\n"); -X -X return 0; -} -X -static int cfg_dsp(int argc, char *argv[]) -{ -X int io, irq, mem; -X -X if (argc < 3 || -X sscanf(argv[0], "0x%x", &io) != 1 || -X sscanf(argv[1], "%d", &irq) != 1 || -X sscanf(argv[2], "0x%x", &mem) != 1) -X usage(); -X -X if (!(io == 0x290 || -X io == 0x260 || -X io == 0x250 || -X io == 0x240 || -X io == 0x230 || -X io == 0x220 || -X io == 0x210 || -X io == 0x3e0)) { -X fprintf(stderr, "error: io must be one of " -X "210, 220, 230, 240, 250, 260, 290, or 3E0\n"); -X usage(); -X } -X -X if (!(irq == 5 || -X irq == 7 || -X irq == 9 || -X irq == 10 || -X irq == 11 || -X irq == 12)) { -X fprintf(stderr, "error: irq must be one of " -X "5, 7, 9, 10, 11 or 12\n"); -X usage(); -X } -X -X if (!(mem == 0xb0000 || -X mem == 0xc8000 || -X mem == 0xd0000 || -X mem == 0xd8000 || -X mem == 0xe0000 || -X mem == 0xe8000)) { -X fprintf(stderr, "error: mem must be one of " -X "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); -X usage(); -X } -X -X return msnd_write_cfg_logical(config_port, 0, io, 0, irq, mem); -} -X -static int cfg_mpu(int argc, char *argv[]) -{ -X int io, irq; -X -X if (argc < 2 || -X sscanf(argv[0], "0x%x", &io) != 1 || -X sscanf(argv[1], "%d", &irq) != 1) -X usage(); -X -X return msnd_write_cfg_logical(config_port, 1, io, 0, irq, 0); -} -X -static int cfg_ide(int argc, char *argv[]) -{ -X int io0, io1, irq; -X -X if (argc < 3 || -X sscanf(argv[0], "0x%x", &io0) != 1 || -X sscanf(argv[0], "0x%x", &io1) != 1 || -X sscanf(argv[1], "%d", &irq) != 1) -X usage(); -X -X return msnd_write_cfg_logical(config_port, 2, io0, io1, irq, 0); -} -X -static int cfg_joystick(int argc, char *argv[]) -{ -X int io; -X -X if (argc < 1 || -X sscanf(argv[0], "0x%x", &io) != 1) -X usage(); -X -X return msnd_write_cfg_logical(config_port, 3, io, 0, 0, 0); -} -X -int main(int argc, char *argv[]) -{ -X char *device; -X int rv = 0; -X -X --argc; ++argv; -X -X if (argc < 2) -X usage(); -X -X sscanf(argv[0], "0x%x", &config_port); -X if (config_port != 0x250 && config_port != 0x260 && config_port != 0x270) { -X fprintf(stderr, "error: <config port> must be 0x250, 0x260 or 0x270\n"); -X exit(1); -X } -X if (ioperm(config_port, 2, 1)) { -X perror("ioperm"); -X fprintf(stderr, "note: pinnaclecfg must be run as root\n"); -X exit(1); -X } -X device = argv[1]; -X -X argc -= 2; argv += 2; -X -X if (strcmp(device, "reset") == 0) -X rv = cfg_reset(); -X else if (strcmp(device, "show") == 0) -X rv = cfg_show(); -X else if (strcmp(device, "dsp") == 0) -X rv = cfg_dsp(argc, argv); -X else if (strcmp(device, "mpu") == 0) -X rv = cfg_mpu(argc, argv); -X else if (strcmp(device, "ide") == 0) -X rv = cfg_ide(argc, argv); -X else if (strcmp(device, "joystick") == 0) -X rv = cfg_joystick(argc, argv); -X else { -X fprintf(stderr, "error: unknown device %s\n", device); -X usage(); -X } -X -X if (rv) -X fprintf(stderr, "error: device configuration failed\n"); -X -X return 0; -} -SHAR_EOF - $shar_touch -am 1204092598 'MultiSound.d/pinnaclecfg.c' && - chmod 0664 'MultiSound.d/pinnaclecfg.c' || - $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed' -366bdf27f0db767a3c7921d0a6db20fe MultiSound.d/pinnaclecfg.c -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`" - test 10235 -eq "$shar_count" || - $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10235,' 'current size' "$shar_count!" - fi -fi -# ============= MultiSound.d/Makefile ============== -if test -f 'MultiSound.d/Makefile' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'MultiSound.d/Makefile' '(file already exists)' -else - $echo 'x -' extracting 'MultiSound.d/Makefile' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' && -CC = gcc -CFLAGS = -O -PROGS = setdigital msndreset pinnaclecfg conv -X -all: $(PROGS) -X -clean: -X rm -f $(PROGS) -SHAR_EOF - $shar_touch -am 1204092398 'MultiSound.d/Makefile' && - chmod 0664 'MultiSound.d/Makefile' || - $echo 'restore of' 'MultiSound.d/Makefile' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'MultiSound.d/Makefile:' 'MD5 check failed' -76ca8bb44e3882edcf79c97df6c81845 MultiSound.d/Makefile -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`" - test 106 -eq "$shar_count" || - $echo 'MultiSound.d/Makefile:' 'original size' '106,' 'current size' "$shar_count!" - fi -fi -# ============= MultiSound.d/conv.l ============== -if test -f 'MultiSound.d/conv.l' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'MultiSound.d/conv.l' '(file already exists)' -else - $echo 'x -' extracting 'MultiSound.d/conv.l' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/conv.l' && -%% -[ \n\t,\r] -\;.* -DB -[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); } -%% -int yywrap() { return 1; } -main() { yylex(); } -SHAR_EOF - $shar_touch -am 0828231798 'MultiSound.d/conv.l' && - chmod 0664 'MultiSound.d/conv.l' || - $echo 'restore of' 'MultiSound.d/conv.l' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'MultiSound.d/conv.l:' 'MD5 check failed' -d2411fc32cd71a00dcdc1f009e858dd2 MultiSound.d/conv.l -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/conv.l'`" - test 141 -eq "$shar_count" || - $echo 'MultiSound.d/conv.l:' 'original size' '141,' 'current size' "$shar_count!" - fi -fi -# ============= MultiSound.d/msndreset.c ============== -if test -f 'MultiSound.d/msndreset.c' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'MultiSound.d/msndreset.c' '(file already exists)' -else - $echo 'x -' extracting 'MultiSound.d/msndreset.c' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/msndreset.c' && -/********************************************************************* -X * -X * msndreset.c - resets the MultiSound card -X * -X * Copyright (C) 1998 Andrew Veliath -X * -X * This program is free software; you can redistribute it and/or modify -X * it under the terms of the GNU General Public License as published by -X * the Free Software Foundation; either version 2 of the License, or -X * (at your option) any later version. -X * -X * This program is distributed in the hope that it will be useful, -X * but WITHOUT ANY WARRANTY; without even the implied warranty of -X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -X * GNU General Public License for more details. -X * -X * You should have received a copy of the GNU General Public License -X * along with this program; if not, write to the Free Software -X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -X * -X ********************************************************************/ -X -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/soundcard.h> -X -int main(int argc, char *argv[]) -{ -X int fd; -X -X if (argc != 2) { -X fprintf(stderr, "usage: msndreset <mixer device>\n"); -X exit(1); -X } -X -X if ((fd = open(argv[1], O_RDWR)) < 0) { -X perror(argv[1]); -X exit(1); -X } -X -X if (ioctl(fd, SOUND_MIXER_PRIVATE1, 0) < 0) { -X fprintf(stderr, "error: msnd ioctl reset failed\n"); -X perror("ioctl"); -X close(fd); -X exit(1); -X } -X -X close(fd); -X -X return 0; -} -SHAR_EOF - $shar_touch -am 1204100698 'MultiSound.d/msndreset.c' && - chmod 0664 'MultiSound.d/msndreset.c' || - $echo 'restore of' 'MultiSound.d/msndreset.c' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'MultiSound.d/msndreset.c:' 'MD5 check failed' -c52f876521084e8eb25e12e01dcccb8a MultiSound.d/msndreset.c -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/msndreset.c'`" - test 1472 -eq "$shar_count" || - $echo 'MultiSound.d/msndreset.c:' 'original size' '1472,' 'current size' "$shar_count!" - fi -fi -rm -fr _sh01426 -exit 0 diff --git a/Documentation/sound/oss/OPL3 b/Documentation/sound/oss/OPL3 deleted file mode 100644 index 2468ff827688..000000000000 --- a/Documentation/sound/oss/OPL3 +++ /dev/null @@ -1,6 +0,0 @@ -A pure OPL3 card is nice and easy to configure. Simply do - -insmod opl3 io=0x388 - -Change the I/O address in the very unlikely case this card is differently -configured diff --git a/Documentation/sound/oss/Opti b/Documentation/sound/oss/Opti deleted file mode 100644 index 4cd5d9ab3580..000000000000 --- a/Documentation/sound/oss/Opti +++ /dev/null @@ -1,218 +0,0 @@ -Support for the OPTi 82C931 chip --------------------------------- -Note: parts of this README file apply also to other -cards that use the mad16 driver. - -Some items in this README file are based on features -added to the sound driver after Linux-2.1.91 was out. -By the time of writing this I do not know which official -kernel release will include these features. -Please do not report inconsistencies on older Linux -kernels. - -The OPTi 82C931 is supported in its non-PnP mode. -Usually you do not need to set jumpers, etc. The sound driver -will check the card status and if it is required it will -force the card into a mode in which it can be programmed. - -If you have another OS installed on your computer it is recommended -that Linux and the other OS use the same resources. - -Also, it is recommended that resources specified in /etc/modprobe.d/*.conf -and resources specified in /etc/isapnp.conf agree. - -Compiling the sound driver --------------------------- -I highly recommend that you build a modularized sound driver. -This document does not cover a sound-driver which is built in -the kernel. - -Sound card support should be enabled as a module (chose m). -Answer 'm' for these items: - Generic OPL2/OPL3 FM synthesizer support (CONFIG_SOUND_ADLIB) - Microsoft Sound System support (CONFIG_SOUND_MSS) - Support for OPTi MAD16 and/or Mozart based cards (CONFIG_SOUND_MAD16) - FM synthesizer (YM3812/OPL-3) support (CONFIG_SOUND_YM3812) - -The configuration menu may ask for addresses, IRQ lines or DMA -channels. If the card is used as a module the module loading -options will override these values. - -For the OPTi 931 you can answer 'n' to: - Support MIDI in older MAD16 based cards (requires SB) (CONFIG_SOUND_MAD16_OLDCARD) -If you do need MIDI support in a Mozart or C928 based card you -need to answer 'm' to the above question. In that case you will -also need to answer 'm' to: - '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB) - -Go on and compile your kernel and modules. Install the modules. Run depmod -a. - -Using isapnptools ------------------ -In most systems with a PnP BIOS you do not need to use isapnp. The -initialization provided by the BIOS is sufficient for the driver -to pick up the card and continue initialization. - -If that fails, or if you have other PnP cards, you need to use isapnp -to initialize the card. -This was tested with isapnptools-1.11 but I recommend that you use -isapnptools-1.13 (or newer). Run pnpdump to dump the information -about your PnP cards. Then edit the resulting file and select -the options of your choice. This file is normally installed as -/etc/isapnp.conf. - -The driver has one limitation with respect to I/O port resources: -IO3 base must be 0x0E0C. Although isapnp allows other ports, this -address is hard-coded into the driver. - -Using kmod and autoloading the sound driver -------------------------------------------- -Config files in '/etc/modprobe.d/' are used as below: - -alias mixer0 mad16 -alias audio0 mad16 -alias midi0 mad16 -alias synth0 opl3 -options sb mad16=1 -options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0 -options opl3 io=0x388 -install mad16 /sbin/modprobe -i mad16 && /sbin/ad1848_mixer_reroute 14 8 15 3 16 6 - -If you have an MPU daughtercard or onboard MPU you will want to add to the -"options mad16" line - eg - -options mad16 irq=5 dma=0 dma16=3 io=0x530 mpu_io=0x330 mpu_irq=9 - -To set the I/O and IRQ of the MPU. - - -Explain: - -alias mixer0 mad16 -alias audio0 mad16 -alias midi0 mad16 -alias synth0 opl3 - -When any sound device is opened the kernel requests auto-loading -of char-major-14. There is a built-in alias that translates this -request to loading the main sound module. - -The sound module in its turn will request loading of a sub-driver -for mixer, audio, midi or synthesizer device. The first 3 are -supported by the mad16 driver. The synth device is supported -by the opl3 driver. - -There is currently no way to autoload the sound device driver -if more than one card is installed. - -options sb mad16=1 - -This is left for historical reasons. If you enable the -config option 'Support MIDI in older MAD16 based cards (requires SB)' -or if you use an older mad16 driver it will force loading of the -SoundBlaster driver. This option tells the SB driver not to look -for a SB card but to wait for the mad16 driver. - -options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0 -options opl3 io=0x388 - -post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6 - -This sets resources and options for the mad16 and opl3 drivers. -I use two DMA channels (only one is required) to enable full duplex. -joystick=1 enables the joystick port. cdtype=0 disables the cd port. -You can also set mpu_io and mpu_irq in the mad16 options for the -uart401 driver. - -This tells modprobe to run /sbin/ad1848_mixer_reroute after -mad16 is successfully loaded and initialized. The source -for ad1848_mixer_reroute is appended to the end of this readme -file. It is impossible for the sound driver to know the actual -connections to the mixer. The 3 inputs intended for cd, synth -and line-in are mapped to the generic inputs line1, line2 and -line3. This program reroutes these mixer channels to their -right names (note the right mapping depends on the actual sound -card that you use). -The numeric parameters mean: - 14=line1 8=cd - reroute line1 to the CD input. - 15=line2 3=synth - reroute line2 to the synthesizer input. - 16=line3 6=line - reroute line3 to the line input. -For reference on other input names look at the file -/usr/include/linux/soundcard.h. - -Using a joystick ------------------ -You must enable a joystick in the mad16 options. (also -in /etc/isapnp.conf if you use it). -Tested with regular analog joysticks. - -A CDROM drive connected to the sound card ------------------------------------------ -The 82C931 chip has support only for secondary ATAPI cdrom. -(cdtype=8). Loading the mad16 driver resets the C931 chip -and if a cdrom was already mounted it may cause a complete -system hang. Do not use the sound card if you have an alternative. -If you do use the sound card it is important that you load -the mad16 driver (use "modprobe mad16" to prevent auto-unloading) -before the cdrom is accessed the first time. - -Using the sound driver built-in to the kernel may help here, but... -Most new systems have a PnP BIOS and also two IDE controllers. -The IDE controller on the sound card may be needed only on older -systems (which have only one IDE controller) but these systems -also do not have a PnP BIOS - requiring isapnptools and a modularized -driver. - -Known problems --------------- -1. See the section on "A CDROM drive connected to the sound card". - -2. On my system the codec cannot capture companded sound samples. - (eg., recording from /dev/audio). When any companded capture is - requested I get stereo-16 bit samples instead. Playback of - companded samples works well. Apparently this problem is not common - to all C931 based cards. I do not know how to identify cards that - have this problem. - -Source for ad1848_mixer_reroute.c ---------------------------------- -#include <stdio.h> -#include <fcntl.h> -#include <linux/soundcard.h> - -static char *mixer_names[SOUND_MIXER_NRDEVICES] = - SOUND_DEVICE_LABELS; - -int -main(int argc, char **argv) { - int val, from, to; - int i, fd; - - fd = open("/dev/mixer", O_RDWR); - if(fd < 0) { - perror("/dev/mixer"); - return 1; - } - - for(i = 2; i < argc; i += 2) { - from = atoi(argv[i-1]); - to = atoi(argv[i]); - - if(to == SOUND_MIXER_NONE) - fprintf(stderr, "%s: turning off mixer %s\n", - argv[0], mixer_names[to]); - else - fprintf(stderr, "%s: rerouting mixer %s to %s\n", - argv[0], mixer_names[from], mixer_names[to]); - - val = from << 8 | to; - - if(ioctl(fd, SOUND_MIXER_PRIVATE2, &val)) { - perror("AD1848 mixer reroute"); - return 1; - } - } - - return 0; -} - diff --git a/Documentation/sound/oss/PAS16 b/Documentation/sound/oss/PAS16 deleted file mode 100644 index 5c27229eec8c..000000000000 --- a/Documentation/sound/oss/PAS16 +++ /dev/null @@ -1,162 +0,0 @@ -Pro Audio Spectrum 16 for 2.3.99 and later -========================================= -by Thomas Molina (tmolina@home.com) -last modified 3 Mar 2001 -Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken -from Configure.help, Riccardo Facchetti for stuff from README.OSS, -and others whose names I could not find. - -This documentation is relevant for the PAS16 driver (pas2_card.c and -friends) under kernel version 2.3.99 and later. If you are -unfamiliar with configuring sound under Linux, please read the -Sound-HOWTO, Documentation/sound/oss/Introduction and other -relevant docs first. - -The following information is relevant information from README.OSS -and legacy docs for the Pro Audio Spectrum 16 (PAS16): -================================================================== - -The pas2_card.c driver supports the following cards -- -Pro Audio Spectrum 16 (PAS16) and compatibles: - Pro Audio Spectrum 16 - Pro Audio Studio 16 - Logitech Sound Man 16 - NOTE! The original Pro Audio Spectrum as well as the PAS+ are not - and will not be supported by the driver. - -The sound driver configuration dialog -------------------------------------- - -Sound configuration starts by making some yes/no questions. Be careful -when answering to these questions since answering y to a question may -prevent some later ones from being asked. For example don't answer y to -the question about (PAS16) if you don't really have a PAS16. Sound -configuration may also be made modular by answering m to configuration -options presented. - -Note also that all questions may not be asked. The configuration program -may disable some questions depending on the earlier choices. It may also -select some options automatically as well. - - "ProAudioSpectrum 16 support", - - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_, - Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that - you read the above list correctly). Don't answer 'y' if you - have some other card made by Media Vision or Logitech since they - are not PAS16 compatible. - NOTE! Since 3.5-beta10 you need to enable SB support (next question) - if you want to use the SB emulation of PAS16. It's also possible to - the emulation if you want to use a true SB card together with PAS16 - (there is another question about this that is asked later). - - "Generic OPL2/OPL3 FM synthesizer support", - - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - The PAS16 has an OPL3-compatible FM chip. - -With PAS16 you can use two audio device files at the same time. /dev/dsp (and -/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and -/dev/audio1) is connected to the SB emulation (8 bit mono only). - - -The new stuff for 2.3.99 and later -============================================================================ -The following configuration options are relevant to configuring the PAS16: - -Sound card support -CONFIG_SOUND - If you have a sound card in your computer, i.e. if it can say more - than an occasional beep, say Y. Be sure to have all the information - about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. - - You want to read the Sound-HOWTO, available from - http://www.tldp.org/docs.html#howto . General information - about the modular sound system is contained in the files - Documentation/sound/oss/Introduction. The file - Documentation/sound/oss/README.OSS contains some slightly outdated but - still useful information as well. - -OSS sound modules -CONFIG_SOUND_OSS - OSS is the Open Sound System suite of sound card drivers. They make - sound programming easier since they provide a common API. Say Y or M - here (the module will be called sound.o) if you haven't found a - driver for your sound card above, then pick your driver from the - list below. - -Persistent DMA buffers -CONFIG_SOUND_DMAP - Linux can often have problems allocating DMA buffers for ISA sound - cards on machines with more than 16MB of RAM. This is because ISA - DMA buffers must exist below the 16MB boundary and it is quite - possible that a large enough free block in this region cannot be - found after the machine has been running for a while. If you say Y - here the DMA buffers (64Kb) will be allocated at boot time and kept - until the shutdown. This option is only useful if you said Y to - "OSS sound modules", above. If you said M to "OSS sound modules" - then you can get the persistent DMA buffer functionality by passing - the command-line argument "dmabuf=1" to the sound.o module. - - Say y here for PAS16. - -ProAudioSpectrum 16 support -CONFIG_SOUND_PAS - Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio - 16 or Logitech SoundMan 16 sound card. Don't answer Y if you have - some other card made by Media Vision or Logitech since they are not - PAS16 compatible. It is not necessary to enable the separate - Sound Blaster support; it is included in the PAS driver. - - If you compile the driver into the kernel, you have to add - "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2> - to the kernel command line. - -FM Synthesizer (YM3812/OPL-3) support -CONFIG_SOUND_YM3812 - Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - Answering Y is usually a safe and recommended choice, however some - cards may have software (TSR) FM emulation. Enabling FM support with - these cards may cause trouble (I don't currently know of any such - cards, however). - Please read the file Documentation/sound/oss/OPL3 if your card has an - OPL3 chip. - If you compile the driver into the kernel, you have to add - "opl3=<io>" to the kernel command line. - - If you compile your drivers into the kernel, you MUST configure - OPL3 support as a module for PAS16 support to work properly. - You can then get OPL3 functionality by issuing the command: - insmod opl3 - In addition, you must either add the following line to - /etc/modprobe.d/*.conf: - options opl3 io=0x388 - or else add the following line to /etc/lilo.conf: - opl3=0x388 - - -EXAMPLES -=================================================================== -To use the PAS16 in my computer I have enabled the following sound -configuration options: - -CONFIG_SOUND=y -CONFIG_SOUND_OSS=y -CONFIG_SOUND_TRACEINIT=y -CONFIG_SOUND_DMAP=y -CONFIG_SOUND_PAS=y -CONFIG_SOUND_SB=n -CONFIG_SOUND_YM3812=m - -I have also included the following append line in /etc/lilo.conf: -append="pas2=0x388,10,3,-1,0x220,5,1,-1 sb=0x220,5,1,-1 opl3=0x388" - -The io address of 0x388 is default configuration on the PAS16. The -irq of 10 and dma of 3 may not match your installation. The above -configuration enables PAS16, 8-bit Soundblaster and OPL3 -functionality. If Soundblaster functionality is not desired, the -following line would be appropriate: -append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388" - -If sound is built totally modular, the above options may be -specified in /etc/modprobe.d/*.conf for pas2, sb and opl3 -respectively. diff --git a/Documentation/sound/oss/PSS b/Documentation/sound/oss/PSS deleted file mode 100644 index 187b9525e1f6..000000000000 --- a/Documentation/sound/oss/PSS +++ /dev/null @@ -1,41 +0,0 @@ -The PSS cards and other ECHO based cards provide an onboard DSP with -downloadable programs and also has an AD1848 "Microsoft Sound System" -device. The PSS driver enables MSS and MPU401 modes of the card. SB -is not enabled since it doesn't work concurrently with MSS. - -If you build this driver as a module then the driver takes the following -parameters - -pss_io. The I/O base the PSS card is configured at (normally 0x220 - or 0x240) - -mss_io The base address of the Microsoft Sound System interface. - This is normally 0x530, but may be 0x604 or other addresses. - -mss_irq The interrupt assigned to the Microsoft Sound System - emulation. IRQ's 3,5,7,9,10,11 and 12 are available. If you - get IRQ errors be sure to check the interrupt is set to - "ISA/Legacy" in the BIOS on modern machines. - -mss_dma The DMA channel used by the Microsoft Sound System. - This can be 0, 1, or 3. DMA 0 is not available on older - machines and will cause a crash on them. - -mpu_io The MPU emulation base address. This sets the base of the - synthesizer. It is typically 0x330 but can be altered. - -mpu_irq The interrupt to use for the synthesizer. It must differ - from the IRQ used by the Microsoft Sound System port. - - -The mpu_io/mpu_irq fields are optional. If they are not specified the -synthesizer parts are not configured. - -When the module is loaded it looks for a file called -/etc/sound/pss_synth. This is the firmware file from the DOS install disks. -This fil holds a general MIDI emulation. The file expected is called -genmidi.ld on newer DOS driver install disks and synth.ld on older ones. - -You can also load alternative DSP algorithms into the card if you wish. One -alternative driver can be found at http://www.mpg123.de/ - diff --git a/Documentation/sound/oss/PSS-updates b/Documentation/sound/oss/PSS-updates deleted file mode 100644 index 11914a1dc7e7..000000000000 --- a/Documentation/sound/oss/PSS-updates +++ /dev/null @@ -1,88 +0,0 @@ - This file contains notes for users of PSS sound cards who wish to use the -newly added features of the newest version of this driver. - - The major enhancements present in this new revision of this driver is the -addition of two new module parameters that allow you to take full advantage of -all the features present on your PSS sound card. These features include the -ability to enable both the builtin CDROM and joystick ports. - -pss_enable_joystick - - This parameter is basically a flag. A 0 will leave the joystick port -disabled, while a non-zero value would enable the joystick port. The default -setting is pss_enable_joystick=0 as this keeps this driver fully compatible -with systems that were using previous versions of this driver. If you wish to -enable the joystick port you will have to add pss_enable_joystick=1 as an -argument to the driver. To actually use the joystick port you will then have -to load the joystick driver itself. Just remember to load the joystick driver -AFTER the pss sound driver. - -pss_cdrom_port - - This parameter takes a port address as its parameter. Any available port -address can be specified to enable the CDROM port, except for 0x0 and -1 as -these values would leave the port disabled. Like the joystick port, the cdrom -port will require that an appropriate CDROM driver be loaded before you can make -use of the newly enabled CDROM port. Like the joystick port option above, -remember to load the CDROM driver AFTER the pss sound driver. While it may -differ on some PSS sound cards, all the PSS sound cards that I have seen have a -builtin Wearnes CDROM port. If this is the case with your PSS sound card you -should load aztcd with the appropriate port option that matches the port you -assigned to the CDROM port when you loaded your pss sound driver. (ex. -modprobe pss pss_cdrom_port=0x340 && modprobe aztcd aztcd=0x340) The default -setting of this parameter leaves the CDROM port disabled to maintain full -compatibility with systems using previous versions of this driver. - - Other options have also been added for the added convenience and utility -of the user. These options are only available if this driver is loaded as a -module. - -pss_no_sound - - This module parameter is a flag that can be used to tell the driver to -just configure non-sound components. 0 configures all components, a non-0 -value will only attempt to configure the CDROM and joystick ports. This -parameter can be used by a user who only wished to use the builtin joystick -and/or CDROM port(s) of his PSS sound card. If this driver is loaded with this -parameter and with the parameter below set to true then a user can safely unload -this driver with the following command "rmmod pss && rmmod ad1848 && rmmod -mpu401 && rmmod sound && rmmod soundcore" and retain the full functionality of -his CDROM and/or joystick port(s) while gaining back the memory previously used -by the sound drivers. This default setting of this parameter is 0 to retain -full behavioral compatibility with previous versions of this driver. - -pss_keep_settings - - This parameter can be used to specify whether you want the driver to reset -all emulations whenever its unloaded. This can be useful for those who are -sharing resources (io ports, IRQ's, DMA's) between different ISA cards. This -flag can also be useful in that future versions of this driver may reset all -emulations by default on the driver's unloading (as it probably should), so -specifying it now will ensure that all future versions of this driver will -continue to work as expected. The default value of this parameter is 1 to -retain full behavioral compatibility with previous versions of this driver. - -pss_firmware - - This parameter can be used to specify the file containing the firmware -code so that a user could tell the driver where that file is located instead -of having to put it in a predefined location with a predefined name. The -default setting of this parameter is "/etc/sound/pss_synth" as this was the -path and filename the hardcoded value in the previous versions of this driver. - -Examples: - -# Normal PSS sound card system, loading of drivers. -# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules). - -/sbin/modprobe pss pss_io=0x220 mpu_io=0x338 mpu_irq=9 mss_io=0x530 mss_irq=10 mss_dma=1 pss_cdrom_port=0x340 pss_enable_joystick=1 -/sbin/modprobe aztcd aztcd=0x340 -/sbin/modprobe joystick - -# System using the PSS sound card just for its CDROM and joystick ports. -# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules). - -/sbin/modprobe pss pss_io=0x220 pss_cdrom_port=0x340 pss_enable_joystick=1 pss_no_sound=1 -/sbin/rmmod pss && /sbin/rmmod ad1848 && /sbin/rmmod mpu401 && /sbin/rmmod sound && /sbin/rmmod soundcore # This line not needed, but saves memory. -/sbin/modprobe aztcd aztcd=0x340 -/sbin/modprobe joystick diff --git a/Documentation/sound/oss/README.OSS b/Documentation/sound/oss/README.OSS deleted file mode 100644 index a085ea3611a1..000000000000 --- a/Documentation/sound/oss/README.OSS +++ /dev/null @@ -1,1455 +0,0 @@ -Introduction ------------- - -This file is a collection of all the old Readme files distributed with -OSS/Lite by Hannu Savolainen. Since the new Linux sound driver is founded -on it I think these information may still be interesting for users that -have to configure their sound system. - -Be warned: Alan Cox is the current maintainer of the Linux sound driver so if -you have problems with it, please contact him or the current device-specific -driver maintainer (e.g. for aedsp16 specific problems contact me). If you have -patches, contributions or suggestions send them to Alan: I'm sure they are -welcome. - -In this document you will find a lot of references about OSS/Lite or ossfree: -they are gone forever. Keeping this in mind and with a grain of salt this -document can be still interesting and very helpful. - -[ File edited 17.01.1999 - Riccardo Facchetti ] -[ Edited miroSOUND section 19.04.2001 - Robert Siemer ] - -OSS/Free version 3.8 release notes ----------------------------------- - -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 above). - -Please check http://www.opensound.com/pguide for more info about programming -with OSS API. - - ==================================================== -- THIS VERSION ____REQUIRES____ Linux 2.1.57 OR LATER. - ==================================================== - -Packages "snd-util-3.8.tar.gz" and "snd-data-0.1.tar.Z" -contain useful utilities to be used with this driver. -See http://www.opensound.com/ossfree/ for -download instructions. - -If you are looking for the installation instructions, please -look forward into this document. - -Supported sound cards ---------------------- - -See below. - -Contributors ------------- - -This driver contains code by several contributors. In addition several other -persons have given useful suggestions. The following is a list of major -contributors. (I could have forgotten some names.) - - Craig Metz 1/2 of the PAS16 Mixer and PCM support - Rob Hooft Volume computation algorithm for the FM synth. - Mika Liljeberg uLaw encoding and decoding routines - Jeff Tranter Linux SOUND HOWTO document - Greg Lee Volume computation algorithm for the GUS and - lots of valuable suggestions. - Andy Warner ISC port - Jim Lowe, - Amancio Hasty Jr FreeBSD/NetBSD port - Anders Baekgaard Bug hunting and valuable suggestions. - Joerg Schubert SB16 DSP support (initial version). - Andrew Robinson Improvements to the GUS driver - Megens SA MIDI recording for SB and SB Pro (initial version). - Mikael Nordqvist Linear volume support for GUS and - nonblocking /dev/sequencer. - Ian Hartas SVR4.2 port - Markus Aroharju and - Risto Kankkunen Major contributions to the mixer support - of GUS v3.7. - Hunyue Yau Mixer support for SG NX Pro. - Marc Hoffman PSS support (initial version). - Rainer Vranken Initialization for Jazz16 (initial version). - Peter Trattler Initial version of loadable module support for Linux. - JRA Gibson 16 bit mode for Jazz16 (initial version) - Davor Jadrijevic MAD16 support (initial version) - Gregor Hoffleit Mozart support (initial version) - Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support - James Hightower Spotting a tiny but important bug in CS423x support. - Denis Sablic OPTi 82C924 specific enhancements (non PnP mode) - Tim MacKenzie Full duplex support for OPTi 82C930. - - Please look at lowlevel/README for more contributors. - -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 a major waste of time to try to improve a -several months old version. Information about the latest version can be found -from http://www.opensound.com/ossfree. In general there is no point in -sending me patches relative to production kernels. - -Sponsors etc. -------------- - -The following companies have greatly helped development of this driver -in form of a free copy of their product: - -Novell, Inc. UnixWare personal edition + SDK -The Santa Cruz Operation, Inc. A SCO OpenServer + SDK -Ensoniq Corp, a SoundScape card and extensive amount of assistance -MediaTrix Peripherals Inc, a AudioTrix Pro card + SDK -Acer, Inc. a pair of AcerMagic S23 cards. - -In addition the following companies have provided me sufficient amount -of technical information at least some of their products (free or $$$): - -Advanced Gravis Computer Technology Ltd. -Media Vision Inc. -Analog Devices Inc. -Logitech Inc. -Aztech Labs Inc. -Crystal Semiconductor Corporation, -Integrated Circuit Systems Inc. -OAK Technology -OPTi -Turtle Beach -miro -Ad Lib Inc. ($$) -Music Quest Inc. ($$) -Creative Labs ($$$) - -If you have some problems -========================= - -Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?). -Also look at the home page (http://www.opensound.com/ossfree). It may -contain info about some recent bug fixes. - -It's likely that you have some problems when trying to use the sound driver -first time. Sound cards don't have standard configuration so there are no -good default configuration to use. Please try to use same I/O, DMA and IRQ -values for the sound card than with DOS. - -If you get an error message when trying to use the driver, please look -at /var/adm/messages for more verbose error message. - - -The following errors are likely with /dev/dsp and /dev/audio. - - - "No such device or address". - This error indicates that there are no suitable hardware for the - device file or the sound driver has been compiled without support for - this particular device. For example /dev/audio and /dev/dsp will not - work if "digitized voice support" was not enabled during "make config". - - - "Device or resource busy". Probably the IRQ (or DMA) channel - required by the sound card is in use by some other device/driver. - - - "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict. - Look at the kernel messages in /var/adm/notice for more info. - - - "Invalid argument". The application is calling ioctl() - with impossible parameters. Check that the application is - for sound driver version 2.X or later. - -Linux installation -================== - -IMPORTANT! Read this if you are installing a separately - distributed version of this driver. - - Check that your kernel version works with this - release of the driver (see Readme). Also verify - that your current kernel version doesn't have more - recent sound driver version than this one. IT'S HIGHLY - RECOMMENDED THAT YOU USE THE SOUND DRIVER VERSION THAT - IS DISTRIBUTED WITH KERNEL SOURCES. - -- When installing separately distributed sound driver you should first - read the above notice. Then try to find proper directory where and how - to install the driver sources. You should not try to install a separately - distributed driver version if you are not able to find the proper way - yourself (in this case use the version that is distributed with kernel - sources). Remove old version of linux/drivers/sound directory before - installing new files. - -- To build the device files you need to run the enclosed shell script - (see below). You need to do this only when installing sound driver - first time or when upgrading to much recent version than the earlier - one. - -- Configure and compile Linux as normally (remember to include the - sound support during "make config"). Please refer to kernel documentation - for instructions about configuring and compiling kernel. File Readme.cards - contains card specific instructions for configuring this driver for - use with various sound cards. - -Boot time configuration (using lilo and insmod) ------------------------------------------------ - -This information has been removed. Too many users didn't believe -that it's really not necessary to use this method. Please look at -Readme of sound driver version 3.0.1 if you still want to use this method. - -Problems --------- - -Common error messages: - -- /dev/???????: No such file or directory. -Run the script at the end of this file. - -- /dev/???????: No such device. -You are not running kernel which contains the sound driver. When using -modularized sound driver this error means that the sound driver is not -loaded. - -- /dev/????: No such device or address. -Sound driver didn't detect suitable card when initializing. Please look at -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.opensound.com/ossfree for more info. - -Configuring version 3.8 (for Linux) with some common sound cards -================================================================ - -This document describes configuring sound cards with the freeware version of -Open Sound Systems (OSS/Free). Information about the commercial version -(OSS/Linux) and its configuration is available from -http://www.opensound.com/linux.html. Information presented here is -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 sound card. 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 - http://www.opensound.com/ossfree for info about - cards introduced recently. - - When configuring the sound driver, you should carefully - check each sound configuration option (particularly - "Support for /dev/dsp and /dev/audio"). The default values - offered by these programs are not necessarily valid. - - -THE BIGGEST MISTAKES YOU CAN MAKE -================================= - -1. Assuming that the card is Sound Blaster compatible when it's not. --------------------------------------------------------------------- - -The number one mistake is to assume that your card is compatible with -Sound Blaster. Only the cards made by Creative Technology or which have -one or more chips labeled by Creative are SB compatible. In addition there -are few sound chipsets which are SB compatible in Linux such as ESS1688 or -Jazz16. Note that SB compatibility in DOS/Windows does _NOT_ mean anything -in Linux. - -IF YOU REALLY ARE 150% SURE YOU HAVE A SOUND BLASTER YOU CAN SKIP THE REST OF -THIS CHAPTER. - -For most other "supposed to be SB compatible" cards you have to use other -than SB drivers (see below). It is possible to get most sound cards to work -in SB mode but in general it's a complete waste of time. There are several -problems which you will encounter by using SB mode with cards that are not -truly SB compatible: - -- The SB emulation is at most SB Pro (DSP version 3.x) which means that -you get only 8 bit audio (there is always an another ("native") mode which -gives the 16 bit capability). The 8 bit only operation is the reason why -many users claim that sound quality in Linux is much worse than in DOS. -In addition some applications require 16 bit mode and they produce just -noise with a 8 bit only device. -- The card may work only in some cases but refuse to work most of the -time. The SB compatible mode always requires special initialization which is -done by the DOS/Windows drivers. This kind of cards work in Linux after -you have warm booted it after DOS but they don't work after cold boot -(power on or reset). -- You get the famous "DMA timed out" messages. Usually all SB clones have -software selectable IRQ and DMA settings. If the (power on default) values -currently used by the card don't match configuration of the driver you will -get the above error message whenever you try to record or play. There are -few other reasons to the DMA timeout message but using the SB mode seems -to be the most common cause. - -2. Trying to use a PnP (Plug & Play) card just like an ordinary sound card --------------------------------------------------------------------------- - -Plug & Play is a protocol defined by Intel and Microsoft. It lets operating -systems to easily identify and reconfigure I/O ports, IRQs and DMAs of ISA -cards. The problem with PnP cards is that the standard Linux doesn't currently -(versions 2.1.x and earlier) don't support PnP. This means that you will have -to use some special tricks (see later) to get a PnP card alive. Many PnP cards -work after they have been initialized but this is not always the case. - -There are sometimes both PnP and non-PnP versions of the same sound card. -The non-PnP version is the original model which usually has been discontinued -more than an year ago. The PnP version has the same name but with "PnP" -appended to it (sometimes not). This causes major confusion since the non-PnP -model works with Linux but the PnP one doesn't. - -You should carefully check if "Plug & Play" or "PnP" is mentioned in the name -of the card or in the documentation or package that came with the card. -Everything described in the rest of this document is not necessarily valid for -PnP models of sound cards even you have managed to wake up the card properly. -Many PnP cards are simply too different from their non-PnP ancestors which are -covered by this document. - - -Cards that are not (fully) supported by this driver -=================================================== - -See http://www.opensound.com/ossfree for information about sound cards -to be supported in future. - - -How to use sound without recompiling kernel and/or sound driver -=============================================================== - -There is a commercial sound driver which comes in precompiled form and doesn't -require recompiling of the kernel. See http://www.4Front-tech.com/oss.html for -more info. - - -Configuring PnP cards -===================== - -New versions of most sound cards use the so-called ISA PnP protocol for -soft configuring their I/O, IRQ, DMA and shared memory resources. -Currently at least cards made by Creative Technology (SB32 and SB32AWE -PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and -Aztech (some Sound Galaxy models) use PnP technology. The CS4232/4236 audio -chip by Crystal Semiconductor (Intel Atlantis, HP Pavilion and many other -motherboards) is also based on PnP technology but there is a "native" driver -available for it (see information about CS4232 later in this document). - -PnP sound cards (as well as most other PnP ISA cards) are not supported -by this version of the driver . Proper -support for them should be released during 97 once the kernel level -PnP support is available. - -There is a method to get most of the PnP cards to work. The basic method -is the following: - -1) Boot DOS so the card's DOS drivers have a chance to initialize it. -2) _Cold_ boot to Linux by using "loadlin.exe". Hitting ctrl-alt-del -works with older machines but causes a hard reset of all cards on recent -(Pentium) machines. -3) If you have the sound driver in Linux configured properly, the card should -work now. "Proper" means that I/O, IRQ and DMA settings are the same as in -DOS. The hard part is to find which settings were used. See the documentation of -your card for more info. - -Windows 95 could work as well as DOS but running loadlin may be difficult. -Probably you should "shut down" your machine to MS-DOS mode before running it. - -Some machines have a BIOS utility for setting PnP resources. This is a good -way to configure some cards. In this case you don't need to boot DOS/Win95 -before starting Linux. - -Another way to initialize PnP cards without DOS/Win95 is a Linux based -PnP isolation tool. When writing this there is a pre alpha test version -of such a tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The -file is called isapnptools-*. Please note that this tool is just a temporary -solution which may be incompatible with future kernel versions having proper -support for PnP cards. There are bugs in setting DMA channels in earlier -versions of isapnptools so at least version 1.6 is required with sound cards. - -Yet another way to use PnP cards is to use (commercial) OSS/Linux drivers. See -http://www.opensound.com/linux.html for more info. This is probably the way you -should do it if you don't want to spend time recompiling the kernel and -required tools. - - -Read this before trying to configure the driver -=============================================== - -There are currently many cards that work with this driver. Some of the cards -have native support while others work since they emulate some other -card (usually SB, MSS/WSS and/or MPU401). The following cards have native -support in the driver. Detailed instructions for configuring these cards -will be given later in this document. - -Pro Audio Spectrum 16 (PAS16) and compatibles: - Pro Audio Spectrum 16 - Pro Audio Studio 16 - Logitech Sound Man 16 - NOTE! The original Pro Audio Spectrum as well as the PAS+ are not - and will not be supported by the driver. - -Media Vision Jazz16 based cards - Pro Sonic 16 - Logitech SoundMan Wave - (Other Jazz based cards should work but I don't have any reports - about them). - -Sound Blasters - SB 1.0 to 2.0 - SB Pro - SB 16 - SB32/64/AWE - Configure SB32/64/AWE just like SB16. See lowlevel/README.awe - for information about using the wave table synth. - NOTE! AWE63/Gold and 16/32/AWE "PnP" cards need to be activated - using isapnptools before they work with OSS/Free. - SB16 compatible cards by other manufacturers than Creative. - You have been fooled since there are _no_ SB16 compatible - cards on the market (as of May 1997). It's likely that your card - 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" - (try with the MAD16 driver). - - ====================================================================== - "Supposed to be SB compatible" cards. - Forget the SB compatibility and check for other alternatives - first. The only cards that work with the SB driver in - Linux have been made by Creative Technology (there is at least - one chip on the card with "CREATIVE" printed on it). The - only other SB compatible chips are ESS and Jazz16 chips - (maybe ALSxxx chips too but they probably don't work). - Most other "16 bit SB compatible" cards such as "OPTi/MAD16" or - "Crystal" are _NOT_ SB compatible in Linux. - - Practically all sound cards have some kind of SB emulation mode - in addition to their native (16 bit) mode. In most cases this - (8 bit only) SB compatible mode doesn't work with Linux. If - you get it working it may cause problems with games and - applications which require 16 bit audio. Some 16 bit only - applications don't check if the card actually supports 16 bits. - They just dump 16 bit data to a 8 bit card which produces just - noise. - - In most cases the 16 bit native mode is supported by Linux. - Use the SB mode with "clones" only if you don't find anything - better from the rest of this doc. - ====================================================================== - -Gravis Ultrasound (GUS) - GUS - GUS + the 16 bit option - GUS MAX - GUS ACE (No MIDI port and audio recording) - GUS PnP (with RAM) - -MPU-401 and compatibles - The driver works both with the full (intelligent mode) MPU-401 - cards (such as MPU IPC-T and MQX-32M) and with the UART only - dumb MIDI ports. MPU-401 is currently the most common MIDI - interface. Most sound cards are compatible with it. However, - don't enable MPU401 mode blindly. Many cards with native support - in the driver have their own MPU401 driver. Enabling the standard one - will cause a conflict with these cards. So check if your card is - in the list of supported cards before enabling MPU401. - -Windows Sound System (MSS/WSS) - Even when Microsoft has discontinued their own Sound System card - they managed to make it a standard. MSS compatible cards are based on - a codec chip which is easily available from at least two manufacturers - (AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor). - Currently most sound cards are based on one of the MSS compatible codec - chips. The CS4231 is used in the high quality cards such as GUS MAX, - MediaTrix AudioTrix Pro and TB Tropez (GUS MAX is not MSS compatible). - - Having a AD1848, CS4248 or CS4231 codec chip on the card is a good - sign. Even if the card is not MSS compatible, it could be easy to write - support for it. Note also that most MSS compatible cards - require special boot time initialization which may not be present - in the driver. Also, some MSS compatible cards have native support. - Enabling the MSS support with these cards is likely to - cause a conflict. So check if your card is listed in this file before - enabling the MSS support. - -Yamaha FM synthesizers (OPL2, OPL3 (not OPL3-SA) and OPL4) - Most sound cards have a FM synthesizer chip. The OPL2 is a 2 - operator chip used in the original AdLib card. Currently it's used - only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator - FM chip which provides better sound quality and/or more available - voices than the OPL2. The OPL4 is a new chip that has an OPL3 and - a wave table synthesizer packed onto the same chip. The driver supports - just the OPL3 mode directly. Most cards with an OPL4 (like - SM Wave and AudioTrix Pro) support the OPL4 mode using MPU401 - emulation. Writing a native OPL4 support is difficult - since Yamaha doesn't give information about their sample ROM chip. - - Enable the generic OPL2/OPL3 FM synthesizer support if your - card has a FM chip made by Yamaha. Don't enable it if your card - has a software (TRS) based FM emulator. - - ---------------------------------------------------------------- - 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. 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 sound cards. 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 these 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 sound card. Due to its nature a fast CPU is - required (P133 is minimum). Although SoftOSS does _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 CONFIG_SOFTOSS_RATE and CONFIG_SOFTOSS_VOICES - parameters properly (they will be prompted by make config). It's - recommended to set CONFIG_SOFTOSS_VOICES to 32. If you have a - P166MMX or faster (PPro200 is not faster) you can set - CONFIG_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 CONFIG_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 the system's RAM so much RAM is - required. SoftOSS should never be used on machines with less than 16 MB - of RAM since this is potentially dangerous (you may accidentally 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 the Gravis - Ultrasound card is not in public domain (even though 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 sound card - architecture based on the above chips. The DSP chip is used - for emulation of SB Pro, FM and General MIDI/MT32. - - There are several cards based on this architecture. The most known - ones are Orchid SW32 and Cardinal DSP16. - - The driver supports downloading DSP algorithms to these cards. - - NOTE! You will have to use the "old" config script when configuring - PSS cards. - -MediaTrix AudioTrix Pro - The ATP card is built around a CS4231 codec and an OPL4 synthesizer - chips. The OPL4 mode is supported by a microcontroller running a - General MIDI emulator. There is also a SB 1.5 compatible playback mode. - -Ensoniq SoundScape and compatibles - Ensoniq has designed a sound card architecture based on the - OTTO synthesizer chip used in their professional MIDI synthesizers. - Several companies (including Ensoniq, Reveal and Spea) are selling - cards based on this architecture. - - NOTE! The SoundScape PnP is not supported by OSS/Free. Ensoniq VIVO and - 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. - -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 sound cards, including some - cards by Reveal miro and Turtle Beach (Tropez). The purpose of these - chips is to connect other audio components to the PC bus. The - interface chip performs address decoding for the other chips. - NOTE! Tropez Plus is not MAD16 but CS4232 based. - NOTE! MAD16 PnP cards (82C924, 82C925, 82C931) are not MAD16 compatible - in the PnP mode. You will have to use them in MSS mode after having - initialized them using isapnptools or DOS. 82C931 probably requires - initialization using DOS/Windows (running isapnptools is not enough). - It's possible to use 82C931 with OSS/Free by jumpering it to non-PnP - mode (provided that the card has a jumper for this). In non-PnP mode - 82C931 is compatible with 82C930 and should work with the MAD16 driver - (without need to use isapnptools or DOS to initialize it). All OPTi - chips are supported by OSS/Linux (both in PnP and non-PnP modes). - -Audio Excel DSP16 - Support for this card was written by Riccardo Faccetti - (riccardo@cdc8g5.cdc.polimi.it). The AEDSP16 driver included in - the lowlevel/ directory. To use it you should enable the - "Additional low level drivers" option. - -Crystal CS4232 and CS4236 based cards such as AcerMagic S23, TB Tropez _Plus_ and - many PC motherboards (Compaq, HP, Intel, ...) - CS4232 is a PnP multimedia chip which contains a CS3231A codec, - SB and MPU401 emulations. There is support for OPL3 too. - Unfortunately the MPU401 mode doesn't work (I don't know how to - initialize it). CS4236 is an enhanced (compatible) version of CS4232. - NOTE! Don't ever try to use isapnptools with CS4232 since this will just - freeze your machine (due to chip bugs). If you have problems in getting - CS4232 working you could try initializing it with DOS (CS4232C.EXE) and - then booting Linux using loadlin. CS4232C.EXE loads a secret firmware - patch which is not documented by Crystal. - -Turtle Beach Maui and Tropez "classic" - This driver version supports sample, patch and program loading commands - described in the Maui/Tropez User's manual. - There is now full initialization support too. The audio side of - the Tropez is based on the MAD16 chip (see above). - NOTE! Tropez Plus is different card than Tropez "classic" and will not - work fully in Linux. You can get audio features working by configuring - the card as a CS4232 based card (above). - - -Jumpers and software configuration -================================== - -Some of the earliest sound cards were jumper configurable. You have to -configure the driver use I/O, IRQ and DMA settings -that match the jumpers. Just few 8 bit cards are fully jumper -configurable (SB 1.x/2.x, SB Pro and clones). -Some cards made by Aztech have an EEPROM which contains the -config info. These cards behave much like hardware jumpered cards. - -Most cards have jumper for the base I/O address but other parameters -are software configurable. Sometimes there are few other jumpers too. - -Latest cards are fully software configurable or they are PnP ISA -compatible. There are no jumpers on the board. - -The driver handles software configurable cards automatically. Just configure -the driver to use I/O, IRQ and DMA settings which are known to work. -You could usually use the same values than with DOS and/or Windows. -Using different settings is possible but not recommended since it may cause -some trouble (for example when warm booting from an OS to another or -when installing new hardware to the machine). - -Sound driver sets the soft configurable parameters of the card automatically -during boot. Usually you don't need to run any extra initialization -programs when booting Linux but there are some exceptions. See the -card-specific instructions below for more info. - -The drawback of software configuration is that the driver needs to know -how the card must be initialized. It cannot initialize unknown cards -even if they are otherwise compatible with some other cards (like SB, -MPU401 or Windows Sound System). - - -What if your card was not listed above? -======================================= - -The first thing to do is to look at the major IC chips on the card. -Many of the latest sound cards are based on some standard chips. If you -are lucky, all of them could be supported by the driver. The most common ones -are the OPTi MAD16, Mozart, SoundScape (Ensoniq) and the PSS architectures -listed above. Also look at the end of this file for list of unsupported -cards and the ones which could be supported later. - -The last resort is to send _exact_ name and model information of the card -to me together with a list of the major IC chips (manufactured, model) to -me. I could then try to check if your card looks like something familiar. - -There are many more cards in the world than listed above. The first thing to -do with these cards is to check if they emulate some other card or interface -such as SB, MSS and/or MPU401. In this case there is a chance to get the -card to work by booting DOS before starting Linux (boot DOS, hit ctrl-alt-del -and boot Linux without hard resetting the machine). In this method the -DOS based driver initializes the hardware to use known I/O, IRQ and DMA -settings. If sound driver is configured to use the same settings, everything -should work OK. - - -Configuring sound driver (with Linux) -===================================== - -The sound driver is currently distributed as part of the Linux kernel. The -files are in /usr/src/linux/drivers/sound/. - -**************************************************************************** -* ALWAYS USE THE SOUND DRIVER VERSION WHICH IS DISTRIBUTED WITH * -* THE KERNEL SOURCE PACKAGE YOU ARE USING. SOME ALPHA AND BETA TEST * -* VERSIONS CAN BE INSTALLED FROM A SEPARATELY DISTRIBUTED PACKAGE * -* BUT CHECK THAT THE PACKAGE IS NOT MUCH OLDER (OR NEWER) THAN THE * -* KERNEL YOU ARE USING. IT'S POSSIBLE THAT THE KERNEL/DRIVER * -* INTERFACE CHANGES BETWEEN KERNEL RELEASES WHICH MAY CAUSE SOME * -* INCOMPATIBILITY PROBLEMS. * -* * -* IN CASE YOU INSTALL A SEPARATELY DISTRIBUTED SOUND DRIVER VERSION, * -* BE SURE TO REMOVE OR RENAME THE OLD SOUND DRIVER DIRECTORY BEFORE * -* INSTALLING THE NEW ONE. LEAVING OLD FILES TO THE SOUND DRIVER * -* DIRECTORY _WILL_ CAUSE PROBLEMS WHEN THE DRIVER IS USED OR * -* COMPILED. * -**************************************************************************** - -To configure the driver, run "make config" in the kernel source directory -(/usr/src/linux). Answer "y" or "m" to the question about Sound card support -(after the questions about mouse, CD-ROM, ftape, etc. support). Questions -about options for sound will then be asked. - -After configuring the kernel and sound driver and compile the kernel -following instructions in the kernel README. - -The sound driver configuration dialog -------------------------------------- - -Sound configuration starts by making some yes/no questions. Be careful -when answering to these questions since answering y to a question may -prevent some later ones from being asked. For example don't answer y to -the first question (PAS16) if you don't really have a PAS16. Don't enable -more cards than you really need since they just consume memory. Also -some drivers (like MPU401) may conflict with your SCSI controller and -prevent kernel from booting. If you card was in the list of supported -cards (above), please look at the card specific config instructions -(later in this file) before starting to configure. Some cards must be -configured in way which is not obvious. - -So here is the beginning of the config dialog. Answer 'y' or 'n' to these -questions. The default answer is shown so that (y/n) means 'y' by default and -(n/y) means 'n'. To use the default value, just hit ENTER. But be careful -since using the default _doesn't_ guarantee anything. - -Note also that all questions may not be asked. The configuration program -may disable some questions depending on the earlier choices. It may also -select some options automatically as well. - - "ProAudioSpectrum 16 support", - - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_, - Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that - you read the above list correctly). Don't answer 'y' if you - have some other card made by Media Vision or Logitech since they - are not PAS16 compatible. - NOTE! Since 3.5-beta10 you need to enable SB support (next question) - if you want to use the SB emulation of PAS16. It's also possible to - the emulation if you want to use a true SB card together with PAS16 - (there is another question about this that is asked later). - "Sound Blaster support", - - Answer 'y' if you have an original SB card made by Creative Labs - or a full 100% hardware compatible clone (like Thunderboard or - SM Games). If your card was in the list of supported cards (above), - please look at the card specific instructions later in this file - before answering this question. For an unknown card you may answer - 'y' if the card claims to be SB compatible. - Enable this option also with PAS16 (changed since v3.5-beta9). - - Don't enable SB if you have a MAD16 or Mozart compatible card. - - "Generic OPL2/OPL3 FM synthesizer support", - - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - Answering 'y' is usually a safe and recommended choice. However some - cards may have software (TSR) FM emulation. Enabling FM support - with these cards may cause trouble. However I don't currently know - such cards. - "Gravis Ultrasound support", - - Answer 'y' if you have GUS or GUS MAX. Answer 'n' if you don't - have GUS since the GUS driver consumes much memory. - Currently I don't have experiences with the GUS ACE so I don't - know what to answer with it. - "MPU-401 support (NOT for SB16)", - - Be careful with this question. The MPU401 interface is supported - by almost any sound card today. However some natively supported cards - have their own driver for MPU401. Enabling the MPU401 option with - these cards will cause a conflict. Also enabling MPU401 on a system - that doesn't really have a MPU401 could cause some trouble. If your - card was in the list of supported cards (above), please look at - the card specific instructions later in this file. - - In MOST cases this MPU401 driver should only be used with "true" - MIDI-only MPU401 professional cards. In most other cases there - is another way to get the MPU401 compatible interface of a - sound card to work. - Support for the MPU401 compatible MIDI port of SB16, ESS1688 - and MV Jazz16 cards is included in the SB driver. Use it instead - of this separate MPU401 driver with these cards. As well - Soundscape, PSS and Maui drivers include their own MPU401 - options. - - It's safe to answer 'y' if you have a true MPU401 MIDI interface - card. - "6850 UART Midi support", - - It's safe to answer 'n' to this question in all cases. The 6850 - UART interface is so rarely used. - "PSS (ECHO-ADI2111) support", - - Answer 'y' only if you have Orchid SW32, Cardinal DSP16 or some - other card based on the PSS chipset (AD1848 codec + ADSP-2115 - DSP chip + Echo ESC614 ASIC CHIP). - "16 bit sampling option of GUS (_NOT_ GUS MAX)", - - Answer 'y' if you have installed the 16 bit sampling daughtercard - to your GUS. Answer 'n' if you have GUS MAX. Enabling this option - disables GUS MAX support. - "GUS MAX support", - - Answer 'y' only if you have a GUS MAX. - "Microsoft Sound System support", - - Again think carefully before answering 'y' to this question. It's - safe to answer 'y' in case you have the original Windows Sound - System card made by Microsoft or Aztech SG 16 Pro (or NX16 Pro). - Also you may answer 'y' in case your card was not listed earlier - in this file. For cards having native support in the driver, consult - the card specific instructions later in this file. Some drivers - have their own MSS support and enabling this option will cause a - conflict. - Note! The MSS driver permits configuring two DMA channels. This is a - "nonstandard" feature and works only with very few cards (if any). - In most cases the second DMA channel should be disabled or set to - the same channel than the first one. Trying to configure two separate - channels with cards that don't support this feature will prevent - audio (at least recording) from working. - "Ensoniq Soundscape support", - - Answer 'y' if you have a sound card based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, - Spea and Reveal (note that Reveal makes other cards also). The oldest - cards made by Spea don't work properly with Linux. - Soundscape PnP as well as Ensoniq VIVO work only with the commercial - OSS/Linux version. - "MediaTrix AudioTrix Pro support", - - Answer 'y' if you have the AudioTrix Pro. - "Support for MAD16 and/or Mozart based cards", - - Answer y if your card has a Mozart (OAK OTI-601) or MAD16 - (OPTi 82C928, 82C929, 82C924/82C925 or 82C930) audio interface chip. - These chips are - currently quite common so it's possible that many no-name cards - have one of them. In addition the MAD16 chip is used in some - cards made by known manufacturers such as Turtle Beach (Tropez), - Reveal (some models) and Diamond (some recent models). - Note OPTi 82C924 and 82C925 are MAD16 compatible only in non PnP - mode (jumper selectable on many cards). - "Support for TB Maui" - - This enables TB Maui specific initialization. Works with TB Maui - and TB Tropez (may not work with Tropez Plus). - - -Then the configuration program asks some y/n questions about the higher -level services. It's recommended to answer 'y' to each of these questions. -Answer 'n' only if you know you will not need the option. - - "MIDI interface support", - - Answering 'n' disables /dev/midi## devices and access to any - MIDI ports using /dev/sequencer and /dev/music. This option - also affects any MPU401 and/or General MIDI compatible devices. - "FM synthesizer (YM3812/OPL-3) support", - - Answer 'y' here. - "/dev/sequencer support", - - Answering 'n' disables /dev/sequencer and /dev/music. - -Entering the I/O, IRQ and DMA config parameters ------------------------------------------------ - -After the above questions the configuration program prompts for the -card specific configuration information. Usually just a set of -I/O address, IRQ and DMA numbers are asked. With some cards the program -asks for some files to be used during initialization of the card. For example -many cards have a DSP chip or microprocessor which must be initialized by -downloading a program (microcode) file to the card. - -Instructions for answering these questions are given in the next section. - - -Card specific information -========================= - -This section gives additional instructions about configuring some cards. -Please refer manual of your card for valid I/O, IRQ and DMA numbers. Using -the same settings with DOS/Windows and Linux is recommended. Using -different values could cause some problems when switching between -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 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 -using different values with DOS and Linux is likely to cause troubles. The -DOS driver is not able to reset the card properly after warm boot from Linux -if Linux has used different IRQ or DMA values. - -The original (steam) Sound Blaster (versions 1.x and 2.x) use always -DMA1. There is no way to change it. - -The SB16 needs two DMA channels. A 8 bit one (1 or 3) is required for -8 bit operation and a 16 bit one (5, 6 or 7) for the 16 bit mode. In theory -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 IDs. 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). - -SB Clones ---------- - -First of all: There are no SB16 clones. There are SB Pro clones with a -16 bit mode which is not SB16 compatible. The most likely alternative is that -the 16 bit mode means MSS/WSS. - -There are just a few fully 100% hardware SB or SB Pro compatible cards. -I know just Thunderboard and SM Games. Other cards require some kind of -hardware initialization before they become SB compatible. Check if your card -was listed in the beginning of this file. In this case you should follow -instructions for your card later in this file. - -For other not fully SB clones you may try initialization using DOS in -the following way: - - - Boot DOS so that the card specific driver gets run. - - Hit ctrl-alt-del (or use loadlin) to boot Linux. Don't - switch off power or press the reset button. - - If you use the same I/O, IRQ and DMA settings in Linux, the - card should work. - -If your card is both SB and MSS compatible, I recommend using the MSS mode. -Most cards of this kind are not able to work in the SB and the MSS mode -simultaneously. Using the MSS mode provides 16 bit recording and playback. - -ProAudioSpectrum 16 and compatibles ------------------------------------ - -PAS16 has a SB emulation chip which can be used together with the native -(16 bit) mode of the card. To enable this emulation you should configure -the driver to have SB support too (this has been changed since version -3.5-beta9 of this driver). - -With current driver versions it's also possible to use PAS16 together with -another SB compatible card. In this case you should configure SB support -for the other card and to disable the SB emulation of PAS16 (there is a -separate questions about this). - -With PAS16 you can use two audio device files at the same time. /dev/dsp (and -/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and -/dev/audio1) is connected to the SB emulation (8 bit mono only). - -Gravis Ultrasound ------------------ - -There are many different revisions of the Ultrasound card (GUS). The -earliest ones (pre 3.7) don't have a hardware mixer. With these cards -the driver uses a software emulation for synth and pcm playbacks. It's -also possible to switch some of the inputs (line in, mic) off by setting -mixer volume of the channel level below 10%. For recording you have -to select the channel as a recording source and to use volume above 10%. - -GUS 3.7 has a hardware mixer. - -GUS MAX and the 16 bit sampling daughtercard have a CS4231 codec chip which -also contains a mixer. - -Configuring GUS is simple. Just enable the GUS support and GUS MAX or -the 16 bit daughtercard if you have them. Note that enabling the daughter -card disables GUS MAX driver. - -NOTE for owners of the 16 bit daughtercard: By default the daughtercard -uses /dev/dsp (and /dev/audio). Command "ln -sf /dev/dsp1 /dev/dsp" -selects the daughter card as the default device. - -With just the standard GUS enabled the configuration program prompts -for the I/O, IRQ and DMA numbers for the card. Use the same values than -with DOS. - -With the daughter card option enabled you will be prompted for the I/O, -IRQ and DMA numbers for the daughter card. You have to use different I/O -and DMA values than for the standard GUS. The daughter card permits -simultaneous recording and playback. Use /dev/dsp (the daughtercard) for -recording and /dev/dsp1 (GUS GF1) for playback. - -GUS MAX uses the same I/O address and IRQ settings than the original GUS -(GUS MAX = GUS + a CS4231 codec). In addition an extra DMA channel may be used. -Using two DMA channels permits simultaneous playback using two devices -(dev/dsp0 and /dev/dsp1). The second DMA channel is required for -full duplex audio. -To enable the second DMA channels, give a valid DMA channel when the config -program asks for the GUS MAX DMA (entering -1 disables the second DMA). -Using 16 bit DMA channels (5,6 or 7) is recommended. - -If you have problems in recording with GUS MAX, you could try to use -just one 8 bit DMA channel. Recording will not work with one DMA -channel if it's a 16 bit one. - -Microphone input of GUS MAX is connected to mixer in little bit nonstandard -way. There is actually two microphone volume controls. Normal "mic" controls -only recording level. Mixer control "speaker" is used to control volume of -microphone signal connected directly to line/speaker out. So just decrease -volume of "speaker" if you have problems with microphone feedback. - -GUS ACE works too but any attempt to record or to use the MIDI port -will fail. - -GUS PnP (with RAM) is partially supported but it needs to be initialized using -DOS or isapnptools before starting the driver. - -MPU401 and Windows Sound System -------------------------------- - -Again. Don't enable these options in case your card is listed -somewhere else in this file. - -Configuring these cards is obvious (or it should be). With MSS -you should probably enable the OPL3 synth also since -most MSS compatible cards have it. However check that this is true -before enabling OPL3. - -Sound driver supports more than one MPU401 compatible cards at the same time -but the config program asks config info for just the first of them. -Adding the second or third MPU interfaces must be done manually by -editing sound/local.h (after running the config program). Add defines for -MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file. - -CAUTION! - -The default I/O base of Adaptec AHA-1542 SCSI controller is 0x330 which -is also the default of the MPU401 driver. Don't configure the sound driver to -use 0x330 as the MPU401 base if you have a AHA1542. The kernel will not boot -if you make this mistake. - -PSS ---- - -Even the PSS cards are compatible with SB, MSS and MPU401, you must not -enable these options when configuring the driver. The configuration -program handles these options itself. (You may use the SB, MPU and MSS options -together with PSS if you have another card on the system). - -The PSS driver enables MSS and MPU401 modes of the card. SB is not enabled -since it doesn't work concurrently with MSS. The driver loads also a -DSP algorithm which is used to for the general MIDI emulation. The -algorithm file (.ld) is read by the config program and written to a -file included when the pss.c is compiled. For this reason the config -program asks if you want to download the file. Use the genmidi.ld file -distributed with the DOS/Windows drivers of the card (don't use the mt32.ld). -With some cards the file is called 'synth.ld'. You must have access to -the file when configuring the driver. The easiest way is to mount the DOS -partition containing the file with Linux. - -It's possible to load your own DSP algorithms and run them with the card. -Look at the directory pss_test of snd-util-3.0.tar.gz for more info. - -AudioTrix Pro -------------- - -You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition -to the native AudioTrix driver. Don't enable MSS or MPU drivers. - -Configuring ATP is little bit tricky since it uses so many I/O, IRQ and -DMA numbers. Using the same values than with DOS/Win is a good idea. Don't -attempt to use the same IRQ or DMA channels twice. - -The SB mode of ATP is implemented so the ATP driver just enables SB -in the proper address. The SB driver handles the rest. You have to configure -both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O -settings. - -Also the ATP has a microcontroller for the General MIDI emulation (OPL4). -For this reason the driver asks for the name of a file containing the -microcode (TRXPRO.HEX). This file is usually located in the directory -where the DOS drivers were installed. You must have access to this file -when configuring the driver. - -If you have the effects daughtercard, it must be initialized by running -the setfx program of snd-util-3.0.tar.gz package. This step is not required -when using the (future) binary distribution version of the driver. - -Ensoniq SoundScape ------------------- - -NOTE! The new PnP SoundScape is not supported yet. Soundscape compatible - cards made by Reveal don't work with Linux. They use older revision - of the Soundscape chipset which is not fully compatible with - newer cards made by Ensoniq. - -The SoundScape driver handles initialization of MSS and MPU supports -itself so you don't need to enable other drivers than SoundScape -(enable also the /dev/dsp, /dev/sequencer and MIDI supports). - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!!!!! !!!! -!!!!! NOTE! Before version 3.5-beta6 there WERE two sets of audio !!!! -!!!!! device files (/dev/dsp0 and /dev/dsp1). The first one WAS !!!! -!!!!! used only for card initialization and the second for audio !!!! -!!!!! purposes. It WAS required to change /dev/dsp (a symlink) to !!!! -!!!!! point to /dev/dsp1. !!!! -!!!!! !!!! -!!!!! This is not required with OSS versions 3.5-beta6 and later !!!! -!!!!! since there is now just one audio device file. Please !!!! -!!!!! change /dev/dsp to point back to /dev/dsp0 if you are !!!! -!!!!! upgrading from an earlier driver version using !!!! -!!!!! (cd /dev;rm dsp;ln -s dsp0 dsp). !!!! -!!!!! !!!! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -The configuration program asks one DMA channel and two interrupts. One IRQ -and one DMA is used by the MSS codec. The second IRQ is required for the -MPU401 mode (you have to use different IRQs for both purposes). -There were earlier two DMA channels for SoundScape but the current driver -version requires just one. - -The SoundScape card has a Motorola microcontroller which must initialized -_after_ boot (the driver doesn't initialize it during boot). -The initialization is done by running the 'ssinit' program which is -distributed in the snd-util-3.0.tar.gz package. You have to edit two -defines in the ssinit.c and then compile the program. You may run ssinit -manually (after each boot) or add it to /etc/rc.d/rc.local. - -The ssinit program needs the microcode file that comes with the DOS/Windows -driver of the card. You will need to use version 1.30.00 or later -of the microcode file (sndscape.co0 or sndscape.co1 depending on -your card model). THE OLD sndscape.cod WILL NOT WORK. IT WILL HANG YOUR -MACHINE. The only way to get the new microcode file is to download -and install the DOS/Windows driver from ftp://ftp.ensoniq.com/pub. - -Then you have to select the proper microcode file to use: soundscape.co0 -is the right one for most cards and sndscape.co1 is for few (older) cards -made by Reveal and/or Spea. The driver has capability to detect the card -version during boot. Look at the boot log messages in /var/adm/messages -and locate the sound driver initialization message for the SoundScape -card. If the driver displays string <Ensoniq Soundscape (old)>, you have -an old card and you will need to use sndscape.co1. For other cards use -soundscape.co0. New Soundscape revisions such as Elite and PnP use -code files with higher numbers (.co2, .co3, etc.). - -NOTE! Ensoniq Soundscape VIVO is not compatible with other Soundscape cards. - Currently it's possible to use it in Linux only with OSS/Linux - drivers. - -Check /var/adm/messages after running ssinit. The driver prints -the board version after downloading the microcode file. That version -number must match the number in the name of the microcode file (extension). - -Running ssinit with a wrong version of the sndscape.co? file is not -dangerous as long as you don't try to use a file called sndscape.cod. -If you have initialized the card using a wrong microcode file (sounds -are terrible), just modify ssinit.c to use another microcode file and try -again. It's possible to use an earlier version of sndscape.co[01] but it -may sound weird. - -MAD16 (Pro) and Mozart ----------------------- - -You need to enable just the MAD16 /Mozart support when configuring -the driver. _Don't_ enable SB, MPU401 or MSS. However you will need the -/dev/audio, /dev/sequencer and MIDI supports. - -Mozart and OPTi 82C928 (the original MAD16) chips don't support -MPU401 mode so enter just 0 when the configuration program asks the -MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) and 82C930 chips have MPU401 -mode. - -TB Tropez is based on the 82C929 chip. It has two MIDI ports. -The one connected to the MAD16 chip is the second one (there is a second -MIDI connector/pins somewhere??). If you have not connected the second MIDI -port, just disable the MIDI port of MAD16. The 'Maui' compatible synth of -Tropez is jumper configurable and not connected to the MAD16 chip (the -Maui driver can be used with it). - -Some MAD16 based cards may cause feedback, whistle or terrible noise if the -line3 mixer channel is turned too high. This happens at least with Shuttle -Sound System. Current driver versions set volume of line3 low enough so -this should not be a problem. - -If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer -chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4 -to the file linux/drivers/sound/local.h (after running make config). - -MAD16 cards having a CS4231 codec support full duplex mode. This mode -can be enabled by configuring the card to use two DMA channels. Possible -DMA channel pairs are: 0&1, 1&0 and 3&0. - -NOTE! Cards having an OPTi 82C924/82C925 chip work with OSS/Free only in -non-PnP mode (usually jumper selectable). The PnP mode is supported only -by OSS/Linux. - -MV Jazz (ProSonic) ------------------- - -The Jazz16 driver is just a hack made to the SB Pro driver. However it works -fairly well. You have to enable SB, SB Pro (_not_ SB16) and MPU401 supports -when configuring the driver. The configuration program asks later if you -want support for MV Jazz16 based cards (after asking SB base address). Answer -'y' here and the driver asks the second (16 bit) DMA channel. - -The Jazz16 driver uses the MPU401 driver in a way which will cause -problems if you have another MPU401 compatible card. In this case you must -give address of the Jazz16 based MPU401 interface when the config -program prompts for the MPU401 information. Then look at the MPU401 -specific section for instructions about configuring more than one MPU401 cards. - -Logitech Soundman Wave ----------------------- - -Read the above MV Jazz specific instructions first. - -The Logitech SoundMan Wave (don't confuse this with the SM16 or SM Games) is -a MV Jazz based card which has an additional OPL4 based wave table -synthesizer. The OPL4 chip is handled by an on board microcontroller -which must be initialized during boot. The config program asks if -you have a SM Wave immediately after asking the second DMA channel of jazz16. -If you answer 'y', the config program will ask name of the file containing -code to be loaded to the microcontroller. The file is usually called -MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file -may also be called as TSUNAMI.BIN or something else (older cards?). - -The OPL4 synth will be inaccessible without loading the microcontroller code. - -Also remember to enable SB MPU401 support if you want to use the OPL4 mode. -(Don't enable the 'normal' MPU401 device as with some earlier driver -versions (pre 3.5-alpha8)). - -NOTE! Don't answer 'y' when the driver asks about SM Games support - (the next question after the MIDI0001.BIN name). However - answering 'y' doesn't cause damage your computer so don't panic. - -Sound Galaxies --------------- - -There are many different Sound Galaxy cards made by Aztech. The 8 bit -ones are fully SB or SB Pro compatible and there should be no problems -with them. - -The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have -an EEPROM chip for storing the configuration data. There is a microcontroller -which initializes the card to match the EEPROM settings when the machine -is powered on. These cards actually behave just like they have jumpers -for all of the settings. Configure driver for MSS, MPU, SB/SB Pro and OPL3 -supports with these cards. - -There are some new Sound Galaxies in the market. I have no experience with -them so read the card's manual carefully. - -ESS ES1688 and ES688 'AudioDrive' based cards ---------------------------------------------- - -Support for these two ESS chips is embedded in the SB driver. -Configure these cards just like SB. Enable the 'SB MPU401 MIDI port' -if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode -so you don't need to enable it (the driver uses normal SB MIDI automatically -with ES688). - -NOTE! ESS cards are not compatible with MSS/WSS so don't worry if MSS support -of OSS doesn't work with it. - -There are some ES1688/688 based sound cards and (particularly) motherboards -which use software configurable I/O port relocation feature of the chip. -This ESS proprietary feature is supported only by OSS/Linux. - -There are ES1688 based cards which use different interrupt pin assignment than -recommended by ESS (5, 7, 9/2 and 10). In this case all IRQs don't work. -At least a card called (Pearl?) Hypersound 16 supports IRQ 15 but it doesn't -work. - -ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688 -probably works with OSS/Free after initialization using isapnptools. - -Reveal cards ------------- - -There are several different cards made/marketed by Reveal. Some of them -are compatible with SoundScape and some use the MAD16 chip. You may have -to look at the card and try to identify its origin. - -Diamond -------- - -The oldest (Sierra Aria based) sound cards made by Diamond are not supported -(they may work if the card is initialized using DOS). The recent (LX?) -models are based on the MAD16 chip which is supported by the driver. - -Audio Excel DSP16 ------------------ - -Support for this card is currently not functional. A new driver for it -should be available later this year. - -PCMCIA cards ------------- - -Sorry, can't help. Some cards may work and some don't. - -TI TM4000M notebooks --------------------- - -These computers have a built in sound support based on the Jazz chipset. -Look at the instructions for MV Jazz (above). It's also important to note -that there is something wrong with the mouse port and sound at least on -some TM models. Don't enable the "C&T 82C710 mouse port support" when -configuring Linux. Having it enabled is likely to cause mysterious problems -and kernel failures when sound is used. - -miroSOUND ---------- - -The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used -successfully. These cards are based on the MAD16, OPL4, and CS4231A chips -and everything said in the section about MAD16 cards applies here, -too. The only major difference between the PCMxx and other MAD16 cards -is that instead of the mixer in the CS4231 codec a separate mixer -controlled by an on-board 80C32 microcontroller is used. Control of -the mixer takes place via the ACI (miro's audio control interface) -protocol that is implemented in a separate lowlevel driver. Make sure -you compile this ACI driver together with the normal MAD16 support -when you use a miroSOUND PCMxx card. The ACI mixer is controlled by -/dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load -time). Only in special cases you want to change something regularly on -the CS4231 mixer. - -The miroSOUND PCM12 and PCM20 radio is capable of full duplex -operation (simultaneous PCM replay and recording), which allows you to -implement nice real-time signal processing audio effect software and -network telephones. The ACI mixer has to be switched into the "solo" -mode for duplex operation in order to avoid feedback caused by the -mixer (input hears output signal). You can de-/activate this mode -through toggling the record button for the wave controller with an -OSS-mixer. - -The PCM20 contains a radio tuner, which is also controlled by -ACI. This radio tuner is supported by the ACI driver together with the -miropcm20.o module. Also the 7-band equalizer is integrated -(limited by the OSS-design). Development has started and maybe -finished for the RDS decoder on this card, too. You will be able to -read RadioText, the Programme Service name, Programme TYpe and -others. Even the v4l radio module benefits from it with a refined -strength value. See aci.[ch] and miropcm20*.[ch] for more details. - -The following configuration parameters have worked fine for the PCM12 -in Markus Kuhn's system, many other configurations might work, too: -CONFIG_MAD16_BASE=0x530, CONFIG_MAD16_IRQ=11, CONFIG_MAD16_DMA=3, -CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10, -DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000. - -Bas van der Linden is using his PCM1-pro with a configuration that -differs in: CONFIG_MAD16_IRQ=7, CONFIG_MAD16_DMA=1, CONFIG_MAD16_MPU_IRQ=9 - -Compaq Deskpro XL ------------------ - -The builtin sound hardware of Compaq Deskpro XL is now supported. -You need to configure the driver with MSS and OPL3 supports enabled. -In addition you need to manually edit linux/drivers/sound/local.h and -to add a line containing "#define DESKPROXL" if you used -make menuconfig/xconfig. - -Others? -------- - -Since there are so many different sound cards, it's likely that I have -forgotten to mention many of them. Please inform me if you know yet another -card which works with Linux, please inform me (or is anybody else -willing to maintain a database of supported cards (just like in XF86)?). - -Cards not supported yet -======================= - -Please check the version of sound driver you are using before -complaining that your card is not supported. It's possible you are -using a driver version which was released months before your card was -introduced. - -First of all, there is an easy way to make most sound cards work with Linux. -Just use the DOS based driver to initialize the card to a known state, then use -loadlin.exe to boot Linux. If Linux is configured to use the same I/O, IRQ and -DMA numbers as DOS, the card could work. -(ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with -new motherboards). This method works also with all/most PnP sound cards. - -Don't get fooled with SB compatibility. Most cards are compatible with -SB but that may require a TSR which is not possible with Linux. If -the card is compatible with MSS, it's a better choice. Some cards -don't work in the SB and MSS modes at the same time. - -Then there are cards which are no longer manufactured and/or which -are relatively rarely used (such as the 8 bit ProAudioSpectrum -models). It's extremely unlikely that such cards ever get supported. -Adding support for a new card requires much work and increases time -required in maintaining the driver (some changes need to be done -to all low level drivers and be tested too, maybe with multiple -operating systems). For this reason I have made a decision to not support -obsolete cards. It's possible that someone else makes a separately -distributed driver (diffs) for the card. - -Writing a driver for a new card is not possible if there are no -programming information available about the card. If you don't -find your new card from this file, look from the home page -(http://www.opensound.com/ossfree). Then please contact -manufacturer of the card and ask if they have (or are willing to) -released technical details of the card. Do this before contacting me. I -can only answer 'no' if there are no programming information available. - -I have made decision to not accept code based on reverse engineering -to the driver. There are three main reasons: First I don't want to break -relationships to sound card manufacturers. The second reason is that -maintaining and supporting a driver without any specs will be a pain. -The third reason is that companies have freedom to refuse selling their -products to other than Windows users. - -Some companies don't give low level technical information about their -products to public or at least their require signing a NDA. It's not -possible to implement a freeware driver for them. However it's possible -that support for such cards become available in the commercial version -of this driver (see http://www.4Front-tech.com/oss.html for more info). - -There are some common audio chipsets that are not supported yet. For example -Sierra Aria and IBM Mwave. It's possible that these architectures -get some support in future but I can't make any promises. Just look -at the home page (http://www.opensound.com/ossfree/) -for latest info. - -Information about unsupported sound cards and chipsets is welcome as well -as free copies of sound cards, SDKs and operating systems. - -If you have any corrections and/or comments, please contact me. - -Hannu Savolainen -hannu@opensound.com - -home page of OSS/Free: http://www.opensound.com/ossfree - -home page of commercial OSS -(Open Sound System) drivers: http://www.opensound.com/oss.html diff --git a/Documentation/sound/oss/README.modules b/Documentation/sound/oss/README.modules deleted file mode 100644 index cdc039421a46..000000000000 --- a/Documentation/sound/oss/README.modules +++ /dev/null @@ -1,106 +0,0 @@ -Building a modular sound driver -================================ - - The following information is current as of linux-2.1.85. Check the other -readme files, especially README.OSS, for information not specific to -making sound modular. - - First, configure your kernel. This is an idea of what you should be -setting in the sound section: - -<M> Sound card support - -<M> 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support - - I have SoundBlaster. Select your card from the list. - -<M> Generic OPL2/OPL3 FM synthesizer support -<M> FM synthesizer (YM3812/OPL-3) support - - If you don't set these, you will probably find you can play .wav files -but not .midi. As the help for them says, set them unless you know your -card does not use one of these chips for FM support. - - Once you are configured, make zlilo, modules, modules_install; reboot. -Note that it is no longer necessary or possible to configure sound in the -drivers/sound dir. Now one simply configures and makes one's kernel and -modules in the usual way. - - Then, add to your /etc/modprobe.d/oss.conf something like: - -alias char-major-14-* sb -install sb /sbin/modprobe -i sb && /sbin/modprobe adlib_card -options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 -options adlib_card io=0x388 # FM synthesizer - - Alternatively, if you have compiled in kernel level ISAPnP support: - -alias char-major-14 sb -softdep sb post: adlib_card -options adlib_card io=0x388 - - The effect of this is that the sound driver and all necessary bits and -pieces autoload on demand, assuming you use kerneld (a sound choice) and -autoclean when not in use. Also, options for the device drivers are -set. They will not work without them. Change as appropriate for your card. -If you are not yet using the very cool kerneld, you will have to "modprobe --k sb" yourself to get things going. Eventually things may be fixed so -that this kludgery is not necessary; for the time being, it seems to work -well. - - Replace 'sb' with the driver for your card, and give it the right -options. To find the filename of the driver, look in -/lib/modules/<kernel-version>/misc. Mine looks like: - -adlib_card.o # This is the generic OPLx driver -opl3.o # The OPL3 driver -sb.o # <<The SoundBlaster driver. Yours may differ.>> -sound.o # The sound driver -uart401.o # Used by sb, maybe other cards - - Whichever card you have, try feeding it the options that would be the -default if you were making the driver wired, not as modules. You can -look at function referred to by module_init() for the card to see what -args are expected. - - Note that at present there is no way to configure the io, irq and other -parameters for the modular drivers as one does for the wired drivers.. One -needs to pass the modules the necessary parameters as arguments, either -with /etc/modprobe.d/*.conf or with command-line args to modprobe, e.g. - -modprobe sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 -modprobe adlib_card io=0x388 - - recommend using /etc/modprobe.d/*.conf. - -Persistent DMA Buffers: - -The sound modules normally allocate DMA buffers during open() and -deallocate them during close(). Linux can often have problems allocating -DMA buffers for ISA cards on machines with more than 16MB RAM. This is -because ISA DMA buffers must exist below the 16MB boundary and it is quite -possible that we can't find a large enough free block in this region after -the machine has been running for any amount of time. The way to avoid this -problem is to allocate the DMA buffers during module load and deallocate -them when the module is unloaded. For this to be effective we need to load -the sound modules right after the kernel boots, either manually or by an -init script, and keep them around until we shut down. This is a little -wasteful of RAM, but it guarantees that sound always works. - -To make the sound driver use persistent DMA buffers we need to pass the -sound.o module a "dmabuf=1" command-line argument. This is normally done -in /etc/modprobe.d/*.conf files like so: - -options sound dmabuf=1 - -If you have 16MB or less RAM or a PCI sound card, this is wasteful and -unnecessary. It is possible that machine with 16MB or less RAM will find -this option useful, but if your machine is so memory-starved that it -cannot find a 64K block free, you will be wasting even more RAM by keeping -the sound modules loaded and the DMA buffers allocated when they are not -needed. The proper solution is to upgrade your RAM. But you do also have -this improper solution as well. Use it wisely. - - I'm afraid I know nothing about anything but my setup, being more of a -text-mode guy anyway. If you have options for other cards or other helpful -hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb. diff --git a/Documentation/sound/oss/README.ymfsb b/Documentation/sound/oss/README.ymfsb deleted file mode 100644 index b6b77906b58d..000000000000 --- a/Documentation/sound/oss/README.ymfsb +++ /dev/null @@ -1,107 +0,0 @@ -Legacy audio driver for YMF7xx PCI cards. - - -FIRST OF ALL -============ - - This code references YAMAHA's sample codes and data sheets. - I respect and thank for all people they made open the information - about YMF7xx cards. - - And this codes heavily based on Jeff Garzik <jgarzik@pobox.com>'s - old VIA 82Cxxx driver (via82cxxx.c). I also respect him. - - -DISCLIMER -========= - - This driver is currently at early ALPHA stage. It may cause serious - damage to your computer when used. - PLEASE USE IT AT YOUR OWN RISK. - - -ABOUT THIS DRIVER -================= - - This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754 - cards. When enabled, your card acts as "SoundBlaster Pro" compatible card. - It can only play 22.05kHz / 8bit / Stereo samples, control external MIDI - port. - If you want to use your card as recent "16-bit" card, you should use - Alsa or OSS/Linux driver. Of course you can write native PCI driver for - your cards :) - - -USAGE -===== - - # modprobe ymfsb (options) - - -OPTIONS FOR MODULE -================== - - io : SB base address (0x220, 0x240, 0x260, 0x280) - synth_io : OPL3 base address (0x388, 0x398, 0x3a0, 0x3a8) - dma : DMA number (0,1,3) - master_volume: AC'97 PCM out Vol (0-100) - spdif_out : SPDIF-out flag (0:disable 1:enable) - - These options will change in future... - - -FREQUENCY -========= - - When playing sounds via this driver, you will hear its pitch is slightly - lower than original sounds. Since this driver recognizes your card acts - with 21.739kHz sample rates rather than 22.050kHz (I think it must be - hardware restriction). So many players become tone deafness. - To prevent this, you should express some options to your sound player - that specify correct sample frequency. For example, to play your MP3 file - correctly with mpg123, specify the frequency like following: - - % mpg123 -r 21739 foo.mp3 - - -SPDIF OUT -========= - - With installing modules with option 'spdif_out=1', you can enjoy your - sounds from SPDIF-out of your card (if it had). - Its Fs is fixed to 48kHz (It never means the sample frequency become - up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your - digital-in capable components has to be able to handle 48kHz Fs. - - -COPYING -======= - - 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, 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. - - -TODO -==== - * support for multiple cards - (set the different SB_IO,MPU_IO,OPL_IO for each cards) - - * support for OPL (dmfm) : There will be no requirements... :-< - - -AUTHOR -====== - - Daisuke Nagano <breeze.nagano@nifty.ne.jp> - diff --git a/Documentation/sound/oss/SoundPro b/Documentation/sound/oss/SoundPro deleted file mode 100644 index 9d4db1f29d3c..000000000000 --- a/Documentation/sound/oss/SoundPro +++ /dev/null @@ -1,105 +0,0 @@ -Documentation for the SoundPro CMI8330 extensions in the WSS driver (ad1848.o) ------------------------------------------------------------------------------- - -( Be sure to read Documentation/sound/oss/CMI8330 too ) - -Ion Badulescu, ionut@cs.columbia.edu -February 24, 1999 - -(derived from the OPL3-SA2 documentation by Scott Murray) - -The SoundPro CMI8330 (ISA) is a chip usually found on some Taiwanese -motherboards. The official name in the documentation is CMI8330, SoundPro -is the nickname and the big inscription on the chip itself. - -The chip emulates a WSS as well as a SB16, but it has certain differences -in the mixer section which require separate support. It also emulates an -MPU401 and an OPL3 synthesizer, so you probably want to enable support -for these, too. - -The chip identifies itself as an AD1848, but its mixer is significantly -more advanced than the original AD1848 one. If your system works with -either WSS or SB16 and you are having problems with some mixer controls -(no CD audio, no line-in, etc), you might want to give this driver a try. -Detection should work, but it hasn't been widely tested, so it might still -mis-identify the chip. You can still force soundpro=1 in the modprobe -parameters for ad1848. Please let me know if it happens to you, so I can -adjust the detection routine. - -The chip is capable of doing full-duplex, but since the driver sees it as an -AD1848, it cannot take advantage of this. Moreover, the full-duplex mode is -not achievable through the WSS interface, b/c it needs a dma16 line which is -assigned only to the SB16 subdevice (with isapnp). Windows documentation -says the user must use WSS Playback and SB16 Recording for full-duplex, so -it might be possible to do the same thing under Linux. You can try loading -up both ad1848 and sb then use one for playback and the other for -recording. I don't know if this works, b/c I haven't tested it. Anyway, if -you try it, be very careful: the SB16 mixer *mostly* works, but certain -settings can have unexpected effects. Use the WSS mixer for best results. - -There is also a PCI SoundPro chip. I have not seen this chip, so I have -no idea if the driver will work with it. I suspect it won't. - -As with PnP cards, some configuration is required. There are two ways -of doing this. The most common is to use the isapnptools package to -initialize the card, and use the kernel module form of the sound -subsystem and sound drivers. Alternatively, some BIOS's allow manual -configuration of installed PnP devices in a BIOS menu, which should -allow using the non-modular sound drivers, i.e. built into the kernel. -Since in this latter case you cannot use module parameters, you will -have to enable support for the SoundPro at compile time. - -The IRQ and DMA values can be any that are considered acceptable for a -WSS. Assuming you've got isapnp all happy, then you should be able to -do something like the following (which *must* match the isapnp/BIOS -configuration): - -modprobe ad1848 io=0x530 irq=11 dma=0 soundpro=1 --and maybe- -modprobe sb io=0x220 irq=5 dma=1 dma16=5 - --then- -modprobe mpu401 io=0x330 irq=9 -modprobe opl3 io=0x388 - -If all goes well and you see no error messages, you should be able to -start using the sound capabilities of your system. If you get an -error message while trying to insert the module(s), then make -sure that the values of the various arguments match what you specified -in your isapnp configuration file, and that there is no conflict with -another device for an I/O port or interrupt. Checking the contents of -/proc/ioports and /proc/interrupts can be useful to see if you're -butting heads with another device. - -If you do not see the chipset version message, and none of the other -messages present in the system log are helpful, try adding 'debug=1' -to the ad1848 parameters, email me the syslog results and I'll do -my best to help. - -Lastly, if you're using modules and want to set up automatic module -loading with kmod, the kernel module loader, here is the section I -currently use in my conf.modules file: - -# Sound -post-install sound modprobe -k ad1848; modprobe -k mpu401; modprobe -k opl3 -options ad1848 io=0x530 irq=11 dma=0 -options sb io=0x220 irq=5 dma=1 dma16=5 -options mpu401 io=0x330 irq=9 -options opl3 io=0x388 - -The above ensures that ad1848 will be loaded whenever the sound system -is being used. - -Good luck. - -Ion - -NOT REALLY TESTED: -- recording -- recording device selection -- full-duplex - -TODO: -- implement mixer support for surround, loud, digital CD switches. -- come up with a scheme which allows recording volumes for each subdevice. -This is a major OSS API change. diff --git a/Documentation/sound/oss/Soundblaster b/Documentation/sound/oss/Soundblaster deleted file mode 100644 index b288d464ba8b..000000000000 --- a/Documentation/sound/oss/Soundblaster +++ /dev/null @@ -1,53 +0,0 @@ -modprobe sound -insmod uart401 -insmod sb ... - -This loads the driver for the Sound Blaster and assorted clones. Cards that -are covered by other drivers should not be using this driver. - -The Sound Blaster module takes the following arguments - -io I/O address of the Sound Blaster chip (0x220,0x240,0x260,0x280) -irq IRQ of the Sound Blaster chip (5,7,9,10) -dma 8-bit DMA channel for the Sound Blaster (0,1,3) -dma16 16-bit DMA channel for SB16 and equivalent cards (5,6,7) -mpu_io I/O for MPU chip if present (0x300,0x330) - -sm_games=1 Set if you have a Logitech soundman games -acer=1 Set this to detect cards in some ACER notebooks -mwave_bug=1 Set if you are trying to use this driver with mwave (see on) -type Use this to specify a specific card type - -The following arguments are taken if ISAPnP support is compiled in - -isapnp=0 Set this to disable ISAPnP detection (use io=0xXXX etc. above) -multiple=0 Set to disable detection of multiple Soundblaster cards. - Consider it a bug if this option is needed, and send in a - report. -pnplegacy=1 Set this to be able to use a PnP card(s) along with a single - non-PnP (legacy) card. Above options for io, irq, etc. are - needed, and will apply only to the legacy card. -reverse=1 Reverses the order of the search in the PnP table. -uart401=1 Set to enable detection of mpu devices on some clones. -isapnpjump=n Jumps to slot n in the driver's PnP table. Use the source, - Luke. - -You may well want to load the opl3 driver for synth music on most SB and -clone SB devices - -insmod opl3 io=0x388 - -Using Mwave - -To make this driver work with Mwave you must set mwave_bug. You also need -to warm boot from DOS/Windows with the required firmware loaded under this -OS. IBM are being difficult about documenting how to load this firmware. - -Avance Logic ALS007 - -This card is supported; see the separate file ALS007 for full details. - -Avance Logic ALS100 - -This card is supported; setup should be as for a standard Sound Blaster 16. -The driver will identify the audio device as a "Sound Blaster 16 (ALS-100)". diff --git a/Documentation/sound/oss/Tropez+ b/Documentation/sound/oss/Tropez+ deleted file mode 100644 index b93a6b734fc0..000000000000 --- a/Documentation/sound/oss/Tropez+ +++ /dev/null @@ -1,26 +0,0 @@ -From: Paul Barton-Davis <pbd@op.net> - -Here is the configuration I use with a Tropez+ and my modular -driver: - - alias char-major-14 wavefront - alias synth0 wavefront - alias mixer0 cs4232 - alias audio0 cs4232 - pre-install wavefront modprobe "-k" "cs4232" - post-install wavefront modprobe "-k" "opl3" - options wavefront io=0x200 irq=9 - options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0 - options opl3 io=0x388 - -Things to note: - - the wavefront options "io" and "irq" ***MUST*** match the "synthio" - and "synthirq" cs4232 options. - - you can do without the opl3 module if you don't - want to use the OPL/[34] synth on the soundcard - - the opl3 io parameter is conventionally not adjustable. - -Please see drivers/sound/README.wavefront for more details. diff --git a/Documentation/sound/oss/VIBRA16 b/Documentation/sound/oss/VIBRA16 deleted file mode 100644 index 68a5a46beb88..000000000000 --- a/Documentation/sound/oss/VIBRA16 +++ /dev/null @@ -1,80 +0,0 @@ -Sound Blaster 16X Vibra addendum --------------------------------- -by Marius Ilioaea <mariusi@protv.ro> - Stefan Laudat <stefan@asit.ro> - -Sat Mar 6 23:55:27 EET 1999 - - Hello again, - - Playing with a SB Vibra 16x soundcard we found it very difficult -to setup because the kernel reported a lot of DMA errors and wouldn't -simply play any sound. - A good starting point is that the vibra16x chip full-duplex facility -is neither still exploited by the sb driver found in the linux kernel -(tried it with a 2.2.2-ac7), nor in the commercial OSS package (it reports -it as half-duplex soundcard). Oh, I almost forgot, the RedHat sndconfig -failed detecting it ;) - So, the big problem still remains, because the sb module wants a -8-bit and a 16-bit dma, which we could not allocate for vibra... it supports -only two 8-bit dma channels, the second one will be passed to the module -as a 16 bit channel, the kernel will yield about that but everything will -be okay, trust us. - The only inconvenient you may find is that you will have -some sound playing jitters if you have HDD dma support enabled - but this -will happen with almost all soundcards... - - A fully working isapnp.conf is just here: - -<snip here> - -(READPORT 0x0203) -(ISOLATE PRESERVE) -(IDENTIFY *) -(VERBOSITY 2) -(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING -# SB 16 and OPL3 devices -(CONFIGURE CTL00f0/-1 (LD 0 -(INT 0 (IRQ 5 (MODE +E))) -(DMA 0 (CHANNEL 1)) -(DMA 1 (CHANNEL 3)) -(IO 0 (SIZE 16) (BASE 0x0220)) -(IO 2 (SIZE 4) (BASE 0x0388)) -(NAME "CTL00f0/-1[0]{Audio }") -(ACT Y) -)) - -# Joystick device - only if you need it :-/ - -(CONFIGURE CTL00f0/-1 (LD 1 -(IO 0 (SIZE 1) (BASE 0x0200)) -(NAME "CTL00f0/-1[1]{Game }") -(ACT Y) -)) -(WAITFORKEY) - -<end of snipping> - - So, after a good kernel modules compilation and a 'depmod -a kernel_ver' -you may want to: - -modprobe sb io=0x220 irq=5 dma=1 dma16=3 - - Or, take the hard way: - -modprobe soundcore -modprobe sound -modprobe uart401 -modprobe sb io=0x220 irq=5 dma=1 dma16=3 -# do you need MIDI? -modprobe opl3=0x388 - - Just in case, the kernel sound support should be: - -CONFIG_SOUND=m -CONFIG_SOUND_OSS=m -CONFIG_SOUND_SB=m - - Enjoy your new noisy Linux box! ;) - - diff --git a/Documentation/sound/oss/WaveArtist b/Documentation/sound/oss/WaveArtist deleted file mode 100644 index f4f3407cd818..000000000000 --- a/Documentation/sound/oss/WaveArtist +++ /dev/null @@ -1,170 +0,0 @@ - - (the following is from the armlinux CVS) - - WaveArtist mixer and volume levels can be accessed via these commands: - - nn30 read registers nn, where nn = 00 - 09 for mixer settings - 0a - 13 for channel volumes - mm31 write the volume setting in pairs, where mm = (nn - 10) / 2 - rr32 write the mixer settings in pairs, where rr = nn/2 - xx33 reset all settings to default - 0y34 select mono source, y=0 = left, y=1 = right - - bits - nn 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 00 | 0 | 0 0 1 1 | left line mixer gain | left aux1 mixer gain |lmute| -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 01 | 0 | 0 1 0 1 | left aux2 mixer gain | right 2 left mic gain |mmute| -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 02 | 0 | 0 1 1 1 | left mic mixer gain | left mic | left mixer gain |dith | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 03 | 0 | 1 0 0 1 | left mixer input select |lrfg | left ADC gain | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 04 | 0 | 1 0 1 1 | right line mixer gain | right aux1 mixer gain |rmute| -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 05 | 0 | 1 1 0 1 | right aux2 mixer gain | left 2 right mic gain |test | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 06 | 0 | 1 1 1 1 | right mic mixer gain | right mic |right mixer gain |rbyps| -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 07 | 1 | 0 0 0 1 | right mixer select |rrfg | right ADC gain | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 08 | 1 | 0 0 1 1 | mono mixer gain |right ADC mux sel|left ADC mux sel | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 09 | 1 | 0 1 0 1 |loopb|left linout|loop|ADCch|TxFch|OffCD|test |loopb|loopb|osamp| -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 0a | 0 | left PCM channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 0b | 0 | right PCM channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 0c | 0 | left FM channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 0d | 0 | right FM channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 0e | 0 | left wavetable channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 0f | 0 | right wavetable channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 10 | 0 | left PCM expansion channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 11 | 0 | right PCM expansion channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 12 | 0 | left FM expansion channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - 13 | 0 | right FM expansion channel volume | -----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+ - - lmute: left mute - mmute: mono mute - dith: dithds - lrfg: - rmute: right mute - rbyps: right bypass - rrfg: - ADCch: - TxFch: - OffCD: - osamp: - - And the following diagram is derived from the description in the CVS archive: - - MIC L (mouthpiece) - +------+ - -->PreAmp>-\ - +--^---+ | - | | - r2b4-5 | +--------+ - /----*-------------------------------->5 | - | | | - | /----------------------------------->4 | - | | | | - | | /--------------------------------->3 1of5 | +---+ - | | | | mux >-->AMP>--> ADC L - | | | /------------------------------->2 | +-^-+ - | | | | | | | - Line | | | | +----+ +------+ +---+ /---->1 | r3b3-0 - ------------*->mute>--> Gain >--> | | | | - L | | | +----+ +------+ | | | *->0 | - | | | | | | +---^----+ - Aux2 | | | +----+ +------+ | | | | - ----------*--->mute>--> Gain >--> M | | r8b0-2 - L | | +----+ +------+ | | | - | | | | \------\ - Aux1 | | +----+ +------+ | | | - --------*----->mute>--> Gain >--> I | | - L | +----+ +------+ | | | - | | | | - | +----+ +------+ | | +---+ | - *------->mute>--> Gain >--> X >-->AMP>--* - | +----+ +------+ | | +-^-+ | - | | | | | - | +----+ +------+ | | r2b1-3 | - | /----->mute>--> Gain >--> E | | - | | +----+ +------+ | | | - | | | | | - | | +----+ +------+ | | | - | | /--->mute>--> Gain >--> R | | - | | | +----+ +------+ | | | - | | | | | | r9b8-9 - | | | +----+ +------+ | | | | - | | | /->mute>--> Gain >--> | | +---v---+ - | | | | +----+ +------+ +---+ /-*->0 | - DAC | | | | | | | - ------------*----------------------------------->? | +----+ - L | | | | | Mux >-->mute>--> L output - | | | | /->? | +--^-+ - | | | | | | | | - | | | /--------->? | r0b0 - | | | | | | +-------+ - | | | | | | - Mono | | | | | | +-------+ - ----------* | \---> | +----+ - | | | | | | Mix >-->mute>--> Mono output - | | | | *-> | +--^-+ - | | | | | +-------+ | - | | | | | r1b0 - DAC | | | | | +-------+ - ------------*-------------------------*--------->1 | +----+ - R | | | | | | Mux >-->mute>--> R output - | | | | +----+ +------+ +---+ *->0 | +--^-+ - | | | \->mute>--> Gain >--> | | +---^---+ | - | | | +----+ +------+ | | | | r5b0 - | | | | | | r6b0 - | | | +----+ +------+ | | | - | | \--->mute>--> Gain >--> M | | - | | +----+ +------+ | | | - | | | | | - | | +----+ +------+ | | | - | *----->mute>--> Gain >--> I | | - | | +----+ +------+ | | | - | | | | | - | | +----+ +------+ | | +---+ | - \------->mute>--> Gain >--> X >-->AMP>--* - | +----+ +------+ | | +-^-+ | - /--/ | | | | - Aux1 | +----+ +------+ | | r6b1-3 | - -------*------>mute>--> Gain >--> E | | - R | | +----+ +------+ | | | - | | | | | - Aux2 | | +----+ +------+ | | /------/ - ---------*---->mute>--> Gain >--> R | | - R | | | +----+ +------+ | | | - | | | | | | +--------+ - Line | | | +----+ +------+ | | | *->0 | - -----------*-->mute>--> Gain >--> | | | | - R | | | | +----+ +------+ +---+ \---->1 | - | | | | | | - | | | \-------------------------------->2 | +---+ - | | | | Mux >-->AMP>--> ADC R - | | \---------------------------------->3 | +-^-+ - | | | | | - | \------------------------------------>4 | r7b3-0 - | | | - \-----*-------------------------------->5 | - | +---^----+ - r6b4-5 | | - | | r8b3-5 - +--v---+ | - -->PreAmp>-/ - +------+ - MIC R (electret mic) diff --git a/Documentation/sound/oss/btaudio b/Documentation/sound/oss/btaudio deleted file mode 100644 index effdb9a3f898..000000000000 --- a/Documentation/sound/oss/btaudio +++ /dev/null @@ -1,92 +0,0 @@ - -Intro -===== - -people start bugging me about this with questions, looks like I -should write up some documentation for this beast. That way I -don't have to answer that much mails I hope. Yes, I'm lazy... - - -You might have noticed that the bt878 grabber cards have actually -_two_ PCI functions: - -$ lspci -[ ... ] -00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02) -00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02) -[ ... ] - -The first does video, it is backward compatible to the bt848. The second -does audio. btaudio is a driver for the second function. It's a sound -driver which can be used for recording sound (and _only_ recording, no -playback). As most TV cards come with a short cable which can be plugged -into your sound card's line-in you probably don't need this driver if all -you want to do is just watching TV... - - -Driver Status -============= - -Still somewhat experimental. The driver should work stable, i.e. it -should'nt crash your box. It might not work as expected, have bugs, -not being fully OSS API compliant, ... - -Latest versions are available from http://bytesex.org/bttv/, the -driver is in the bttv tarball. Kernel patches might be available too, -have a look at http://bytesex.org/bttv/listing.html. - -The chip knows two different modes. btaudio registers two dsp -devices, one for each mode. They can not be used at the same time. - - -Digital audio mode -================== - -The chip gives you 16 bit stereo sound. The sample rate depends on -the external source which feeds the bt878 with digital sound via I2S -interface. There is a insmod option (rate) to tell the driver which -sample rate the hardware uses (32000 is the default). - -One possible source for digital sound is the msp34xx audio processor -chip which provides digital sound via I2S with 32 kHz sample rate. My -Hauppauge board works this way. - -The Osprey-200 reportly gives you digital sound with 44100 Hz sample -rate. It is also possible that you get no sound at all. - - -analog mode (A/D) -================= - -You can tell the driver to use this mode with the insmod option "analog=1". -The chip has three analog inputs. Consequently you'll get a mixer device -to control these. - -The analog mode supports mono only. Both 8 + 16 bit. Both are _signed_ -int, which is uncommon for the 8 bit case. Sample rate range is 119 kHz -to 448 kHz. Yes, the number of digits is correct. The driver supports -downsampling by powers of two, so you can ask for more usual sample rates -like 44 kHz too. - -With my Hauppauge I get noisy sound on the second input (mapped to line2 -by the mixer device). Others get a useable signal on line1. - - -some examples -============= - -* read audio data from btaudio (dsp2), send to es1730 (dsp,dsp1): - $ sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp - -* read audio data from btaudio, send to esound daemon (which might be - running on another host): - $ sox -c 2 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -r 32000 - $ sox -c 1 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -m -r 32000 - - -Have fun, - - Gerd - --- -Gerd Knorr <kraxel@bytesex.org> diff --git a/Documentation/sound/oss/mwave b/Documentation/sound/oss/mwave deleted file mode 100644 index 5fbcb1609275..000000000000 --- a/Documentation/sound/oss/mwave +++ /dev/null @@ -1,185 +0,0 @@ - How to try to survive an IBM Mwave under Linux SB drivers - - -+ IBM have now released documentation of sorts and Torsten is busy - trying to make the Mwave work. This is not however a trivial task. - ----------------------------------------------------------------------------- - -OK, first thing - the IRQ problem IS a problem, whether the test is bypassed or -not. It is NOT a Linux problem, but an MWAVE problem that is fixed with the -latest MWAVE patches. So, in other words, don't bypass the test for MWAVES! - -I have Windows 95 on /dev/hda1, swap on /dev/hda2, and Red Hat 5 on /dev/hda3. - -The steps, then: - - Boot to Linux. - Mount Windows 95 file system (assume mount point = /dos95). - mkdir /dos95/linux - mkdir /dos95/linux/boot - mkdir /dos95/linux/boot/parms - - Copy the kernel, any initrd image, and loadlin to /dos95/linux/boot/. - - Reboot to Windows 95. - - Edit C:/msdos.sys and add or change the following: - - Logo=0 - BootGUI=0 - - Note that msdos.sys is a text file but it needs to be made 'unhidden', - readable and writable before it can be edited. This can be done with - DOS' "attrib" command. - - Edit config.sys to have multiple config menus. I have one for windows 95 and - five for Linux, like this: ------------- -[menu] -menuitem=W95, Windows 95 -menuitem=LINTP, Linux - ThinkPad -menuitem=LINTP3, Linux - ThinkPad Console -menuitem=LINDOC, Linux - Docked -menuitem=LINDOC3, Linux - Docked Console -menuitem=LIN1, Linux - Single User Mode -REM menudefault=W95,10 - -[W95] - -[LINTP] - -[LINDOC] - -[LINTP3] - -[LINDOC3] - -[LIN1] - -[COMMON] -FILES=30 -REM Please read README.TXT in C:\MWW subdirectory before changing the DOS= statement. -DOS=HIGH,UMB -DEVICE=C:\MWW\MANAGER\MWD50430.EXE -SHELL=c:\command.com /e:2048 -------------------- - -The important things are the SHELL and DEVICE statements. - - Then change autoexec.bat. Basically everything in there originally should be - done ONLY when Windows 95 is booted. Then you add new things specifically - for Linux. Mine is as follows - ---------------- -@ECHO OFF -if "%CONFIG%" == "W95" goto W95 - -REM -REM Linux stuff -REM -SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP -SET BLASTER=A220 I5 D1 -SET MWROOT=C:\MWW -SET LIBPATH=C:\MWW\DLL -SET PATH=C:\WINDOWS;C:\MWW\DLL; -CALL MWAVE START NOSHOW -c:\linux\boot\loadlin.exe @c:\linux\boot\parms\%CONFIG%.par - -:W95 -REM -REM Windows 95 stuff -REM -c:\toolkit\guard -SET MSINPUT=C:\MSINPUT -SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP -REM The following is used by DOS games to recognize Sound Blaster hardware. -REM If hardware settings are changed, please change this line as well. -REM See the Mwave README file for instructions. -SET BLASTER=A220 I5 D1 -SET MWROOT=C:\MWW -SET LIBPATH=C:\MWW\DLL -SET PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;E:\ORAWIN95\BIN;f:\msdev\bin;e:\v30\bin.dbg;v:\devt\v30\bin;c:\JavaSDK\Bin;C:\MWW\DLL; -SET INCLUDE=f:\MSDEV\INCLUDE;F:\MSDEV\MFC\INCLUDE -SET LIB=F:\MSDEV\LIB;F:\MSDEV\MFC\LIB -win - ------------------------- - -Now build a file in c:\linux\boot\parms for each Linux config that you have. - -For example, my LINDOC3 config is for a docked Thinkpad at runlevel 3 with no -initrd image, and has a parameter file named LINDOC3.PAR in c:\linux\boot\parms: - ------------------------ -# LOADLIN @param_file image=other_image root=/dev/other -# -# Linux Console in docking station -# -c:\linux\boot\zImage.krn # First value must be filename of Linux kernel. -root=/dev/hda3 # device which gets mounted as root FS -ro # Other kernel arguments go here. -apm=off -doc=yes -3 ------------------------ - -The doc=yes parameter is an environment variable used by my init scripts, not -a kernel argument. - -However, the apm=off parameter IS a kernel argument! APM, at least in my setup, -causes the kernel to crash when loaded via loadlin (but NOT when loaded via -LILO). The APM stuff COULD be forced out of the kernel via the kernel compile -options. Instead, I got an unofficial patch to the APM drivers that allows them -to be dynamically deactivated via kernel arguments. Whatever you chose to -document, APM, it seems, MUST be off for setups like mine. - -Now make sure C:\MWW\MWCONFIG.REF looks like this: - ----------------------- -[NativeDOS] -Default=SB1.5 -SBInputSource=CD -SYNTH=FM -QSound=OFF -Reverb=OFF -Chorus=OFF -ReverbDepth=5 -ChorusDepth=5 -SBInputVolume=5 -SBMainVolume=10 -SBWaveVolume=10 -SBSynthVolume=10 -WaveTableVolume=10 -AudioPowerDriver=ON - -[FastCFG] -Show=No -HideOption=Off ------------------------------ - -OR the Default= line COULD be - -Default=SBPRO - -Reboot to Windows 95 and choose Linux. When booted, use sndconfig to configure -the sound modules and voilà - ThinkPad sound with Linux. - -Now the gotchas - you can either have CD sound OR Mixers but not both. That's a -problem with the SB1.5 (CD sound) or SBPRO (Mixers) settings. No one knows why -this is! - -For some reason MPEG3 files, when played through mpg123, sound like they -are playing at 1/8th speed - not very useful! If you have ANY insight -on why this second thing might be happening, I would be grateful. - -=========================================================== - _/ _/_/_/_/ - _/_/ _/_/ _/ - _/ _/_/ _/_/_/_/ Martin John Bartlett - _/ _/ _/ _/ (martin@nitram.demon.co.uk) -_/ _/_/_/_/ - _/ -_/ _/ - _/_/ -=========================================================== diff --git a/Documentation/sound/oss/oss-parameters.txt b/Documentation/sound/oss/oss-parameters.txt deleted file mode 100644 index cc675f25eee4..000000000000 --- a/Documentation/sound/oss/oss-parameters.txt +++ /dev/null @@ -1,51 +0,0 @@ - OSS Kernel Parameters - ~~~~~~~~~~~~~~~~~~~~~ - -See Documentation/admin-guide/kernel-parameters.rst for general information on -specifying module parameters. - -This document may not be entirely up to date and comprehensive. The command -"modinfo -p ${modulename}" shows a current list of all parameters of a loadable -module. Loadable modules, after being loaded into the running kernel, also -reveal their parameters in /sys/module/${modulename}/parameters/. Some of these -parameters may be changed at runtime by the command -"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}". - - - ad1848= [HW,OSS] - Format: <io>,<irq>,<dma>,<dma2>,<type> - - aedsp16= [HW,OSS] Audio Excel DSP 16 - Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq> - See also header of sound/oss/aedsp16.c. - - dmasound= [HW,OSS] Sound subsystem buffers - - mpu401= [HW,OSS] - Format: <io>,<irq> - - opl3= [HW,OSS] - Format: <io> - - pas2= [HW,OSS] Format: - <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16> - - pss= [HW,OSS] Personal Sound System (ECHO ESC614) - Format: - <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq> - - sscape= [HW,OSS] - Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq> - - trix= [HW,OSS] MediaTrix AudioTrix Pro - Format: - <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq> - - uart401= [HW,OSS] - Format: <io>,<irq> - - uart6850= [HW,OSS] - Format: <io>,<irq> - - waveartist= [HW,OSS] - Format: <io>,<irq>,<dma>,<dma2> diff --git a/Documentation/sound/oss/ultrasound b/Documentation/sound/oss/ultrasound deleted file mode 100644 index eed331c738a3..000000000000 --- a/Documentation/sound/oss/ultrasound +++ /dev/null @@ -1,30 +0,0 @@ -modprobe sound -insmod ad1848 -insmod gus io=* irq=* dma=* ... - -This loads the driver for the Gravis Ultrasound family of sound cards. - -The gus module takes the following arguments - -io I/O address of the Ultrasound card (eg. io=0x220) -irq IRQ of the Sound Blaster card -dma DMA channel for the Sound Blaster -dma16 2nd DMA channel, only needed for full duplex operation -type 1 for PnP card -gus16 1 for using 16 bit sampling daughter board -no_wave_dma Set to disable DMA usage for wavetable (see note) -db16 ??? - - -no_wave_dma option - -This option defaults to a value of 0, which allows the Ultrasound wavetable -DSP to use DMA for playback and downloading samples. This is the same -as the old behaviour. If set to 1, no DMA is needed for downloading samples, -and allows owners of a GUS MAX to make use of simultaneous digital audio -(/dev/dsp), MIDI, and wavetable playback. - - -If you have problems in recording with GUS MAX, you could try to use -just one 8 bit DMA channel. Recording will not work with one DMA -channel if it's a 16 bit one. diff --git a/MAINTAINERS b/MAINTAINERS index 2d3d750b19c0..01f0b76dcc06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -527,11 +527,6 @@ W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/input/misc/adxl34x.c -AEDSP16 DRIVER -M: Riccardo Facchetti <fizban@tin.it> -S: Maintained -F: sound/oss/aedsp16.c - AF9013 MEDIA DRIVER M: Antti Palosaari <crope@iki.fi> L: linux-media@vger.kernel.org @@ -9199,12 +9194,6 @@ F: include/linux/dt-bindings/mux/ F: include/linux/mux/ F: drivers/mux/ -MULTISOUND SOUND DRIVER -M: Andrew Veliath <andrewtv@usa.net> -S: Maintained -F: Documentation/sound/oss/MultiSound -F: sound/oss/msnd* - MULTITECH MULTIPORT CARD (ISICOM) S: Orphan F: drivers/tty/isicom.c diff --git a/sound/Kconfig b/sound/Kconfig index d7d2aac9542e..b6d047985905 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -3,25 +3,7 @@ menuconfig SOUND depends on HAS_IOMEM help If you have a sound card in your computer, i.e. if it can say more - than an occasional beep, say Y. Be sure to have all the information - about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. - - You want to read the Sound-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. General information about - the modular sound system is contained in the files - <file:Documentation/sound/oss/Introduction>. The file - <file:Documentation/sound/oss/README.OSS> contains some slightly - outdated but still useful information as well. Newer sound - driver documentation is found in <file:Documentation/sound/alsa/*>. - - If you have a PnP sound card and you want to configure it at boot - time using the ISA PnP tools (read - <http://www.roestock.demon.co.uk/isapnptools/>), then you need to - compile the sound card support as a module and load that module - after the PnP configuration is finished. To do this, choose M here - and read <file:Documentation/sound/oss/README.modules>; the module - will be called soundcore. + than an occasional beep, say Y. if SOUND @@ -114,19 +96,6 @@ source "sound/synth/Kconfig" endif # SND -menuconfig SOUND_PRIME - tristate "Open Sound System (DEPRECATED)" - select SOUND_OSS_CORE - depends on BROKEN - help - Say 'Y' or 'M' to enable Open Sound System drivers. - -if SOUND_PRIME - -source "sound/oss/Kconfig" - -endif # SOUND_PRIME - endif # !UML endif # SOUND diff --git a/sound/Makefile b/sound/Makefile index 6de45d2c32f7..e5794fdd3d79 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -2,8 +2,7 @@ # obj-$(CONFIG_SOUND) += soundcore.o -obj-$(CONFIG_SOUND_PRIME) += oss/ -obj-$(CONFIG_DMASOUND) += oss/ +obj-$(CONFIG_DMASOUND) += oss/dmasound/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ obj-$(CONFIG_SND_AOA) += aoa/ diff --git a/sound/oss/CHANGELOG b/sound/oss/CHANGELOG deleted file mode 100644 index 8706cd66ca1f..000000000000 --- a/sound/oss/CHANGELOG +++ /dev/null @@ -1,369 +0,0 @@ -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). - -Since 3.8-beta8 -- Lot of fixes to audio playback code in dmabuf.c - -Since 3.8-beta6 -- Fixed the famous Quake delay bug. - -Since 3.8-beta5 -- Fixed many bugs in audio playback. - -Since 3.8-beta4 -- Just minor changes. - -Since 3.8-beta1 -- Major rewrite of audio playback handling. -- Added AWE32 support by Takashi Iwai (in ./lowlevel/). - -Since 3.7-beta# -- Passing of ioctl() parameters between soundcard.c and other modules has been -changed so that arg always points to kernel space. -- Some bugfixes. - -Since 3.7-beta5 -- Disabled MIDI input with GUS PnP (Interwave). There seems to be constant -stream of received 0x00 bytes when the MIDI receiver is enabled. - -Since 3.5 -- Changes almost everywhere. -- Support for OPTi 82C924-based sound cards. - -Since 3.5.4-beta8 -- Fixed a bug in handling of non-fragment sized writes in 16 bit/stereo mode - with GUS. -- Limited minimum fragment size with some audio devices (GUS=512 and - SB=32). These devices require more time to "recover" from processing - of each fragment. - -Since 3.5.4-beta6/7 -- There seems to be problems in the OPTi 82C930 so cards based on this - chip don't necessarily work yet. There are problems in detecting the - MIDI interface. Also mixer volumes may be seriously wrong on some systems. - You can safely use this driver version with C930 if it looks to work. - However please don't complain if you have problems with it. C930 support - should be fixed in future releases. -- Got initialization of GUS PnP to work. With this version GUS PnP should - work in GUS compatible mode after initialization using isapnptools. -- Fixed a bug in handling of full duplex cards in write only mode. This has - been causing "audio device opening" errors with RealAudio player. - -Since 3.5.4.beta5 -- Changes to OPTi 82C930 driver. -- Major changes to the Soundscape driver. The driver requires now just one - DMA channel. The extra audio/dsp device (the "Not functional" one) used - for code download in the earlier versions has been eliminated. There is now - just one /dev/dsp# device which is used both for code download and audio. - -Since 3.5.4.beta4 -- Minor changes. - -Since 3.5.4-beta2 -- Fixed silent playback with ESS 688/1688. -- Got SB16 to work without the 16 bit DMA channel (only the 8 bit one - is required for 8 and 16 bit modes). -- Added the "lowlevel" subdirectory for additional low level drivers that - are not part of USS core. See lowlevel/README for more info. -- Included support for ACI mixer (by Markus Kuhn). ACI is a mixer used in - miroPCM sound cards. See lowlevel/aci.readme for more info. -- Support for Aztech Washington chipset (AZT2316 ASIC). - -Since 3.5.4-beta1 -- Reduced clicking with AD1848. -- Support for OPTi 82C930. Only half duplex at this time. 16 bit playback - is sometimes just white noise (occurs randomly). - -Since 3.5.2 -- Major changes to the SB/Jazz16/ESS driver (most parts rewritten). - The most noticeable new feature is support for multiple SB cards at the same - time. -- Renamed sb16_midi.c to uart401.c. Also modified it to work also with - other MPU401 UART compatible cards than SB16/ESS/Jazz. -- Some changes which reduce clicking in audio playback. -- Copying policy is now GPL. - -Since 3.5.1 -- TB Maui initialization support -Since 3.5 -- Improved handling of playback underrun situations. - -Since 3.5-beta10 -- Bug fixing - -Since 3.5-beta9 -- Fixed for compatibility with Linux 1.3.70 and later. -- Changed boot time passing of 16 bit DMA channel number to SB driver. - -Since 3.5-beta8 -- Minor changes - -Since 3.5-beta7 -- enhancements to configure program (by Jeff Tranter): - - prompts are in same format as 1.3.x Linux kernel config program - - on-line help for each question - - fixed some compile warnings detected by gcc/g++ -Wall - - minor grammatical changes to prompts - -Since 3.5-beta6 -- Fixed bugs in mmap() support. -- Minor changes to Maui driver. - -Since 3.5-beta5 -- Fixed crash after recording with ESS688. It's generally a good - idea to stop inbound DMA transfers before freeing the memory - buffer. -- Fixed handling of AD1845 codec (for example Shuttle Sound System). -- Few other fixes. - -Since 3.5-beta4 -- Fixed bug in handling of uninitialized instruments with GUS. - -Since 3.5-beta3 -- Few changes which decrease popping at end/beginning of audio playback. - -Since 3.5-beta2 -- Removed MAD16+CS4231 hack made in previous version since it didn't - help. -- Fixed the above bug in proper way and in proper place. Many thanks - to James Hightower. - -Since 3.5-beta1 -- Bug fixes. -- Full duplex audio with MAD16+CS4231 may work now. The driver configures - SB DMA of MAD16 so that it doesn't conflict with codec's DMA channels. - The side effect is that all 8 bit DMA channels (0,1,3) are populated in - duplex mode. - -Since 3.5-alpha9 -- Bug fixes (mostly in Jazz16 and ESS1688/688 supports). -- Temporarily disabled recording with ESS1688/688 since it causes crash. -- Changed audio buffer partitioning algorithm so that it selects - smaller fragment size than earlier. This improves real time capabilities - of the driver and makes recording to disk to work better. Unfortunately - this change breaks some programs which assume that fragments cannot be - shorter than 4096 bytes. - -Since 3.5-alpha8 -- Bug fixes - -Since 3.5-alpha7 -- Linux kernel compatible configuration (_EXPERIMENTAL_). Enable - using command "cd /linux/drivers/sound;make script" and then - just run kernel's make config normally. -- Minor fixes to the SB support. Hopefully the driver works with - all SB models now. -- Added support for ESS ES1688 "AudioDrive" based cards. - -Since 3.5-alpha6 -- SB Pro and SB16 supports are no longer separately selectable options. - Enabling SB enables them too. -- Changed all #ifndef EXCLUDE_xx stuff to #ifdef CONFIG_xx. Modified -configure to handle this. -- Removed initialization messages from the -modularized version. They can be enabled by using init_trace=1 in -the insmod command line (insmod sound init_trace=1). -- More AIX stuff. -- Added support for synchronizing dsp/audio devices with /dev/sequencer. -- mmap() support for dsp/audio devices. - -Since 3.5-alpha5 -- AIX port. -- Changed some xxx_PATCH macros in soundcard.h to work with - big endian machines. - -Since 3.5-alpha4 -- Removed the 'setfx' stuff from the version distributed with kernel - sources. Running 'setfx' is required again. - -Since 3.5-alpha3 -- Moved stuff from the 'setfx' program to the AudioTrix Pro driver. - -Since 3.5-alpha2 -- Modifications to makefile and configure.c. Unnecessary sources - are no longer compiled. Newly created local.h is also copied to - /etc/soundconf. "make oldconfig" reads /etc/soundconf and produces - new local.h which is compatible with current version of the driver. -- Some fixes to the SB16 support. -- Fixed random protection fault in gus_wave.c - -Since 3.5-alpha1 -- Modified to work with Linux-1.3.33 and later -- Some minor changes - -Since 3.0.2 -- Support for CS4232 based PnP cards (AcerMagic S23 etc). -- Full duplex support for some CS4231, CS4232 and AD1845 based cards -(GUS MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards -having a codec mentioned above). -- Almost fully rewritten loadable modules support. -- Fixed some bugs. -- Huge amount of testing (more testing is still required). -- mmap() support (works with some cards). Requires much more testing. -- Sample/patch/program loading for TB Maui/Tropez. No initialization -since TB doesn't allow me to release that code. -- Using CS4231 compatible codecs as timer for /dev/music. - -Since 3.0.1 -- Added allocation of I/O ports, DMA channels and interrupts -to the initialization code. This may break modules support since -the driver may not free some resources on unload. Should be fixed soon. - -Since 3.0 -- Some important bug fixes. -- select() for /dev/dsp and /dev/audio (Linux only). -(To use select() with read, you have to call read() to start -the recording. Calling write() kills recording immediately so -use select() carefully when you are writing a half duplex app. -Full duplex mode is not implemented yet.) Select works also with -/dev/sequencer and /dev/music. Maybe with /dev/midi## too. - -Since 3.0-beta2 -- Minor fixes. -- Added Readme.cards - -Since 3.0-beta1 -- Minor fixes to the modules support. -- Eliminated call to sb_free_irq() in ad1848.c -- Rewritten MAD16&Mozart support (not tested with MAD16 Pro). -- Fix to DMA initialization of PSS cards. -- Some fixes to ad1848/cs42xx mixer support (GUS MAX, MSS, etc.) -- Fixed some bugs in the PSS driver which caused I/O errors with - the MSS mode (/dev/dsp). - -Since 3.0-950506 -- Recording with GUS MAX fixed. It works when the driver is configured - to use two DMA channels with GUS MAX (16 bit ones recommended). - -Since 3.0-94xxxx -- Too many changes - -Since 3.0-940818 -- Fixes for Linux 1.1.4x. -- Disables Disney Sound System with SG NX Pro 16 (less noise). - -Since 2.90-2 -- Fixes to soundcard.h -- Non blocking mode to /dev/sequencer -- Experimental detection code for Ensoniq Soundscape. - -Since 2.90 -- Minor and major bug fixes - -Since pre-3.0-940712 -- GUS MAX support -- Partially working MSS/WSS support (could work with some cards). -- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs - (GUS MAX, GUS16, WSS etc). Hardware ADPCM is possible with GUS16 and - GUS MAX, but it doesn't work yet. -Since pre-3.0-940426 -- AD1848/CS4248/CS4231 codec support (MSS, GUS MAX, Aztec, Orchid etc). -This codec chip is used in various sound cards. This version is developed -for the 16 bit daughtercard of GUS. It should work with other cards also -if the following requirements are met: - - The I/O, IRQ and DMA settings are jumper selectable or - the card is initialized by booting DOS before booting Linux (etc.). - - You add the IO, IRQ and DMA settings manually to the local.h. - (Just define GUS16_BASE, GUS16_IRQ and GUS16_DMA). Note that - the base address bust be the base address of the codec chip not the - card itself. For the GUS16 these are the same but most MSS compatible - cards have the codec located at card_base+4. -- Some minor changes - -Since 2.5 (******* MAJOR REWRITE ***********) - -This version is based on v2.3. I have tried to maintain two versions -together so that this one should have the same features than v2.5. -Something may still be missing. If you notice such things, please let me -know. - -The Readme.v30 contains more details. - -- /dev/midi## devices. -- /dev/sequencer2 - -Since 2.5-beta2 -- Some fine tuning to the GUS v3.7 mixer code. -- Fixed speed limits for the plain SB (1.0 to 2.0). - -Since 2.5-beta -- Fixed OPL-3 detection with SB. Caused problems with PAS16. -- GUS v3.7 mixer support. - -Since 2.4 -- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h). -- Fixed truncated sound on /dev/dsp when the device is closed. -- Linear volume mode for GUS -- Pitch bends larger than +/- 2 octaves. -- MIDI recording for SB and SB Pro. (Untested). -- Some other fixes. -- SB16 MIDI and DSP drivers only initialized if SB16 actually installed. -- Implemented better detection for OPL-3. This should be useful if you - have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3. -- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested). - -Since 2.3b -- Fixed bug which made it impossible to make long recordings to disk. - Recording was not restarted after a buffer overflow situation. -- Limited mixer support for GUS. -- Numerous improvements to the GUS driver by Andrew Robinson. Including - some click removal etc. - -Since 2.3 -- Fixed some minor bugs in the SB16 driver. - -Since 2.2b -- Full SB16 DSP support. 8/16 bit, mono/stereo -- The SCO and FreeBSD versions should be in sync now. There are some - problems with SB16 and GUS in the FreeBSD versions. - The DMA buffer allocation of the SCO version has been polished but - there could still be some problems. At least it hogs memory. - The DMA channel - configuration method used in the SCO/System is a hack. -- Support for the MPU emulation of the SB16. -- Some big arrays are now allocated boot time. This makes the BSS segment - smaller which makes it possible to use the full driver with - NetBSD. These arrays are not allocated if no suitable sound card is available. -- Fixed a bug in the compute_and_set_volume in gus_wave.c -- Fixed the too fast mono playback problem of SB Pro and PAS16. - -Since 2.2 -- Stereo recording for SB Pro. Somehow it was missing and nobody - had noticed it earlier. -- Minor polishing. -- Interpreting of boot time arguments (sound=) for Linux. -- Breakup of sb_dsp.c. Parts of the code has been moved to - sb_mixer.c and sb_midi.c - -Since 2.1 -- Preliminary support for SB16. - - The SB16 mixer is supported in its native mode. - - Digitized voice capability up to 44.1 kHz/8 bit/mono - (16 bit and stereo support coming in the next release). -- Fixed some bugs in the digitized voice driver for PAS16. -- Proper initialization of the SB emulation of latest PAS16 models. - -- Significantly improved /dev/dsp and /dev/audio support. - - Now supports half duplex mode. It's now possible to record and - playback without closing and reopening the device. - - It's possible to use smaller buffers than earlier. There is a new - ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4. - This call instructs the driver to use smaller buffers. The default - buffer size (0.5 to 1.0 seconds) is divided by n. Should be called - immediately after opening the device. - -Since 2.0 -Just cosmetic changes. diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig deleted file mode 100644 index 4033fe58f0cf..000000000000 --- a/sound/oss/Kconfig +++ /dev/null @@ -1,533 +0,0 @@ -# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net> -# More hacking for modularisation. -# -# Prompt user for primary drivers. - -config SOUND_BCM_CS4297A - tristate "Crystal Sound CS4297a (for Swarm)" - depends on SIBYTE_SWARM - help - The BCM91250A has a Crystal CS4297a on synchronous serial - port B (in addition to the DB-9 serial port). Say Y or M - here to enable the sound chip instead of the UART. Also - note that CONFIG_KGDB should not be enabled at the same - time, since it also attempts to use this UART port. - -config SOUND_MSNDCLAS - tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on (m || !STANDALONE) && ISA - help - Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or - Monterey (not for the Pinnacle or Fiji). - - See <file:Documentation/sound/oss/MultiSound> for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at <http://www.turtlebeach.com/site/kb_ftp/790.asp>. - -comment "Compiled-in MSND Classic support requires firmware during compilation." - depends on SOUND_PRIME && SOUND_MSNDCLAS=y - -config MSNDCLAS_HAVE_BOOT - bool - depends on SOUND_MSNDCLAS=y && !STANDALONE - default y - -config MSNDCLAS_INIT_FILE - string "Full pathname of MSNDINIT.BIN firmware file" - depends on SOUND_MSNDCLAS - default "/etc/sound/msndinit.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDCLAS_PERM_FILE - string "Full pathname of MSNDPERM.BIN firmware file" - depends on SOUND_MSNDCLAS - default "/etc/sound/msndperm.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDCLAS_IRQ - int "MSND Classic IRQ 5, 7, 9, 10, 11, 12" - depends on SOUND_MSNDCLAS=y - default "5" - help - Interrupt Request line for the MultiSound Classic and related cards. - -config MSNDCLAS_MEM - hex "MSND Classic memory B0000, C8000, D0000, D8000, E0000, E8000" - depends on SOUND_MSNDCLAS=y - default "D0000" - help - Memory-mapped I/O base address for the MultiSound Classic and - related cards. - -config MSNDCLAS_IO - hex "MSND Classic I/O 210, 220, 230, 240, 250, 260, 290, 3E0" - depends on SOUND_MSNDCLAS=y - default "290" - help - I/O port address for the MultiSound Classic and related cards. - -config SOUND_MSNDPIN - tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" - depends on (m || !STANDALONE) && ISA - help - Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. - See <file:Documentation/sound/oss/MultiSound> for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at <http://www.turtlebeach.com/site/kb_ftp/600.asp>. - -comment "Compiled-in MSND Pinnacle support requires firmware during compilation." - depends on SOUND_PRIME && SOUND_MSNDPIN=y - -config MSNDPIN_HAVE_BOOT - bool - depends on SOUND_MSNDPIN=y - default y - -config MSNDPIN_INIT_FILE - string "Full pathname of PNDSPINI.BIN firmware file" - depends on SOUND_MSNDPIN - default "/etc/sound/pndspini.bin" - help - The MultiSound cards have two firmware files which are required - for operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDPIN_PERM_FILE - string "Full pathname of PNDSPERM.BIN firmware file" - depends on SOUND_MSNDPIN - default "/etc/sound/pndsperm.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDPIN_IRQ - int "MSND Pinnacle IRQ 5, 7, 9, 10, 11, 12" - depends on SOUND_MSNDPIN=y - default "5" - help - Interrupt request line for the primary synthesizer on MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_MEM - hex "MSND Pinnacle memory B0000, C8000, D0000, D8000, E0000, E8000" - depends on SOUND_MSNDPIN=y - default "D0000" - help - Memory-mapped I/O base address for the primary synthesizer on - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_IO - hex "MSND Pinnacle I/O 210, 220, 230, 240, 250, 260, 290, 3E0" - depends on SOUND_MSNDPIN=y - default "290" - help - Memory-mapped I/O base address for the primary synthesizer on - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_DIGITAL - bool "MSND Pinnacle has S/PDIF I/O" - depends on SOUND_MSNDPIN=y - help - If you have the S/PDIF daughter board for the Pinnacle or Fiji, - answer Y here; otherwise, say N. If you have this, you will be able - to play and record from the S/PDIF port (digital signal). See - <file:Documentation/sound/oss/MultiSound> for information on how to make - use of this capability. - -config MSNDPIN_NONPNP - bool "MSND Pinnacle non-PnP Mode" - depends on SOUND_MSNDPIN=y - help - The Pinnacle and Fiji card resources can be configured either with - PnP, or through a configuration port. Say Y here if your card is NOT - in PnP mode. For the Pinnacle, configuration in non-PnP mode allows - use of the IDE and joystick peripherals on the card as well; these - do not show up when the card is in PnP mode. Specifying zero for any - resource of a device will disable the device. If you are running the - card in PnP mode, you must say N here and use isapnptools to - configure the card's resources. - -comment "MSND Pinnacle DSP section will be configured to above parameters." - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP - -config MSNDPIN_CFG - hex "MSND Pinnacle config port 250,260,270" - depends on MSNDPIN_NONPNP - default "250" - help - This is the port which the Pinnacle and Fiji uses to configure the - card's resources when not in PnP mode. If your card is in PnP mode, - then be sure to say N to the previous option, "MSND Pinnacle Non-PnP - Mode". - -comment "Pinnacle-specific Device Configuration (0 disables)" - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP - -config MSNDPIN_MPU_IO - hex "MSND Pinnacle MPU I/O (e.g. 330)" - depends on MSNDPIN_NONPNP - default "0" - help - Memory-mapped I/O base address for the Kurzweil daughterboard - synthesizer on MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_MPU_IRQ - int "MSND Pinnacle MPU IRQ (e.g. 9)" - depends on MSNDPIN_NONPNP - default "0" - help - Interrupt request number for the Kurzweil daughterboard - synthesizer on MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IO0 - hex "MSND Pinnacle IDE I/O 0 (e.g. 170)" - depends on MSNDPIN_NONPNP - default "0" - help - CD-ROM drive 0 memory-mapped I/O base address for the MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IO1 - hex "MSND Pinnacle IDE I/O 1 (e.g. 376)" - depends on MSNDPIN_NONPNP - default "0" - help - CD-ROM drive 1 memory-mapped I/O base address for the MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IRQ - int "MSND Pinnacle IDE IRQ (e.g. 15)" - depends on MSNDPIN_NONPNP - default "0" - help - Interrupt request number for the IDE CD-ROM interface on the - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_JOYSTICK_IO - hex "MSND Pinnacle joystick I/O (e.g. 200)" - depends on MSNDPIN_NONPNP - default "0" - help - Memory-mapped I/O base address for the joystick port on MultiSound - Pinnacle and Fiji sound cards. - -config MSND_FIFOSIZE - int "MSND buffer size (kB)" - depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y - default "128" - help - Configures the size of each audio buffer, in kilobytes, for - recording and playing in the MultiSound drivers (both the Classic - and Pinnacle). Larger values reduce the chance of data overruns at - the expense of overall latency. If unsure, use the default. - -menuconfig SOUND_OSS - tristate "OSS sound modules" - depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER) - depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN - help - OSS is the Open Sound System suite of sound card drivers. They make - sound programming easier since they provide a common API. Say Y or - M here (the module will be called sound) if you haven't found a - driver for your sound card above, then pick your driver from the - list below. - -if SOUND_OSS - -config SOUND_TRACEINIT - bool "Verbose initialisation" - help - Verbose soundcard initialization -- affects the format of autoprobe - and initialization messages at boot time. - -config SOUND_DMAP - bool "Persistent DMA buffers" - ---help--- - Linux can often have problems allocating DMA buffers for ISA sound - cards on machines with more than 16MB of RAM. This is because ISA - DMA buffers must exist below the 16MB boundary and it is quite - possible that a large enough free block in this region cannot be - found after the machine has been running for a while. If you say Y - here the DMA buffers (64Kb) will be allocated at boot time and kept - until the shutdown. This option is only useful if you said Y to - "OSS sound modules", above. If you said M to "OSS sound modules" - then you can get the persistent DMA buffer functionality by passing - the command-line argument "dmabuf=1" to the sound module. - - Say Y unless you have 16MB or more RAM or a PCI sound card. - -config SOUND_VMIDI - tristate "Loopback MIDI device support" - help - Support for MIDI loopback on port 1 or 2. - -config SOUND_TRIX - tristate "MediaTrix AudioTrix Pro support" - help - Answer Y if you have the AudioTriX Pro sound card manufactured - by MediaTrix. - -config TRIX_HAVE_BOOT - bool "Have TRXPRO.HEX firmware file" - depends on SOUND_TRIX=y && !STANDALONE - help - The MediaTrix AudioTrix Pro has an on-board microcontroller which - needs to be initialized by downloading the code from the file - TRXPRO.HEX in the DOS driver directory. If you don't have the - TRXPRO.HEX file handy you may skip this step. However, the SB and - MPU-401 modes of AudioTrix Pro will not work without this file! - -config TRIX_BOOT_FILE - string "Full pathname of TRXPRO.HEX firmware file" - depends on TRIX_HAVE_BOOT - default "/etc/sound/trxpro.hex" - help - Enter the full pathname of your TRXPRO.HEX file, starting from /. - -config SOUND_MSS - tristate "Microsoft Sound System support" - ---help--- - Again think carefully before answering Y to this question. It's - safe to answer Y if you have the original Windows Sound System card - made by Microsoft or Aztech SG 16 Pro (or NX16 Pro). Also you may - say Y in case your card is NOT among these: - - ATI Stereo F/X, AdLib, Audio Excell DSP16, Cardinal DSP16, - Ensoniq SoundScape (and compatibles made by Reveal and Spea), - Gravis Ultrasound, Gravis Ultrasound ACE, Gravis Ultrasound Max, - Gravis Ultrasound with 16 bit option, Logitech Sound Man 16, - Logitech SoundMan Games, Logitech SoundMan Wave, MAD16 Pro (OPTi - 82C929), Media Vision Jazz16, MediaTriX AudioTriX Pro, Microsoft - Windows Sound System (MSS/WSS), Mozart (OAK OTI-601), Orchid - SW32, Personal Sound System (PSS), Pro Audio Spectrum 16, Pro - Audio Studio 16, Pro Sonic 16, Roland MPU-401 MIDI interface, - Sound Blaster 1.0, Sound Blaster 16, Sound Blaster 16ASP, Sound - Blaster 2.0, Sound Blaster AWE32, Sound Blaster Pro, TI TM4000M - notebook, ThunderBoard, Turtle Beach Tropez, Yamaha FM - synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface. - - For cards having native support in VoxWare, consult the card - specific instructions in <file:Documentation/sound/oss/README.OSS>. - Some drivers have their own MSS support and saying Y to this option - will cause a conflict. - - If you compile the driver into the kernel, you have to add - "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command - line. - -config SOUND_MPU401 - tristate "MPU-401 support (NOT for SB16)" - ---help--- - Be careful with this question. The MPU401 interface is supported by - all sound cards. However, some natively supported cards have their - own driver for MPU401. Enabling this MPU401 option with these cards - will cause a conflict. Also, enabling MPU401 on a system that - doesn't really have a MPU401 could cause some trouble. If your card - was in the list of supported cards, look at the card specific - instructions in the <file:Documentation/sound/oss/README.OSS> file. It - is safe to answer Y if you have a true MPU401 MIDI interface card. - - If you compile the driver into the kernel, you have to add - "mpu401=<io>,<irq>" to the kernel command line. - -config SOUND_PAS - tristate "ProAudioSpectrum 16 support" - ---help--- - Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio - 16 or Logitech SoundMan 16 sound card. Answer N if you have some - other card made by Media Vision or Logitech since those are not - PAS16 compatible. Please read <file:Documentation/sound/oss/PAS16>. - It is not necessary to add Sound Blaster support separately; it - is included in PAS support. - - If you compile the driver into the kernel, you have to add - "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2> - to the kernel command line. - -config PAS_JOYSTICK - bool "Enable PAS16 joystick port" - depends on SOUND_PAS=y - help - Say Y here to enable the Pro Audio Spectrum 16's auxiliary joystick - port. - -config SOUND_PSS - tristate "PSS (AD1848, ADSP-2115, ESC614) support" - help - Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven - ADSP-16 or some other card based on the PSS chipset (AD1848 codec + - ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on - how to compile it into the kernel or as a module see the file - <file:Documentation/sound/oss/PSS>. - - If you compile the driver into the kernel, you have to add - "pss=<io>,<mssio>,<mssirq>,<mssdma>,<mpuio>,<mpuirq>" to the kernel - command line. - -config PSS_MIXER - bool "Enable PSS mixer (Beethoven ADSP-16 and other compatible)" - depends on SOUND_PSS - help - Answer Y for Beethoven ADSP-16. You may try to say Y also for other - cards if they have master volume, bass, treble, and you can't - control it under Linux. If you answer N for Beethoven ADSP-16, you - can't control master volume, bass, treble and synth volume. - - If you said M to "PSS support" above, you may enable or disable this - PSS mixer with the module parameter pss_mixer. For more information - see the file <file:Documentation/sound/oss/PSS>. - -config PSS_HAVE_BOOT - bool "Have DSPxxx.LD firmware file" - depends on SOUND_PSS && !STANDALONE - help - If you have the DSPxxx.LD file or SYNTH.LD file for you card, say Y - to include this file. Without this file the synth device (OPL) may - not work. - -config PSS_BOOT_FILE - string "Full pathname of DSPxxx.LD firmware file" - depends on PSS_HAVE_BOOT - default "/etc/sound/dsp001.ld" - help - Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file, - starting from /. - -config SOUND_SB - tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" - ---help--- - Answer Y if you have an original Sound Blaster card made by Creative - Labs or a 100% hardware compatible clone (like the Thunderboard or - SM Games). For an unknown card you may answer Y if the card claims - to be Sound Blaster-compatible. - - Please read the file <file:Documentation/sound/oss/Soundblaster>. - - You should also say Y here for cards based on the Avance Logic - ALS-007 and ALS-1X0 chips (read <file:Documentation/sound/oss/ALS>) and - for cards based on ESS chips (read - <file:Documentation/sound/oss/ESS1868> and - <file:Documentation/sound/oss/ESS>). If you have an IBM Mwave - card, say Y here and read <file:Documentation/sound/oss/mwave>. - - If you compile the driver into the kernel and don't want to use - isapnp, you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel - command line. - - You can say M here to compile this driver as a module; the module is - called sb. - -config SOUND_YM3812 - tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" - ---help--- - Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - Answering Y is usually a safe and recommended choice, however some - cards may have software (TSR) FM emulation. Enabling FM support with - these cards may cause trouble (I don't currently know of any such - cards, however). Please read the file - <file:Documentation/sound/oss/OPL3> if your card has an OPL3 chip. - - If you compile the driver into the kernel, you have to add - "opl3=<io>" to the kernel command line. - - If unsure, say Y. - -config SOUND_UART6850 - tristate "6850 UART support" - help - This option enables support for MIDI interfaces based on the 6850 - UART chip. This interface is rarely found on sound cards. It's safe - to answer N to this question. - - If you compile the driver into the kernel, you have to add - "uart6850=<io>,<irq>" to the kernel command line. - -config SOUND_AEDSP16 - tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" - ---help--- - Answer Y if you have a Gallant's Audio Excel DSP 16 card. This - driver supports Audio Excel DSP 16 but not the III nor PnP versions - of this card. - - The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or - a Microsoft Sound System card, so you should have said Y to either - "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" - or "Microsoft Sound System support", above, and you need to answer - the "MSS emulation" and "SBPro emulation" questions below - accordingly. You should say Y to one and only one of these two - questions. - - Read the <file:Documentation/sound/oss/README.OSS> file and the head of - <file:sound/oss/aedsp16.c> as well as - <file:Documentation/sound/oss/AudioExcelDSP16> to get more information - about this driver and its configuration. - -config SC6600 - bool "SC-6600 based audio cards (new Audio Excel DSP 16)" - depends on SOUND_AEDSP16 - help - The SC6600 is the new version of DSP mounted on the Audio Excel DSP - 16 cards. Find in the manual the FCC ID of your audio card and - answer Y if you have an SC6600 DSP. - -config SC6600_JOY - bool "Activate SC-6600 Joystick Interface" - depends on SC6600 - help - Say Y here in order to use the joystick interface of the Audio Excel - DSP 16 card. - -config SC6600_CDROM - int "SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)" - depends on SC6600 - default "4" - help - This is used to activate the CD-ROM interface of the Audio Excel - DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no - CD-ROM present. - -config SC6600_CDROMBASE - hex "SC-6600 CDROM Interface I/O Address" - depends on SC6600 - default "0" - help - Base I/O port address for the CD-ROM interface of the Audio Excel - DSP 16 card. - -config SOUND_VIDC - tristate "VIDC 16-bit sound" - depends on ARM && ARCH_ACORN - help - 16-bit support for the VIDC onboard sound hardware found on Acorn - machines. - -config SOUND_WAVEARTIST - tristate "Netwinder WaveArtist" - depends on ARM && ARCH_NETWINDER - help - Say Y here to include support for the Rockwell WaveArtist sound - system. This driver is mainly for the NetWinder. - -config SOUND_KAHLUA - tristate "XpressAudio Sound Blaster emulation" - depends on SOUND_SB - -endif # SOUND_OSS - diff --git a/sound/oss/Makefile b/sound/oss/Makefile deleted file mode 100644 index 9bdbbde2173e..000000000000 --- a/sound/oss/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -# Makefile for the Linux sound card driver -# -# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net> -# Rewritten to use lists instead of if-statements. - -# Each configuration option enables a list of files. - -obj-$(CONFIG_SOUND_OSS) += sound.o - -# Please leave it as is, cause the link order is significant ! - -obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o -obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o -obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_MSS) += ad1848.o -obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o -obj-$(CONFIG_SOUND_MPU401) += mpu401.o -obj-$(CONFIG_SOUND_UART6850) += uart6850.o -obj-$(CONFIG_SOUND_YM3812) += opl3.o -obj-$(CONFIG_SOUND_VMIDI) += v_midi.o -obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o -obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o -obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o -obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o -obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o - -obj-$(CONFIG_DMASOUND) += dmasound/ - -# Declare multi-part drivers. - -sound-objs := \ - dev_table.o soundcard.o \ - audio.o dmabuf.o \ - midi_synth.o midibuf.o \ - sequencer.o sound_timer.o sys_timer.o - -pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o -sb-objs := sb_card.o -sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o -vidc_mod-objs := vidc.o vidc_fill.o - -hostprogs-y := bin2hex hex2hex - -# Files generated that shall be removed upon make clean -clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \ - pss_boot.h trix_boot.h - -# Firmware files that need translation -# -# The translated files are protected by a file that keeps track -# of what name was used to build them. If the name changes, they -# will be forced to be remade. -# - -# Turtle Beach MultiSound - -ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y) - $(obj)/msnd_classic.o: $(obj)/msndperm.c $(obj)/msndinit.c - - $(obj)/msndperm.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_PERM_FILE)) $(obj)/bin2hex - $(obj)/bin2hex msndperm < $< > $@ - - $(obj)/msndinit.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_INIT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex msndinit < $< > $@ -endif - -ifeq ($(CONFIG_MSNDPIN_HAVE_BOOT),y) - $(obj)/msnd_pinnacle.o: $(obj)/pndsperm.c $(obj)/pndspini.c - - $(obj)/pndsperm.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_PERM_FILE)) $(obj)/bin2hex - $(obj)/bin2hex pndsperm < $< > $@ - - $(obj)/pndspini.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_INIT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex pndspini < $< > $@ -endif - -# PSS (ECHO-ADI2111) - -$(obj)/pss.o: $(obj)/pss_boot.h - -ifeq ($(CONFIG_PSS_HAVE_BOOT),y) - $(obj)/pss_boot.h: $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex pss_synth < $< > $@ -else - $(obj)/pss_boot.h: - $(Q)( \ - echo 'static unsigned char * pss_synth = NULL;'; \ - echo 'static int pss_synthLen = 0;'; \ - ) > $@ -endif - -# MediaTrix AudioTrix Pro - -$(obj)/trix.o: $(obj)/trix_boot.h - -ifeq ($(CONFIG_TRIX_HAVE_BOOT),y) - $(obj)/trix_boot.h: $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) $(obj)/hex2hex - $(obj)/hex2hex -i trix_boot < $< > $@ -else - $(obj)/trix_boot.h: - $(Q)( \ - echo 'static unsigned char * trix_boot = NULL;'; \ - echo 'static int trix_boot_len = 0;'; \ - ) > $@ -endif diff --git a/sound/oss/README.FIRST b/sound/oss/README.FIRST deleted file mode 100644 index 90fdcf063d2d..000000000000 --- a/sound/oss/README.FIRST +++ /dev/null @@ -1,6 +0,0 @@ -The modular sound driver patches were 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/sound/oss/ad1848.c b/sound/oss/ad1848.c deleted file mode 100644 index 2421f59cf279..000000000000 --- a/sound/oss/ad1848.c +++ /dev/null @@ -1,3062 +0,0 @@ -/* - * sound/oss/ad1848.c - * - * The low level driver for the AD1848/CS4248 codec chip which - * is used for example in the MS Sound System. - * - * The CS4231 which is used in the GUS MAX and some other cards is - * upwards compatible with AD1848 and this driver is able to drive it. - * - * CS4231A and AD1845 are upward compatible with CS4231. However - * the new features of these chips are different. - * - * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). - * CS4232A is an improved version of CS4232. - * - * - * - * 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. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * general sleep/wakeup clean up. - * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free - * of irqs. Use dev_id. - * Christoph Hellwig : adapted to module_init/module_exit - * Aki Laukkanen : added power management support - * Arnaldo C. de Melo : added missing restore_flags in ad1848_resume - * Miguel Freitas : added ISA PnP support - * Alan Cox : Added CS4236->4239 identification - * Daniel T. Cobra : Alernate config/mixer for later chips - * Alan Cox : Merged chip idents and config code - * - * TODO - * APM save restore assist code on IBM thinkpad - * - * Status: - * Tested. Believed fully functional. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/stddef.h> -#include <linux/slab.h> -#include <linux/isapnp.h> -#include <linux/pnp.h> -#include <linux/spinlock.h> - -#include "sound_config.h" - -#include "ad1848.h" -#include "ad1848_mixer.h" - -typedef struct -{ - spinlock_t lock; - int base; - int irq; - int dma1, dma2; - int dual_dma; /* 1, when two DMA channels allocated */ - int subtype; - unsigned char MCE_bit; - unsigned char saved_regs[64]; /* Includes extended register space */ - 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 -#define MD_1845 4 -#define MD_4232 5 -#define MD_C930 6 -#define MD_IWAVE 7 -#define MD_4235 8 /* Crystal Audio CS4235 */ -#define MD_1845_SSCAPE 9 /* Ensoniq Soundscape PNP*/ -#define MD_4236 10 /* 4236 and higher */ -#define MD_42xB 11 /* CS 42xB */ -#define MD_4239 12 /* CS4239 */ - - /* 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; -} 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; -} -ad1848_port_info; - -static struct address_info cfg; -static int nr_ad1848_devs; - -static bool deskpro_xl; -static bool deskpro_m; -static bool soundpro; - -#ifndef EXCLUDE_TIMERS -static int timer_installed = -1; -#endif - -static int loaded; - -static int ad_format_mask[13 /*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, - AFMT_U8 | AFMT_S16_LE /* CS4235 */, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/, - 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]; - -#define io_Index_Addr(d) ((d)->base) -#define io_Indexed_Data(d) ((d)->base+1) -#define io_Status(d) ((d)->base+2) -#define io_Polled_IO(d) ((d)->base+3) - -static struct { - unsigned char flags; -#define CAP_F_TIMER 0x01 -} capabilities [10 /*devc->model */ ] = { - {0} - ,{0} /* MD_1848 */ - ,{CAP_F_TIMER} /* MD_4231 */ - ,{CAP_F_TIMER} /* MD_4231A */ - ,{CAP_F_TIMER} /* MD_1845 */ - ,{CAP_F_TIMER} /* MD_4232 */ - ,{0} /* MD_C930 */ - ,{CAP_F_TIMER} /* MD_IWAVE */ - ,{0} /* MD_4235 */ - ,{CAP_F_TIMER} /* MD_1845_SSCAPE */ -}; - -#ifdef CONFIG_PNP -static int isapnp = 1; -static int isapnpjump; -static bool reverse; - -static int audio_activated; -#else -static int isapnp; -#endif - - - -static int ad1848_open(int dev, int mode); -static void ad1848_close(int dev); -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); -static irqreturn_t adintr(int irq, void *dev_id); - -#ifndef EXCLUDE_TIMERS -static int ad1848_tmr_install(int dev); -static void ad1848_tmr_reprogram(int dev); -#endif - -static int ad_read(ad1848_info * devc, int reg) -{ - int x; - int timeout = 900000; - - while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ - timeout--; - - if(reg < 32) - { - outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - x = inb(io_Indexed_Data(devc)); - } - else - { - int xreg, xra; - - xreg = (reg & 0xff) - 32; - xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2); - outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); - x = inb(io_Indexed_Data(devc)); - } - - return x; -} - -static void ad_write(ad1848_info * devc, int reg, int data) -{ - int timeout = 900000; - - while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */ - timeout--; - - if(reg < 32) - { - outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc)); - } - else - { - int xreg, xra; - - xreg = (reg & 0xff) - 32; - xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2); - outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); - outb((unsigned char) (data & 0xff), io_Indexed_Data(devc)); - } -} - -static void wait_for_calibration(ad1848_info * devc) -{ - int timeout; - - /* - * 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(KERN_WARNING "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) && (devc->model != MD_1845_SSCAPE)) - printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n"); -} - -static void ad_mute(ad1848_info * devc) -{ - 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); - } - -} - -static void ad_unmute(ad1848_info * devc) -{ -} - -static void ad_enter_MCE(ad1848_info * devc) -{ - int timeout = 1000; - unsigned short prev; - - while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ - timeout--; - - devc->MCE_bit = 0x40; - prev = inb(io_Index_Addr(devc)); - if (prev & 0x40) - { - return; - } - outb((devc->MCE_bit), io_Index_Addr(devc)); -} - -static void ad_leave_MCE(ad1848_info * devc) -{ - unsigned char prev, acal; - int timeout = 1000; - - while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ - timeout--; - - acal = ad_read(devc, 9); - - devc->MCE_bit = 0x00; - prev = inb(io_Index_Addr(devc)); - outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ - - if ((prev & 0x40) == 0) /* Not in MCE mode */ - { - return; - } - outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ - if (acal & 0x08) /* Auto calibration is enabled */ - wait_for_calibration(devc); -} - -static int ad1848_set_recmask(ad1848_info * devc, int mask) -{ - unsigned char recdev; - int i, n; - unsigned long flags; - - 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++; - - spin_lock_irqsave(&devc->lock,flags); - if (!soundpro) { - 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); - } else { /* soundpro */ - unsigned char val; - int set_rec_bit; - int j; - - for (i = 0; i < 32; i++) { /* For each bit */ - if ((devc->supported_rec_devices & (1 << i)) == 0) - continue; /* Device not supported */ - - for (j = LEFT_CHN; j <= RIGHT_CHN; j++) { - if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */ - continue; - - /* - * This is tricky: - * set_rec_bit becomes 1 if the corresponding bit in mask is set - * then it gets flipped if the polarity is inverse - */ - set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol; - - val = ad_read(devc, devc->mix_devices[i][j].recreg); - val &= ~(1 << devc->mix_devices[i][j].recpos); - val |= (set_rec_bit << devc->mix_devices[i][j].recpos); - ad_write(devc, devc->mix_devices[i][j].recreg, val); - } - } - } - spin_unlock_irqrestore(&devc->lock,flags); - - /* 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 oss_change_bits(ad1848_info *devc, unsigned char *regval, - unsigned char *muteval, int dev, int chn, int newval) -{ - unsigned char mask; - int shift; - int mute; - int mutemask; - int set_mute_bit; - - set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol; - - 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); /* Clear bits */ - *regval |= (newval & mask) << shift; /* Set new value */ - - *muteval &= mutemask; - *muteval |= mute; -} - -static int ad1848_mixer_get(ad1848_info * devc, int dev) -{ - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; - - dev = devc->mixer_reroute[dev]; - - return devc->levels[dev]; -} - -static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel) -{ - int regoffs, muteregoffs; - unsigned char val, muteval; - unsigned long flags; - - regoffs = devc->mix_devices[dev][channel].regno; - muteregoffs = devc->mix_devices[dev][channel].mutereg; - val = ad_read(devc, regoffs); - - if (muteregoffs != regoffs) { - muteval = ad_read(devc, muteregoffs); - oss_change_bits(devc, &val, &muteval, dev, channel, value); - } - else - oss_change_bits(devc, &val, &val, dev, channel, value); - - spin_lock_irqsave(&devc->lock,flags); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; - if (muteregoffs != regoffs) { - ad_write(devc, muteregoffs, muteval); - devc->saved_regs[muteregoffs] = muteval; - } - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retvol; - - if (dev > 31) - return -EINVAL; - - if (!(devc->supported_devices & (1 << dev))) - return -EINVAL; - - dev = devc->mixer_reroute[dev]; - - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ - right = left; - - retvol = left | (right << 8); - - /* Scale volumes */ - left = mix_cvt[left]; - right = mix_cvt[right]; - - devc->levels[dev] = retvol; - - /* - * Set the left channel - */ - ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN); - - /* - * Set the right channel - */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - goto out; - ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); - - out: - return retvol; -} - -static void ad1848_mixer_reset(ad1848_info * devc) -{ - int i; - char name[32]; - unsigned long flags; - - 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; - - devc->supported_rec_devices = MODE1_REC_DEVICES; - - switch (devc->model) - { - case MD_4231: - case MD_4231A: - case MD_1845: - case MD_1845_SSCAPE: - 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_42xB: - case MD_4239: - devc->mix_devices = &(cs42xb_mix_devices[0]); - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - case MD_4232: - case MD_4235: - case MD_4236: - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - - case MD_1848: - if (soundpro) { - devc->supported_devices = SPRO_MIXER_DEVICES; - devc->supported_rec_devices = SPRO_REC_DEVICES; - devc->mix_devices = &(spro_mix_devices[0]); - break; - } - - default: - devc->supported_devices = MODE1_MIXER_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; - - spin_lock_irqsave(&devc->lock,flags); - if (!soundpro) { - 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 */ - } else { - /* - * From the "wouldn't it be nice if the mixer API had (better) - * support for custom stuff" category - */ - /* Enable surround mode and SB16 mixer */ - ad_write(devc, 16, 0x60); - } - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int ad1848_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - ad1848_info *devc = mixer_devs[dev]->devc; - int val; - - if (cmd == SOUND_MIXER_PRIVATE1) - { - if (get_user(val, (int __user *)arg)) - return -EFAULT; - - if (val != 0xffff) - { - unsigned long flags; - val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); - devc->mixer_output_port = val; - val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ - devc->mixer_output_port = val; - spin_lock_irqsave(&devc->lock,flags); - 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 */ - spin_unlock_irqrestore(&devc->lock,flags); - } - val = devc->mixer_output_port; - return put_user(val, (int __user *)arg); - } - if (cmd == SOUND_MIXER_PRIVATE2) - { - if (get_user(val, (int __user *)arg)) - return -EFAULT; - return(ad1848_control(AD1848_MIXER_REROUTE, val)); - } - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - { - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = ad1848_set_recmask(devc, val); - break; - - default: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = ad1848_mixer_set(devc, cmd & 0xff, val); - break; - } - return put_user(val, (int __user *)arg); - } - else - { - switch (cmd & 0xff) - { - /* - * Return parameters - */ - - case SOUND_MIXER_RECSRC: - val = devc->recmask; - break; - - case SOUND_MIXER_DEVMASK: - val = devc->supported_devices; - break; - - case SOUND_MIXER_STEREODEVS: - val = devc->supported_devices; - if (devc->model != MD_C930) - val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - break; - - case SOUND_MIXER_RECMASK: - val = devc->supported_rec_devices; - break; - - case SOUND_MIXER_CAPS: - val=SOUND_CAP_EXCL_INPUT; - break; - - default: - val = ad1848_mixer_get(devc, cmd & 0xff); - break; - } - return put_user(val, (int __user *)arg); - } - } - else - return -EINVAL; -} - -static int 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 || devc->model == MD_1845_SSCAPE) /* 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(KERN_WARNING "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_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - if (arg != 1 && arg != 2) - return portc->channels; - - portc->channels = arg; - return arg; -} - -static unsigned int 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 */ - - 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 = -{ - .owner = THIS_MODULE, - .open = ad1848_open, - .close = ad1848_close, - .output_block = ad1848_output_block, - .start_input = ad1848_start_input, - .prepare_for_input = ad1848_prepare_for_input, - .prepare_for_output = ad1848_prepare_for_output, - .halt_io = ad1848_halt, - .halt_input = ad1848_halt_input, - .halt_output = ad1848_halt_output, - .trigger = ad1848_trigger, - .set_speed = ad1848_set_speed, - .set_bits = ad1848_set_bits, - .set_channels = ad1848_set_channels -}; - -static struct mixer_operations ad1848_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "SOUNDPORT", - .name = "AD1848/CS4248/CS4231", - .ioctl = ad1848_mixer_ioctl -}; - -static int ad1848_open(int dev, int mode) -{ - ad1848_info *devc; - 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; - - /* here we don't have to protect against intr */ - spin_lock(&devc->lock); - if (portc->open_mode || (devc->open_mode & mode)) - { - spin_unlock(&devc->lock); - 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; - spin_unlock(&devc->lock); - ad1848_trigger(dev, 0); - - if (mode & OPEN_READ) - devc->record_dev = dev; - if (mode & OPEN_WRITE) - devc->playback_dev = dev; -/* - * Mute output until the playback really starts. This decreases clicking (hope so). - */ - spin_lock_irqsave(&devc->lock,flags); - ad_mute(devc); - spin_unlock_irqrestore(&devc->lock,flags); - - return 0; -} - -static void 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; - - devc->intr_active = 0; - ad1848_halt(dev); - - spin_lock_irqsave(&devc->lock,flags); - - devc->audio_mode = 0; - devc->open_mode &= ~portc->open_mode; - portc->open_mode = 0; - - ad_unmute(devc); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void 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; /* - * Auto DMA mode on. No need to react - */ - } - spin_lock_irqsave(&devc->lock,flags); - - 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; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void 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 - */ - } - spin_lock_irqsave(&devc->lock,flags); - - 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; - spin_unlock_irqrestore(&devc->lock,flags); -} - -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_mute(devc); - - spin_lock_irqsave(&devc->lock,flags); - 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 || devc->model == MD_1845_SSCAPE) /* 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 */ - } - old_fs = ad_read(devc, 8); - - if (devc->model == MD_4232 || devc->model >= MD_4236) - { - 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. - */ - spin_unlock_irqrestore(&devc->lock,flags); - devc->xfer_count = 0; - -#ifndef EXCLUDE_TIMERS - if (dev == timer_installed && devc->timer_running) - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram(dev); - } -#endif - ad1848_halt_output(dev); - return 0; -} - -static int 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; - - spin_lock_irqsave(&devc->lock,flags); - 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) || (devc->model == MD_1845_SSCAPE)) /* 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 && devc->model != MD_1845_SSCAPE) - { - /* - * 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. - */ - spin_unlock_irqrestore(&devc->lock,flags); - devc->xfer_count = 0; - -#ifndef EXCLUDE_TIMERS - if (dev == timer_installed && devc->timer_running) - { - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram(dev); - } - } -#endif - ad1848_halt_input(dev); - return 0; -} - -static void ad1848_halt(int dev) -{ - 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); - - 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; -} - -static void ad1848_halt_input(int dev) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; - - if (!(ad_read(devc, 9) & 0x02)) - return; /* Capture not enabled */ - - spin_lock_irqsave(&devc->lock,flags); - - ad_mute(devc); - - { - int tmout; - - if(!isa_dma_bridge_buggy) - 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 */ - - if(!isa_dma_bridge_buggy) - 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 */ - - devc->audio_mode &= ~PCM_ENABLE_INPUT; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_halt_output(int dev) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; - - if (!(ad_read(devc, 9) & 0x01)) - return; /* Playback not enabled */ - - spin_lock_irqsave(&devc->lock,flags); - - ad_mute(devc); - { - int tmout; - - if(!isa_dma_bridge_buggy) - 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 */ - - if(!isa_dma_bridge_buggy) - 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 */ - - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void 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; - - spin_lock_irqsave(&devc->lock,flags); - 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); - } - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_init_hw(ad1848_info * devc) -{ - int i; - int *init_values; - - /* - * Initial values for the indirect registers of CS4248/AD1848. - */ - static int init_values_a[] = - { - 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, 0x1f, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - static int init_values_b[] = - { - /* - Values for the newer chips - Some of the register initialization values were changed. In - order to get rid of the click that preceded PCM playback, - calibration was disabled on the 10th byte. On that same byte, - dual DMA was enabled; on the 11th byte, ADC dithering was - enabled, since that is theoretically desirable; on the 13th - byte, Mode 3 was selected, to enable access to extended - registers. - */ - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x06, 0x00, 0xe0, 0x01, 0x00, 0x00, - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - /* - * Select initialisation data - */ - - init_values = init_values_a; - if(devc->model >= MD_4236) - init_values = init_values_b; - - 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) - { - if (devc->model == MD_1845_SSCAPE) - ad_write(devc, 12, ad_read(devc, 12) | 0x50); - else - ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - - if (devc->model == MD_IWAVE) - ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - - if (devc->model != MD_1845_SSCAPE) - 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_1845 || devc->model == MD_1845_SSCAPE) - 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 (soundpro) - ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - } - - outb((0), io_Status(devc)); /* Clear pending interrupts */ - - /* - * Toggle the MCE bit. It completes the initialization phase. - */ - - ad_enter_MCE(devc); /* In case the bit was off */ - ad_leave_MCE(devc); - - ad1848_mixer_reset(devc); -} - -int ad1848_detect(struct resource *ports, 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; - int sscape_flag = 0; - int io_base = ports->start; - - 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 == 0x87654321) - { - sscape_flag = 1; - *ad_flags = 0; - } - - if (*ad_flags == 0x12345677) - { - cs4248_flag = 1; - *ad_flags = 0; - } - } - if (nr_ad1848_devs >= MAX_AUDIO_DEV) - { - printk(KERN_ERR "ad1848 - Too many audio devices\n"); - return 0; - } - spin_lock_init(&devc->lock); - 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->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. Let's - * 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. - */ - - /* - * 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 */ - - 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? */ - { - 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; - - /* - * 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); - if ((id & 0xe7) == 0x80) /* Device busy??? */ - id = ad_read(devc, 25); - if ((id & 0xe7) == 0x80) /* Device still busy??? */ - id = ad_read(devc, 25); - DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25))); - - if ((id & 0xe7) == 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 */ - } - else - { - switch (id & 0x1f) { - case 3: /* CS4236/CS4235/CS42xB/CS4239 */ - { - int xid; - ad_write(devc, 12, ad_read(devc, 12) | 0x60); /* switch to mode 3 */ - ad_write(devc, 23, 0x9c); /* select extended register 25 */ - xid = inb(io_Indexed_Data(devc)); - ad_write(devc, 12, ad_read(devc, 12) & ~0x60); /* back to mode 0 */ - switch (xid & 0x1f) - { - case 0x00: - devc->chip_name = "CS4237B(B)"; - devc->model = MD_42xB; - break; - case 0x08: - /* Seems to be a 4238 ?? */ - devc->chip_name = "CS4238"; - devc->model = MD_42xB; - break; - case 0x09: - devc->chip_name = "CS4238B"; - devc->model = MD_42xB; - break; - case 0x0b: - devc->chip_name = "CS4236B"; - devc->model = MD_4236; - break; - case 0x10: - devc->chip_name = "CS4237B"; - devc->model = MD_42xB; - break; - case 0x1d: - devc->chip_name = "CS4235"; - devc->model = MD_4235; - break; - case 0x1e: - devc->chip_name = "CS4239"; - devc->model = MD_4239; - break; - default: - printk("Chip ident is %X.\n", xid&0x1F); - devc->chip_name = "CS42xx"; - devc->model = MD_4232; - break; - } - } - break; - - case 2: /* CS4232/CS4232A */ - devc->chip_name = "CS4232"; - devc->model = MD_4232; - break; - - case 0: - if ((id & 0xe0) == 0xa0) - { - devc->chip_name = "CS4231A"; - devc->model = MD_4231A; - } - else - { - devc->chip_name = "CS4321"; - devc->model = MD_4231; - } - break; - - default: /* maybe */ - 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->chip_name = "CS4231"; - devc->model = MD_4231; - } - } - } - } - ad_write(devc, 25, tmp1); /* Restore bits */ - - DDB(printk("ad1848_detect() - step K\n")); - } - } else if (tmp1 == 0x0a) { - /* - * Is it perhaps a SoundPro CMI8330? - * If so, then we should be able to change indirect registers - * greater than I15 after activating MODE2, even though reading - * back I12 does not show it. - */ - - /* - * Let's try comparing register values - */ - for (i = 0; i < 16; i++) { - if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) { - DDB(printk("ad1848 detect step H(%d/%x/%x) - SoundPro chip?\n", i, tmp1, tmp2)); - soundpro = 1; - devc->chip_name = "SoundPro CMI 8330"; - break; - } - } - } - - 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 (sscape_flag == 1) - devc->model = MD_1845_SSCAPE; - - return 1; -} - -int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback, - int dma_capture, int share_dma, int *osp, struct module *owner) -{ - /* - * 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->subtype = cfg.card_subtype; - 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); - - rename_region(ports, devc->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; - } - - portc = kmalloc(sizeof(ad1848_port_info), GFP_KERNEL); - if(portc==NULL) { - release_region(devc->base, 4); - return -1; - } - - 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) - { - release_region(devc->base, 4); - kfree(portc); - return -1; - } - - audio_devs[my_dev]->portc = portc; - audio_devs[my_dev]->mixer_dev = -1; - if (owner) - audio_devs[my_dev]->d->owner = owner; - memset((char *) portc, 0, sizeof(*portc)); - - nr_ad1848_devs++; - - ad1848_init_hw(devc); - - if (irq > 0) - { - devc->dev_no = my_dev; - if (request_irq(devc->irq, adintr, 0, devc->name, - (void *)(long)my_dev) < 0) - { - printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n"); - /* Don't free it either then.. */ - devc->irq = 0; - } - if (capabilities[devc->model].flags & CAP_F_TIMER) - { -#ifndef CONFIG_SMP - int x; - unsigned char tmp = ad_read(devc, 16); -#endif - - devc->timer_ticks = 0; - - ad_write(devc, 21, 0x00); /* Timer MSB */ - ad_write(devc, 20, 0x10); /* Timer LSB */ -#ifndef CONFIG_SMP - 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", irq); - else - { - DDB(printk("Interrupt test OK\n")); - devc->irq_ok = 1; - } -#else - devc->irq_ok = 1; -#endif - } - else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ - } else if (irq < 0) - devc->dev_no = my_dev; - -#ifndef EXCLUDE_TIMERS - if ((capabilities[devc->model].flags & CAP_F_TIMER) && - devc->irq_ok) - ad1848_tmr_install(my_dev); -#endif - - if (!share_dma) - { - if (sound_alloc_dma(dma_playback, devc->name)) - printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma(dma_capture, devc->name)) - printk(KERN_WARNING "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; - if (owner) - mixer_devs[e]->owner = owner; - } - return my_dev; -} - -int ad1848_control(int cmd, int arg) -{ - ad1848_info *devc; - unsigned long flags; - - if (nr_ad1848_devs < 1) - return -ENODEV; - - devc = &adev_info[nr_ad1848_devs - 1]; - - switch (cmd) - { - case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845 && devc->model != MD_1845_SSCAPE) - return -EINVAL; - spin_lock_irqsave(&devc->lock,flags); - ad_enter_MCE(devc); - ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); - ad_leave_MCE(devc); - spin_unlock_irqrestore(&devc->lock,flags); - break; - - case AD1848_MIXER_REROUTE: - { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; - - if (o < 0 || o >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - - if (!(devc->supported_devices & (1 << o)) && - !(devc->supported_rec_devices & (1 << o))) - return -EINVAL; - - 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); - break; - } - - /* Make the mixer control identified by o to appear as n */ - if (n < 0 || n >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - - devc->mixer_reroute[n] = o; /* Rename the control */ - if (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_devices &= ~(1 << o); - devc->supported_rec_devices &= ~(1 << o); - } - break; - } - return 0; -} - -void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) -{ - int i, mixer, 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; - } - } - - if (devc != NULL) - { - kfree(audio_devs[dev]->portc); - release_region(devc->base, 4); - - if (!share_dma) - { - if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */ - free_irq(devc->irq, (void *)(long)devc->dev_no); - - sound_free_dma(dma_playback); - - if (dma_playback != dma_capture) - sound_free_dma(dma_capture); - - } - mixer = audio_devs[devc->dev_no]->mixer_dev; - if(mixer>=0) - sound_unload_mixerdev(mixer); - - nr_ad1848_devs--; - for ( ; i < nr_ad1848_devs ; i++) - adev_info[i] = adev_info[i+1]; - } - else - printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); -} - -static irqreturn_t adintr(int irq, void *dev_id) -{ - unsigned char status; - ad1848_info *devc; - int dev; - int alt_stat = 0xff; - unsigned char c930_stat = 0; - int cnt = 0; - - dev = (long)dev_id; - devc = (ad1848_info *) audio_devs[dev]->devc; - -interrupt_again: /* Jump back here if int status doesn't reset */ - - status = inb(io_Status(devc)); - - if (status == 0x80) - printk(KERN_DEBUG "adintr: Why?\n"); - if (devc->model == MD_1848) - outb((0), io_Status(devc)); /* Clear interrupt status */ - - if (status & 0x01) - { - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - - spin_lock(&devc->lock); - - /* 0xe0e is C930 address port - * 0xe0f is C930 data port - */ - outb(11, 0xe0e); - c930_stat = inb(0xe0f); - outb((~c930_stat), 0xe0f); - - spin_unlock(&devc->lock); - - alt_stat = (c930_stat << 2) & 0x30; - } - else if (devc->model != MD_1848) - { - spin_lock(&devc->lock); - alt_stat = ad_read(devc, 24); - ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ - spin_unlock(&devc->lock); - } - - 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++; -#ifndef EXCLUDE_TIMERS - 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; - } - return IRQ_HANDLED; -} - -/* - * Experimental initialization sequence for the integrated sound system - * of the Compaq Deskpro M. - */ - -static int init_deskpro_m(struct address_info *hw_config) -{ - unsigned char tmp; - - if ((tmp = inb(0xc44)) == 0xff) - { - DDB(printk("init_deskpro_m: Dead port 0xc44\n")); - return 0; - } - - outb(0x10, 0xc44); - outb(0x40, 0xc45); - outb(0x00, 0xc46); - outb(0xe8, 0xc47); - outb(0x14, 0xc44); - outb(0x40, 0xc45); - outb(0x00, 0xc46); - outb(0xe8, 0xc47); - outb(0x10, 0xc44); - - return 1; -} - -/* - * Experimental initialization sequence for the integrated sound system - * of Compaq Deskpro XL. - */ - -static int 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; - } - /* - * OK. It looks like a Deskpro so let's proceed. - */ - - /* - * I/O port 0xc44 Audio configuration register. - * - * bits 0xc0: Audio revision bits - * 0x00 = Compaq Business Audio - * 0x40 = MS Sound System Compatible (reset default) - * 0x80 = Reserved - * 0xc0 = Reserved - * bit 0x20: No Wait State Enable - * 0x00 = Disabled (reset default, DMA mode) - * 0x20 = Enabled (programmed I/O mode) - * bit 0x10: MS Sound System Decode Enable - * 0x00 = Decoding disabled (reset default) - * 0x10 = Decoding enabled - * bit 0x08: FM Synthesis Decode Enable - * 0x00 = Decoding Disabled (reset default) - * 0x08 = Decoding enabled - * bit 0x04 Bank select - * 0x00 = Bank 0 - * 0x04 = Bank 1 - * bits 0x03 MSS Base address - * 0x00 = 0x530 (reset default) - * 0x01 = 0x604 - * 0x02 = 0xf40 - * 0x03 = 0xe80 - */ - -#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)); -#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 */ - -#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)); -#endif - - /* - * I/O port 0xc45 FM Address Decode/MSS ID Register. - * - * bank=0, bits 0xfe: FM synthesis Decode Compare bits 7:1 (default=0x88) - * bank=0, bit 0x01: SBIC Power Control Bit - * 0x00 = Powered up - * 0x01 = Powered down - * bank=1, bits 0xfc: MSS ID (default=0x40) - */ - -#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)); -#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) */ - -#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)); -#endif - - - /* - * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. - * - * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) - * bank=1, bits 0xff: Audio addressing ASIC id - */ - -#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)); -#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 */ - -#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)); -#endif - - /* - * I/O port 0xc47 FM Address Decode Register. - * - * bank=0, bits 0xff: Decode enable selection for various FM address bits - * bank=1, bits 0xff: Reserved - */ - -#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)); -#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 */ - -#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)); -#endif - - /* - * I/O port 0xc6f = Audio Disable Function Register - */ - -#ifdef DEBUGXL - printk("Port 0xc6f (before) = %02x\n", inb(0xc6f)); -#endif - - outb((0x80), 0xc6f); - -#ifdef DEBUGXL - printk("Port 0xc6f (after) = %02x\n", inb(0xc6f)); -#endif - - return 1; -} - -int probe_ms_sound(struct address_info *hw_config, struct resource *ports) -{ - unsigned char tmp; - - DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); - - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - /* check_opl3(0x388, hw_config); */ - return ad1848_detect(ports, NULL, hw_config->osp); - } - - if (deskpro_xl && hw_config->card_subtype == 2) /* Compaq Deskpro XL */ - { - if (!init_deskpro(hw_config)) - return 0; - } - - if (deskpro_m) /* Compaq Deskpro M */ - { - if (!init_deskpro_m(hw_config)) - 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 or 0x0f. - */ - - 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(ports, 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; - - MDB(printk(KERN_ERR "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(ports, NULL, hw_config->osp))) - return 0; - - hw_config->card_subtype = 1; - return 1; - } - if ((hw_config->irq != 5) && - (hw_config->irq != 7) && - (hw_config->irq != 9) && - (hw_config->irq != 10) && - (hw_config->irq != 11) && - (hw_config->irq != 12)) - { - printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk(KERN_ERR "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(KERN_ERR "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(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - return 0; - } - return ad1848_detect(ports, NULL, hw_config->osp); -} - -void attach_ms_sound(struct address_info *hw_config, struct resource *ports, struct module *owner) -{ - static signed char interrupt_bits[12] = - { - -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - signed char bits; - char 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 */ - { - hw_config->slots[0] = ad1848_init("MS Sound System", ports, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0, - hw_config->osp, - owner); - return; - } - /* - * Set the IRQ and DMA addresses. - */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == -1) - { - printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); - release_region(ports->start, 4); - release_region(ports->start - 4, 4); - return; - } - outb((bits | 0x40), config_port); - if ((inb(version_port) & 0x40) == 0) - printk(KERN_ERR "[MSS: IRQ Conflict?]\n"); - -/* - * 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; - - 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(KERN_WARNING "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 */ - - hw_config->slots[0] = ad1848_init("MS Sound System", ports, - hw_config->irq, - dma, dma2, 0, - hw_config->osp, - THIS_MODULE); -} - -void unload_ms_sound(struct address_info *hw_config) -{ - ad1848_unload(hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0); - sound_unload_audiodev(hw_config->slots[0]); - release_region(hw_config->io_base, 4); -} - -#ifndef EXCLUDE_TIMERS - -/* - * Timer stuff (for /dev/music). - */ - -static unsigned int current_interval; - -static unsigned int 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; - - spin_lock_irqsave(&devc->lock,flags); - - /* - * Length of the timer interval (in nanoseconds) depends on the - * selected crystal oscillator. Check this from bit 0x01 of I8. - * - * AD1845 has just one oscillator which has cycle time of 10.050 us - * (when a 24.576 MHz xtal oscillator is used). - * - * Convert requested interval to nanoseconds before computing - * the timer divider. - */ - - if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) - 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; - - if (divider < 100) /* Don't allow shorter intervals than about 1ms */ - divider = 100; - - 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; - spin_unlock_irqrestore(&devc->lock,flags); - - return current_interval = (divider * xtal_nsecs + 500) / 1000; -} - -static void 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); -} - -static void ad1848_tmr_disable(int dev) -{ - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - - spin_lock_irqsave(&devc->lock,flags); - ad_write(devc, 16, ad_read(devc, 16) & ~0x40); - devc->timer_running = 0; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_tmr_restart(int dev) -{ - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - - if (current_interval == 0) - return; - - spin_lock_irqsave(&devc->lock,flags); - ad_write(devc, 16, ad_read(devc, 16) | 0x40); - devc->timer_running = 1; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static struct sound_lowlev_timer ad1848_tmr = -{ - 0, - 2, - ad1848_tmr_start, - ad1848_tmr_disable, - ad1848_tmr_restart -}; - -static int ad1848_tmr_install(int dev) -{ - 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); - - return 1; -} -#endif /* EXCLUDE_TIMERS */ - -EXPORT_SYMBOL(ad1848_detect); -EXPORT_SYMBOL(ad1848_init); -EXPORT_SYMBOL(ad1848_unload); -EXPORT_SYMBOL(ad1848_control); -EXPORT_SYMBOL(probe_ms_sound); -EXPORT_SYMBOL(attach_ms_sound); -EXPORT_SYMBOL(unload_ms_sound); - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; -static int __initdata type = 0; - -module_param_hw(io, int, ioport, 0); /* I/O for a raw AD1848 card */ -module_param_hw(irq, int, irq, 0); /* IRQ to use */ -module_param_hw(dma, int, dma, 0); /* First DMA channel */ -module_param_hw(dma2, int, dma, 0); /* Second DMA channel */ -module_param(type, int, 0); /* Card type */ -module_param(deskpro_xl, bool, 0); /* Special magic for Deskpro XL boxen */ -module_param(deskpro_m, bool, 0); /* Special magic for Deskpro M box */ -module_param(soundpro, bool, 0); /* More special magic for SoundPro chips */ - -#ifdef CONFIG_PNP -module_param(isapnp, int, 0); -module_param(isapnpjump, int, 0); -module_param(reverse, bool, 0); -MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); -MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); -MODULE_PARM_DESC(reverse, "When set to 1, will reverse ISAPnP search order"); - -static struct pnp_dev *ad1848_dev = NULL; - -/* Please add new entries at the end of the table */ -static struct { - char *name; - unsigned short card_vendor, card_device, - vendor, function; - short mss_io, irq, dma, dma2; /* index into isapnp table */ - int type; -} ad1848_isapnp_list[] __initdata = { - {"CMI 8330 SoundPRO", - ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), - 0, 0, 0,-1, 0}, - {"CS4232 based card", - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0000), - 0, 0, 0, 1, 0}, - {"CS4232 based card", - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), - 0, 0, 0, 1, 0}, - {"OPL3-SA2 WSS mode", - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), - 1, 0, 0, 1, 1}, - {"Advanced Gravis InterWave Audio", - ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), - 0, 0, 0, 1, 0}, - {NULL} -}; - -#ifdef MODULE -static struct isapnp_device_id id_table[] = { - { ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0000), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), 0 }, - /* The main driver for this card is opl3sa2 - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), 0 }, - */ - { ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), 0 }, - {0} -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); -#endif - -static struct pnp_dev *activate_dev(char *devname, char *resname, struct pnp_dev *dev) -{ - int err; - - err = pnp_device_attach(dev); - if (err < 0) - return(NULL); - - if((err = pnp_activate_dev(dev)) < 0) { - printk(KERN_ERR "ad1848: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); - - pnp_device_detach(dev); - - return(NULL); - } - audio_activated = 1; - return(dev); -} - -static struct pnp_dev __init *ad1848_init_generic(struct pnp_card *bus, - struct address_info *hw_config, int slot) -{ - - /* Configure Audio device */ - if((ad1848_dev = pnp_find_dev(bus, ad1848_isapnp_list[slot].vendor, ad1848_isapnp_list[slot].function, NULL))) - { - if((ad1848_dev = activate_dev(ad1848_isapnp_list[slot].name, "ad1848", ad1848_dev))) - { - hw_config->io_base = pnp_port_start(ad1848_dev, ad1848_isapnp_list[slot].mss_io); - hw_config->irq = pnp_irq(ad1848_dev, ad1848_isapnp_list[slot].irq); - hw_config->dma = pnp_dma(ad1848_dev, ad1848_isapnp_list[slot].dma); - if(ad1848_isapnp_list[slot].dma2 != -1) - hw_config->dma2 = pnp_dma(ad1848_dev, ad1848_isapnp_list[slot].dma2); - else - hw_config->dma2 = -1; - hw_config->card_subtype = ad1848_isapnp_list[slot].type; - } else - return(NULL); - } else - return(NULL); - - return(ad1848_dev); -} - -static int __init ad1848_isapnp_init(struct address_info *hw_config, struct pnp_card *bus, int slot) -{ - char *busname = bus->name[0] ? bus->name : ad1848_isapnp_list[slot].name; - - /* Initialize this baby. */ - - if(ad1848_init_generic(bus, hw_config, slot)) { - /* We got it. */ - - printk(KERN_NOTICE "ad1848: PnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", - busname, - hw_config->io_base, hw_config->irq, hw_config->dma, - hw_config->dma2); - return 1; - } - return 0; -} - -static int __init ad1848_isapnp_probe(struct address_info *hw_config) -{ - static int first = 1; - int i; - - /* Count entries in sb_isapnp_list */ - for (i = 0; ad1848_isapnp_list[i].card_vendor != 0; i++); - i--; - - /* Check and adjust isapnpjump */ - if( isapnpjump < 0 || isapnpjump > i) { - isapnpjump = reverse ? i : 0; - printk(KERN_ERR "ad1848: Valid range for isapnpjump is 0-%d. Adjusted to %d.\n", i, isapnpjump); - } - - if(!first || !reverse) - i = isapnpjump; - first = 0; - while(ad1848_isapnp_list[i].card_vendor != 0) { - static struct pnp_card *bus = NULL; - - while ((bus = pnp_find_card( - ad1848_isapnp_list[i].card_vendor, - ad1848_isapnp_list[i].card_device, - bus))) { - - if(ad1848_isapnp_init(hw_config, bus, i)) { - isapnpjump = i; /* start next search from here */ - return 0; - } - } - i += reverse ? -1 : 1; - } - - return -ENODEV; -} -#endif - - -static int __init init_ad1848(void) -{ - printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - -#ifdef CONFIG_PNP - if(isapnp && (ad1848_isapnp_probe(&cfg) < 0) ) { - printk(KERN_NOTICE "ad1848: No ISAPnP cards found, trying standard ones...\n"); - isapnp = 0; - } -#endif - - if(io != -1) { - struct resource *ports; - if( isapnp == 0 ) - { - if(irq == -1 || dma == -1) { - printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n"); - return -EINVAL; - } - - cfg.irq = irq; - cfg.io_base = io; - cfg.dma = dma; - cfg.dma2 = dma2; - cfg.card_subtype = type; - } - - ports = request_region(io + 4, 4, "ad1848"); - - if (!ports) - return -EBUSY; - - if (!request_region(io, 4, "WSS config")) { - release_region(io + 4, 4); - return -EBUSY; - } - - if (!probe_ms_sound(&cfg, ports)) { - release_region(io + 4, 4); - release_region(io, 4); - return -ENODEV; - } - attach_ms_sound(&cfg, ports, THIS_MODULE); - loaded = 1; - } - return 0; -} - -static void __exit cleanup_ad1848(void) -{ - if(loaded) - unload_ms_sound(&cfg); - -#ifdef CONFIG_PNP - if(ad1848_dev){ - if(audio_activated) - pnp_device_detach(ad1848_dev); - } -#endif -} - -module_init(init_ad1848); -module_exit(cleanup_ad1848); - -#ifndef MODULE -static int __init setup_ad1848(char *str) -{ - /* io, irq, dma, dma2, type */ - int ints[6]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - type = ints[5]; - - return 1; -} - -__setup("ad1848=", setup_ad1848); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h deleted file mode 100644 index b95ebe28d426..000000000000 --- a/sound/oss/ad1848.h +++ /dev/null @@ -1,24 +0,0 @@ - -#include <linux/interrupt.h> - -#define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */ -#define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ - -#define AD1848_SET_XTAL 1 -#define AD1848_MIXER_REROUTE 2 - -#define AD1848_REROUTE(oldctl, newctl) \ - ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl)) - - -int ad1848_init(char *name, struct resource *ports, int irq, int dma_playback, - int dma_capture, int share_dma, int *osp, struct module *owner); -void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); - -int ad1848_detect (struct resource *ports, int *flags, int *osp); -int ad1848_control(int cmd, int arg); - -void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner); - -int probe_ms_sound(struct address_info *hw_config, struct resource *ports); -void unload_ms_sound(struct address_info *hw_info); diff --git a/sound/oss/ad1848_mixer.h b/sound/oss/ad1848_mixer.h deleted file mode 100644 index 2cf719b5fbbc..000000000000 --- a/sound/oss/ad1848_mixer.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * sound/oss/ad1848_mixer.h - * - * Definitions for the mixer of AD1848 and compatible codecs. - */ - -/* - * 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. - */ - - -/* - * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. - * Sound card manufacturers have connected actual inputs (CD, synth, line, - * etc) to these inputs in different order. Therefore it's difficult - * to assign mixer channels to these inputs correctly. The following - * contains two alternative mappings. The first one is for GUS MAX and - * the second is just a generic one (line1, line2 and line3). - * (Actually this is not a mapping but rather some kind of interleaving - * solution). - */ -#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE1 | SOUND_MASK_IMIX) - -#define SPRO_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_LINE1) - -#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE2 | \ - SOUND_MASK_IGAIN | \ - SOUND_MASK_PCM | SOUND_MASK_IMIX) - -#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \ - SOUND_MASK_MIC | \ - SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \ - SOUND_MASK_IGAIN | \ - SOUND_MASK_PCM | SOUND_MASK_IMIX) - -#define MODE3_MIXER_DEVICES (MODE2_MIXER_DEVICES | SOUND_MASK_VOLUME) - -/* OPTi 82C930 has no IMIX level control, but it can still be selected as an - * input - */ -#define C930_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \ - SOUND_MASK_MIC | SOUND_MASK_VOLUME | \ - SOUND_MASK_LINE3 | \ - SOUND_MASK_IGAIN | SOUND_MASK_PCM) - -#define SPRO_MIXER_DEVICES (SOUND_MASK_VOLUME | SOUND_MASK_PCM | \ - SOUND_MASK_LINE | SOUND_MASK_SYNTH | \ - SOUND_MASK_CD | SOUND_MASK_MIC | \ - SOUND_MASK_SPEAKER | SOUND_MASK_LINE1 | \ - SOUND_MASK_OGAIN) - -struct mixer_def { - unsigned int regno:6; /* register number for volume */ - unsigned int polarity:1; /* volume polarity: 0=normal, 1=reversed */ - unsigned int bitpos:3; /* position of bits in register for volume */ - unsigned int nbits:3; /* number of bits in register for volume */ - unsigned int mutereg:6; /* register number for mute bit */ - unsigned int mutepol:1; /* mute polarity: 0=normal, 1=reversed */ - unsigned int mutepos:4; /* position of mute bit in register */ - unsigned int recreg:6; /* register number for recording bit */ - unsigned int recpol:1; /* recording polarity: 0=normal, 1=reversed */ - unsigned int recpos:4; /* position of recording bit in register */ -}; - -static char mix_cvt[101] = { - 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, - 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, - 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, - 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, - 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99, - 100 -}; - -typedef struct mixer_def mixer_ent; -typedef mixer_ent mixer_ents[2]; - -/* - * Most of the mixer entries work in backwards. Setting the polarity field - * makes them to work correctly. - * - * The channel numbering used by individual sound cards is not fixed. Some - * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. - * The current version doesn't try to compensate this. - */ - -#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ - [name] = {{reg_l, pola_l, pos_l, len_l, reg_l, 0, mute_bit, 0, 0, 8}, \ - {reg_r, pola_r, pos_r, len_r, reg_r, 0, mute_bit, 0, 0, 8}} - -#define MIX_ENT2(name, reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ - rec_reg_l, rec_pola_l, rec_pos_l, \ - reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ - rec_reg_r, rec_pola_r, rec_pos_r) \ - [name] = {{reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ - rec_reg_l, rec_pola_l, rec_pos_l}, \ - {reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ - rec_reg_r, rec_pola_r, rec_pos_r}} - -static mixer_ents ad1848_mix_devices[32] = { - MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) -}; - -static mixer_ents iwave_mix_devices[32] = { - MIX_ENT(SOUND_MIXER_VOLUME, 25, 1, 0, 5, 27, 1, 0, 5, 8), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_IMIX, 16, 1, 0, 5, 17, 1, 0, 5, 8), - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) -}; - -static mixer_ents cs42xb_mix_devices[32] = { - /* Digital master volume actually has seven bits, but we only use - six to avoid the discontinuity when the analog gain kicks in. */ - MIX_ENT(SOUND_MIXER_VOLUME, 46, 1, 0, 6, 47, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_MIC, 34, 1, 0, 5, 35, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), - /* For the IMIX entry, it was not possible to use the MIX_ENT macro - because the mute bit is in different positions for the two - channels and requires reverse polarity. */ - [SOUND_MIXER_IMIX] = {{13, 1, 2, 6, 13, 1, 0, 0, 0, 8}, - {42, 1, 0, 6, 42, 1, 7, 0, 0, 8}}, - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE3, 38, 1, 0, 6, 39, 1, 0, 6, 7) -}; - -/* OPTi 82C930 has somewhat different port addresses. - * Note: VOLUME == SPEAKER, SYNTH == LINE2, LINE == LINE3, CD == LINE1 - * VOLUME, SYNTH, LINE, CD are not enabled above. - * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc. - */ -static mixer_ents c930_mix_devices[32] = { - MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 1, 5, 23, 1, 1, 5, 7), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 5, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 5, 7, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 1, 5, 23, 1, 1, 5, 7), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_MIC, 20, 1, 1, 4, 21, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) -}; - -static mixer_ents spro_mix_devices[32] = { - MIX_ENT (SOUND_MIXER_VOLUME, 19, 0, 4, 4, 19, 0, 0, 4, 8), - MIX_ENT (SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT2(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 23, 0, 3, 0, 0, 8, - 5, 1, 1, 4, 23, 0, 3, 0, 0, 8), - MIX_ENT (SOUND_MIXER_PCM, 6, 1, 1, 4, 7, 1, 1, 4, 8), - MIX_ENT (SOUND_MIXER_SPEAKER, 18, 0, 3, 2, 0, 0, 0, 0, 8), - MIX_ENT2(SOUND_MIXER_LINE, 20, 0, 4, 4, 17, 1, 4, 16, 0, 2, - 20, 0, 0, 4, 17, 1, 3, 16, 0, 1), - MIX_ENT2(SOUND_MIXER_MIC, 18, 0, 0, 3, 17, 1, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - MIX_ENT2(SOUND_MIXER_CD, 21, 0, 4, 4, 17, 1, 2, 16, 0, 4, - 21, 0, 0, 4, 17, 1, 1, 16, 0, 3), - MIX_ENT (SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_OGAIN, 17, 1, 6, 1, 0, 0, 0, 0, 8), - /* This is external wavetable */ - MIX_ENT2(SOUND_MIXER_LINE1, 22, 0, 4, 4, 23, 1, 1, 23, 0, 4, - 22, 0, 0, 4, 23, 1, 0, 23, 0, 5), -}; - -static int default_mixer_levels[32] = -{ - 0x3232, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x4b4b, /* FM */ - 0x3232, /* PCM */ - 0x1515, /* PC Speaker */ - 0x2020, /* Ext Line */ - 0x1010, /* Mic */ - 0x4b4b, /* CD */ - 0x0000, /* Recording monitor */ - 0x4b4b, /* Second PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ - 0x4b4b, /* Output gain */ - 0x2020, /* Line1 */ - 0x2020, /* Line2 */ - 0x1515 /* Line3 (usually line in)*/ -}; - -#define LEFT_CHN 0 -#define RIGHT_CHN 1 - -/* - * Channel enable bits for ioctl(SOUND_MIXER_PRIVATE1) - */ - -#ifndef AUDIO_SPEAKER -#define AUDIO_SPEAKER 0x01 /* Enable mono output */ -#define AUDIO_HEADPHONE 0x02 /* Sparc only */ -#define AUDIO_LINE_OUT 0x04 /* Sparc only */ -#endif diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c deleted file mode 100644 index f058ed6bdb69..000000000000 --- a/sound/oss/aedsp16.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* - sound/oss/aedsp16.c - - Audio Excel DSP 16 software configuration routines - Copyright (C) 1995,1996,1997,1998 Riccardo Facchetti (fizban@tin.it) - - 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. - - */ -/* - * Include the main OSS Lite header file. It include all the os, OSS Lite, etc - * headers needed by this source. - */ -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/init.h> -#include "sound_config.h" - -/* - - READ THIS - - This module started to configure the Audio Excel DSP 16 Sound Card. - Now works with the SC-6000 (old aedsp16) and new SC-6600 based cards. - - NOTE: I have NO idea about Audio Excel DSP 16 III. If someone owns this - audio card and want to see the kernel support for it, please contact me. - - Audio Excel DSP 16 is an SB pro II, Microsoft Sound System and MPU-401 - compatible card. - It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq), - so before this module, the only way to configure the DSP under linux was - boot the MS-DOS loading the sound.sys device driver (this driver soft- - configure the sound board hardware by massaging someone of its registers), - and then ctrl-alt-del to boot linux with the DSP configured by the DOS - driver. - - This module works configuring your Audio Excel DSP 16's irq, dma and - mpu-401-irq. The OSS Lite routines rely on the fact that if the - hardware is there, they can detect it. The problem with AEDSP16 is - that no hardware can be found by the probe routines if the sound card - is not configured properly. Sometimes the kernel probe routines can find - an SBPRO even when the card is not configured (this is the standard setup - of the card), but the SBPRO emulation don't work well if the card is not - properly initialized. For this reason - - aedsp16_init_board() - - routine is called before the OSS Lite probe routines try to detect the - hardware. - - NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS) - - NOTE: Now it works with SC-6000 and SC-6600 based audio cards. The new cards - have no jumper switch at all. No more WSS or MPU-401 I/O port switches. They - have to be configured by software. - - NOTE: The driver is merged with the new OSS Lite sound driver. It works - as a lowlevel driver. - - The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS; - the OSS Lite sound driver can be configured for SBPRO and MSS cards - at the same time, but the aedsp16 can't be two cards!! - When we configure it, we have to choose the SBPRO or the MSS emulation - for AEDSP16. We also can install a *REAL* card of the other type (see [1]). - - NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO - please let me know if it works. - - The MPU-401 support can be compiled in together with one of the other - two operating modes. - - NOTE: This is something like plug-and-play: we have only to plug - the AEDSP16 board in the socket, and then configure and compile - a kernel that uses the AEDSP16 software configuration capability. - No jumper setting is needed! - - For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3 - you have just to make config the OSS Lite package, configuring - the AEDSP16 sound card, then activating the SBPro emulation mode - and at last configuring IRQ and DMA. - Compile the kernel and run it. - - NOTE: This means for SC-6000 cards that you can choose irq and dma, - but not the I/O addresses. To change I/O addresses you have to set - them with jumpers. For SC-6600 cards you have no jumpers so you have - to set up your full card configuration in the make config. - - You can change the irq/dma/mirq settings WITHOUT THE NEED to open - your computer and massage the jumpers (there are no irq/dma/mirq - jumpers to be configured anyway, only I/O BASE values have to be - configured with jumpers) - - For some ununderstandable reason, the card default of irq 7, dma 1, - don't work for me. Seems to be an IRQ or DMA conflict. Under heavy - HDD work, the kernel start to erupt out a lot of messages like: - - 'Sound: DMA timed out - IRQ/DRQ config error?' - - For what I can say, I have NOT any conflict at irq 7 (under linux I'm - using the lp polling driver), and dma line 1 is unused as stated by - /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so - I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows! - Anyway a setting of irq 10, dma 3 works really fine. - - NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know - the emulation mode, all the installed hardware and the hardware - configuration (irq and dma settings of all the hardware). - - This init module should work with SBPRO+MSS, when one of the two is - the AEDSP16 emulation and the other the real card. (see [1]) - For example: - - AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other - AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other - - MPU401 should work. (see [2]) - - [1] - --- - Date: Mon, 29 Jul 1997 08:35:40 +0100 - From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk> - - [...] - Just to let you know got my Audio Excel (emulating a MSS) working - with my original SB16, thanks for the driver! - [...] - --- - - [2] Not tested by me for lack of hardware. - - TODO, WISHES AND TECH - - - About I/O ports allocation - - - Request the 2x0h region (port base) in any case if we are using this card. - - NOTE: the "aedsp16 (base)" string with which we are requesting the aedsp16 - port base region (see code) does not mean necessarily that we are emulating - sbpro. Even if this region is the sbpro I/O ports region, we use this - region to access the control registers of the card, and if emulating - sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro - registers are not used, in no way, to emulate an sbpro: they are - used only for configuration purposes. - - Started Fri Mar 17 16:13:18 MET 1995 - - v0.1 (ALPHA, was a user-level program called AudioExcelDSP16.c) - - Initial code. - v0.2 (ALPHA) - - Cleanups. - - Integrated with Linux voxware v 2.90-2 kernel sound driver. - - SoundBlaster Pro mode configuration. - - Microsoft Sound System mode configuration. - - MPU-401 mode configuration. - v0.3 (ALPHA) - - Cleanups. - - Rearranged the code to let aedsp16_init_board be more general. - - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h - inclusion too. We rely on os.h - - Used the to get a variable - len string (we are not sure about the len of Copyright string). - This works with any SB and compatible. - - Added the code to request_region at device init (should go in - the main body of voxware). - v0.4 (BETA) - - Better configure.c patch for aedsp16 configuration (better - logic of inclusion of AEDSP16 support) - - Modified the conditional compilation to better support more than - one sound card of the emulated type (read the NOTES above) - - Moved the sb init routine from the attach to the very first - probe in sb_card.c - - Rearrangements and cleanups - - Wiped out some unnecessary code and variables: this is kernel - code so it is better save some TEXT and DATA - - Fixed the request_region code. We must allocate the aedsp16 (sbpro) - I/O ports in any case because they are used to access the DSP - configuration registers and we can not allow anyone to get them. - v0.5 - - cleanups on comments - - prep for diffs against v3.0-proto-950402 - v0.6 - - removed the request_region()s when compiling the MODULE sound.o - because we are not allowed (by the actual voxware structure) to - release_region() - v0.7 (pre ALPHA, not distributed) - - started porting this module to kernel 1.3.84. Dummy probe/attach - routines. - v0.8 (ALPHA) - - attached all the init routines. - v0.9 (BETA) - - Integrated with linux-pre2.0.7 - - Integrated with configuration scripts. - - Cleaned up and beautyfied the code. - v0.9.9 (BETA) - - Thanks to Piercarlo Grandi: corrected the conditonal compilation code. - Now only the code configured is compiled in, with some memory saving. - v0.9.10 - - Integration into the sound/lowlevel/ section of the sound driver. - - Re-organized the code. - v0.9.11 (not distributed) - - Rewritten the init interface-routines to initialize the AEDSP16 in - one shot. - - More cosmetics. - - SC-6600 support. - - More soft/hard configuration. - v0.9.12 - - Refined the v0.9.11 code with conditional compilation to distinguish - between SC-6000 and SC-6600 code. - v1.0.0 - - Prep for merging with OSS Lite and Linux kernel 2.1.13 - - Corrected a bug in request/check/release region calls (thanks to the - new kernel exception handling). - v1.1 - - Revamped for integration with new modularized sound drivers: to enhance - the flexibility of modular version, I have removed all the conditional - compilation for SBPRO, MPU and MSS code. Now it is all managed with - the ae_config structure. - v1.2 - - Module informations added. - - Removed aedsp16_delay_10msec(), now using mdelay(10) - - All data and funcs moved to .*.init section. - v1.3 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/27 - - got rid of check_region - - Known Problems: - - Audio Excel DSP 16 III don't work with this driver. - - Credits: - Many thanks to Gerald Britton <gbritton@CapAccess.org>. He helped me a - lot in testing the 0.9.11 and 0.9.12 versions of this driver. - - */ - - -#define VERSION "1.3" /* Version of Audio Excel DSP 16 driver */ - -#undef AEDSP16_DEBUG /* Define this to 1 to enable debug code */ -#undef AEDSP16_DEBUG_MORE /* Define this to 1 to enable more debug */ -#undef AEDSP16_INFO /* Define this to 1 to enable info code */ - -#if defined(AEDSP16_DEBUG) -# define DBG(x) printk x -# if defined(AEDSP16_DEBUG_MORE) -# define DBG1(x) printk x -# else -# define DBG1(x) -# endif -#else -# define DBG(x) -# define DBG1(x) -#endif - -/* - * Misc definitions - */ -#define TRUE 1 -#define FALSE 0 - -/* - * Region Size for request/check/release region. - */ -#define IOBASE_REGION_SIZE 0x10 - -/* - * Hardware related defaults - */ -#define DEF_AEDSP16_IOB 0x220 /* 0x220(default) 0x240 */ -#define DEF_AEDSP16_IRQ 7 /* 5 7(default) 9 10 11 */ -#define DEF_AEDSP16_MRQ 0 /* 5 7 9 10 0(default), 0 means disable */ -#define DEF_AEDSP16_DMA 1 /* 0 1(default) 3 */ - -/* - * Commands of AEDSP16's DSP (SBPRO+special). - * Some of them are COMMAND_xx, in the future they may change. - */ -#define WRITE_MDIRQ_CFG 0x50 /* Set M&I&DRQ mask (the real config) */ -#define COMMAND_52 0x52 /* */ -#define READ_HARD_CFG 0x58 /* Read Hardware Config (I/O base etc) */ -#define COMMAND_5C 0x5c /* */ -#define COMMAND_60 0x60 /* */ -#define COMMAND_66 0x66 /* */ -#define COMMAND_6C 0x6c /* */ -#define COMMAND_6E 0x6e /* */ -#define COMMAND_88 0x88 /* */ -#define DSP_INIT_MSS 0x8c /* Enable Microsoft Sound System mode */ -#define COMMAND_C5 0xc5 /* */ -#define GET_DSP_VERSION 0xe1 /* Get DSP Version */ -#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright */ - -/* - * Offsets of AEDSP16 DSP I/O ports. The offset is added to base I/O port - * to have the actual I/O port. - * Register permissions are: - * (wo) == Write Only - * (ro) == Read Only - * (w-) == Write - * (r-) == Read - */ -#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ -#define DSP_READ 0x0a /* offset of DSP READ (ro) */ -#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ -#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ -#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ -#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ - - -#define RETRY 10 /* Various retry values on I/O opera- */ -#define STATUSRETRY 1000 /* tions. Sometimes we have to */ -#define HARDRETRY 500000 /* wait for previous cmd to complete */ - -/* - * Size of character arrays that store name and version of sound card - */ -#define CARDNAMELEN 15 /* Size of the card's name in chars */ -#define CARDVERLEN 10 /* Size of the card's version in chars */ -#define CARDVERDIGITS 2 /* Number of digits in the version */ - -#if defined(CONFIG_SC6600) -/* - * Bitmapped flags of hard configuration - */ -/* - * Decode macros (xl == low byte, xh = high byte) - */ -#define IOBASE(xl) ((xl & 0x01)?0x240:0x220) -#define JOY(xl) (xl & 0x02) -#define MPUADDR(xl) ( \ - (xl & 0x0C)?0x330: \ - (xl & 0x08)?0x320: \ - (xl & 0x04)?0x310: \ - 0x300) -#define WSSADDR(xl) ((xl & 0x10)?0xE80:0x530) -#define CDROM(xh) (xh & 0x20) -#define CDROMADDR(xh) (((xh & 0x1F) << 4) + 0x200) -/* - * Encode macros - */ -#define BLDIOBASE(xl, val) { \ - xl &= ~0x01; \ - if (val == 0x240) \ - xl |= 0x01; \ - } -#define BLDJOY(xl, val) { \ - xl &= ~0x02; \ - if (val == 1) \ - xl |= 0x02; \ - } -#define BLDMPUADDR(xl, val) { \ - xl &= ~0x0C; \ - switch (val) { \ - case 0x330: \ - xl |= 0x0C; \ - break; \ - case 0x320: \ - xl |= 0x08; \ - break; \ - case 0x310: \ - xl |= 0x04; \ - break; \ - case 0x300: \ - xl |= 0x00; \ - break; \ - default: \ - xl |= 0x00; \ - break; \ - } \ - } -#define BLDWSSADDR(xl, val) { \ - xl &= ~0x10; \ - if (val == 0xE80) \ - xl |= 0x10; \ - } -#define BLDCDROM(xh, val) { \ - xh &= ~0x20; \ - if (val == 1) \ - xh |= 0x20; \ - } -#define BLDCDROMADDR(xh, val) { \ - int tmp = val; \ - tmp -= 0x200; \ - tmp >>= 4; \ - tmp &= 0x1F; \ - xh |= tmp; \ - xh &= 0x7F; \ - xh |= 0x40; \ - } -#endif /* CONFIG_SC6600 */ - -/* - * Bit mapped flags for calling aedsp16_init_board(), and saving the current - * emulation mode. - */ -#define INIT_NONE (0 ) -#define INIT_SBPRO (1<<0) -#define INIT_MSS (1<<1) -#define INIT_MPU401 (1<<2) - -static int soft_cfg __initdata = 0; /* bitmapped config */ -static int soft_cfg_mss __initdata = 0; /* bitmapped mss config */ -static int ver[CARDVERDIGITS] __initdata = {0, 0}; /* DSP Ver: - hi->ver[0] lo->ver[1] */ - -#if defined(CONFIG_SC6600) -static int hard_cfg[2] /* lo<-hard_cfg[0] hi<-hard_cfg[1] */ - __initdata = { 0, 0}; -#endif /* CONFIG_SC6600 */ - -#if defined(CONFIG_SC6600) -/* Decoded hard configuration */ -struct d_hcfg { - int iobase; - int joystick; - int mpubase; - int wssbase; - int cdrom; - int cdrombase; -}; - -static struct d_hcfg decoded_hcfg __initdata = {0, }; - -#endif /* CONFIG_SC6600 */ - -/* orVals contain the values to be or'ed */ -struct orVals { - int val; /* irq|mirq|dma */ - int or; /* soft_cfg |= TheStruct.or */ -}; - -/* aedsp16_info contain the audio card configuration */ -struct aedsp16_info { - int base_io; /* base I/O address for accessing card */ - int irq; /* irq value for DSP I/O */ - int mpu_irq; /* irq for mpu401 interface I/O */ - int dma; /* dma value for DSP I/O */ - int mss_base; /* base I/O for Microsoft Sound System */ - int mpu_base; /* base I/O for MPU-401 emulation */ - int init; /* Initialization status of the card */ -}; - -/* - * Magic values that the DSP will eat when configuring irq/mirq/dma - */ -/* DSP IRQ conversion array */ -static struct orVals orIRQ[] __initdata = { - {0x05, 0x28}, - {0x07, 0x08}, - {0x09, 0x10}, - {0x0a, 0x18}, - {0x0b, 0x20}, - {0x00, 0x00} -}; - -/* MPU-401 IRQ conversion array */ -static struct orVals orMIRQ[] __initdata = { - {0x05, 0x04}, - {0x07, 0x44}, - {0x09, 0x84}, - {0x0a, 0xc4}, - {0x00, 0x00} -}; - -/* DMA Channels conversion array */ -static struct orVals orDMA[] __initdata = { - {0x00, 0x01}, - {0x01, 0x02}, - {0x03, 0x03}, - {0x00, 0x00} -}; - -static struct aedsp16_info ae_config = { - .base_io = DEF_AEDSP16_IOB, - .irq = DEF_AEDSP16_IRQ, - .mpu_irq = DEF_AEDSP16_MRQ, - .dma = DEF_AEDSP16_DMA, - .mss_base = -1, - .mpu_base = -1, - .init = INIT_NONE -}; - -/* - * Buffers to store audio card informations - */ -static char DSPCopyright[CARDNAMELEN + 1] __initdata = {0, }; -static char DSPVersion[CARDVERLEN + 1] __initdata = {0, }; - -static int __init aedsp16_wait_data(int port) -{ - int loop = STATUSRETRY; - unsigned char ret = 0; - - DBG1(("aedsp16_wait_data (0x%x): ", port)); - - do { - ret = inb(port + DSP_DATAVAIL); - /* - * Wait for data available (bit 7 of ret == 1) - */ - } while (!(ret & 0x80) && loop--); - - if (ret & 0x80) { - DBG1(("success.\n")); - return TRUE; - } - - DBG1(("failure.\n")); - return FALSE; -} - -static int __init aedsp16_read(int port) -{ - int inbyte; - - DBG((" Read DSP Byte (0x%x): ", port)); - - if (aedsp16_wait_data(port) == FALSE) { - DBG(("failure.\n")); - return -1; - } - - inbyte = inb(port + DSP_READ); - - DBG(("read [0x%x]/{%c}.\n", inbyte, inbyte)); - - return inbyte; -} - -static int __init aedsp16_test_dsp(int port) -{ - return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE); -} - -static int __init aedsp16_dsp_reset(int port) -{ - /* - * Reset DSP - */ - - DBG(("Reset DSP:\n")); - - outb(1, (port + DSP_RESET)); - udelay(10); - outb(0, (port + DSP_RESET)); - udelay(10); - udelay(10); - if (aedsp16_test_dsp(port) == TRUE) { - DBG(("success.\n")); - return TRUE; - } else - DBG(("failure.\n")); - return FALSE; -} - -static int __init aedsp16_write(int port, int cmd) -{ - unsigned char ret; - int loop = HARDRETRY; - - DBG((" Write DSP Byte (0x%x) [0x%x]: ", port, cmd)); - - do { - ret = inb(port + DSP_STATUS); - /* - * DSP ready to receive data if bit 7 of ret == 0 - */ - if (!(ret & 0x80)) { - outb(cmd, port + DSP_COMMAND); - DBG(("success.\n")); - return 0; - } - } while (loop--); - - DBG(("timeout.\n")); - printk("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd); - - return -1; -} - -#if defined(CONFIG_SC6600) - -#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) -void __init aedsp16_pinfo(void) { - DBG(("\n Base address: %x\n", decoded_hcfg.iobase)); - DBG((" Joystick : %s present\n", decoded_hcfg.joystick?"":" not")); - DBG((" WSS addr : %x\n", decoded_hcfg.wssbase)); - DBG((" MPU-401 addr: %x\n", decoded_hcfg.mpubase)); - DBG((" CDROM : %s present\n", (decoded_hcfg.cdrom!=4)?"":" not")); - DBG((" CDROMADDR : %x\n\n", decoded_hcfg.cdrombase)); -} -#endif - -static void __init aedsp16_hard_decode(void) { - - DBG((" aedsp16_hard_decode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); - -/* - * Decode Cfg Bytes. - */ - decoded_hcfg.iobase = IOBASE(hard_cfg[0]); - decoded_hcfg.joystick = JOY(hard_cfg[0]); - decoded_hcfg.wssbase = WSSADDR(hard_cfg[0]); - decoded_hcfg.mpubase = MPUADDR(hard_cfg[0]); - decoded_hcfg.cdrom = CDROM(hard_cfg[1]); - decoded_hcfg.cdrombase = CDROMADDR(hard_cfg[1]); - -#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) - printk(" Original sound card configuration:\n"); - aedsp16_pinfo(); -#endif - -/* - * Now set up the real kernel configuration. - */ - decoded_hcfg.iobase = ae_config.base_io; - decoded_hcfg.wssbase = ae_config.mss_base; - decoded_hcfg.mpubase = ae_config.mpu_base; - -#if defined(CONFIG_SC6600_JOY) - decoded_hcfg.joystick = CONFIG_SC6600_JOY; /* Enable */ -#endif -#if defined(CONFIG_SC6600_CDROM) - decoded_hcfg.cdrom = CONFIG_SC6600_CDROM; /* 4:N-3:I-2:G-1:P-0:S */ -#endif -#if defined(CONFIG_SC6600_CDROMBASE) - decoded_hcfg.cdrombase = CONFIG_SC6600_CDROMBASE; /* 0 Disable */ -#endif - -#if defined(AEDSP16_DEBUG) - DBG((" New Values:\n")); - aedsp16_pinfo(); -#endif - - DBG(("success.\n")); -} - -static void __init aedsp16_hard_encode(void) { - - DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); - - hard_cfg[0] = 0; - hard_cfg[1] = 0; - - hard_cfg[0] |= 0x20; - - BLDIOBASE (hard_cfg[0], decoded_hcfg.iobase); - BLDWSSADDR(hard_cfg[0], decoded_hcfg.wssbase); - BLDMPUADDR(hard_cfg[0], decoded_hcfg.mpubase); - BLDJOY(hard_cfg[0], decoded_hcfg.joystick); - BLDCDROM(hard_cfg[1], decoded_hcfg.cdrom); - BLDCDROMADDR(hard_cfg[1], decoded_hcfg.cdrombase); - -#if defined(AEDSP16_DEBUG) - aedsp16_pinfo(); -#endif - - DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); - DBG(("success.\n")); - -} - -static int __init aedsp16_hard_write(int port) { - - DBG(("aedsp16_hard_write:\n")); - - if (aedsp16_write(port, COMMAND_6C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6C); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, COMMAND_5C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, hard_cfg[0])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[0]); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, hard_cfg[1])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[1]); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, COMMAND_C5)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_C5); - DBG(("failure.\n")); - return FALSE; - } - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_hard_read(int port) { - - DBG(("aedsp16_hard_read:\n")); - - if (aedsp16_write(port, READ_HARD_CFG)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - - if ((hard_cfg[0] = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - if ((hard_cfg[1] = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_read(port) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_ext_cfg_write(int port) { - - int extcfg, val; - - if (aedsp16_write(port, COMMAND_66)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_66); - return FALSE; - } - - extcfg = 7; - if (decoded_hcfg.cdrom != 2) - extcfg = 0x0F; - if ((decoded_hcfg.cdrom == 4) || - (decoded_hcfg.cdrom == 3)) - extcfg &= ~2; - if (decoded_hcfg.cdrombase == 0) - extcfg &= ~2; - if (decoded_hcfg.mpubase == 0) - extcfg &= ~1; - - if (aedsp16_write(port, extcfg)) { - printk("[AEDSP16] Write extcfg: failed!\n"); - return FALSE; - } - if (aedsp16_write(port, 0)) { - printk("[AEDSP16] Write extcfg: failed!\n"); - return FALSE; - } - if (decoded_hcfg.cdrom == 3) { - if (aedsp16_write(port, COMMAND_52)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52); - return FALSE; - } - if ((val = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n" - , COMMAND_52); - return FALSE; - } - val &= 0x7F; - if (aedsp16_write(port, COMMAND_60)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60); - return FALSE; - } - if (aedsp16_write(port, val)) { - printk("[AEDSP16] Write val: failed!\n"); - return FALSE; - } - } - - return TRUE; -} - -#endif /* CONFIG_SC6600 */ - -static int __init aedsp16_cfg_write(int port) { - if (aedsp16_write(port, WRITE_MDIRQ_CFG)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); - return FALSE; - } - if (aedsp16_write(port, soft_cfg)) { - printk("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n"); - return FALSE; - } - return TRUE; -} - -static int __init aedsp16_init_mss(int port) -{ - DBG(("aedsp16_init_mss:\n")); - - mdelay(10); - - if (aedsp16_write(port, DSP_INIT_MSS)) { - printk("[AEDSP16] aedsp16_init_mss [0x%x]: failed!\n", - DSP_INIT_MSS); - DBG(("failure.\n")); - return FALSE; - } - - mdelay(10); - - if (aedsp16_cfg_write(port) == FALSE) - return FALSE; - - outb(soft_cfg_mss, ae_config.mss_base); - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_setup_board(int port) { - int loop = RETRY; - -#if defined(CONFIG_SC6600) - int val = 0; - - if (aedsp16_hard_read(port) == FALSE) { - printk("[AEDSP16] aedsp16_hard_read: failed!\n"); - return FALSE; - } - - if (aedsp16_write(port, COMMAND_52)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52); - return FALSE; - } - - if ((val = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - COMMAND_52); - return FALSE; - } -#endif - - do { - if (aedsp16_write(port, COMMAND_88)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_88); - return FALSE; - } - mdelay(10); - } while ((aedsp16_wait_data(port) == FALSE) && loop--); - - if (aedsp16_read(port) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - COMMAND_88); - return FALSE; - } - -#if !defined(CONFIG_SC6600) - if (aedsp16_write(port, COMMAND_5C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C); - return FALSE; - } -#endif - - if (aedsp16_cfg_write(port) == FALSE) - return FALSE; - -#if defined(CONFIG_SC6600) - if (aedsp16_write(port, COMMAND_60)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60); - return FALSE; - } - if (aedsp16_write(port, val)) { - printk("[AEDSP16] DATA 0x%x: failed!\n", val); - return FALSE; - } - if (aedsp16_write(port, COMMAND_6E)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6E); - return FALSE; - } - if (aedsp16_write(port, ver[0])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", ver[0]); - return FALSE; - } - if (aedsp16_write(port, ver[1])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", ver[1]); - return FALSE; - } - - if (aedsp16_hard_write(port) == FALSE) { - printk("[AEDSP16] aedsp16_hard_write: failed!\n"); - return FALSE; - } - - if (aedsp16_write(port, COMMAND_5C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C); - return FALSE; - } - -#if defined(THIS_IS_A_THING_I_HAVE_NOT_TESTED_YET) - if (aedsp16_cfg_write(port) == FALSE) - return FALSE; -#endif - -#endif - - return TRUE; -} - -static int __init aedsp16_stdcfg(int port) { - if (aedsp16_write(port, WRITE_MDIRQ_CFG)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); - return FALSE; - } - /* - * 0x0A == (IRQ 7, DMA 1, MIRQ 0) - */ - if (aedsp16_write(port, 0x0A)) { - printk("[AEDSP16] aedsp16_stdcfg: failed!\n"); - return FALSE; - } - return TRUE; -} - -static int __init aedsp16_dsp_version(int port) -{ - int len = 0; - int ret; - - DBG(("Get DSP Version:\n")); - - if (aedsp16_write(ae_config.base_io, GET_DSP_VERSION)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_VERSION); - DBG(("failed.\n")); - return FALSE; - } - - do { - if ((ret = aedsp16_read(port)) == -1) { - DBG(("failed.\n")); - return FALSE; - } - /* - * We already know how many int are stored (2), so we know when the - * string is finished. - */ - ver[len++] = ret; - } while (len < CARDVERDIGITS); - sprintf(DSPVersion, "%d.%d", ver[0], ver[1]); - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_dsp_copyright(int port) -{ - int len = 0; - int ret; - - DBG(("Get DSP Copyright:\n")); - - if (aedsp16_write(ae_config.base_io, GET_DSP_COPYRIGHT)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_COPYRIGHT); - DBG(("failed.\n")); - return FALSE; - } - - do { - if ((ret = aedsp16_read(port)) == -1) { - /* - * If no more data available, return to the caller, no error if len>0. - * We have no other way to know when the string is finished. - */ - if (len) - break; - else { - DBG(("failed.\n")); - return FALSE; - } - } - - DSPCopyright[len++] = ret; - - } while (len < CARDNAMELEN); - - DBG(("success.\n")); - - return TRUE; -} - -static void __init aedsp16_init_tables(void) -{ - int i = 0; - - memset(DSPCopyright, 0, CARDNAMELEN + 1); - memset(DSPVersion, 0, CARDVERLEN + 1); - - for (i = 0; orIRQ[i].or; i++) - if (orIRQ[i].val == ae_config.irq) { - soft_cfg |= orIRQ[i].or; - soft_cfg_mss |= orIRQ[i].or; - } - - for (i = 0; orMIRQ[i].or; i++) - if (orMIRQ[i].or == ae_config.mpu_irq) - soft_cfg |= orMIRQ[i].or; - - for (i = 0; orDMA[i].or; i++) - if (orDMA[i].val == ae_config.dma) { - soft_cfg |= orDMA[i].or; - soft_cfg_mss |= orDMA[i].or; - } -} - -static int __init aedsp16_init_board(void) -{ - aedsp16_init_tables(); - - if (aedsp16_dsp_reset(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_dsp_reset: failed!\n"); - return FALSE; - } - if (aedsp16_dsp_copyright(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_dsp_copyright: failed!\n"); - return FALSE; - } - - /* - * My AEDSP16 card return SC-6000 in DSPCopyright, so - * if we have something different, we have to be warned. - */ - if (strcmp("SC-6000", DSPCopyright)) - printk("[AEDSP16] Warning: non SC-6000 audio card!\n"); - - if (aedsp16_dsp_version(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_dsp_version: failed!\n"); - return FALSE; - } - - if (aedsp16_stdcfg(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_stdcfg: failed!\n"); - return FALSE; - } - -#if defined(CONFIG_SC6600) - if (aedsp16_hard_read(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_hard_read: failed!\n"); - return FALSE; - } - - aedsp16_hard_decode(); - - aedsp16_hard_encode(); - - if (aedsp16_hard_write(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_hard_write: failed!\n"); - return FALSE; - } - - if (aedsp16_ext_cfg_write(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_ext_cfg_write: failed!\n"); - return FALSE; - } -#endif /* CONFIG_SC6600 */ - - if (aedsp16_setup_board(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_setup_board: failed!\n"); - return FALSE; - } - - if (ae_config.mss_base != -1) { - if (ae_config.init & INIT_MSS) { - if (aedsp16_init_mss(ae_config.base_io) == FALSE) { - printk("[AEDSP16] Can not initialize" - "Microsoft Sound System mode.\n"); - return FALSE; - } - } - } - -#if !defined(MODULE) || defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) - - printk("Audio Excel DSP 16 init v%s (%s %s) [", - VERSION, DSPCopyright, - DSPVersion); - - if (ae_config.mpu_base != -1) { - if (ae_config.init & INIT_MPU401) { - printk("MPU401"); - if ((ae_config.init & INIT_MSS) || - (ae_config.init & INIT_SBPRO)) - printk(" "); - } - } - - if (ae_config.mss_base == -1) { - if (ae_config.init & INIT_SBPRO) { - printk("SBPro"); - if (ae_config.init & INIT_MSS) - printk(" "); - } - } - - if (ae_config.mss_base != -1) - if (ae_config.init & INIT_MSS) - printk("MSS"); - - printk("]\n"); -#endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */ - - mdelay(10); - - return TRUE; -} - -static int __init init_aedsp16_sb(void) -{ - DBG(("init_aedsp16_sb: ")); - -/* - * If the card is already init'ed MSS, we can not init it to SBPRO too - * because the board can not emulate simultaneously MSS and SBPRO. - */ - if (ae_config.init & INIT_MSS) - return FALSE; - if (ae_config.init & INIT_SBPRO) - return FALSE; - - ae_config.init |= INIT_SBPRO; - - DBG(("done.\n")); - - return TRUE; -} - -static void uninit_aedsp16_sb(void) -{ - DBG(("uninit_aedsp16_sb: ")); - - ae_config.init &= ~INIT_SBPRO; - - DBG(("done.\n")); -} - -static int __init init_aedsp16_mss(void) -{ - DBG(("init_aedsp16_mss: ")); - -/* - * If the card is already init'ed SBPRO, we can not init it to MSS too - * because the board can not emulate simultaneously MSS and SBPRO. - */ - if (ae_config.init & INIT_SBPRO) - return FALSE; - if (ae_config.init & INIT_MSS) - return FALSE; -/* - * We must allocate the CONFIG_AEDSP16_BASE region too because these are the - * I/O ports to access card's control registers. - */ - if (!(ae_config.init & INIT_MPU401)) { - if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE, - "aedsp16 (base)")) { - printk( - "AEDSP16 BASE I/O port region is already in use.\n"); - return FALSE; - } - } - - ae_config.init |= INIT_MSS; - - DBG(("done.\n")); - - return TRUE; -} - -static void uninit_aedsp16_mss(void) -{ - DBG(("uninit_aedsp16_mss: ")); - - if ((!(ae_config.init & INIT_MPU401)) && - (ae_config.init & INIT_MSS)) { - release_region(ae_config.base_io, IOBASE_REGION_SIZE); - DBG(("AEDSP16 base region released.\n")); - } - - ae_config.init &= ~INIT_MSS; - DBG(("done.\n")); -} - -static int __init init_aedsp16_mpu(void) -{ - DBG(("init_aedsp16_mpu: ")); - - if (ae_config.init & INIT_MPU401) - return FALSE; - -/* - * We must request the CONFIG_AEDSP16_BASE region too because these are the I/O - * ports to access card's control registers. - */ - if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) { - if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE, - "aedsp16 (base)")) { - printk( - "AEDSP16 BASE I/O port region is already in use.\n"); - return FALSE; - } - } - - ae_config.init |= INIT_MPU401; - - DBG(("done.\n")); - - return TRUE; -} - -static void uninit_aedsp16_mpu(void) -{ - DBG(("uninit_aedsp16_mpu: ")); - - if ((!(ae_config.init & (INIT_MSS | INIT_SBPRO))) && - (ae_config.init & INIT_MPU401)) { - release_region(ae_config.base_io, IOBASE_REGION_SIZE); - DBG(("AEDSP16 base region released.\n")); - } - - ae_config.init &= ~INIT_MPU401; - - DBG(("done.\n")); -} - -static int __init init_aedsp16(void) -{ - int initialized = FALSE; - - DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n", - ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq)); - - if (ae_config.mss_base == -1) { - if (init_aedsp16_sb() == FALSE) { - uninit_aedsp16_sb(); - } else { - initialized = TRUE; - } - } - - if (ae_config.mpu_base != -1) { - if (init_aedsp16_mpu() == FALSE) { - uninit_aedsp16_mpu(); - } else { - initialized = TRUE; - } - } - -/* - * In the sequence of init routines, the MSS init MUST be the last! - * This because of the special register programming the MSS mode needs. - * A board reset would disable the MSS mode restoring the default SBPRO - * mode. - */ - if (ae_config.mss_base != -1) { - if (init_aedsp16_mss() == FALSE) { - uninit_aedsp16_mss(); - } else { - initialized = TRUE; - } - } - - if (initialized) - initialized = aedsp16_init_board(); - return initialized; -} - -static void __exit uninit_aedsp16(void) -{ - if (ae_config.mss_base != -1) - uninit_aedsp16_mss(); - else - uninit_aedsp16_sb(); - if (ae_config.mpu_base != -1) - uninit_aedsp16_mpu(); -} - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata mpu_irq = -1; -static int __initdata mss_base = -1; -static int __initdata mpu_base = -1; - -module_param_hw(io, int, ioport, 0); -MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)"); -module_param_hw(irq, int, irq, 0); -MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)"); -module_param_hw(dma, int, dma, 0); -MODULE_PARM_DESC(dma, "dma line (0 1 3)"); -module_param_hw(mpu_irq, int, irq, 0); -MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)"); -module_param_hw(mss_base, int, ioport, 0); -MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)"); -module_param_hw(mpu_base, int, ioport, 0); -MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)"); -MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>"); -MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION); -MODULE_LICENSE("GPL"); - -static int __init do_init_aedsp16(void) { - printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n"); - if (io == -1 || dma == -1 || irq == -1) { - printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n"); - return -EINVAL; - } - - ae_config.base_io = io; - ae_config.irq = irq; - ae_config.dma = dma; - - ae_config.mss_base = mss_base; - ae_config.mpu_base = mpu_base; - ae_config.mpu_irq = mpu_irq; - - if (init_aedsp16() == FALSE) { - printk(KERN_ERR "aedsp16: initialization failed\n"); - /* - * XXX - * What error should we return here ? - */ - return -EINVAL; - } - return 0; -} - -static void __exit cleanup_aedsp16(void) { - uninit_aedsp16(); -} - -module_init(do_init_aedsp16); -module_exit(cleanup_aedsp16); - -#ifndef MODULE -static int __init setup_aedsp16(char *str) -{ - /* io, irq, dma, mss_io, mpu_io, mpu_irq */ - int ints[7]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - mss_base = ints[4]; - mpu_base = ints[5]; - mpu_irq = ints[6]; - return 1; -} - -__setup("aedsp16=", setup_aedsp16); -#endif diff --git a/sound/oss/audio.c b/sound/oss/audio.c deleted file mode 100644 index 09c932f899b8..000000000000 --- a/sound/oss/audio.c +++ /dev/null @@ -1,985 +0,0 @@ -/* - * sound/oss/audio.c - * - * Device file manager for /dev/audio - */ - -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Thomas Sailer : moved several static variables into struct audio_operations - * (which is grossly misnamed btw.) because they have the same - * lifetime as the rest in there and dynamic allocation saves - * 12k or so - * Thomas Sailer : use more logical O_NONBLOCK semantics - * Daniel Rodriksson: reworked the use of the device specific copy_user - * still generic - * Horst von Brand: Add missing #include <linux/string.h> - * Chris Rankin : Update the module-usage counter for the coprocessor, - * and decrement the counters again if we cannot open - * the audio device. - */ - -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/kmod.h> - -#include "sound_config.h" -#include "ulaw.h" -#include "coproc.h" - -#define NEUTRAL8 0x80 -#define NEUTRAL16 0x00 - - -static int dma_ioctl(int dev, unsigned int cmd, void __user *arg); - -static int set_format(int dev, int fmt) -{ - if (fmt != AFMT_QUERY) - { - audio_devs[dev]->local_conversion = 0; - - if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ - { - if (fmt == AFMT_MU_LAW) - { - fmt = AFMT_U8; - audio_devs[dev]->local_conversion = CNV_MU_LAW; - } - else - fmt = AFMT_U8; /* This is always supported */ - } - audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt); - audio_devs[dev]->local_format = fmt; - } - else - return audio_devs[dev]->local_format; - - if (audio_devs[dev]->local_conversion) - return audio_devs[dev]->local_conversion; - else - return audio_devs[dev]->local_format; -} - -int audio_open(int dev, struct file *file) -{ - int ret; - int bits; - int dev_type = dev & 0x0f; - int mode = translate_mode(file); - const struct audio_driver *driver; - const struct coproc_operations *coprocessor; - - dev = dev >> 4; - - if (dev_type == SND_DEV_DSP16) - bits = 16; - else - bits = 8; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - driver = audio_devs[dev]->d; - - if (!try_module_get(driver->owner)) - return -ENODEV; - - if ((ret = DMAbuf_open(dev, mode)) < 0) - goto error_1; - - if ( (coprocessor = audio_devs[dev]->coproc) != NULL ) { - if (!try_module_get(coprocessor->owner)) - goto error_2; - - if ((ret = coprocessor->open(coprocessor->devc, COPR_PCM)) < 0) { - printk(KERN_WARNING "Sound: Can't access coprocessor device\n"); - goto error_3; - } - } - - audio_devs[dev]->local_conversion = 0; - - if (dev_type == SND_DEV_AUDIO) - set_format(dev, AFMT_MU_LAW); - else - set_format(dev, bits); - - audio_devs[dev]->audio_mode = AM_NONE; - - return 0; - - /* - * Clean-up stack: this is what needs (un)doing if - * we can't open the audio device ... - */ - error_3: - module_put(coprocessor->owner); - - error_2: - DMAbuf_release(dev, mode); - - error_1: - module_put(driver->owner); - - return ret; -} - -static void 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; - - /* 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(KERN_ERR "audio: Buffer error 2\n"); - - memset(dmap->raw_buf + p * dmap->fragment_size, - dmap->neutral_byte, - dmap->fragment_size); - } - - dmap->flags |= DMA_DIRTY; -} - -void audio_release(int dev, struct file *file) -{ - const struct coproc_operations *coprocessor; - int mode = translate_mode(file); - - dev = dev >> 4; - - /* - * We do this in DMAbuf_release(). Why are we doing it - * here? Why don't we test the file mode before setting - * both flags? DMAbuf_release() does. - * ...pester...pester...pester... - */ - audio_devs[dev]->dmap_out->closing = 1; - audio_devs[dev]->dmap_in->closing = 1; - - /* - * We need to make sure we allocated the dmap_out buffer - * before we go mucking around with it in sync_output(). - */ - if (mode & OPEN_WRITE) - sync_output(dev); - - if ( (coprocessor = audio_devs[dev]->coproc) != NULL ) { - coprocessor->close(coprocessor->devc, COPR_PCM); - module_put(coprocessor->owner); - } - DMAbuf_release(dev, mode); - - module_put(audio_devs[dev]->d->owner); -} - -static void translate_bytes(const unsigned char *table, unsigned char *buff, int n) -{ - unsigned long i; - - if (n <= 0) - return; - - for (i = 0; i < n; ++i) - buff[i] = table[buff[i]]; -} - -int audio_write(int dev, struct file *file, const char __user *buf, int count) -{ - int c, p, l, buf_size, used, returned; - int err; - char *dma_buf; - - dev = dev >> 4; - - p = 0; - c = count; - - if(count < 0) - return -EINVAL; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_devs[dev]->audio_mode |= AM_WRITE; - else - audio_devs[dev]->audio_mode = AM_WRITE; - - if (!count) /* Flush output */ - { - sync_output(dev); - return 0; - } - - while (c) - { - if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, !!(file->f_flags & O_NONBLOCK))) < 0) - { - /* Handle nonblocking mode */ - if ((file->f_flags & O_NONBLOCK) && err == -EAGAIN) - return p? p : -EAGAIN; /* No more space. Return # of accepted bytes */ - return err; - } - l = c; - - if (l > buf_size) - l = buf_size; - - returned = l; - used = l; - 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(KERN_ERR "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(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf); - return -EDOM; - } - if(copy_from_user(dma_buf, &(buf)[p], l)) - return -EFAULT; - } - else audio_devs[dev]->d->copy_user (dev, - dma_buf, 0, - buf, p, - c, buf_size, - &used, &returned, - l); - l = returned; - - if (audio_devs[dev]->local_conversion & CNV_MU_LAW) - { - translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); - } - c -= used; - p += used; - DMAbuf_move_wrpointer(dev, l); - - } - - return count; -} - -int audio_read(int dev, struct file *file, char __user *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_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - sync_output(dev); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_devs[dev]->audio_mode |= AM_READ; - else - audio_devs[dev]->audio_mode = AM_READ; - - while(c) - { - if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, !!(file->f_flags & O_NONBLOCK))) < 0) - { - /* - * Nonblocking mode handling. Return current # of bytes - */ - - if (p > 0) /* Avoid throwing away data */ - return p; /* Return it instead */ - - if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN) - return -EAGAIN; - - return buf_no; - } - if (l > c) - l = c; - - /* - * Insert any local processing here. - */ - - if (audio_devs[dev]->local_conversion & CNV_MU_LAW) - { - translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l); - } - - { - char *fixit = dmabuf; - - if(copy_to_user(&(buf)[p], fixit, l)) - return -EFAULT; - } - - DMAbuf_rmchars(dev, buf_no, l); - - p += l; - c -= l; - } - - return count - c; -} - -int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) -{ - int val, count; - unsigned long flags; - struct dma_buffparms *dmap; - int __user *p = arg; - - dev = dev >> 4; - - if (_IOC_TYPE(cmd) == 'C') { - if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ - return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); - /* else - printk(KERN_DEBUG"/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; - - 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, NULL); - return 0; - - case SNDCTL_DSP_RESET: - audio_devs[dev]->audio_mode = AM_NONE; - DMAbuf_reset(dev); - return 0; - - case SNDCTL_DSP_GETFMTS: - val = audio_devs[dev]->format_mask | AFMT_MU_LAW; - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - val = set_format(dev, val); - break; - - case SNDCTL_DSP_GETISPACE: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - return dma_ioctl(dev, cmd, arg); - - case SNDCTL_DSP_GETOSPACE: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - return dma_ioctl(dev, cmd, arg); - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETCAPS: - val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode == OPEN_READWRITE) - val |= DSP_CAP_DUPLEX; - if (audio_devs[dev]->coproc) - val |= DSP_CAP_COPROC; - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - val |= DSP_CAP_BATCH; - if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ - val |= DSP_CAP_TRIGGER; - break; - - case SOUND_PCM_WRITE_RATE: - if (get_user(val, p)) - return -EFAULT; - val = audio_devs[dev]->d->set_speed(dev, val); - break; - - case SOUND_PCM_READ_RATE: - val = audio_devs[dev]->d->set_speed(dev, 0); - break; - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - if (val > 1 || val < 0) - return -EINVAL; - val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - val = audio_devs[dev]->d->set_channels(dev, val); - break; - - case SOUND_PCM_READ_CHANNELS: - val = audio_devs[dev]->d->set_channels(dev, 0); - break; - - case SOUND_PCM_READ_BITS: - val = audio_devs[dev]->d->set_bits(dev, 0); - break; - - case SNDCTL_DSP_SETDUPLEX: - if (audio_devs[dev]->open_mode != OPEN_READWRITE) - return -EPERM; - return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; - - case SNDCTL_DSP_PROFILE: - if (get_user(val, p)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->applic_profile = val; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->applic_profile = val; - return 0; - - case SNDCTL_DSP_GETODELAY: - dmap = audio_devs[dev]->dmap_out; - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (!(dmap->flags & DMA_ALLOC_DONE)) - { - val=0; - break; - } - - spin_lock_irqsave(&dmap->lock,flags); - /* Compute number of bytes that have been played */ - count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - if (count < dmap->fragment_size && dmap->qhead != 0) - count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - count += dmap->byte_counter; - - /* Subtract current count from the number of bytes written by app */ - count = dmap->user_counter - count; - if (count < 0) - count = 0; - spin_unlock_irqrestore(&dmap->lock,flags); - val = count; - break; - - default: - return dma_ioctl(dev, cmd, arg); - } - return put_user(val, p); -} - -void audio_init_devices(void) -{ - /* - * NOTE! This routine could be called several times during boot. - */ -} - -void 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]; - - 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); - - if (sz == 8) - dmap->neutral_byte = NEUTRAL8; - else - dmap->neutral_byte = NEUTRAL16; - - if (sr < 1 || nc < 1 || sz < 1) - { -/* printk(KERN_DEBUG "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 /= 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 */ - - /* - * 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; - - if (bsz == dmap->buffsize) - bsz /= 2; /* Needs at least 2 buffers */ - - /* - * Split the computed fragment to smaller parts. After 3.5a9 - * the default subdivision is 4 which should give better - * 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 */ -#ifdef OS_DMA_ALIGN_CHECK - 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; -} - -static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact) -{ - if (fact == 0) - { - fact = dmap->subdivision; - if (fact == 0) - fact = 1; - return 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 fact; -} - -static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact) -{ - int bytes, count; - - if (fact == 0) - return -EIO; - - if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; - - bytes = fact & 0xffff; - count = (fact >> 16) & 0x7fff; - - if (count == 0) - count = MAX_SUB_BUFFERS; - else if (count < MAX_SUB_BUFFERS) - count++; - - if (bytes < 4 || bytes > 17) /* <16 || > 512k */ - 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]->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; -#endif - - 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 && - audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->fragment_size /= 2; /* Needs at least 2 buffers */ - - dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - return bytes | ((count - 1) << 16); -} - -static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; - struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; - struct dma_buffparms *dmap; - audio_buf_info info; - count_info cinfo; - int fact, ret, changed, bits, count, err; - unsigned long flags; - - switch (cmd) - { - case SNDCTL_DSP_SUBDIVIDE: - ret = 0; - if (get_user(fact, (int __user *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_subdivide(dev, dmap_out, 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, fact); - if (ret < 0) - return ret; - break; - - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_GETOSPACE: - dmap = dmap_out; - 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 (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(bits, (int __user *)arg)) - return -EFAULT; - bits &= audio_devs[dev]->open_mode; - if (audio_devs[dev]->d->trigger == NULL) - return -EINVAL; - if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && - (bits & PCM_ENABLE_OUTPUT)) - return -EINVAL; - - if (bits & PCM_ENABLE_INPUT) - { - spin_lock_irqsave(&dmap_in->lock,flags); - changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_INPUT; - if (changed && audio_devs[dev]->go) - { - reorganize_buffers(dev, dmap_in, 1); - if ((err = audio_devs[dev]->d->prepare_for_input(dev, - dmap_in->fragment_size, dmap_in->nbufs)) < 0) { - spin_unlock_irqrestore(&dmap_in->lock,flags); - return err; - } - dmap_in->dma_mode = DMODE_INPUT; - audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; - DMAbuf_activate_recording(dev, dmap_in); - } else - audio_devs[dev]->enable_bits &= ~PCM_ENABLE_INPUT; - spin_unlock_irqrestore(&dmap_in->lock,flags); - } - if (bits & PCM_ENABLE_OUTPUT) - { - spin_lock_irqsave(&dmap_out->lock,flags); - changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_OUTPUT; - if (changed && - (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 |= PCM_ENABLE_OUTPUT; - dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; - DMAbuf_launch_output(dev, dmap_out); - } else - audio_devs[dev]->enable_bits &= ~PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&dmap_out->lock,flags); - } -#if 0 - if (changed && audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); -#endif - /* Falls through... */ - - case SNDCTL_DSP_GETTRIGGER: - ret = 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; - - case SNDCTL_DSP_GETIPTR: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - spin_lock_irqsave(&dmap_in->lock,flags); - cinfo.bytes = dmap_in->byte_counter; - cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; - if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) - cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */ - cinfo.blocks = dmap_in->qlen; - cinfo.bytes += cinfo.ptr; - if (dmap_in->mapping_flags & DMA_MAP_MAPPED) - dmap_in->qlen = 0; /* Reset interrupt counter */ - spin_unlock_irqrestore(&dmap_in->lock,flags); - if (copy_to_user(arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - - spin_lock_irqsave(&dmap_out->lock,flags); - cinfo.bytes = dmap_out->byte_counter; - cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; - if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) - cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ - cinfo.blocks = dmap_out->qlen; - cinfo.bytes += cinfo.ptr; - if (dmap_out->mapping_flags & DMA_MAP_MAPPED) - dmap_out->qlen = 0; /* Reset interrupt counter */ - spin_unlock_irqrestore(&dmap_out->lock,flags); - if (copy_to_user(arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - { - ret=0; - break; - } - spin_lock_irqsave(&dmap_out->lock,flags); - /* Compute number of bytes that have been played */ - count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); - if (count < dmap_out->fragment_size && dmap_out->qhead != 0) - count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ - count += dmap_out->byte_counter; - /* Subtract current count from the number of bytes written by app */ - count = dmap_out->user_counter - count; - if (count < 0) - count = 0; - spin_unlock_irqrestore(&dmap_out->lock,flags); - ret = count; - 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; - - case SNDCTL_DSP_GETBLKSIZE: - 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_READ || - (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; - ret = dmap->fragment_size; - break; - - case SNDCTL_DSP_SETFRAGMENT: - ret = 0; - if (get_user(fact, (int __user *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_set_fragment(dev, dmap_out, fact); - if (ret < 0) - return ret; - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_set_fragment(dev, dmap_in, fact); - if (ret < 0) - return ret; - if (!arg) /* don't know what this is good for, but preserve old semantics */ - return 0; - break; - - default: - if (!audio_devs[dev]->d->ioctl) - return -EINVAL; - return audio_devs[dev]->d->ioctl(dev, cmd, arg); - } - return put_user(ret, (int __user *)arg); -} diff --git a/sound/oss/bin2hex.c b/sound/oss/bin2hex.c deleted file mode 100644 index b59109eb0db4..000000000000 --- a/sound/oss/bin2hex.c +++ /dev/null @@ -1,39 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -int main( int argc, const char * argv [] ) -{ - const char * varname; - int i = 0; - int c; - int id = 0; - - if(argv[1] && strcmp(argv[1],"-i")==0) - { - argv++; - argc--; - id=1; - } - - if(argc==1) - { - fprintf(stderr, "bin2hex: [-i] firmware\n"); - exit(1); - } - - varname = argv[1]; - printf( "/* automatically generated by bin2hex */\n" ); - printf( "static unsigned char %s [] %s =\n{\n", varname , id?"__initdata":""); - - while ( ( c = getchar( ) ) != EOF ) - { - if ( i != 0 && i % 10 == 0 ) - printf( "\n" ); - printf( "0x%02lx,", c & 0xFFl ); - i++; - } - - printf( "};\nstatic int %sLen = %d;\n", varname, i ); - return 0; -} diff --git a/sound/oss/coproc.h b/sound/oss/coproc.h deleted file mode 100644 index 7bec21bbdd88..000000000000 --- a/sound/oss/coproc.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Definitions for various on board processors on the sound cards. For - * example DSP processors. - */ - -/* - * Coprocessor access types - */ -#define COPR_CUSTOM 0x0001 /* Custom applications */ -#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */ -#define COPR_PCM 0x0004 /* Digitized voice applications */ -#define COPR_SYNTH 0x0008 /* Music synthesis */ diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c deleted file mode 100644 index 6dad51596b70..000000000000 --- a/sound/oss/dev_table.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * sound/oss/dev_table.c - * - * Device call tables. - * - * - * 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/init.h> - -#include "sound_config.h" - -struct audio_operations *audio_devs[MAX_AUDIO_DEV]; -EXPORT_SYMBOL(audio_devs); - -int num_audiodevs; -EXPORT_SYMBOL(num_audiodevs); - -struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; -EXPORT_SYMBOL(mixer_devs); - -int num_mixers; -EXPORT_SYMBOL(num_mixers); - -struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; -EXPORT_SYMBOL(synth_devs); - -int num_synths; - -struct midi_operations *midi_devs[MAX_MIDI_DEV]; -EXPORT_SYMBOL(midi_devs); - -int num_midis; -EXPORT_SYMBOL(num_midis); - -struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { - &default_sound_timer, NULL -}; -EXPORT_SYMBOL(sound_timer_devs); - -int num_sound_timers = 1; - - -static int sound_alloc_audiodev(void); - -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) -{ - struct audio_driver *d; - struct audio_operations *op; - int num; - - 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 (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_nblocks++; - if (sound_nblocks >= MAX_MEM_BLOCKS) - sound_nblocks = MAX_MEM_BLOCKS - 1; - - op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations))); - sound_nblocks++; - if (sound_nblocks >= MAX_MEM_BLOCKS) - sound_nblocks = MAX_MEM_BLOCKS - 1; - - if (d == NULL || op == NULL) { - printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name); - sound_unload_audiodev(num); - return -ENOMEM; - } - init_waitqueue_head(&op->in_sleeper); - init_waitqueue_head(&op->out_sleeper); - init_waitqueue_head(&op->poll_sleeper); - 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; - strlcpy(op->name, name, sizeof(op->name)); - op->flags = flags; - op->format_mask = format_mask; - op->devc = devc; - - /* - * Hardcoded defaults - */ - audio_devs[num] = op; - - DMAbuf_init(num, dma1, dma2); - - audio_init_devices(); - return num; -} -EXPORT_SYMBOL(sound_install_audiodrv); - -int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, - int driver_size, void *devc) -{ - struct mixer_operations *op; - - int n = sound_alloc_mixerdev(); - - 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; - } - - /* FIXME: This leaks a mixer_operations struct every time its called - until you unload sound! */ - - op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations))); - sound_nblocks++; - if (sound_nblocks >= MAX_MEM_BLOCKS) - sound_nblocks = MAX_MEM_BLOCKS - 1; - - if (op == NULL) { - printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); - return -ENOMEM; - } - memcpy((char *) op, (char *) driver, driver_size); - - strlcpy(op->name, name, sizeof(op->name)); - op->devc = devc; - - mixer_devs[n] = op; - return n; -} -EXPORT_SYMBOL(sound_install_mixer); - -void sound_unload_audiodev(int dev) -{ - if (dev != -1) { - DMAbuf_deinit(dev); - audio_devs[dev] = NULL; - unregister_sound_dsp((dev<<4)+3); - } -} -EXPORT_SYMBOL(sound_unload_audiodev); - -static int sound_alloc_audiodev(void) -{ - int i = register_sound_dsp(&oss_sound_fops, -1); - if(i==-1) - return i; - i>>=4; - if(i>=num_audiodevs) - num_audiodevs = i + 1; - return i; -} - -int sound_alloc_mididev(void) -{ - int i = register_sound_midi(&oss_sound_fops, -1); - if(i==-1) - return i; - i>>=4; - if(i>=num_midis) - num_midis = i + 1; - return i; -} -EXPORT_SYMBOL(sound_alloc_mididev); - -int sound_alloc_synthdev(void) -{ - int i; - - for (i = 0; i < MAX_SYNTH_DEV; i++) { - if (synth_devs[i] == NULL) { - if (i >= num_synths) - num_synths++; - return i; - } - } - return -1; -} -EXPORT_SYMBOL(sound_alloc_synthdev); - -int sound_alloc_mixerdev(void) -{ - int i = register_sound_mixer(&oss_sound_fops, -1); - if(i==-1) - return -1; - i>>=4; - if(i>=num_mixers) - num_mixers = i + 1; - return i; -} -EXPORT_SYMBOL(sound_alloc_mixerdev); - -int sound_alloc_timerdev(void) -{ - int i; - - 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; -} -EXPORT_SYMBOL(sound_alloc_timerdev); - -void sound_unload_mixerdev(int dev) -{ - if (dev != -1) { - mixer_devs[dev] = NULL; - unregister_sound_mixer(dev<<4); - num_mixers--; - } -} -EXPORT_SYMBOL(sound_unload_mixerdev); - -void sound_unload_mididev(int dev) -{ - if (dev != -1) { - midi_devs[dev] = NULL; - unregister_sound_midi((dev<<4)+2); - } -} -EXPORT_SYMBOL(sound_unload_mididev); - -void sound_unload_synthdev(int dev) -{ - if (dev != -1) - synth_devs[dev] = NULL; -} -EXPORT_SYMBOL(sound_unload_synthdev); - -void sound_unload_timerdev(int dev) -{ - if (dev != -1) - sound_timer_devs[dev] = NULL; -} -EXPORT_SYMBOL(sound_unload_timerdev); - diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h deleted file mode 100644 index 0199a317c5a9..000000000000 --- a/sound/oss/dev_table.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - * dev_table.h - * - * Global definitions for device call tables - * - * - * 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. - */ - - -#ifndef _DEV_TABLE_H_ -#define _DEV_TABLE_H_ - -#include <linux/spinlock.h> -/* - * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) - * Numbers 1000 to N are reserved for driver's internal use. - */ - -#define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ -#define SNDCARD_VIDC 28 /* ARMs VIDC */ -#define SNDCARD_SBPNP 29 -#define SNDCARD_SOFTOSS 36 -#define SNDCARD_VMIDI 37 -#define SNDCARD_OPL3SA1 38 /* Note: clash in msnd.h */ -#define SNDCARD_OPL3SA1_SB 39 -#define SNDCARD_OPL3SA1_MPU 40 -#define SNDCARD_WAVEFRONT 41 -#define SNDCARD_OPL3SA2 42 -#define SNDCARD_OPL3SA2_MPU 43 -#define SNDCARD_WAVEARTIST 44 /* Waveartist */ -#define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ -#define SNDCARD_AD1816 88 - -/* - * NOTE! NOTE! NOTE! NOTE! - * - * If you modify this file, please check the dev_table.c also. - * - * NOTE! NOTE! NOTE! NOTE! - */ - -struct driver_info -{ - char *driver_id; - int card_subtype; /* Driver specific. Usually 0 */ - int card_type; /* From soundcard.h */ - char *name; - void (*attach) (struct address_info *hw_config); - int (*probe) (struct address_info *hw_config); - void (*unload) (struct address_info *hw_config); -}; - -struct card_info -{ - int card_type; /* Link (search key) to the driver list */ - struct address_info config; - int enabled; - void *for_driver_use; -}; - - -/* - * Device specific parameters (used only by dmabuf.c) - */ -#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR) - -#define DMODE_NONE 0 -#define DMODE_OUTPUT PCM_ENABLE_OUTPUT -#define DMODE_INPUT PCM_ENABLE_INPUT - -struct dma_buffparms -{ - int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ - int closing; - - /* - * Pointers to raw buffers - */ - - char *raw_buf; - unsigned long raw_buf_phys; - int buffsize; - - /* - * Device state tables - */ - - unsigned long flags; -#define DMA_BUSY 0x00000001 -#define DMA_RESTART 0x00000002 -#define DMA_ACTIVE 0x00000004 -#define DMA_STARTED 0x00000008 -#define DMA_EMPTY 0x00000010 -#define DMA_ALLOC_DONE 0x00000020 -#define DMA_SYNCING 0x00000040 -#define DMA_DIRTY 0x00000080 -#define DMA_POST 0x00000100 -#define DMA_NODMA 0x00000200 -#define DMA_NOTIMEOUT 0x00000400 - - int open_mode; - - /* - * Queue parameters. - */ - int qlen; - int qhead; - int qtail; - spinlock_t lock; - - int cfrag; /* Current incomplete fragment (write) */ - - int nbufs; - int counts[MAX_SUB_BUFFERS]; - int subdivision; - - int fragment_size; - int needs_reorg; - int max_fragments; - - int bytes_in_use; - - int underrun_count; - unsigned long byte_counter; - unsigned long user_counter; - unsigned long max_byte_counter; - int data_rate; /* Bytes/second */ - - int mapping_flags; -#define DMA_MAP_MAPPED 0x00000001 - char neutral_byte; - int dma; /* DMA channel */ - - 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 */ -}; - -/* - * Structure for use with various microcontrollers and DSP processors - * in the recent sound cards. - */ -typedef struct coproc_operations -{ - char name[64]; - struct module *owner; - int (*open) (void *devc, int sub_device); - void (*close) (void *devc, int sub_device); - int (*ioctl) (void *devc, unsigned int cmd, void __user * arg, int local); - void (*reset) (void *devc); - - void *devc; /* Driver specific info */ -} coproc_operations; - -struct audio_driver -{ - struct module *owner; - int (*open) (int dev, int mode); - void (*close) (int dev); - void (*output_block) (int dev, unsigned long buf, - int count, int intrflag); - void (*start_input) (int dev, unsigned long buf, - int count, int intrflag); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - int (*prepare_for_input) (int dev, int bufsize, int nbufs); - int (*prepare_for_output) (int dev, int bufsize, int nbufs); - void (*halt_io) (int dev); - int (*local_qlen)(int dev); - void (*copy_user) (int dev, - char *localbuf, int localoffs, - const char __user *userbuf, int useroffs, - int max_in, int max_out, - int *used, int *returned, - int len); - void (*halt_input) (int dev); - void (*halt_output) (int dev); - void (*trigger) (int dev, int bits); - int (*set_speed)(int dev, int speed); - unsigned int (*set_bits)(int dev, unsigned int bits); - short (*set_channels)(int dev, short channels); - void (*postprocess_write)(int dev); /* Device spesific postprocessing for written data */ - void (*preprocess_read)(int dev); /* Device spesific preprocessing for read data */ - void (*mmap)(int dev); -}; - -struct audio_operations -{ - char name[128]; - int flags; -#define NOTHING_SPECIAL 0x00 -#define NEEDS_RESTART 0x01 -#define DMA_AUTOMODE 0x02 -#define DMA_DUPLEX 0x04 -#define DMA_PSEUDO_AUTOMODE 0x08 -#define DMA_HARDSTOP 0x10 -#define DMA_EXACT 0x40 -#define DMA_NORESET 0x80 - int format_mask; /* Bitmask for supported audio formats */ - void *devc; /* Driver specific info */ - struct audio_driver *d; - void *portc; /* Driver specific info */ - struct dma_buffparms *dmap_in, *dmap_out; - struct coproc_operations *coproc; - int mixer_dev; - int enable_bits; - int open_mode; - int go; - int min_fragment; /* 0 == unlimited */ - int max_fragment; /* 0 == unlimited */ - int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ - - /* fields formerly in dmabuf.c */ - wait_queue_head_t in_sleeper; - wait_queue_head_t out_sleeper; - wait_queue_head_t poll_sleeper; - - /* fields formerly in audio.c */ - int audio_mode; - -#define AM_NONE 0 -#define AM_WRITE OPEN_WRITE -#define AM_READ OPEN_READ - - int local_format; - int audio_format; - int local_conversion; -#define CNV_MU_LAW 0x00000001 - - /* large structures at the end to keep offsets small */ - struct dma_buffparms dmaps[2]; -}; - -int *load_mixer_volumes(char *name, int *levels, int present); - -struct mixer_operations -{ - struct module *owner; - char id[16]; - char name[64]; - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - - void *devc; - int modify_counter; -}; - -struct synth_operations -{ - struct module *owner; - char *id; /* Unique identifier (ASCII) max 29 char */ - struct synth_info *info; - int midi_dev; - int synth_type; - int synth_subtype; - - int (*open) (int dev, int mode); - void (*close) (int dev); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - int (*kill_note) (int dev, int voice, int note, int velocity); - int (*start_note) (int dev, int voice, int note, int velocity); - int (*set_instr) (int dev, int voice, int instr); - void (*reset) (int dev); - void (*hw_control) (int dev, unsigned char *event); - int (*load_patch) (int dev, int format, const char __user *addr, - int count, int pmgr_flag); - void (*aftertouch) (int dev, int voice, int pressure); - void (*controller) (int dev, int voice, int ctrl_num, int value); - void (*panning) (int dev, int voice, int value); - void (*volume_method) (int dev, int mode); - void (*bender) (int dev, int chn, int value); - int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc); - void (*setup_voice) (int dev, int voice, int chn); - int (*send_sysex)(int dev, unsigned char *bytes, int len); - - struct voice_alloc_info alloc; - struct channel_info chn_info[16]; - int emulation; -#define EMU_GM 1 /* General MIDI */ -#define EMU_XG 2 /* Yamaha XG */ -#define MAX_SYSEX_BUF 64 - unsigned char sysex_buf[MAX_SYSEX_BUF]; - int sysex_ptr; -}; - -struct midi_input_info -{ - /* MIDI input scanner variables */ -#define MI_MAX 10 - volatile int m_busy; - unsigned char m_buf[MI_MAX]; - unsigned char m_prev_status; /* For running status */ - int m_ptr; -#define MST_INIT 0 -#define MST_DATA 1 -#define MST_SYSEX 2 - int m_state; - int m_left; -}; - -struct midi_operations -{ - struct module *owner; - struct midi_info info; - struct synth_operations *converter; - struct midi_input_info in_info; - int (*open) (int dev, int mode, - void (*inputintr)(int dev, unsigned char data), - void (*outputintr)(int dev) - ); - void (*close) (int dev); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - int (*outputc) (int dev, unsigned char data); - int (*start_read) (int dev); - int (*end_read) (int dev); - void (*kick)(int dev); - int (*command) (int dev, unsigned char *data); - int (*buffer_status) (int dev); - int (*prefix_cmd) (int dev, unsigned char status); - struct coproc_operations *coproc; - void *devc; -}; - -struct sound_lowlev_timer -{ - int dev; - int priority; - unsigned int (*tmr_start)(int dev, unsigned int usecs); - void (*tmr_disable)(int dev); - void (*tmr_restart)(int dev); -}; - -struct sound_timer_operations -{ - struct module *owner; - struct sound_timer_info info; - int priority; - int devlink; - int (*open)(int dev, int mode); - void (*close)(int dev); - int (*event)(int dev, unsigned char *ev); - unsigned long (*get_time)(int dev); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - void (*arm_timer)(int dev, long time); -}; - -extern struct sound_timer_operations default_sound_timer; - -extern struct audio_operations *audio_devs[MAX_AUDIO_DEV]; -extern int num_audiodevs; -extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; -extern int num_mixers; -extern struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; -extern int num_synths; -extern struct midi_operations *midi_devs[MAX_MIDI_DEV]; -extern int num_midis; -extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; -extern int num_sound_timers; - -extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); -void sound_timer_init (struct sound_lowlev_timer *t, char *name); -void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan); - -#define AUDIO_DRIVER_VERSION 2 -#define MIXER_DRIVER_VERSION 2 -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); -int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, - 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_mixerdev(void); -int sound_alloc_timerdev(void); -int sound_alloc_synthdev(void); -int sound_alloc_mididev(void); -#endif /* _DEV_TABLE_H_ */ - diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c deleted file mode 100644 index c5dd396c66a2..000000000000 --- a/sound/oss/dmabuf.c +++ /dev/null @@ -1,1268 +0,0 @@ -/* - * sound/oss/dmabuf.c - * - * The DMA buffer manager for digitized voice applications - */ -/* - * 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. - * - * Thomas Sailer : moved several static variables into struct audio_operations - * (which is grossly misnamed btw.) because they have the same - * lifetime as the rest in there and dynamic allocation saves - * 12k or so - * Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to - * determine if it was woken up by the expiring timeout or by - * an explicit wake_up. The return value from schedule_timeout - * can be used instead; if 0, the wakeup was due to the timeout. - * - * Rob Riggs Added persistent DMA buffers (1998/10/17) - */ - -#define BE_CONSERVATIVE -#define SAMPLE_ROUNDUP 0 - -#include <linux/mm.h> -#include <linux/gfp.h> -#include <linux/sched/signal.h> - -#include "sound_config.h" -#include "sleep.h" - -#define DMAP_FREE_ON_CLOSE 0 -#define DMAP_KEEP_ON_CLOSE 1 -extern int sound_dmap_flag; - -static void dma_reset_output(int dev); -static void dma_reset_input(int dev); -static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode); - - - -static int debugmem; /* switched off by default */ -static int dma_buffsize = DSP_BUFFSIZE; - -static long dmabuf_timeout(struct dma_buffparms *dmap) -{ - long tmout; - - 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; - return tmout; -} - -static int sound_alloc_dmap(struct dma_buffparms *dmap) -{ - char *start_addr, *end_addr; - int dma_pagesize; - int sz, size; - struct page *page; - - dmap->mapping_flags &= ~DMA_MAP_MAPPED; - - if (dmap->raw_buf != NULL) - return 0; /* Already done */ - if (dma_buffsize < 4096) - dma_buffsize = 4096; - dma_pagesize = (dmap->dma < 4) ? (64 * 1024) : (128 * 1024); - - /* - * Now check for the Cyrix problem. - */ - - if(isa_dma_bridge_buggy==2) - dma_pagesize=32768; - - dmap->raw_buf = NULL; - dmap->buffsize = dma_buffsize; - if (dmap->buffsize > dma_pagesize) - dmap->buffsize = dma_pagesize; - start_addr = NULL; - /* - * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. Don't accept smaller than 8k buffer for performance - * reasons. - */ - while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) { - for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); - dmap->buffsize = PAGE_SIZE * (1 << sz); - start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA|__GFP_NOWARN, sz); - if (start_addr == 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 (debugmem) - printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); - - /* 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 = dma_map_single(NULL, start_addr, dmap->buffsize, DMA_BIDIRECTIONAL); - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - SetPageReserved(page); - return 0; -} - -static void sound_free_dmap(struct dma_buffparms *dmap) -{ - int sz, size; - struct page *page; - unsigned long start_addr, end_addr; - - if (dmap->raw_buf == NULL) - return; - 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); - - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + dmap->buffsize; - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - ClearPageReserved(page); - - dma_unmap_single(NULL, dmap->raw_buf_phys, dmap->buffsize, DMA_BIDIRECTIONAL); - free_pages((unsigned long) dmap->raw_buf, sz); - dmap->raw_buf = NULL; -} - - -/* Intel version !!!!!!!!! */ - -static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, int count, int dma_mode) -{ - unsigned long flags; - int chan = dmap->dma; - - /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - - flags = claim_dma_lock(); - disable_dma(chan); - clear_dma_ff(chan); - set_dma_mode(chan, dma_mode); - set_dma_addr(chan, physaddr); - set_dma_count(chan, count); - enable_dma(chan); - release_dma_lock(flags); - - return 0; -} - -static void dma_init_buffers(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 */ -} - -static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffparms *dmap) -{ - int err; - - if (dmap->flags & DMA_BUSY) - return -EBUSY; - if ((err = sound_alloc_dmap(dmap)) < 0) - return err; - - if (dmap->raw_buf == NULL) { - printk(KERN_WARNING "Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - if (dmap->dma >= 0 && sound_open_dma(dmap->dma, adev->name)) { - printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma); - return -EBUSY; - } - dma_init_buffers(dmap); - spin_lock_init(&dmap->lock); - 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; - return 0; -} - -static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap) -{ - unsigned long flags; - - if (dmap->dma >= 0) { - sound_close_dma(dmap->dma); - flags=claim_dma_lock(); - disable_dma(dmap->dma); - release_dma_lock(flags); - } - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; - - if (sound_dmap_flag == DMAP_FREE_ON_CLOSE) - sound_free_dmap(dmap); -} - - -static unsigned int default_set_bits(int dev, unsigned int bits) -{ - mm_segment_t fs = get_fs(); - - set_fs(get_ds()); - audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (void __user *)&bits); - set_fs(fs); - return bits; -} - -static int default_set_speed(int dev, int speed) -{ - mm_segment_t fs = get_fs(); - - set_fs(get_ds()); - audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (void __user *)&speed); - set_fs(fs); - return speed; -} - -static short default_set_channels(int dev, short channels) -{ - int c = channels; - mm_segment_t fs = get_fs(); - - set_fs(get_ds()); - audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (void __user *)&c); - set_fs(fs); - return c; -} - -static void 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; -} - -int DMAbuf_open(int dev, int mode) -{ - struct audio_operations *adev = audio_devs[dev]; - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (!adev) - return -ENXIO; - if (!(adev->flags & DMA_DUPLEX)) - adev->dmap_in = adev->dmap_out; - check_driver(adev->d); - - if ((retval = adev->d->open(dev, mode)) < 0) - return retval; - dmap_out = adev->dmap_out; - dmap_in = adev->dmap_in; - if (dmap_in == dmap_out) - adev->flags &= ~DMA_DUPLEX; - - if (mode & OPEN_WRITE) { - if ((retval = open_dmap(adev, mode, dmap_out)) < 0) { - adev->d->close(dev); - return retval; - } - } - adev->enable_bits = mode; - - if (mode == OPEN_READ || (mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) { - if ((retval = open_dmap(adev, mode, dmap_in)) < 0) { - adev->d->close(dev); - if (mode & OPEN_WRITE) - close_dmap(adev, dmap_out); - return retval; - } - } - adev->open_mode = mode; - adev->go = 1; - - adev->d->set_bits(dev, 8); - adev->d->set_channels(dev, 1); - adev->d->set_speed(dev, DSP_DEFAULT_SPEED); - if (adev->dmap_out->dma_mode == DMODE_OUTPUT) - memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, - adev->dmap_out->bytes_in_use); - return 0; -} -/* MUST not hold the spinlock */ -void DMAbuf_reset(int 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); -} - -static void dma_reset_output(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags,f ; - struct dma_buffparms *dmap = adev->dmap_out; - - if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ - return; - - /* - * First wait until the current fragment has been played completely - */ - spin_lock_irqsave(&dmap->lock,flags); - adev->dmap_out->flags |= DMA_SYNCING; - - adev->dmap_out->underrun_count = 0; - if (!signal_pending(current) && adev->dmap_out->qlen && - adev->dmap_out->underrun_count == 0){ - spin_unlock_irqrestore(&dmap->lock,flags); - oss_broken_sleep_on(&adev->out_sleeper, dmabuf_timeout(dmap)); - spin_lock_irqsave(&dmap->lock,flags); - } - adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - - /* - * Finally shut the device off - */ - if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_output) - adev->d->halt_io(dev); - else - adev->d->halt_output(dev); - adev->dmap_out->flags &= ~DMA_STARTED; - - f=claim_dma_lock(); - clear_dma_ff(dmap->dma); - disable_dma(dmap->dma); - release_dma_lock(f); - - dmap->byte_counter = 0; - reorganize_buffers(dev, adev->dmap_out, 0); - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - spin_unlock_irqrestore(&dmap->lock,flags); -} - -static void dma_reset_input(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - struct dma_buffparms *dmap = adev->dmap_in; - - spin_lock_irqsave(&dmap->lock,flags); - if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input) - adev->d->halt_io(dev); - else - adev->d->halt_input(dev); - adev->dmap_in->flags &= ~DMA_STARTED; - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - reorganize_buffers(dev, adev->dmap_in, 1); - spin_unlock_irqrestore(&dmap->lock,flags); -} -/* MUST be called with holding the dmap->lock */ -void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) -{ - struct audio_operations *adev = audio_devs[dev]; - - if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ - dmap->dma_mode = DMODE_OUTPUT; - - if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { - if (!(dmap->flags & DMA_STARTED)) { - reorganize_buffers(dev, dmap, 0); - if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs)) - return; - if (!(dmap->flags & DMA_NODMA)) - local_start_dma(adev, 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; - adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (adev->d->trigger) - adev->d->trigger(dev,adev->enable_bits * adev->go); - } - dmap->flags |= DMA_ACTIVE; -} - -int DMAbuf_sync(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - int n = 0; - struct dma_buffparms *dmap; - - if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { - dmap = adev->dmap_out; - spin_lock_irqsave(&dmap->lock,flags); - if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output(dev, dmap); - adev->dmap_out->flags |= DMA_SYNCING; - adev->dmap_out->underrun_count = 0; - while (!signal_pending(current) && n++ < adev->dmap_out->nbufs && - adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { - long t = dmabuf_timeout(dmap); - spin_unlock_irqrestore(&dmap->lock,flags); - /* FIXME: not safe may miss events */ - t = oss_broken_sleep_on(&adev->out_sleeper, t); - spin_lock_irqsave(&dmap->lock,flags); - if (!t) { - adev->dmap_out->flags &= ~DMA_SYNCING; - spin_unlock_irqrestore(&dmap->lock,flags); - return adev->dmap_out->qlen; - } - } - adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - - /* - * 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. - */ - - /* still holding the lock */ - if (adev->d->local_qlen) { /* Device has hidden buffers */ - while (!signal_pending(current) && - adev->d->local_qlen(dev)){ - spin_unlock_irqrestore(&dmap->lock,flags); - oss_broken_sleep_on(&adev->out_sleeper, - dmabuf_timeout(dmap)); - spin_lock_irqsave(&dmap->lock,flags); - } - } - spin_unlock_irqrestore(&dmap->lock,flags); - } - adev->dmap_out->dma_mode = DMODE_NONE; - return adev->dmap_out->qlen; -} - -int DMAbuf_release(int dev, int mode) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap; - unsigned long flags; - - dmap = adev->dmap_out; - if (adev->open_mode & OPEN_WRITE) - adev->dmap_out->closing = 1; - - if (adev->open_mode & OPEN_READ){ - adev->dmap_in->closing = 1; - dmap = adev->dmap_in; - } - if (adev->open_mode & OPEN_WRITE) - if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)) - if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) - DMAbuf_sync(dev); - if (adev->dmap_out->dma_mode == DMODE_OUTPUT) - memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use); - - DMAbuf_reset(dev); - spin_lock_irqsave(&dmap->lock,flags); - adev->d->close(dev); - - if (adev->open_mode & OPEN_WRITE) - close_dmap(adev, adev->dmap_out); - - if (adev->open_mode == OPEN_READ || - (adev->open_mode != OPEN_WRITE && - (adev->flags & DMA_DUPLEX))) - close_dmap(adev, adev->dmap_in); - adev->open_mode = 0; - spin_unlock_irqrestore(&dmap->lock,flags); - return 0; -} -/* called with dmap->lock dold */ -int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) -{ - struct audio_operations *adev = audio_devs[dev]; - int err; - - if (!(adev->open_mode & OPEN_READ)) - return 0; - if (!(adev->enable_bits & PCM_ENABLE_INPUT)) - return 0; - if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ - /* release lock - it's not recursive */ - spin_unlock_irq(&dmap->lock); - DMAbuf_sync(dev); - DMAbuf_reset(dev); - spin_lock_irq(&dmap->lock); - dmap->dma_mode = DMODE_NONE; - } - if (!dmap->dma_mode) { - reorganize_buffers(dev, dmap, 1); - if ((err = adev->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(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); - adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (adev->d->trigger) - adev->d->trigger(dev, adev->enable_bits * adev->go); - } - return 0; -} -/* acquires lock */ -int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = adev->dmap_in; - - if (!(adev->open_mode & OPEN_READ)) - return -EIO; - spin_lock_irqsave(&dmap->lock,flags); - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) { -/* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ - spin_unlock_irqrestore(&dmap->lock,flags); - return -EINVAL; - } else while (dmap->qlen <= 0 && n++ < 10) { - long timeout = MAX_SCHEDULE_TIMEOUT; - if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { - spin_unlock_irqrestore(&dmap->lock,flags); - return -EAGAIN; - } - if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { - spin_unlock_irqrestore(&dmap->lock,flags); - return err; - } - /* Wait for the next block */ - - if (dontblock) { - spin_unlock_irqrestore(&dmap->lock,flags); - return -EAGAIN; - } - if (adev->go) - timeout = dmabuf_timeout(dmap); - - spin_unlock_irqrestore(&dmap->lock,flags); - timeout = oss_broken_sleep_on(&adev->in_sleeper, timeout); - if (!timeout) { - /* FIXME: include device name */ - err = -EIO; - printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input(dev); - } else - err = -EINTR; - spin_lock_irqsave(&dmap->lock,flags); - } - spin_unlock_irqrestore(&dmap->lock,flags); - - if (dmap->qlen <= 0) - return err ? err : -EINTR; - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; -} - -int DMAbuf_rmchars(int dev, int buff_no, int c) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->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; -} -/* MUST be called with dmap->lock hold */ -int 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 f; - - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else { - int chan = dmap->dma; - - f=claim_dma_lock(); - clear_dma_ff(chan); - - if(!isa_dma_bridge_buggy) - 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; - - if(!isa_dma_bridge_buggy) - enable_dma(dmap->dma); - - release_dma_lock(f); - } - /* printk( "%04x ", pos); */ - - return pos; -} - -/* - * DMAbuf_start_devices() is called by the /dev/music driver to start - * one or more audio devices at desired moment. - */ - -void DMAbuf_start_devices(unsigned int devmask) -{ - struct audio_operations *adev; - int dev; - - for (dev = 0; dev < num_audiodevs; dev++) { - if (!(devmask & (1 << dev))) - continue; - if (!(adev = audio_devs[dev])) - continue; - if (adev->open_mode == 0) - continue; - if (adev->go) - continue; - /* OK to start the device */ - adev->go = 1; - if (adev->d->trigger) - adev->d->trigger(dev,adev->enable_bits * adev->go); - } -} -/* via poll called without a lock ?*/ -int DMAbuf_space_in_queue(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - int len, max, tmp; - struct dma_buffparms *dmap = adev->dmap_out; - int lim = dmap->nbufs; - - if (lim < 2) - lim = 2; - - 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. - */ - - max = dmap->max_fragments; - if (max > lim) - max = lim; - len = dmap->qlen; - - if (adev->d->local_qlen) { - tmp = adev->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; -} -/* MUST not hold the spinlock - this function may sleep */ -static int output_sleep(int dev, int dontblock) -{ - struct audio_operations *adev = audio_devs[dev]; - int err = 0; - struct dma_buffparms *dmap = adev->dmap_out; - long timeout; - long timeout_value; - - if (dontblock) - return -EAGAIN; - if (!(adev->enable_bits & PCM_ENABLE_OUTPUT)) - return -EAGAIN; - - /* - * Wait for free space - */ - if (signal_pending(current)) - return -EINTR; - timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); - if (timeout) - timeout_value = dmabuf_timeout(dmap); - else - timeout_value = MAX_SCHEDULE_TIMEOUT; - timeout_value = oss_broken_sleep_on(&adev->out_sleeper, timeout_value); - if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) { - printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - dma_reset_output(dev); - } else { - if (signal_pending(current)) - err = -EINTR; - } - return err; -} -/* called with the lock held */ -static int find_output_space(int dev, char **buf, int *size) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - unsigned long active_offs; - long len, offs; - int maxfrags; - int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - - *buf = dmap->raw_buf; - if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) - return 0; - -#ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; -#else - active_offs = max(DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT), 0); - /* Check for pointer wrapping situation */ - if (active_offs >= dmap->bytes_in_use) - active_offs = 0; - active_offs += dmap->byte_counter; -#endif - - offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP; - if (offs < 0 || offs >= dmap->bytes_in_use) { - printk(KERN_ERR "Sound: 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; - - 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) { - return 0; - } - if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) - len = (maxfrags * dmap->fragment_size) - occupied_bytes; - *size = len & ~SAMPLE_ROUNDUP; - return (*size > 0); -} -/* acquires lock */ -int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = adev->dmap_out; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) { -/* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ - return -EINVAL; - } - spin_lock_irqsave(&dmap->lock,flags); - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - - if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ - spin_unlock_irqrestore(&dmap->lock,flags); - DMAbuf_reset(dev); - spin_lock_irqsave(&dmap->lock,flags); - } - dmap->dma_mode = DMODE_OUTPUT; - - while (find_output_space(dev, buf, size) <= 0) { - spin_unlock_irqrestore(&dmap->lock,flags); - if ((err = output_sleep(dev, dontblock)) < 0) { - return err; - } - spin_lock_irqsave(&dmap->lock,flags); - } - - spin_unlock_irqrestore(&dmap->lock,flags); - return 0; -} -/* has to acquire dmap->lock */ -int DMAbuf_move_wrpointer(int dev, int l) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - unsigned long ptr; - unsigned long end_ptr, p; - int post; - unsigned long flags; - - spin_lock_irqsave(&dmap->lock,flags); - post= (dmap->flags & DMA_POST); - ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - - dmap->flags &= ~DMA_POST; - dmap->cfrag = -1; - dmap->user_counter += l; - dmap->flags |= DMA_DIRTY; - - if (dmap->byte_counter >= dmap->max_byte_counter) { - /* Wrap the byte counters */ - long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); - decr -= dmap->byte_counter; - dmap->user_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]; - - /* 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; - - /* - * Let the low level driver perform some postprocessing to - * the written data. - */ - if (adev->d->postprocess_write) - adev->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); - - spin_unlock_irqrestore(&dmap->lock,flags); - return 0; -} - -int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "sound: DMA buffer(1) == NULL\n"); - printk("Device %d, chn=%s\n", dev, (dmap == adev->dmap_out) ? "out" : "in"); - return 0; - } - if (dmap->dma < 0) - return 0; - sound_start_dma(dmap, physaddr, count, dma_mode); - return count; -} -EXPORT_SYMBOL(DMAbuf_start_dma); - -static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode) -{ - struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "sound: DMA buffer(2) == NULL\n"); - printk(KERN_ERR "Device %s, chn=%s\n", adev->name, (dmap == adev->dmap_out) ? "out" : "in"); - return 0; - } - if (dmap->flags & DMA_NODMA) - return 1; - if (dmap->dma < 0) - return 0; - sound_start_dma(dmap, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode | DMA_AUTOINIT); - dmap->flags |= DMA_STARTED; - return count; -} - -static void finish_output_interrupt(int dev, struct dma_buffparms *dmap) -{ - struct audio_operations *adev = audio_devs[dev]; - - if (dmap->audio_callback != NULL) - dmap->audio_callback(dev, dmap->callback_parm); - wake_up(&adev->out_sleeper); - wake_up(&adev->poll_sleeper); -} -/* called with dmap->lock held in irq context*/ -static void do_outputintr(int dev, int dummy) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - int this_fragment; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "Sound: 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); - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(adev->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; - } - - 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); - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - if (!(adev->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - - /* - * This is dmap->qlen <= 0 except when closing when - * dmap->qlen < 0 - */ - - while (dmap->qlen <= -dmap->closing) { - dmap->underrun_count++; - dmap->qlen++; - if ((dmap->flags & DMA_DIRTY) && dmap->applic_profile != APF_CPUINTENS) { - dmap->flags &= ~DMA_DIRTY; - memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, - adev->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); - finish_output_interrupt(dev, dmap); -} -/* called in irq context */ -void DMAbuf_outputintr(int dev, int notify_only) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - struct dma_buffparms *dmap = adev->dmap_out; - - spin_lock_irqsave(&dmap->lock,flags); - if (!(dmap->flags & DMA_NODMA)) { - int chan = dmap->dma, pos, n; - unsigned long f; - - f=claim_dma_lock(); - - if(!isa_dma_bridge_buggy) - disable_dma(dmap->dma); - clear_dma_ff(chan); - pos = dmap->bytes_in_use - get_dma_residue(chan); - if(!isa_dma_bridge_buggy) - enable_dma(dmap->dma); - release_dma_lock(f); - - 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); - spin_unlock_irqrestore(&dmap->lock,flags); -} -EXPORT_SYMBOL(DMAbuf_outputintr); - -/* called with dmap->lock held in irq context */ -static void do_inputintr(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "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 (!(adev->flags & DMA_AUTOMODE)) { - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_READ); - adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (adev->d->trigger) - adev->d->trigger(dev, adev->enable_bits * adev->go); - } - dmap->flags |= DMA_ACTIVE; - } else if (dmap->qlen >= (dmap->nbufs - 1)) { - printk(KERN_WARNING "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 (!(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { - local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); - adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1); - if (adev->d->trigger) - adev->d->trigger(dev,adev->enable_bits * adev->go); - } - dmap->flags |= DMA_ACTIVE; - if (dmap->qlen > 0) - { - wake_up(&adev->in_sleeper); - wake_up(&adev->poll_sleeper); - } -} -/* called in irq context */ -void DMAbuf_inputintr(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - unsigned long flags; - - spin_lock_irqsave(&dmap->lock,flags); - - if (!(dmap->flags & DMA_NODMA)) { - int chan = dmap->dma, pos, n; - unsigned long f; - - f=claim_dma_lock(); - if(!isa_dma_bridge_buggy) - disable_dma(dmap->dma); - clear_dma_ff(chan); - pos = dmap->bytes_in_use - get_dma_residue(chan); - if(!isa_dma_bridge_buggy) - enable_dma(dmap->dma); - release_dma_lock(f); - - 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); - spin_unlock_irqrestore(&dmap->lock,flags); -} -EXPORT_SYMBOL(DMAbuf_inputintr); - -void DMAbuf_init(int dev, int dma1, int dma2) -{ - struct audio_operations *adev = audio_devs[dev]; - /* - * NOTE! This routine could be called several times. - */ - - if (adev && adev->dmap_out == NULL) { - if (adev->d == NULL) - panic("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (adev->parent_dev) { /* Use DMA map of the parent dev */ - int parent = adev->parent_dev - 1; - adev->dmap_out = audio_devs[parent]->dmap_out; - adev->dmap_in = audio_devs[parent]->dmap_in; - } else { - adev->dmap_out = adev->dmap_in = &adev->dmaps[0]; - adev->dmap_out->dma = dma1; - if (adev->flags & DMA_DUPLEX) { - adev->dmap_in = &adev->dmaps[1]; - adev->dmap_in->dma = dma2; - } - } - /* Persistent DMA buffers allocated here */ - if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { - if (adev->dmap_in->raw_buf == NULL) - sound_alloc_dmap(adev->dmap_in); - if (adev->dmap_out->raw_buf == NULL) - sound_alloc_dmap(adev->dmap_out); - } - } -} - -/* No kernel lock - DMAbuf_activate_recording protected by global cli/sti */ -static unsigned int poll_input(struct file * file, int dev, poll_table *wait) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - - if (!(adev->open_mode & OPEN_READ)) - return 0; - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - if (dmap->qlen) - return POLLIN | POLLRDNORM; - return 0; - } - if (dmap->dma_mode != DMODE_INPUT) { - if (dmap->dma_mode == DMODE_NONE && - adev->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && adev->go) { - unsigned long flags; - - spin_lock_irqsave(&dmap->lock,flags); - DMAbuf_activate_recording(dev, dmap); - spin_unlock_irqrestore(&dmap->lock,flags); - } - return 0; - } - if (!dmap->qlen) - return 0; - return POLLIN | POLLRDNORM; -} - -static unsigned int poll_output(struct file * file, int dev, poll_table *wait) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - - if (!(adev->open_mode & OPEN_WRITE)) - return 0; - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - if (dmap->qlen) - return POLLOUT | POLLWRNORM; - return 0; - } - if (dmap->dma_mode == DMODE_INPUT) - return 0; - if (dmap->dma_mode == DMODE_NONE) - return POLLOUT | POLLWRNORM; - if (!DMAbuf_space_in_queue(dev)) - return 0; - return POLLOUT | POLLWRNORM; -} - -unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait) -{ - struct audio_operations *adev = audio_devs[dev]; - poll_wait(file, &adev->poll_sleeper, wait); - return poll_input(file, dev, wait) | poll_output(file, dev, wait); -} - -void DMAbuf_deinit(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - /* This routine is called when driver is being unloaded */ - if (!adev) - return; - - /* Persistent DMA buffers deallocated here */ - if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { - sound_free_dmap(adev->dmap_out); - if (adev->flags & DMA_DUPLEX) - sound_free_dmap(adev->dmap_in); - } -} diff --git a/sound/oss/hex2hex.c b/sound/oss/hex2hex.c deleted file mode 100644 index 041ef5c52bc2..000000000000 --- a/sound/oss/hex2hex.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * hex2hex reads stdin in Intel HEX format and produces an - * (unsigned char) array which contains the bytes and writes it - * to stdout using C syntax - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#define ABANDON(why) { fprintf(stderr, "%s\n", why); exit(1); } -#define MAX_SIZE (256*1024) -unsigned char buf[MAX_SIZE]; - -static int loadhex(FILE *inf, unsigned char *buf) -{ - int l=0, c, i; - - while ((c=getc(inf))!=EOF) - { - if (c == ':') /* Sync with beginning of line */ - { - int n, check; - unsigned char sum; - int addr; - int linetype; - - if (fscanf(inf, "%02x", &n) != 1) - ABANDON("File format error"); - sum = n; - - if (fscanf(inf, "%04x", &addr) != 1) - ABANDON("File format error"); - sum += addr/256; - sum += addr%256; - - if (fscanf(inf, "%02x", &linetype) != 1) - ABANDON("File format error"); - sum += linetype; - - if (linetype != 0) - continue; - - for (i=0;i<n;i++) - { - if (fscanf(inf, "%02x", &c) != 1) - ABANDON("File format error"); - if (addr >= MAX_SIZE) - ABANDON("File too large"); - buf[addr++] = c; - if (addr > l) - l = addr; - sum += c; - } - - if (fscanf(inf, "%02x", &check) != 1) - ABANDON("File format error"); - - sum = ~sum + 1; - if (check != sum) - ABANDON("Line checksum error"); - } - } - - return l; -} - -int main( int argc, const char * argv [] ) -{ - const char * varline; - int i,l; - int id=0; - - if(argv[1] && strcmp(argv[1], "-i")==0) - { - argv++; - argc--; - id=1; - } - if(argv[1]==NULL) - { - fprintf(stderr,"hex2hex: [-i] filename\n"); - exit(1); - } - varline = argv[1]; - l = loadhex(stdin, buf); - - printf("/*\n *\t Computer generated file. Do not edit.\n */\n"); - printf("static int %s_len = %d;\n", varline, l); - printf("static unsigned char %s[] %s = {\n", varline, id?"__initdata":""); - - for (i=0;i<l;i++) - { - if (i) printf(","); - if (i && !(i % 16)) printf("\n"); - printf("0x%02x", buf[i]); - } - - printf("\n};\n\n"); - return 0; -} diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c deleted file mode 100644 index c4b0434c7604..000000000000 --- a/sound/oss/kahlua.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Initialisation code for Cyrix/NatSemi VSA1 softaudio - * - * (C) Copyright 2003 Red Hat Inc <alan@lxorguk.ukuu.org.uk> - * - * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems. - * The older version (VSA1) provides fairly good soundblaster emulation - * although there are a couple of bugs: large DMA buffers break record, - * and the MPU event handling seems suspect. VSA2 allows the native driver - * to control the AC97 audio engine directly and requires a different driver. - * - * Thanks to National Semiconductor for providing the needed information - * on the XpressAudio(tm) internals. - * - * 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, 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. - * - * TO DO: - * Investigate whether we can portably support Cognac (5520) in the - * same manner. - */ - -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/slab.h> - -#include "sound_config.h" - -#include "sb.h" - -/* - * Read a soundblaster compatible mixer register. - * In this case we are actually reading an SMI trap - * not real hardware. - */ - -static u8 mixer_read(unsigned long io, u8 reg) -{ - outb(reg, io + 4); - udelay(20); - reg = inb(io + 5); - udelay(20); - return reg; -} - -static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct address_info *hw_config; - unsigned long base; - void __iomem *mem; - unsigned long io; - u16 map; - u8 irq, dma8, dma16; - int oldquiet; - extern int sb_be_quiet; - - base = pci_resource_start(pdev, 0); - if(base == 0UL) - return 1; - - mem = ioremap(base, 128); - if (!mem) - return 1; - map = readw(mem + 0x18); /* Read the SMI enables */ - iounmap(mem); - - /* Map bits - 0:1 * 0x20 + 0x200 = sb base - 2 sb enable - 3 adlib enable - 5 MPU enable 0x330 - 6 MPU enable 0x300 - - The other bits may be used internally so must be masked */ - - io = 0x220 + 0x20 * (map & 3); - - if(map & (1<<2)) - printk(KERN_INFO "kahlua: XpressAudio at 0x%lx\n", io); - else - return 1; - - if(map & (1<<5)) - printk(KERN_INFO "kahlua: MPU at 0x300\n"); - else if(map & (1<<6)) - printk(KERN_INFO "kahlua: MPU at 0x330\n"); - - irq = mixer_read(io, 0x80) & 0x0F; - dma8 = mixer_read(io, 0x81); - - // printk("IRQ=%x MAP=%x DMA=%x\n", irq, map, dma8); - - if(dma8 & 0x20) - dma16 = 5; - else if(dma8 & 0x40) - dma16 = 6; - else if(dma8 & 0x80) - dma16 = 7; - else - { - printk(KERN_ERR "kahlua: No 16bit DMA enabled.\n"); - return 1; - } - - if(dma8 & 0x01) - dma8 = 0; - else if(dma8 & 0x02) - dma8 = 1; - else if(dma8 & 0x08) - dma8 = 3; - else - { - printk(KERN_ERR "kahlua: No 8bit DMA enabled.\n"); - return 1; - } - - if(irq & 1) - irq = 9; - else if(irq & 2) - irq = 5; - else if(irq & 4) - irq = 7; - else if(irq & 8) - irq = 10; - else - { - printk(KERN_ERR "kahlua: SB IRQ not set.\n"); - return 1; - } - - printk(KERN_INFO "kahlua: XpressAudio on IRQ %d, DMA %d, %d\n", - irq, dma8, dma16); - - hw_config = kzalloc(sizeof(struct address_info), GFP_KERNEL); - if(hw_config == NULL) - { - printk(KERN_ERR "kahlua: out of memory.\n"); - return 1; - } - - pci_set_drvdata(pdev, hw_config); - - hw_config->io_base = io; - hw_config->irq = irq; - hw_config->dma = dma8; - hw_config->dma2 = dma16; - hw_config->name = "Cyrix XpressAudio"; - hw_config->driver_use_1 = SB_NO_MIDI | SB_PCI_IRQ; - - if (!request_region(io, 16, "soundblaster")) - goto err_out_free; - - if(sb_dsp_detect(hw_config, 0, 0, NULL)==0) - { - printk(KERN_ERR "kahlua: audio not responding.\n"); - release_region(io, 16); - goto err_out_free; - } - - oldquiet = sb_be_quiet; - sb_be_quiet = 1; - if(sb_dsp_init(hw_config, THIS_MODULE)) - { - sb_be_quiet = oldquiet; - goto err_out_free; - } - sb_be_quiet = oldquiet; - - return 0; - -err_out_free: - kfree(hw_config); - return 1; -} - -static void remove_one(struct pci_dev *pdev) -{ - struct address_info *hw_config = pci_get_drvdata(pdev); - sb_dsp_unload(hw_config, 0); - kfree(hw_config); -} - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("Kahlua VSA1 PCI Audio"); -MODULE_LICENSE("GPL"); - -/* - * 5530 only. The 5510/5520 decode is different. - */ - -static const struct pci_device_id id_tbl[] = { - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, id_tbl); - -static struct pci_driver kahlua_driver = { - .name = "kahlua", - .id_table = id_tbl, - .probe = probe_one, - .remove = remove_one, -}; - - -static int __init kahlua_init_module(void) -{ - printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n"); - return pci_register_driver(&kahlua_driver); -} - -static void kahlua_cleanup_module(void) -{ - pci_unregister_driver(&kahlua_driver); -} - - -module_init(kahlua_init_module); -module_exit(kahlua_cleanup_module); - diff --git a/sound/oss/midi_ctrl.h b/sound/oss/midi_ctrl.h deleted file mode 100644 index 3353e5a67c24..000000000000 --- a/sound/oss/midi_ctrl.h +++ /dev/null @@ -1,22 +0,0 @@ -static unsigned char ctrl_def_values[128] = -{ - 0x40,0x00,0x40,0x40, 0x40,0x40,0x40,0x7f, /* 0 to 7 */ - 0x40,0x40,0x40,0x7f, 0x40,0x40,0x40,0x40, /* 8 to 15 */ - 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 16 to 23 */ - 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 24 to 31 */ - - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */ - - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 88 to 95 */ - - 0x00,0x00,0x7f,0x7f, 0x7f,0x7f,0x00,0x00, /* 96 to 103 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 104 to 111 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 112 to 119 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 120 to 127 */ -}; diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c deleted file mode 100644 index 2292c230d7e6..000000000000 --- a/sound/oss/midi_synth.c +++ /dev/null @@ -1,712 +0,0 @@ -/* - * sound/oss/midi_synth.c - * - * High level midi sequencer manager for dumb MIDI interfaces. - */ -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Andrew Veliath : fixed running status in MIDI input state machine - */ -#define USE_SEQ_MACROS -#define USE_SIMPLE_MACROS - -#include "sound_config.h" - -#define _MIDI_SYNTH_C_ - -#include "midi_synth.h" - -static int midi2synth[MAX_MIDI_DEV]; -static int sysex_state[MAX_MIDI_DEV] = -{0}; -static unsigned char prev_out_status[MAX_MIDI_DEV]; - -#define STORE(cmd) \ -{ \ - int len; \ - unsigned char obuf[8]; \ - cmd; \ - seq_input_event(obuf, len); \ -} - -#define _seqbuf obuf -#define _seqbufptr 0 -#define _SEQ_ADVBUF(x) len=x - -void -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]); */ - ; - } -} -EXPORT_SYMBOL(do_midi_msg); - -static void -midi_outc(int midi_dev, int data) -{ - 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 - */ - return; /* - * Mission complete - */ - } - /* - * Sorry! No space on buffers. - */ - printk("Midi send timed out\n"); -} - -static int -prefix_cmd(int midi_dev, unsigned char status) -{ - if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) - return 1; - - return midi_devs[midi_dev]->prefix_cmd(midi_dev, status); -} - -static void -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 || 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) { - /* Data byte (use running status) */ - inc->m_ptr = 2; - inc->m_buf[1] = data; - inc->m_buf[0] = inc->m_prev_status; - inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; - if (inc->m_left > 0) - inc->m_state = MST_DATA; /* Not done yet */ - else { - inc->m_state = MST_INIT; - do_midi_msg(dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - } - } - 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) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int timeout = 0; - - if (!sysex_state[dev]) - return; - - sysex_state[dev] = 0; - - while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && - timeout < 1000) - timeout++; - - sysex_state[dev] = 0; -} - -static void -midi_synth_output(int dev) -{ - /* - * Currently NOP - */ -} - -int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - /* - * int orig_dev = synth_devs[dev]->midi_dev; - */ - - switch (cmd) { - - case SNDCTL_SYNTH_INFO: - if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info))) - return -EFAULT; - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(midi_synth_ioctl); - -int -midi_synth_kill_note(int dev, int channel, int note, int velocity) -{ - 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; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) - { /* - * Use running status - */ - if (!prefix_cmd(orig_dev, note)) - return 0; - - midi_outc(orig_dev, note); - - if (msg == 0x90) /* - * Running status = Note on - */ - 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; -} -EXPORT_SYMBOL(midi_synth_kill_note); - -int -midi_synth_set_instr(int dev, int channel, int instr_no) -{ - 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; - - leave_sysex(dev); - - 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); - - return 0; -} -EXPORT_SYMBOL(midi_synth_set_instr); - -int -midi_synth_start_note(int dev, int channel, int note, int velocity) -{ - 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; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (chn == channel && msg == 0x90) - { /* - * Use running status - */ - 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; -} -EXPORT_SYMBOL(midi_synth_start_note); - -void -midi_synth_reset(int dev) -{ - - leave_sysex(dev); -} -EXPORT_SYMBOL(midi_synth_reset); - -int -midi_synth_open(int dev, int mode) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int err; - 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; - inc = &midi_devs[orig_dev]->in_info; - - /* save_flags(flags); - cli(); - don't know against what irqhandler to protect*/ - 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); */ - - return 1; -} -EXPORT_SYMBOL(midi_synth_open); - -void -midi_synth_close(int dev) -{ - int orig_dev = synth_devs[dev]->midi_dev; - - leave_sysex(dev); - - /* - * 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); -} -EXPORT_SYMBOL(midi_synth_close); - -void -midi_synth_hw_control(int dev, unsigned char *event) -{ -} -EXPORT_SYMBOL(midi_synth_hw_control); - -int -midi_synth_load_patch(int dev, int format, const char __user *addr, - 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; - - /* Invalid patch format */ - if (format != SYSEX_PATCH) - return -EINVAL; - - /* Patch header too short */ - if (count < hdr_size) - return -EINVAL; - - count -= hdr_size; - - /* - * Copy the header from user space - */ - - if (copy_from_user(&sysex, addr, hdr_size)) - return -EFAULT; - - /* Sysex record too short */ - if ((unsigned)count < (unsigned)sysex.len) - sysex.len = count; - - left = sysex.len; - src_offs = 0; - - for (i = 0; i < left && !signal_pending(current); i++) - { - unsigned char data; - - if (get_user(data, - (unsigned char __user *)(addr + hdr_size + i))) - return -EFAULT; - - eox_seen = (i > 0 && data & 0x80); /* End of sysex */ - - if (eox_seen && data != 0xf7) - data = 0xf7; - - if (i == 0) - { - if (data != 0xf0) - { - printk(KERN_WARNING "midi_synth: Sysex start missing\n"); - return -EINVAL; - } - } - while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && - !signal_pending(current)) - schedule(); - - if (!first_byte && data & 0x80) - return 0; - first_byte = 0; - } - - if (!eox_seen) - midi_outc(orig_dev, 0xf7); - return 0; -} -EXPORT_SYMBOL(midi_synth_load_patch); - -void midi_synth_panning(int dev, int channel, int pressure) -{ -} -EXPORT_SYMBOL(midi_synth_panning); - -void midi_synth_aftertouch(int dev, int channel, int pressure) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; - - if (pressure < 0 || pressure > 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 != 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); -} -EXPORT_SYMBOL(midi_synth_aftertouch); - -void -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); -} -EXPORT_SYMBOL(midi_synth_controller); - -void -midi_synth_bender(int dev, int channel, int value) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int msg, prev_chn; - - if (channel < 0 || channel > 15) - return; - - if (value < 0 || value > 16383) - return; - - leave_sysex(dev); - - 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); -} -EXPORT_SYMBOL(midi_synth_bender); - -void -midi_synth_setup_voice(int dev, int voice, int channel) -{ -} -EXPORT_SYMBOL(midi_synth_setup_voice); - -int -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])) - { -/* - * Hardware level buffer is full. Abort the sysex message. - */ - - int timeout = 0; - - bytes[i] = 0xf7; - sysex_state[dev] = 0; - - while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) && - timeout < 1000) - timeout++; - } - if (!sysex_state[dev]) - return 0; - } - - return 0; -} -EXPORT_SYMBOL(midi_synth_send_sysex); - diff --git a/sound/oss/midi_synth.h b/sound/oss/midi_synth.h deleted file mode 100644 index b64ddd6c4abc..000000000000 --- a/sound/oss/midi_synth.h +++ /dev/null @@ -1,47 +0,0 @@ -int midi_synth_ioctl (int dev, - unsigned int cmd, void __user * arg); -int midi_synth_kill_note (int dev, int channel, int note, int velocity); -int midi_synth_set_instr (int dev, int channel, int instr_no); -int midi_synth_start_note (int dev, int channel, int note, int volume); -void midi_synth_reset (int dev); -int midi_synth_open (int dev, int mode); -void midi_synth_close (int dev); -void midi_synth_hw_control (int dev, unsigned char *event); -int midi_synth_load_patch (int dev, int format, const char __user * addr, - int count, int pmgr_flag); -void midi_synth_panning (int dev, int channel, int pressure); -void midi_synth_aftertouch (int dev, int channel, int pressure); -void midi_synth_controller (int dev, int channel, int ctrl_num, int value); -void midi_synth_bender (int dev, int chn, int value); -void midi_synth_setup_voice (int dev, int voice, int chn); -int midi_synth_send_sysex(int dev, unsigned char *bytes,int len); - -#ifndef _MIDI_SYNTH_C_ -static struct synth_info std_synth_info = -{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS}; - -static struct synth_operations std_midi_synth = -{ - .owner = THIS_MODULE, - .id = "MIDI", - .info = &std_synth_info, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_MIDI, - .synth_subtype = 0, - .open = midi_synth_open, - .close = midi_synth_close, - .ioctl = midi_synth_ioctl, - .kill_note = midi_synth_kill_note, - .start_note = midi_synth_start_note, - .set_instr = midi_synth_set_instr, - .reset = midi_synth_reset, - .hw_control = midi_synth_hw_control, - .load_patch = midi_synth_load_patch, - .aftertouch = midi_synth_aftertouch, - .controller = midi_synth_controller, - .panning = midi_synth_panning, - .bender = midi_synth_bender, - .setup_voice = midi_synth_setup_voice, - .send_sysex = midi_synth_send_sysex -}; -#endif diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c deleted file mode 100644 index 701c7625c971..000000000000 --- a/sound/oss/midibuf.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * sound/oss/midibuf.c - * - * Device file manager for /dev/midi# - */ -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - */ -#include <linux/stddef.h> -#include <linux/kmod.h> -#include <linux/spinlock.h> -#include <linux/sched/signal.h> - -#define MIDIBUF_C - -#include "sound_config.h" - - -/* - * Don't make MAX_QUEUE_SIZE larger than 4000 - */ - -#define MAX_QUEUE_SIZE 4000 - -static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV]; -static wait_queue_head_t input_sleeper[MAX_MIDI_DEV]; - -struct midi_buf -{ - int len, head, tail; - unsigned char queue[MAX_QUEUE_SIZE]; -}; - -struct midi_parms -{ - long prech_timeout; /* - * Timeout before the first ch - */ -}; - -static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL}; -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 DEFINE_TIMER(poll_timer, midi_poll, 0, 0); - -static volatile int open_devs; -static DEFINE_SPINLOCK(lock); - -#define DATA_AVAIL(q) (q->len) -#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len) - -#define QUEUE_BYTE(q, data) \ - if (SPACE_AVAIL(q)) \ - { \ - unsigned long flags; \ - spin_lock_irqsave(&lock, flags); \ - q->queue[q->tail] = (data); \ - q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \ - spin_unlock_irqrestore(&lock, flags); \ - } - -#define REMOVE_BYTE(q, data) \ - if (DATA_AVAIL(q)) \ - { \ - unsigned long flags; \ - spin_lock_irqsave(&lock, flags); \ - data = q->queue[q->head]; \ - q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \ - spin_unlock_irqrestore(&lock, flags); \ - } - -static void drain_midi_queue(int dev) -{ - - /* - * Give the Midi driver time to drain its output queues - */ - - if (midi_devs[dev]->buffer_status != NULL) - wait_event_interruptible_timeout(midi_sleeper[dev], - !midi_devs[dev]->buffer_status(dev), HZ/10); -} - -static void midi_input_intr(int dev, unsigned char data) -{ - if (midi_in_buf[dev] == NULL) - return; - - if (data == 0xfe) /* - * Active sensing - */ - return; /* - * Ignore - */ - - if (SPACE_AVAIL(midi_in_buf[dev])) { - QUEUE_BYTE(midi_in_buf[dev], data); - wake_up(&input_sleeper[dev]); - } -} - -static void midi_output_intr(int dev) -{ - /* - * Currently NOP - */ -} - -static void midi_poll(unsigned long dummy) -{ - unsigned long flags; - int dev; - - spin_lock_irqsave(&lock, flags); - if (open_devs) - { - for (dev = 0; dev < num_midis; dev++) - if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) - { - while (DATA_AVAIL(midi_out_buf[dev])) - { - int ok; - int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; - - spin_unlock_irqrestore(&lock,flags);/* Give some time to others */ - ok = midi_devs[dev]->outputc(dev, c); - spin_lock_irqsave(&lock, flags); - if (!ok) - break; - 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) - wake_up(&midi_sleeper[dev]); - } - poll_timer.expires = (1) + jiffies; - add_timer(&poll_timer); - /* - * Come back later - */ - } - spin_unlock_irqrestore(&lock, flags); -} - -int MIDIbuf_open(int dev, struct file *file) -{ - int mode, err; - - dev = dev >> 4; - mode = translate_mode(file); - - if (num_midis > MAX_MIDI_DEV) - { - printk(KERN_ERR "midi: Too many midi interfaces\n"); - num_midis = MAX_MIDI_DEV; - } - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - return -ENXIO; - /* - * Interrupts disabled. Be careful - */ - - module_put(midi_devs[dev]->owner); - - if ((err = midi_devs[dev]->open(dev, mode, - midi_input_intr, midi_output_intr)) < 0) - return err; - - parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT; - midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf)); - - if (midi_in_buf[dev] == NULL) - { - printk(KERN_WARNING "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] = vmalloc(sizeof(struct midi_buf)); - - if (midi_out_buf[dev] == NULL) - { - printk(KERN_WARNING "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++; - - init_waitqueue_head(&midi_sleeper[dev]); - init_waitqueue_head(&input_sleeper[dev]); - - 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 file *file) -{ - int mode; - - dev = dev >> 4; - mode = translate_mode(file); - - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - return; - - /* - * Wait until the queue is empty - */ - - if (mode != OPEN_READ) - { - midi_devs[dev]->outputc(dev, 0xfe); /* - * Active sensing to shut the - * devices - */ - - wait_event_interruptible(midi_sleeper[dev], - !DATA_AVAIL(midi_out_buf[dev])); - /* - * Sync - */ - - drain_midi_queue(dev); /* - * Ensure the output queues are empty - */ - } - - midi_devs[dev]->close(dev); - - open_devs--; - if (open_devs == 0) - del_timer_sync(&poll_timer); - vfree(midi_in_buf[dev]); - vfree(midi_out_buf[dev]); - midi_in_buf[dev] = NULL; - midi_out_buf[dev] = NULL; - - module_put(midi_devs[dev]->owner); -} - -int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count) -{ - int c, n, i; - unsigned char tmp_data; - - dev = dev >> 4; - - if (!count) - return 0; - - c = 0; - - while (c < count) - { - n = SPACE_AVAIL(midi_out_buf[dev]); - - if (n == 0) { /* - * No space just now. - */ - - if (file->f_flags & O_NONBLOCK) { - c = -EAGAIN; - goto out; - } - - if (wait_event_interruptible(midi_sleeper[dev], - SPACE_AVAIL(midi_out_buf[dev]))) - { - c = -EINTR; - goto out; - } - n = SPACE_AVAIL(midi_out_buf[dev]); - } - if (n > (count - c)) - n = count - c; - - for (i = 0; i < n; i++) - { - /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */ - /* yes, think the same, so I removed the cli() brackets - QUEUE_BYTE is protected against interrupts */ - if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) { - c = -EFAULT; - goto out; - } - QUEUE_BYTE(midi_out_buf[dev], tmp_data); - c++; - } - } -out: - return c; -} - - -int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count) -{ - int n, c = 0; - unsigned char tmp_data; - - dev = dev >> 4; - - if (!DATA_AVAIL(midi_in_buf[dev])) { /* - * No data yet, wait - */ - if (file->f_flags & O_NONBLOCK) { - c = -EAGAIN; - goto out; - } - wait_event_interruptible_timeout(input_sleeper[dev], - DATA_AVAIL(midi_in_buf[dev]), - parms[dev].prech_timeout); - - if (signal_pending(current)) - 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) - { - char *fixit; - REMOVE_BYTE(midi_in_buf[dev], tmp_data); - fixit = (char *) &tmp_data; - /* BROKE BROKE BROKE */ - /* yes removed the cli() brackets again - should q->len,tail&head be atomic_t? */ - if (copy_to_user(&(buf)[c], fixit, 1)) { - c = -EFAULT; - goto out; - } - c++; - } - } -out: - return c; -} - -int MIDIbuf_ioctl(int dev, struct file *file, - unsigned int cmd, void __user *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); -/* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/ - return -ENXIO; - } - else - { - switch (cmd) - { - case SNDCTL_MIDI_PRETIME: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - if (val < 0) - val = 0; - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return put_user(val, (int __user *)arg); - - default: - if (!midi_devs[dev]->ioctl) - return -EINVAL; - return midi_devs[dev]->ioctl(dev, cmd, arg); - } - } -} - -/* No kernel lock - fine */ -unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait) -{ - unsigned int mask = 0; - - dev = dev >> 4; - - /* input */ - poll_wait(file, &input_sleeper[dev], wait); - if (DATA_AVAIL(midi_in_buf[dev])) - mask |= POLLIN | POLLRDNORM; - - /* output */ - poll_wait(file, &midi_sleeper[dev], wait); - if (!SPACE_AVAIL(midi_out_buf[dev])) - mask |= POLLOUT | POLLWRNORM; - - return mask; -} - - -int MIDIbuf_avail(int dev) -{ - if (midi_in_buf[dev]) - return DATA_AVAIL (midi_in_buf[dev]); - return 0; -} -EXPORT_SYMBOL(MIDIbuf_avail); - diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c deleted file mode 100644 index 20e8fa46f647..000000000000 --- a/sound/oss/mpu401.c +++ /dev/null @@ -1,1804 +0,0 @@ -/* - * sound/oss/mpu401.c - * - * The low level driver for Roland MPU-401 compatible Midi cards. - */ -/* - * 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. - * - * - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, use normal request_irq, use dev_id - * Bartlomiej Zolnierkiewicz removed some __init to allow using many drivers - * Chris Rankin Update the module-usage counter for the coprocessor - * Zwane Mwaikambo Changed attach/unload resource freeing - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#define USE_SEQ_MACROS -#define USE_SIMPLE_MACROS - -#include "sound_config.h" - -#include "coproc.h" -#include "mpu401.h" - -static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; - -struct mpu_config -{ - int base; /* - * I/O base - */ - 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; -#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; - -#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; - spinlock_t lock; - }; - -#define DATAPORT(base) (base) -#define COMDPORT(base) (base+1) -#define STATPORT(base) (base+1) - - -static void mpu401_close(int dev); - -static inline int mpu401_status(struct mpu_config *devc) -{ - return inb(STATPORT(devc->base)); -} - -#define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL)) -#define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY)) - -static inline void write_command(struct mpu_config *devc, unsigned char cmd) -{ - outb(cmd, COMDPORT(devc->base)); -} - -static inline int read_data(struct mpu_config *devc) -{ - return inb(DATAPORT(devc->base)); -} - -static inline void write_data(struct mpu_config *devc, unsigned char byte) -{ - outb(byte, DATAPORT(devc->base)); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static struct mpu_config dev_conf[MAX_MIDI_DEV]; - -static int n_mpu_devs; - -static int reset_mpu401(struct mpu_config *devc); -static void set_uart_mode(int dev, struct mpu_config *devc, int arg); - -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 -}; - -static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; - -/* - * States for the input scanner - */ - -#define ST_INIT 0 /* Ready for timing byte or msg */ -#define ST_TIMED 1 /* Leading timing byte rcvd */ -#define ST_DATABYTE 2 /* Waiting for (nr_left) data bytes */ - -#define ST_SYSMSG 100 /* System message (sysx etc). */ -#define ST_SYSEX 101 /* System exclusive msg */ -#define ST_MTC 102 /* Midi Time Code (MTC) qframe msg */ -#define ST_SONGSEL 103 /* Song select */ -#define ST_SONGPOS 104 /* Song position pointer */ - -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 */ -}; - -#define STORE(cmd) \ -{ \ - int len; \ - unsigned char obuf[8]; \ - cmd; \ - seq_input_event(obuf, len); \ -} - -#define _seqbuf obuf -#define _seqbufptr 0 -#define _SEQ_ADVBUF(x) len=x - -static int 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; - - 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; - break; - - /* - * 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; -} - -static void mpu401_input_loop(struct mpu_config *devc) -{ - unsigned long flags; - int busy; - int n; - - spin_lock_irqsave(&devc->lock,flags); - busy = devc->m_busy; - devc->m_busy = 1; - spin_unlock_irqrestore(&devc->lock,flags); - - if (busy) /* Already inside the scanner */ - return; - - n = 50; - - 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); - } - devc->m_busy = 0; -} - -static irqreturn_t mpuintr(int irq, void *dev_id) -{ - struct mpu_config *devc; - int dev = (int)(unsigned long) dev_id; - int handled = 0; - - devc = &dev_conf[dev]; - - if (input_avail(devc)) - { - handled = 1; - 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); - } - } - return IRQ_RETVAL(handled); -} - -static int mpu401_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - int err; - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - return -ENXIO; - - devc = &dev_conf[dev]; - - if (devc->opened) - 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(KERN_ERR "mpu401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401(devc); - } - - if ( (coprocessor = midi_devs[dev]->coproc) != NULL ) - { - if (!try_module_get(coprocessor->owner)) { - mpu401_close(dev); - return -ENODEV; - } - - if ((err = coprocessor->open(coprocessor->devc, COPR_MIDI)) < 0) - { - printk(KERN_WARNING "MPU-401: Can't access coprocessor device\n"); - mpu401_close(dev); - return err; - } - } - - set_uart_mode(dev, devc, 1); - devc->mode = MODE_MIDI; - devc->synthno = 0; - - mpu401_input_loop(devc); - - devc->inputintr = input; - devc->opened = mode; - - return 0; -} - -static void mpu401_close(int dev) -{ - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - devc = &dev_conf[dev]; - if (devc->uart_mode) - reset_mpu401(devc); /* - * This disables the UART mode - */ - devc->mode = 0; - devc->inputintr = NULL; - - coprocessor = midi_devs[dev]->coproc; - if (coprocessor) { - coprocessor->close(coprocessor->devc, COPR_MIDI); - module_put(coprocessor->owner); - } - devc->opened = 0; -} - -static int mpu401_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - - struct mpu_config *devc; - - devc = &dev_conf[dev]; - - /* - * Sometimes it takes about 30000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - spin_lock_irqsave(&devc->lock,flags); - if (!output_ready(devc)) - { - printk(KERN_WARNING "mpu401: Send data timeout\n"); - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - write_data(devc, midi_byte); - spin_unlock_irqrestore(&devc->lock,flags); - return 1; -} - -static int mpu401_command(int dev, mpu_command_rec * cmd) -{ - int i, timeout, ok; - unsigned long flags; - struct mpu_config *devc; - - devc = &dev_conf[dev]; - - if (devc->uart_mode) /* - * Not possible in UART mode - */ - { - printk(KERN_WARNING "mpu401: 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(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; - } - spin_lock_irqsave(&devc->lock,flags); - - if (!output_ready(devc)) - { - spin_unlock_irqrestore(&devc->lock,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; - } - else - { - /* Device is not currently open. Use simpler method */ - if (read_data(devc) == MPU_ACK) - ok = 1; - } - } - } - if (!ok) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -EIO; - } - 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])) - { - spin_unlock_irqrestore(&devc->lock,flags); - printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; - } - } - } - 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) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -EIO; - } - } - } - spin_unlock_irqrestore(&devc->lock,flags); - return 0; -} - -static int mpu_cmd(int dev, int cmd, int data) -{ - int ret; - - 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; - - 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) -{ - 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; - return 1; - } - switch (status) - { - case 0xF0: - if (mpu_cmd(dev, 0xDF, 0) < 0) - return 0; - return 1; - - default: - return 0; - } -} - -static int mpu401_start_read(int dev) -{ - return 0; -} - -static int mpu401_end_read(int dev) -{ - return 0; -} - -static int mpu401_ioctl(int dev, unsigned cmd, void __user *arg) -{ - struct mpu_config *devc; - mpu_command_rec rec; - int val, ret; - - devc = &dev_conf[dev]; - switch (cmd) - { - case SNDCTL_MIDI_MPUMODE: - if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */ - printk(KERN_WARNING "mpu401: Intelligent mode not supported by the HW\n"); - return -EINVAL; - } - if (get_user(val, (int __user *)arg)) - return -EFAULT; - set_uart_mode(dev, devc, !val); - return 0; - - case SNDCTL_MIDI_MPUCMD: - if (copy_from_user(&rec, arg, sizeof(rec))) - return -EFAULT; - if ((ret = mpu401_command(dev, &rec)) < 0) - return ret; - if (copy_to_user(arg, &rec, sizeof(rec))) - return -EFAULT; - return 0; - - default: - return -EINVAL; - } -} - -static void mpu401_kick(int dev) -{ -} - -static int mpu401_buffer_status(int dev) -{ - return 0; /* - * No data in buffers - */ -} - -static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int midi_dev; - struct mpu_config *devc; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL) - return -ENXIO; - - devc = &dev_conf[midi_dev]; - - switch (cmd) - { - - case SNDCTL_SYNTH_INFO: - if (copy_to_user(arg, &mpu_synth_info[midi_dev], - sizeof(struct synth_info))) - return -EFAULT; - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - - default: - return -EINVAL; - } -} - -static int mpu_synth_open(int dev, int mode) -{ - int midi_dev, err; - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) - return -ENXIO; - - devc = &dev_conf[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 (!devc->initialized) - { - if (mpu401_status(devc) == 0xff) /* Bus float */ - { - printk(KERN_ERR "mpu401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401(devc); - } - if (devc->opened) - return -EBUSY; - devc->mode = MODE_SYNTH; - devc->synthno = dev; - - devc->inputintr = NULL; - - coprocessor = midi_devs[midi_dev]->coproc; - if (coprocessor) { - if (!try_module_get(coprocessor->owner)) - return -ENODEV; - - if ((err = coprocessor->open(coprocessor->devc, COPR_MIDI)) < 0) - { - printk(KERN_WARNING "mpu401: Can't access coprocessor device\n"); - return err; - } - } - devc->opened = mode; - reset_mpu401(devc); - - 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) -{ - int midi_dev; - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - 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->inputintr = NULL; - - coprocessor = midi_devs[midi_dev]->coproc; - if (coprocessor) { - coprocessor->close(coprocessor->devc, COPR_MIDI); - module_put(coprocessor->owner); - } - devc->opened = 0; - devc->mode = 0; -} - -#define MIDI_SYNTH_NAME "MPU-401 UART Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct synth_operations mpu401_synth_proto = -{ - .owner = THIS_MODULE, - .id = "MPU401", - .info = NULL, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_MIDI, - .synth_subtype = 0, - .open = mpu_synth_open, - .close = mpu_synth_close, - .ioctl = mpu_synth_ioctl, - .kill_note = midi_synth_kill_note, - .start_note = midi_synth_start_note, - .set_instr = midi_synth_set_instr, - .reset = midi_synth_reset, - .hw_control = midi_synth_hw_control, - .load_patch = midi_synth_load_patch, - .aftertouch = midi_synth_aftertouch, - .controller = midi_synth_controller, - .panning = midi_synth_panning, - .bender = midi_synth_bender, - .setup_voice = midi_synth_setup_voice, - .send_sysex = midi_synth_send_sysex -}; - -static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV]; - -static struct midi_operations mpu401_midi_proto = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - .in_info = {0}, - .open = mpu401_open, - .close = mpu401_close, - .ioctl = mpu401_ioctl, - .outputc = mpu401_out, - .start_read = mpu401_start_read, - .end_read = mpu401_end_read, - .kick = mpu401_kick, - .buffer_status = mpu401_buffer_status, - .prefix_cmd = mpu401_prefix_cmd -}; - -static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; - -static void mpu401_chk_version(int n, struct mpu_config *devc) -{ - int tmp; - - devc->version = devc->revision = 0; - - tmp = mpu_cmd(n, 0xAC, 0); - if (tmp < 0) - return; - if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ - return; - devc->version = tmp; - - if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) { - devc->version = 0; - return; - } - devc->revision = tmp; -} - -int attach_mpu401(struct address_info *hw_config, struct module *owner) -{ - unsigned long flags; - char revision_char; - - int m, ret; - struct mpu_config *devc; - - hw_config->slots[1] = -1; - m = sound_alloc_mididev(); - if (m == -1) - { - printk(KERN_WARNING "MPU-401: Too many midi devices detected\n"); - ret = -ENOMEM; - goto out_err; - } - 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; - spin_lock_init(&devc->lock); - - if (devc->irq < 0) - { - devc->irq *= -1; - devc->shared_irq = 1; - } - - if (!hw_config->always_detect) - { - /* Verify the hardware again */ - if (!reset_mpu401(devc)) - { - printk(KERN_WARNING "mpu401: Device didn't respond\n"); - ret = -ENODEV; - goto out_mididev; - } - if (!devc->shared_irq) - { - if (request_irq(devc->irq, mpuintr, 0, "mpu401", - hw_config) < 0) - { - printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq); - ret = -ENOMEM; - goto out_mididev; - } - } - spin_lock_irqsave(&devc->lock,flags); - mpu401_chk_version(m, devc); - if (devc->version == 0) - mpu401_chk_version(m, devc); - spin_unlock_irqrestore(&devc->lock, flags); - } - - 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 */ - - - mpu401_synth_operations[m] = kmalloc(sizeof(struct synth_operations), GFP_KERNEL); - - if (mpu401_synth_operations[m] == NULL) - { - printk(KERN_ERR "mpu401: Can't allocate memory\n"); - ret = -ENOMEM; - goto out_irq; - } - 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)); - } - if (owner) - mpu401_synth_operations[m]->owner = owner; - - memcpy((char *) &mpu401_midi_operations[m], - (char *) &mpu401_midi_proto, - sizeof(struct midi_operations)); - - mpu401_midi_operations[m].converter = mpu401_synth_operations[m]; - - memcpy((char *) &mpu_synth_info[m], - (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[m].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[m].name, "%s (MPU401)", hw_config->name); - else - sprintf(mpu_synth_info[m].name, - "MPU-401 %d.%d%c MIDI #%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); - - midi_devs[m] = &mpu401_midi_operations[devc->devno]; - - if (owner) - midi_devs[m]->owner = owner; - - hw_config->slots[1] = m; - sequencer_init(); - - return 0; - -out_irq: - free_irq(devc->irq, hw_config); -out_mididev: - sound_unload_mididev(m); -out_err: - release_region(hw_config->io_base, 2); - return ret; -} - -static int reset_mpu401(struct mpu_config *devc) -{ - 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). - */ - - ok = 0; - - timeout_limit = devc->initialized ? 30000 : 100000; - devc->initialized = 1; - - 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--) - { - spin_lock_irqsave(&devc->lock,flags); - if (input_avail(devc)) - if (read_data(devc) == MPU_ACK) - ok = 1; - spin_unlock_irqrestore(&devc->lock,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(KERN_ERR "mpu401: Can't enter UART mode\n"); - devc->uart_mode = 0; - return; - } - } - devc->uart_mode = arg; - -} - -int probe_mpu401(struct address_info *hw_config, struct resource *ports) -{ - int ok = 0; - struct mpu_config tmp_devc; - - 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) -{ - void *p; - int n=hw_config->slots[1]; - - if (n != -1) { - release_region(hw_config->io_base, 2); - if (hw_config->always_detect == 0 && hw_config->irq > 0) - free_irq(hw_config->irq, hw_config); - p=mpu401_synth_operations[n]; - sound_unload_mididev(n); - sound_unload_timerdev(hw_config->slots[2]); - kfree(p); - } -} - -/***************************************************** - * Timer stuff - ****************************************************/ - -static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; -static volatile int curr_tempo, curr_timebase, hw_timebase; -static int max_timebase = 8; /* 8*24=192 ppqn */ -static volatile unsigned long next_event_time; -static volatile unsigned long curr_ticks, curr_clocks; -static unsigned long prev_event_time; -static int metronome_mode; - -static unsigned long 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; -} - -static void 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(KERN_WARNING "mpu401: Can't set HW timebase to %d\n", hw_val * 24); - return; - } - hw_timebase = hw_val * 24; - curr_timebase = val; - -} - -static void tmr_reset(struct mpu_config *devc) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = curr_clocks = 0; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void 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 */ - } -} - -static void stop_metronome(int midi_dev) -{ - mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ -} - -static void 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 */ - } -} - -static int mpu_start_timer(int midi_dev) -{ - struct mpu_config *devc= &dev_conf[midi_dev]; - - tmr_reset(devc); - 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) -{ - int midi_dev = sound_timer_devs[dev]->devlink; - struct mpu_config *devc= &dev_conf[midi_dev]; - - if (timer_open) - return -EBUSY; - - tmr_reset(devc); - 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 */ - - return 0; -} - -static void mpu_timer_close(int dev) -{ - 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); -} - -static int 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; - 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); - - 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(KERN_WARNING "mpu401: 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; -} - -static unsigned long mpu_timer_get_time(int dev) -{ - if (!timer_open) - return 0; - - return curr_ticks; -} - -static int mpu_timer_ioctl(int dev, unsigned int command, void __user *arg) -{ - int midi_dev = sound_timer_devs[dev]->devlink; - int __user *p = (int __user *)arg; - - switch (command) - { - case SNDCTL_TMR_SOURCE: - { - int parm; - - if (get_user(parm, p)) - return -EFAULT; - 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 */ - } - if (put_user(timer_mode, p)) - return -EFAULT; - return timer_mode; - } - break; - - case SNDCTL_TMR_START: - mpu_start_timer(midi_dev); - return 0; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome(midi_dev); - return 0; - - case SNDCTL_TMR_CONTINUE: - if (tmr_running) - return 0; - tmr_running = 1; - mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ - return 0; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - if (get_user(val, p)) - return -EFAULT; - if (val) - set_timebase(midi_dev, val); - if (put_user(curr_timebase, p)) - return -EFAULT; - return curr_timebase; - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - int ret; - - if (get_user(val, p)) - return -EFAULT; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) - { - printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) val); - return ret; - } - curr_tempo = val; - } - if (put_user(curr_tempo, p)) - return -EFAULT; - return curr_tempo; - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - if (get_user(val, p)) - return -EFAULT; - - if (val != 0) /* Can't change */ - return -EINVAL; - val = ((curr_tempo * curr_timebase) + 30)/60; - if (put_user(val, p)) - return -EFAULT; - return val; - } - break; - - case SNDCTL_SEQ_GETTIME: - if (put_user(curr_ticks, p)) - return -EFAULT; - return curr_ticks; - - case SNDCTL_TMR_METRONOME: - if (get_user(metronome_mode, p)) - return -EFAULT; - setup_metronome(midi_dev); - return 0; - - default:; - } - return -EINVAL; -} - -static void mpu_timer_arm(int dev, long time) -{ - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; - next_event_time = prev_event_time = time; - return; -} - -static struct sound_timer_operations mpu_timer = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 Timer", 0}, - .priority = 10, /* Priority */ - .devlink = 0, /* Local device link */ - .open = mpu_timer_open, - .close = mpu_timer_close, - .event = mpu_timer_event, - .get_time = mpu_timer_get_time, - .ioctl = mpu_timer_ioctl, - .arm_timer = mpu_timer_arm -}; - -static void mpu_timer_interrupt(void) -{ - if (!timer_open) - return; - - if (!tmr_running) - return; - - curr_clocks++; - curr_ticks = clocks2ticks(curr_clocks); - - 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; - - 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) - { - 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; - } -} - -static int mpu_timer_init(int midi_dev) -{ - struct mpu_config *devc; - int n; - - devc = &dev_conf[midi_dev]; - - if (timer_initialized) - return -1; /* There is already a similar timer */ - - timer_initialized = 1; - - mpu_timer.devlink = midi_dev; - dev_conf[midi_dev].timer_flag = 1; - - 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->revision) - timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; - - if (devc->revision & 0x02) - timer_caps |= TMR_MODE_CLS; - - - if (devc->revision & 0x40) - max_timebase = 10; /* Has the 216 and 240 ppqn modes */ - } - - timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; - return n; - -} - -EXPORT_SYMBOL(probe_mpu401); -EXPORT_SYMBOL(attach_mpu401); -EXPORT_SYMBOL(unload_mpu401); - -static struct address_info cfg; - -static int io = -1; -static int irq = -1; - -module_param_hw(irq, int, irq, 0); -module_param_hw(io, int, ioport, 0); - -static int __init init_mpu401(void) -{ - int ret; - /* Can be loaded either for module use or to provide functions - to others */ - if (io != -1 && irq != -1) { - struct resource *ports; - cfg.irq = irq; - cfg.io_base = io; - ports = request_region(io, 2, "mpu401"); - if (!ports) - return -EBUSY; - if (probe_mpu401(&cfg, ports) == 0) { - release_region(io, 2); - return -ENODEV; - } - if ((ret = attach_mpu401(&cfg, THIS_MODULE))) - return ret; - } - - return 0; -} - -static void __exit cleanup_mpu401(void) -{ - if (io != -1 && irq != -1) { - /* Check for use by, for example, sscape driver */ - unload_mpu401(&cfg); - } -} - -module_init(init_mpu401); -module_exit(cleanup_mpu401); - -#ifndef MODULE -static int __init setup_mpu401(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} - -__setup("mpu401=", setup_mpu401); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h deleted file mode 100644 index 0ad1e9ee74f7..000000000000 --- a/sound/oss/mpu401.h +++ /dev/null @@ -1,11 +0,0 @@ - -/* From uart401.c */ -int probe_uart401 (struct address_info *hw_config, struct module *owner); -void unload_uart401 (struct address_info *hw_config); - -irqreturn_t uart401intr (int irq, void *dev_id); - -/* From mpu401.c */ -int probe_mpu401(struct address_info *hw_config, struct resource *ports); -int attach_mpu401(struct address_info * hw_config, struct module *owner); -void unload_mpu401(struct address_info *hw_info); diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c deleted file mode 100644 index b63010ad22f1..000000000000 --- a/sound/oss/msnd.c +++ /dev/null @@ -1,413 +0,0 @@ -/********************************************************************* - * - * msnd.c - Driver Base - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Copyright (C) 1998 Andrew Veliath - * - * 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. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/vmalloc.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/interrupt.h> - -#include <asm/io.h> -#include <linux/uaccess.h> -#include <linux/spinlock.h> -#include <asm/irq.h> -#include "msnd.h" - -#define LOGNAME "msnd" - -#define MSND_MAX_DEVS 4 - -static multisound_dev_t *devs[MSND_MAX_DEVS]; -static int num_devs; - -int msnd_register(multisound_dev_t *dev) -{ - int i; - - for (i = 0; i < MSND_MAX_DEVS; ++i) - if (devs[i] == NULL) - break; - - if (i == MSND_MAX_DEVS) - return -ENOMEM; - - devs[i] = dev; - ++num_devs; - return 0; -} - -void msnd_unregister(multisound_dev_t *dev) -{ - int i; - - for (i = 0; i < MSND_MAX_DEVS; ++i) - if (devs[i] == dev) - break; - - if (i == MSND_MAX_DEVS) { - printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n"); - return; - } - - devs[i] = NULL; - --num_devs; -} - -void msnd_init_queue(void __iomem *base, int start, int size) -{ - writew(PCTODSP_BASED(start), base + JQS_wStart); - writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); - writew(0, base + JQS_wHead); - writew(0, base + JQS_wTail); -} - -void msnd_fifo_init(msnd_fifo *f) -{ - f->data = NULL; -} - -void msnd_fifo_free(msnd_fifo *f) -{ - vfree(f->data); - f->data = NULL; -} - -int msnd_fifo_alloc(msnd_fifo *f, size_t n) -{ - msnd_fifo_free(f); - f->data = vmalloc(n); - f->n = n; - f->tail = 0; - f->head = 0; - f->len = 0; - - if (!f->data) - return -ENOMEM; - - return 0; -} - -void msnd_fifo_make_empty(msnd_fifo *f) -{ - f->len = f->tail = f->head = 0; -} - -int msnd_fifo_write_io(msnd_fifo *f, char __iomem *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len != f->n)) { - - int nwritten; - - if (f->head <= f->tail) { - nwritten = len - count; - if (nwritten > f->n - f->tail) - nwritten = f->n - f->tail; - } - else { - nwritten = f->head - f->tail; - if (nwritten > len - count) - nwritten = len - count; - } - - memcpy_fromio(f->data + f->tail, buf, nwritten); - - count += nwritten; - buf += nwritten; - f->len += nwritten; - f->tail += nwritten; - f->tail %= f->n; - } - - return count; -} - -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len != f->n)) { - - int nwritten; - - if (f->head <= f->tail) { - nwritten = len - count; - if (nwritten > f->n - f->tail) - nwritten = f->n - f->tail; - } - else { - nwritten = f->head - f->tail; - if (nwritten > len - count) - nwritten = len - count; - } - - memcpy(f->data + f->tail, buf, nwritten); - - count += nwritten; - buf += nwritten; - f->len += nwritten; - f->tail += nwritten; - f->tail %= f->n; - } - - return count; -} - -int msnd_fifo_read_io(msnd_fifo *f, char __iomem *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len > 0)) { - - int nread; - - if (f->tail <= f->head) { - nread = len - count; - if (nread > f->n - f->head) - nread = f->n - f->head; - } - else { - nread = f->tail - f->head; - if (nread > len - count) - nread = len - count; - } - - memcpy_toio(buf, f->data + f->head, nread); - - count += nread; - buf += nread; - f->len -= nread; - f->head += nread; - f->head %= f->n; - } - - return count; -} - -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len > 0)) { - - int nread; - - if (f->tail <= f->head) { - nread = len - count; - if (nread > f->n - f->head) - nread = f->n - f->head; - } - else { - nread = f->tail - f->head; - if (nread > len - count) - nread = len - count; - } - - memcpy(buf, f->data + f->head, nread); - - count += nread; - buf += nread; - f->len -= nread; - f->head += nread; - f->head %= f->n; - } - - return count; -} - -static int msnd_wait_TXDE(multisound_dev_t *dev) -{ - register unsigned int io = dev->io; - register int timeout = 1000; - - while(timeout-- > 0) - if (msnd_inb(io + HP_ISR) & HPISR_TXDE) - return 0; - - return -EIO; -} - -static int msnd_wait_HC0(multisound_dev_t *dev) -{ - register unsigned int io = dev->io; - register int timeout = 1000; - - while(timeout-- > 0) - if (!(msnd_inb(io + HP_CVR) & HPCVR_HC)) - return 0; - - return -EIO; -} - -int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (msnd_wait_HC0(dev) == 0) { - msnd_outb(cmd, dev->io + HP_CVR); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n"); - - return -EIO; -} - -int msnd_send_word(multisound_dev_t *dev, unsigned char high, - unsigned char mid, unsigned char low) -{ - register unsigned int io = dev->io; - - if (msnd_wait_TXDE(dev) == 0) { - msnd_outb(high, io + HP_TXH); - msnd_outb(mid, io + HP_TXM); - msnd_outb(low, io + HP_TXL); - return 0; - } - - printk(KERN_DEBUG LOGNAME ": Send host word timeout\n"); - - return -EIO; -} - -int msnd_upload_host(multisound_dev_t *dev, char *bin, int len) -{ - int i; - - if (len % 3 != 0) { - printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n"); - return -EINVAL; - } - - for (i = 0; i < len; i += 3) - if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0) - return -EIO; - - msnd_inb(dev->io + HP_RXL); - msnd_inb(dev->io + HP_CVR); - - return 0; -} - -int msnd_enable_irq(multisound_dev_t *dev) -{ - unsigned long flags; - - if (dev->irq_ref++) - return 0; - - printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n"); - - spin_lock_irqsave(&dev->lock, flags); - if (msnd_wait_TXDE(dev) == 0) { - msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); - if (dev->type == msndClassic) - msnd_outb(dev->irqid, dev->io + HP_IRQM); - msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR); - msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR); - enable_irq(dev->irq); - msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n"); - - return -EIO; -} - -int msnd_disable_irq(multisound_dev_t *dev) -{ - unsigned long flags; - - if (--dev->irq_ref > 0) - return 0; - - if (dev->irq_ref < 0) - printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); - - printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n"); - - spin_lock_irqsave(&dev->lock, flags); - if (msnd_wait_TXDE(dev) == 0) { - msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); - if (dev->type == msndClassic) - msnd_outb(HPIRQ_NONE, dev->io + HP_IRQM); - disable_irq(dev->irq); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n"); - - return -EIO; -} - -#ifndef LINUX20 -EXPORT_SYMBOL(msnd_register); -EXPORT_SYMBOL(msnd_unregister); - -EXPORT_SYMBOL(msnd_init_queue); - -EXPORT_SYMBOL(msnd_fifo_init); -EXPORT_SYMBOL(msnd_fifo_free); -EXPORT_SYMBOL(msnd_fifo_alloc); -EXPORT_SYMBOL(msnd_fifo_make_empty); -EXPORT_SYMBOL(msnd_fifo_write_io); -EXPORT_SYMBOL(msnd_fifo_read_io); -EXPORT_SYMBOL(msnd_fifo_write); -EXPORT_SYMBOL(msnd_fifo_read); - -EXPORT_SYMBOL(msnd_send_dsp_cmd); -EXPORT_SYMBOL(msnd_send_word); -EXPORT_SYMBOL(msnd_upload_host); - -EXPORT_SYMBOL(msnd_enable_irq); -EXPORT_SYMBOL(msnd_disable_irq); -#endif - -#ifdef MODULE -MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>"); -MODULE_DESCRIPTION ("Turtle Beach MultiSound Driver Base"); -MODULE_LICENSE("GPL"); - - -int init_module(void) -{ - return 0; -} - -void cleanup_module(void) -{ -} -#endif diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h deleted file mode 100644 index c8be47ec2b7e..000000000000 --- a/sound/oss/msnd.h +++ /dev/null @@ -1,278 +0,0 @@ -/********************************************************************* - * - * msnd.h - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Some parts of this header file were derived from the Turtle Beach - * MultiSound Driver Development Kit. - * - * Copyright (C) 1998 Andrew Veliath - * Copyright (C) 1993 Turtle Beach Systems, Inc. - * - * 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 __MSND_H -#define __MSND_H - -#define VERSION "0.8.3.1" - -#define DEFSAMPLERATE DSP_DEFAULT_SPEED -#define DEFSAMPLESIZE AFMT_U8 -#define DEFCHANNELS 1 - -#define DEFFIFOSIZE 128 - -#define SNDCARD_MSND 38 - -#define SRAM_BANK_SIZE 0x8000 -#define SRAM_CNTL_START 0x7F00 - -#define DSP_BASE_ADDR 0x4000 -#define DSP_BANK_BASE 0x4000 - -#define HP_ICR 0x00 -#define HP_CVR 0x01 -#define HP_ISR 0x02 -#define HP_IVR 0x03 -#define HP_NU 0x04 -#define HP_INFO 0x04 -#define HP_TXH 0x05 -#define HP_RXH 0x05 -#define HP_TXM 0x06 -#define HP_RXM 0x06 -#define HP_TXL 0x07 -#define HP_RXL 0x07 - -#define HP_ICR_DEF 0x00 -#define HP_CVR_DEF 0x12 -#define HP_ISR_DEF 0x06 -#define HP_IVR_DEF 0x0f -#define HP_NU_DEF 0x00 - -#define HP_IRQM 0x09 - -#define HPR_BLRC 0x08 -#define HPR_SPR1 0x09 -#define HPR_SPR2 0x0A -#define HPR_TCL0 0x0B -#define HPR_TCL1 0x0C -#define HPR_TCL2 0x0D -#define HPR_TCL3 0x0E -#define HPR_TCL4 0x0F - -#define HPICR_INIT 0x80 -#define HPICR_HM1 0x40 -#define HPICR_HM0 0x20 -#define HPICR_HF1 0x10 -#define HPICR_HF0 0x08 -#define HPICR_TREQ 0x02 -#define HPICR_RREQ 0x01 - -#define HPCVR_HC 0x80 - -#define HPISR_HREQ 0x80 -#define HPISR_DMA 0x40 -#define HPISR_HF3 0x10 -#define HPISR_HF2 0x08 -#define HPISR_TRDY 0x04 -#define HPISR_TXDE 0x02 -#define HPISR_RXDF 0x01 - -#define HPIO_290 0 -#define HPIO_260 1 -#define HPIO_250 2 -#define HPIO_240 3 -#define HPIO_230 4 -#define HPIO_220 5 -#define HPIO_210 6 -#define HPIO_3E0 7 - -#define HPMEM_NONE 0 -#define HPMEM_B000 1 -#define HPMEM_C800 2 -#define HPMEM_D000 3 -#define HPMEM_D400 4 -#define HPMEM_D800 5 -#define HPMEM_E000 6 -#define HPMEM_E800 7 - -#define HPIRQ_NONE 0 -#define HPIRQ_5 1 -#define HPIRQ_7 2 -#define HPIRQ_9 3 -#define HPIRQ_10 4 -#define HPIRQ_11 5 -#define HPIRQ_12 6 -#define HPIRQ_15 7 - -#define HIMT_PLAY_DONE 0x00 -#define HIMT_RECORD_DONE 0x01 -#define HIMT_MIDI_EOS 0x02 -#define HIMT_MIDI_OUT 0x03 - -#define HIMT_MIDI_IN_UCHAR 0x0E -#define HIMT_DSP 0x0F - -#define HDEX_BASE 0x92 -#define HDEX_PLAY_START (0 + HDEX_BASE) -#define HDEX_PLAY_STOP (1 + HDEX_BASE) -#define HDEX_PLAY_PAUSE (2 + HDEX_BASE) -#define HDEX_PLAY_RESUME (3 + HDEX_BASE) -#define HDEX_RECORD_START (4 + HDEX_BASE) -#define HDEX_RECORD_STOP (5 + HDEX_BASE) -#define HDEX_MIDI_IN_START (6 + HDEX_BASE) -#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE) -#define HDEX_MIDI_OUT_START (8 + HDEX_BASE) -#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE) -#define HDEX_AUX_REQ (10 + HDEX_BASE) - -#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF)) -#define LOWORD(l) ((WORD)(DWORD)(l)) -#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) -#define LOBYTE(w) ((BYTE)(w)) -#define MAKELONG(low,hi) ((long)(((WORD)(low))|(((DWORD)((WORD)(hi)))<<16))) -#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8))) - -#define PCTODSP_OFFSET(w) (USHORT)((w)/2) -#define PCTODSP_BASED(w) (USHORT)(((w)/2) + DSP_BASE_ADDR) -#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2) - -#ifdef SLOWIO -#define msnd_outb outb_p -#define msnd_inb inb_p -#else -#define msnd_outb outb -#define msnd_inb inb -#endif - -/* JobQueueStruct */ -#define JQS_wStart 0x00 -#define JQS_wSize 0x02 -#define JQS_wHead 0x04 -#define JQS_wTail 0x06 -#define JQS__size 0x08 - -/* DAQueueDataStruct */ -#define DAQDS_wStart 0x00 -#define DAQDS_wSize 0x02 -#define DAQDS_wFormat 0x04 -#define DAQDS_wSampleSize 0x06 -#define DAQDS_wChannels 0x08 -#define DAQDS_wSampleRate 0x0A -#define DAQDS_wIntMsg 0x0C -#define DAQDS_wFlags 0x0E -#define DAQDS__size 0x10 - -typedef u8 BYTE; -typedef u16 USHORT; -typedef u16 WORD; -typedef u32 DWORD; -typedef void __iomem * LPDAQD; - -/* Generic FIFO */ -typedef struct { - size_t n, len; - char *data; - int head, tail; -} msnd_fifo; - -typedef struct multisound_dev { - /* Linux device info */ - char *name; - int dsp_minor, mixer_minor; - int ext_midi_dev, hdr_midi_dev; - - /* Hardware resources */ - int io, numio; - int memid, irqid; - int irq, irq_ref; - unsigned char info; - void __iomem *base; - - /* Motorola 56k DSP SMA */ - void __iomem *SMA; - void __iomem *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ; - void __iomem *pwDSPQData, *pwMIDQData, *pwMODQData; - int dspq_data_buff, dspq_buff_size; - - /* State variables */ - enum { msndClassic, msndPinnacle } type; - fmode_t mode; - unsigned long flags; -#define F_RESETTING 0 -#define F_HAVEDIGITAL 1 -#define F_AUDIO_WRITE_INUSE 2 -#define F_WRITING 3 -#define F_WRITEBLOCK 4 -#define F_WRITEFLUSH 5 -#define F_AUDIO_READ_INUSE 6 -#define F_READING 7 -#define F_READBLOCK 8 -#define F_EXT_MIDI_INUSE 9 -#define F_HDR_MIDI_INUSE 10 -#define F_DISABLE_WRITE_NDELAY 11 - wait_queue_head_t writeblock; - wait_queue_head_t readblock; - wait_queue_head_t writeflush; - spinlock_t lock; - int nresets; - unsigned long recsrc; - int left_levels[32]; - int right_levels[32]; - int mixer_mod_count; - int calibrate_signal; - int play_sample_size, play_sample_rate, play_channels; - int play_ndelay; - int rec_sample_size, rec_sample_rate, rec_channels; - int rec_ndelay; - BYTE bCurrentMidiPatch; - - /* Digital audio FIFOs */ - msnd_fifo DAPF, DARF; - int fifosize; - int last_playbank, last_recbank; - - /* MIDI in callback */ - void (*midi_in_interrupt)(struct multisound_dev *); -} multisound_dev_t; - -#ifndef mdelay -# define mdelay(a) udelay((a) * 1000) -#endif - -int msnd_register(multisound_dev_t *dev); -void msnd_unregister(multisound_dev_t *dev); - -void msnd_init_queue(void __iomem *, int start, int size); - -void msnd_fifo_init(msnd_fifo *f); -void msnd_fifo_free(msnd_fifo *f); -int msnd_fifo_alloc(msnd_fifo *f, size_t n); -void msnd_fifo_make_empty(msnd_fifo *f); -int msnd_fifo_write_io(msnd_fifo *f, char __iomem *buf, size_t len); -int msnd_fifo_read_io(msnd_fifo *f, char __iomem *buf, size_t len); -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len); -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len); - -int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd); -int msnd_send_word(multisound_dev_t *dev, unsigned char high, - unsigned char mid, unsigned char low); -int msnd_upload_host(multisound_dev_t *dev, char *bin, int len); -int msnd_enable_irq(multisound_dev_t *dev); -int msnd_disable_irq(multisound_dev_t *dev); - -#endif /* __MSND_H */ diff --git a/sound/oss/msnd_classic.c b/sound/oss/msnd_classic.c deleted file mode 100644 index 3b23a096fa4e..000000000000 --- a/sound/oss/msnd_classic.c +++ /dev/null @@ -1,3 +0,0 @@ -/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */ -#define MSND_CLASSIC -#include "msnd_pinnacle.c" diff --git a/sound/oss/msnd_classic.h b/sound/oss/msnd_classic.h deleted file mode 100644 index 1a17dde2f650..000000000000 --- a/sound/oss/msnd_classic.h +++ /dev/null @@ -1,185 +0,0 @@ -/********************************************************************* - * - * msnd_classic.h - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Some parts of this header file were derived from the Turtle Beach - * MultiSound Driver Development Kit. - * - * Copyright (C) 1998 Andrew Veliath - * Copyright (C) 1993 Turtle Beach Systems, Inc. - * - * 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 __MSND_CLASSIC_H -#define __MSND_CLASSIC_H - - -#define DSP_NUMIO 0x10 - -#define HP_MEMM 0x08 - -#define HP_BITM 0x0E -#define HP_WAIT 0x0D -#define HP_DSPR 0x0A -#define HP_PROR 0x0B -#define HP_BLKS 0x0C - -#define HPPRORESET_OFF 0 -#define HPPRORESET_ON 1 - -#define HPDSPRESET_OFF 0 -#define HPDSPRESET_ON 1 - -#define HPBLKSEL_0 0 -#define HPBLKSEL_1 1 - -#define HPWAITSTATE_0 0 -#define HPWAITSTATE_1 1 - -#define HPBITMODE_16 0 -#define HPBITMODE_8 1 - -#define HIDSP_INT_PLAY_UNDER 0x00 -#define HIDSP_INT_RECORD_OVER 0x01 -#define HIDSP_INPUT_CLIPPING 0x02 -#define HIDSP_MIDI_IN_OVER 0x10 -#define HIDSP_MIDI_OVERRUN_ERR 0x13 - -#define HDEXAR_CLEAR_PEAKS 1 -#define HDEXAR_IN_SET_POTS 2 -#define HDEXAR_AUX_SET_POTS 3 -#define HDEXAR_CAL_A_TO_D 4 -#define HDEXAR_RD_EXT_DSP_BITS 5 - -#define TIME_PRO_RESET_DONE 0x028A -#define TIME_PRO_SYSEX 0x0040 -#define TIME_PRO_RESET 0x0032 - -#define AGND 0x01 -#define SIGNAL 0x02 - -#define EXT_DSP_BIT_DCAL 0x0001 -#define EXT_DSP_BIT_MIDI_CON 0x0002 - -#define BUFFSIZE 0x8000 -#define HOSTQ_SIZE 0x40 - -#define SRAM_CNTL_START 0x7F00 -#define SMA_STRUCT_START 0x7F40 - -#define DAP_BUFF_SIZE 0x2400 -#define DAR_BUFF_SIZE 0x2000 - -#define DAPQ_STRUCT_SIZE 0x10 -#define DARQ_STRUCT_SIZE 0x10 -#define DAPQ_BUFF_SIZE (3 * 0x10) -#define DARQ_BUFF_SIZE (3 * 0x10) -#define MODQ_BUFF_SIZE 0x400 -#define MIDQ_BUFF_SIZE 0x200 -#define DSPQ_BUFF_SIZE 0x40 - -#define DAPQ_DATA_BUFF 0x6C00 -#define DARQ_DATA_BUFF 0x6C30 -#define MODQ_DATA_BUFF 0x6C60 -#define MIDQ_DATA_BUFF 0x7060 -#define DSPQ_DATA_BUFF 0x7260 - -#define DAPQ_OFFSET SRAM_CNTL_START -#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) -#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) -#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) -#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) - -#define MOP_SYNTH 0x10 -#define MOP_EXTOUT 0x32 -#define MOP_EXTTHRU 0x02 -#define MOP_OUTMASK 0x01 - -#define MIP_EXTIN 0x01 -#define MIP_SYNTH 0x00 -#define MIP_INMASK 0x32 - -/* Classic SMA Common Data */ -#define SMA_wCurrPlayBytes 0x0000 -#define SMA_wCurrRecordBytes 0x0002 -#define SMA_wCurrPlayVolLeft 0x0004 -#define SMA_wCurrPlayVolRight 0x0006 -#define SMA_wCurrInVolLeft 0x0008 -#define SMA_wCurrInVolRight 0x000a -#define SMA_wUser_3 0x000c -#define SMA_wUser_4 0x000e -#define SMA_dwUser_5 0x0010 -#define SMA_dwUser_6 0x0014 -#define SMA_wUser_7 0x0018 -#define SMA_wReserved_A 0x001a -#define SMA_wReserved_B 0x001c -#define SMA_wReserved_C 0x001e -#define SMA_wReserved_D 0x0020 -#define SMA_wReserved_E 0x0022 -#define SMA_wReserved_F 0x0024 -#define SMA_wReserved_G 0x0026 -#define SMA_wReserved_H 0x0028 -#define SMA_wCurrDSPStatusFlags 0x002a -#define SMA_wCurrHostStatusFlags 0x002c -#define SMA_wCurrInputTagBits 0x002e -#define SMA_wCurrLeftPeak 0x0030 -#define SMA_wCurrRightPeak 0x0032 -#define SMA_wExtDSPbits 0x0034 -#define SMA_bExtHostbits 0x0036 -#define SMA_bBoardLevel 0x0037 -#define SMA_bInPotPosRight 0x0038 -#define SMA_bInPotPosLeft 0x0039 -#define SMA_bAuxPotPosRight 0x003a -#define SMA_bAuxPotPosLeft 0x003b -#define SMA_wCurrMastVolLeft 0x003c -#define SMA_wCurrMastVolRight 0x003e -#define SMA_bUser_12 0x0040 -#define SMA_bUser_13 0x0041 -#define SMA_wUser_14 0x0042 -#define SMA_wUser_15 0x0044 -#define SMA_wCalFreqAtoD 0x0046 -#define SMA_wUser_16 0x0048 -#define SMA_wUser_17 0x004a -#define SMA__size 0x004c - -#ifdef HAVE_DSPCODEH -# include "msndperm.c" -# include "msndinit.c" -# define PERMCODE msndperm -# define INITCODE msndinit -# define PERMCODESIZE sizeof(msndperm) -# define INITCODESIZE sizeof(msndinit) -#else -# ifndef CONFIG_MSNDCLAS_INIT_FILE -# define CONFIG_MSNDCLAS_INIT_FILE \ - "/etc/sound/msndinit.bin" -# endif -# ifndef CONFIG_MSNDCLAS_PERM_FILE -# define CONFIG_MSNDCLAS_PERM_FILE \ - "/etc/sound/msndperm.bin" -# endif -# define PERMCODEFILE CONFIG_MSNDCLAS_PERM_FILE -# define INITCODEFILE CONFIG_MSNDCLAS_INIT_FILE -# define PERMCODE dspini -# define INITCODE permini -# define PERMCODESIZE sizeof_dspini -# define INITCODESIZE sizeof_permini -#endif -#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)" - -#endif /* __MSND_CLASSIC_H */ diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c deleted file mode 100644 index d2abc2cf3213..000000000000 --- a/sound/oss/msnd_pinnacle.c +++ /dev/null @@ -1,1941 +0,0 @@ -/********************************************************************* - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * Linux 2.0/2.2 Version - * - * msnd_pinnacle.c / msnd_classic.c - * - * -- If MSND_CLASSIC is defined: - * - * -> driver for Turtle Beach Classic/Monterey/Tahiti - * - * -- Else - * - * -> driver for Turtle Beach Pinnacle/Fiji - * - * Copyright (C) 1998 Andrew Veliath - * - * 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. - * - * 12-3-2000 Modified IO port validation Steve Sycamore - * - ********************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/gfp.h> -#include <linux/sched/signal.h> - -#include <asm/irq.h> -#include <asm/io.h> -#include "sound_config.h" -#include "sound_firmware.h" -#ifdef MSND_CLASSIC -# ifndef __alpha__ -# define SLOWIO -# endif -#endif -#include "msnd.h" -#ifdef MSND_CLASSIC -# ifdef CONFIG_MSNDCLAS_HAVE_BOOT -# define HAVE_DSPCODEH -# endif -# include "msnd_classic.h" -# define LOGNAME "msnd_classic" -#else -# ifdef CONFIG_MSNDPIN_HAVE_BOOT -# define HAVE_DSPCODEH -# endif -# include "msnd_pinnacle.h" -# define LOGNAME "msnd_pinnacle" -#endif - -#ifndef CONFIG_MSND_WRITE_NDELAY -# define CONFIG_MSND_WRITE_NDELAY 1 -#endif - -#define get_play_delay_jiffies(size) ((size) * HZ * \ - dev.play_sample_size / 8 / \ - dev.play_sample_rate / \ - dev.play_channels) - -#define get_rec_delay_jiffies(size) ((size) * HZ * \ - dev.rec_sample_size / 8 / \ - dev.rec_sample_rate / \ - dev.rec_channels) - -static DEFINE_MUTEX(msnd_pinnacle_mutex); -static multisound_dev_t dev; - -#ifndef HAVE_DSPCODEH -static char *dspini, *permini; -static int sizeof_dspini, sizeof_permini; -#endif - -static int dsp_full_reset(void); -static void dsp_write_flush(void); - -static __inline__ int chk_send_dsp_cmd(multisound_dev_t *dev, register BYTE cmd) -{ - if (msnd_send_dsp_cmd(dev, cmd) == 0) - return 0; - dsp_full_reset(); - return msnd_send_dsp_cmd(dev, cmd); -} - -static void reset_play_queue(void) -{ - int n; - LPDAQD lpDAQ; - - dev.last_playbank = -1; - writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead); - writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail); - - for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { - writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart); - writew(0, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.play_channels, lpDAQ + DAQDS_wChannels); - writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n, lpDAQ + DAQDS_wFlags); - } -} - -static void reset_record_queue(void) -{ - int n; - LPDAQD lpDAQ; - unsigned long flags; - - dev.last_recbank = 2; - writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead); - writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail); - - /* Critical section: bank 1 access */ - spin_lock_irqsave(&dev.lock, flags); - msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS); - memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - spin_unlock_irqrestore(&dev.lock, flags); - - for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { - writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart); - writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.rec_channels, lpDAQ + DAQDS_wChannels); - writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n, lpDAQ + DAQDS_wFlags); - } -} - -static void reset_queues(void) -{ - if (dev.mode & FMODE_WRITE) { - msnd_fifo_make_empty(&dev.DAPF); - reset_play_queue(); - } - if (dev.mode & FMODE_READ) { - msnd_fifo_make_empty(&dev.DARF); - reset_record_queue(); - } -} - -static int dsp_set_format(struct file *file, int val) -{ - int data, i; - LPDAQD lpDAQ, lpDARQ; - - lpDAQ = dev.base + DAPQ_DATA_BUFF; - lpDARQ = dev.base + DARQ_DATA_BUFF; - - switch (val) { - case AFMT_U8: - case AFMT_S16_LE: - data = val; - break; - default: - data = DEFSAMPLESIZE; - break; - } - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - if (file->f_mode & FMODE_WRITE) - writew(data, lpDAQ + DAQDS_wSampleSize); - if (file->f_mode & FMODE_READ) - writew(data, lpDARQ + DAQDS_wSampleSize); - } - if (file->f_mode & FMODE_WRITE) - dev.play_sample_size = data; - if (file->f_mode & FMODE_READ) - dev.rec_sample_size = data; - - return data; -} - -static int dsp_get_frag_size(void) -{ - int size; - size = dev.fifosize / 4; - if (size > 32 * 1024) - size = 32 * 1024; - return size; -} - -static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int val, i, data, tmp; - LPDAQD lpDAQ, lpDARQ; - audio_buf_info abinfo; - unsigned long flags; - int __user *p = (int __user *)arg; - - lpDAQ = dev.base + DAPQ_DATA_BUFF; - lpDARQ = dev.base + DARQ_DATA_BUFF; - - switch (cmd) { - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - case SNDCTL_DSP_SETDUPLEX: - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETIPTR: - case SNDCTL_DSP_GETOPTR: - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - return -EINVAL; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&dev.lock, flags); - abinfo.fragsize = dsp_get_frag_size(); - abinfo.bytes = dev.DAPF.n - dev.DAPF.len; - abinfo.fragstotal = dev.DAPF.n / abinfo.fragsize; - abinfo.fragments = abinfo.bytes / abinfo.fragsize; - spin_unlock_irqrestore(&dev.lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&dev.lock, flags); - abinfo.fragsize = dsp_get_frag_size(); - abinfo.bytes = dev.DARF.n - dev.DARF.len; - abinfo.fragstotal = dev.DARF.n / abinfo.fragsize; - abinfo.fragments = abinfo.bytes / abinfo.fragsize; - spin_unlock_irqrestore(&dev.lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_RESET: - dev.nresets = 0; - reset_queues(); - return 0; - - case SNDCTL_DSP_SYNC: - dsp_write_flush(); - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - tmp = dsp_get_frag_size(); - if (put_user(tmp, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETFMTS: - val = AFMT_S16_LE | AFMT_U8; - if (put_user(val, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - - if (file->f_mode & FMODE_WRITE) - data = val == AFMT_QUERY - ? dev.play_sample_size - : dsp_set_format(file, val); - else - data = val == AFMT_QUERY - ? dev.rec_sample_size - : dsp_set_format(file, val); - - if (put_user(data, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_NONBLOCK: - if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags) && - file->f_mode & FMODE_WRITE) - dev.play_ndelay = 1; - if (file->f_mode & FMODE_READ) - dev.rec_ndelay = 1; - return 0; - - case SNDCTL_DSP_GETCAPS: - val = DSP_CAP_DUPLEX | DSP_CAP_BATCH; - if (put_user(val, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - - if (val < 8000) - val = 8000; - - if (val > 48000) - val = 48000; - - data = val; - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - if (file->f_mode & FMODE_WRITE) - writew(data, lpDAQ + DAQDS_wSampleRate); - if (file->f_mode & FMODE_READ) - writew(data, lpDARQ + DAQDS_wSampleRate); - } - if (file->f_mode & FMODE_WRITE) - dev.play_sample_rate = data; - if (file->f_mode & FMODE_READ) - dev.rec_sample_rate = data; - - if (put_user(data, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_CHANNELS: - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - - if (cmd == SNDCTL_DSP_CHANNELS) { - switch (val) { - case 1: - case 2: - data = val; - break; - default: - val = data = 2; - break; - } - } else { - switch (val) { - case 0: - data = 1; - break; - default: - val = 1; - case 1: - data = 2; - break; - } - } - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - if (file->f_mode & FMODE_WRITE) - writew(data, lpDAQ + DAQDS_wChannels); - if (file->f_mode & FMODE_READ) - writew(data, lpDARQ + DAQDS_wChannels); - } - if (file->f_mode & FMODE_WRITE) - dev.play_channels = data; - if (file->f_mode & FMODE_READ) - dev.rec_channels = data; - - if (put_user(val, p)) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - -static int mixer_get(int d) -{ - if (d > 31) - return -EINVAL; - - switch (d) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_PCM: - case SOUND_MIXER_LINE: - case SOUND_MIXER_IMIX: - case SOUND_MIXER_LINE1: -#ifndef MSND_CLASSIC - case SOUND_MIXER_MIC: - case SOUND_MIXER_SYNTH: -#endif - return (dev.left_levels[d] >> 8) * 100 / 0xff | - (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8); - default: - return 0; - } -} - -#define update_volm(a,b) \ - writew((dev.left_levels[a] >> 1) * \ - readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \ - dev.SMA + SMA_##b##Left); \ - writew((dev.right_levels[a] >> 1) * \ - readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \ - dev.SMA + SMA_##b##Right); - -#define update_potm(d,s,ar) \ - writeb((dev.left_levels[d] >> 8) * \ - readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \ - dev.SMA + SMA_##s##Left); \ - writeb((dev.right_levels[d] >> 8) * \ - readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \ - dev.SMA + SMA_##s##Right); \ - if (msnd_send_word(&dev, 0, 0, ar) == 0) \ - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - -#define update_pot(d,s,ar) \ - writeb(dev.left_levels[d] >> 8, \ - dev.SMA + SMA_##s##Left); \ - writeb(dev.right_levels[d] >> 8, \ - dev.SMA + SMA_##s##Right); \ - if (msnd_send_word(&dev, 0, 0, ar) == 0) \ - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - -static int mixer_set(int d, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int bLeft, bRight; - int wLeft, wRight; - int updatemaster = 0; - - if (d > 31) - return -EINVAL; - - bLeft = left * 0xff / 100; - wLeft = left * 0xffff / 100; - - bRight = right * 0xff / 100; - wRight = right * 0xffff / 100; - - dev.left_levels[d] = wLeft; - dev.right_levels[d] = wRight; - - switch (d) { - /* master volume unscaled controls */ - case SOUND_MIXER_LINE: /* line pot control */ - /* scaled by IMIX in digital mix */ - writeb(bLeft, dev.SMA + SMA_bInPotPosLeft); - writeb(bRight, dev.SMA + SMA_bInPotPosRight); - if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - break; -#ifndef MSND_CLASSIC - case SOUND_MIXER_MIC: /* mic pot control */ - /* scaled by IMIX in digital mix */ - writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft); - writeb(bRight, dev.SMA + SMA_bMicPotPosRight); - if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - break; -#endif - case SOUND_MIXER_VOLUME: /* master volume */ - writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft); - writew(wRight, dev.SMA + SMA_wCurrMastVolRight); - /* fall through */ - - case SOUND_MIXER_LINE1: /* aux pot control */ - /* scaled by master volume */ - /* fall through */ - - /* digital controls */ - case SOUND_MIXER_SYNTH: /* synth vol (dsp mix) */ - case SOUND_MIXER_PCM: /* pcm vol (dsp mix) */ - case SOUND_MIXER_IMIX: /* input monitor (dsp mix) */ - /* scaled by master volume */ - updatemaster = 1; - break; - - default: - return 0; - } - - if (updatemaster) { - /* update master volume scaled controls */ - update_volm(SOUND_MIXER_PCM, wCurrPlayVol); - update_volm(SOUND_MIXER_IMIX, wCurrInVol); -#ifndef MSND_CLASSIC - update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol); -#endif - update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); - } - - return mixer_get(d); -} - -static void mixer_setup(void) -{ - update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS); - update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); - update_volm(SOUND_MIXER_PCM, wCurrPlayVol); - update_volm(SOUND_MIXER_IMIX, wCurrInVol); -#ifndef MSND_CLASSIC - update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS); - update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol); -#endif -} - -static unsigned long set_recsrc(unsigned long recsrc) -{ - if (dev.recsrc == recsrc) - return dev.recsrc; -#ifdef HAVE_NORECSRC - else if (recsrc == 0) - dev.recsrc = 0; -#endif - else - dev.recsrc ^= recsrc; - -#ifndef MSND_CLASSIC - if (dev.recsrc & SOUND_MASK_IMIX) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } - else if (dev.recsrc & SOUND_MASK_SYNTH) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } - else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } - else { -#ifdef HAVE_NORECSRC - /* Select no input (?) */ - dev.recsrc = 0; -#else - dev.recsrc = SOUND_MASK_IMIX; - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); -#endif - } -#endif /* MSND_CLASSIC */ - - return dev.recsrc; -} - -static unsigned long force_recsrc(unsigned long recsrc) -{ - dev.recsrc = 0; - return set_recsrc(recsrc); -} - -#define set_mixer_info() \ - memset(&info, 0, sizeof(info)); \ - strlcpy(info.id, "MSNDMIXER", sizeof(info.id)); \ - strlcpy(info.name, "MultiSound Mixer", sizeof(info.name)); - -static int mixer_ioctl(unsigned int cmd, unsigned long arg) -{ - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - set_mixer_info(); - info.modify_counter = dev.mixer_mod_count; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } else if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - set_mixer_info(); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } else if (cmd == SOUND_MIXER_PRIVATE1) { - dev.nresets = 0; - dsp_full_reset(); - return 0; - } else if (((cmd >> 8) & 0xff) == 'M') { - int val = 0; - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = set_recsrc(val); - break; - - default: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = mixer_set(cmd & 0xff, val); - break; - } - ++dev.mixer_mod_count; - return put_user(val, (int __user *)arg); - } else { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - val = dev.recsrc; - break; - - case SOUND_MIXER_DEVMASK: - case SOUND_MIXER_STEREODEVS: - val = SOUND_MASK_PCM | - SOUND_MASK_LINE | - SOUND_MASK_IMIX | - SOUND_MASK_LINE1 | -#ifndef MSND_CLASSIC - SOUND_MASK_MIC | - SOUND_MASK_SYNTH | -#endif - SOUND_MASK_VOLUME; - break; - - case SOUND_MIXER_RECMASK: -#ifdef MSND_CLASSIC - val = 0; -#else - val = SOUND_MASK_IMIX | - SOUND_MASK_SYNTH; - if (test_bit(F_HAVEDIGITAL, &dev.flags)) - val |= SOUND_MASK_DIGITAL1; -#endif - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: - if ((val = mixer_get(cmd & 0xff)) < 0) - return -EINVAL; - break; - } - } - - return put_user(val, (int __user *)arg); - } - - return -EINVAL; -} - -static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int minor = iminor(file_inode(file)); - int ret; - - if (cmd == OSS_GETVERSION) { - int sound_version = SOUND_VERSION; - return put_user(sound_version, (int __user *)arg); - } - - ret = -EINVAL; - - mutex_lock(&msnd_pinnacle_mutex); - if (minor == dev.dsp_minor) - ret = dsp_ioctl(file, cmd, arg); - else if (minor == dev.mixer_minor) - ret = mixer_ioctl(cmd, arg); - mutex_unlock(&msnd_pinnacle_mutex); - - return ret; -} - -static void dsp_write_flush(void) -{ - int timeout = get_play_delay_jiffies(dev.DAPF.len); - - if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) - return; - set_bit(F_WRITEFLUSH, &dev.flags); - wait_event_interruptible_timeout( - dev.writeflush, - !test_bit(F_WRITEFLUSH, &dev.flags), - timeout); - clear_bit(F_WRITEFLUSH, &dev.flags); - if (!signal_pending(current)) { - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE)); - } - clear_bit(F_WRITING, &dev.flags); -} - -static void dsp_halt(struct file *file) -{ - if ((file ? file->f_mode : dev.mode) & FMODE_READ) { - clear_bit(F_READING, &dev.flags); - chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP); - msnd_disable_irq(&dev); - if (file) { - printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file); - dev.mode &= ~FMODE_READ; - } - clear_bit(F_AUDIO_READ_INUSE, &dev.flags); - } - if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { - if (test_bit(F_WRITING, &dev.flags)) { - dsp_write_flush(); - chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP); - } - msnd_disable_irq(&dev); - if (file) { - printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file); - dev.mode &= ~FMODE_WRITE; - } - clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags); - } -} - -static int dsp_release(struct file *file) -{ - dsp_halt(file); - return 0; -} - -static int dsp_open(struct file *file) -{ - if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { - set_bit(F_AUDIO_WRITE_INUSE, &dev.flags); - clear_bit(F_WRITING, &dev.flags); - msnd_fifo_make_empty(&dev.DAPF); - reset_play_queue(); - if (file) { - printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file); - dev.mode |= FMODE_WRITE; - } - msnd_enable_irq(&dev); - } - if ((file ? file->f_mode : dev.mode) & FMODE_READ) { - set_bit(F_AUDIO_READ_INUSE, &dev.flags); - clear_bit(F_READING, &dev.flags); - msnd_fifo_make_empty(&dev.DARF); - reset_record_queue(); - if (file) { - printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file); - dev.mode |= FMODE_READ; - } - msnd_enable_irq(&dev); - } - return 0; -} - -static void set_default_play_audio_parameters(void) -{ - dev.play_sample_size = DEFSAMPLESIZE; - dev.play_sample_rate = DEFSAMPLERATE; - dev.play_channels = DEFCHANNELS; -} - -static void set_default_rec_audio_parameters(void) -{ - dev.rec_sample_size = DEFSAMPLESIZE; - dev.rec_sample_rate = DEFSAMPLERATE; - dev.rec_channels = DEFCHANNELS; -} - -static void set_default_audio_parameters(void) -{ - set_default_play_audio_parameters(); - set_default_rec_audio_parameters(); -} - -static int dev_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - int err = 0; - - mutex_lock(&msnd_pinnacle_mutex); - if (minor == dev.dsp_minor) { - if ((file->f_mode & FMODE_WRITE && - test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || - (file->f_mode & FMODE_READ && - test_bit(F_AUDIO_READ_INUSE, &dev.flags))) { - err = -EBUSY; - goto out; - } - - if ((err = dsp_open(file)) >= 0) { - dev.nresets = 0; - if (file->f_mode & FMODE_WRITE) { - set_default_play_audio_parameters(); - if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags)) - dev.play_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; - else - dev.play_ndelay = 0; - } - if (file->f_mode & FMODE_READ) { - set_default_rec_audio_parameters(); - dev.rec_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; - } - } - } - else if (minor == dev.mixer_minor) { - /* nothing */ - } else - err = -EINVAL; -out: - mutex_unlock(&msnd_pinnacle_mutex); - return err; -} - -static int dev_release(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - int err = 0; - - mutex_lock(&msnd_pinnacle_mutex); - if (minor == dev.dsp_minor) - err = dsp_release(file); - else if (minor == dev.mixer_minor) { - /* nothing */ - } else - err = -EINVAL; - mutex_unlock(&msnd_pinnacle_mutex); - return err; -} - -static __inline__ int pack_DARQ_to_DARF(register int bank) -{ - register int size, timeout = 3; - register WORD wTmp; - LPDAQD DAQD; - - /* Increment the tail and check for queue wrap */ - wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size); - if (wTmp > readw(dev.DARQ + JQS_wSize)) - wTmp = 0; - while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--) - udelay(1); - writew(wTmp, dev.DARQ + JQS_wTail); - - /* Get our digital audio queue struct */ - DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF; - - /* Get length of data */ - size = readw(DAQD + DAQDS_wSize); - - /* Read data from the head (unprotected bank 1 access okay - since this is only called inside an interrupt) */ - msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS); - msnd_fifo_write_io( - &dev.DARF, - dev.base + bank * DAR_BUFF_SIZE, - size); - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - - return 1; -} - -static __inline__ int pack_DAPF_to_DAPQ(register int start) -{ - register WORD DAPQ_tail; - register int protect = start, nbanks = 0; - LPDAQD DAQD; - - DAPQ_tail = readw(dev.DAPQ + JQS_wTail); - while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) { - register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); - register int n; - unsigned long flags; - - /* Write the data to the new tail */ - if (protect) { - /* Critical section: protect fifo in non-interrupt */ - spin_lock_irqsave(&dev.lock, flags); - n = msnd_fifo_read_io( - &dev.DAPF, - dev.base + bank_num * DAP_BUFF_SIZE, - DAP_BUFF_SIZE); - spin_unlock_irqrestore(&dev.lock, flags); - } else { - n = msnd_fifo_read_io( - &dev.DAPF, - dev.base + bank_num * DAP_BUFF_SIZE, - DAP_BUFF_SIZE); - } - if (!n) - break; - - if (start) - start = 0; - - /* Get our digital audio queue struct */ - DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF; - - /* Write size of this bank */ - writew(n, DAQD + DAQDS_wSize); - ++nbanks; - - /* Then advance the tail */ - DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); - writew(DAPQ_tail, dev.DAPQ + JQS_wTail); - /* Tell the DSP to play the bank */ - msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); - } - return nbanks; -} - -static int dsp_read(char __user *buf, size_t len) -{ - int count = len; - char *page = (char *)__get_free_page(GFP_KERNEL); - int timeout = get_rec_delay_jiffies(DAR_BUFF_SIZE); - - if (!page) - return -ENOMEM; - - while (count > 0) { - int n, k; - unsigned long flags; - - k = PAGE_SIZE; - if (k > count) - k = count; - - /* Critical section: protect fifo in non-interrupt */ - spin_lock_irqsave(&dev.lock, flags); - n = msnd_fifo_read(&dev.DARF, page, k); - spin_unlock_irqrestore(&dev.lock, flags); - if (copy_to_user(buf, page, n)) { - free_page((unsigned long)page); - return -EFAULT; - } - buf += n; - count -= n; - - if (n == k && count) - continue; - - if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { - dev.last_recbank = -1; - if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) - set_bit(F_READING, &dev.flags); - } - - if (dev.rec_ndelay) { - free_page((unsigned long)page); - return count == len ? -EAGAIN : len - count; - } - - if (count > 0) { - set_bit(F_READBLOCK, &dev.flags); - if (wait_event_interruptible_timeout( - dev.readblock, - test_bit(F_READBLOCK, &dev.flags), - timeout) <= 0) - clear_bit(F_READING, &dev.flags); - if (signal_pending(current)) { - free_page((unsigned long)page); - return -EINTR; - } - } - } - free_page((unsigned long)page); - return len - count; -} - -static int dsp_write(const char __user *buf, size_t len) -{ - int count = len; - char *page = (char *)__get_free_page(GFP_KERNEL); - int timeout = get_play_delay_jiffies(DAP_BUFF_SIZE); - - if (!page) - return -ENOMEM; - - while (count > 0) { - int n, k; - unsigned long flags; - - k = PAGE_SIZE; - if (k > count) - k = count; - - if (copy_from_user(page, buf, k)) { - free_page((unsigned long)page); - return -EFAULT; - } - - /* Critical section: protect fifo in non-interrupt */ - spin_lock_irqsave(&dev.lock, flags); - n = msnd_fifo_write(&dev.DAPF, page, k); - spin_unlock_irqrestore(&dev.lock, flags); - buf += n; - count -= n; - - if (count && n == k) - continue; - - if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { - dev.last_playbank = -1; - if (pack_DAPF_to_DAPQ(1) > 0) - set_bit(F_WRITING, &dev.flags); - } - - if (dev.play_ndelay) { - free_page((unsigned long)page); - return count == len ? -EAGAIN : len - count; - } - - if (count > 0) { - set_bit(F_WRITEBLOCK, &dev.flags); - wait_event_interruptible_timeout( - dev.writeblock, - test_bit(F_WRITEBLOCK, &dev.flags), - timeout); - if (signal_pending(current)) { - free_page((unsigned long)page); - return -EINTR; - } - } - } - - free_page((unsigned long)page); - return len - count; -} - -static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - int minor = iminor(file_inode(file)); - if (minor == dev.dsp_minor) - return dsp_read(buf, count); - else - return -EINVAL; -} - -static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - int minor = iminor(file_inode(file)); - if (minor == dev.dsp_minor) - return dsp_write(buf, count); - else - return -EINVAL; -} - -static __inline__ void eval_dsp_msg(register WORD wMessage) -{ - switch (HIBYTE(wMessage)) { - case HIMT_PLAY_DONE: - if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags)) - break; - dev.last_playbank = LOBYTE(wMessage); - - if (pack_DAPF_to_DAPQ(0) <= 0) { - if (!test_bit(F_WRITEBLOCK, &dev.flags)) { - if (test_and_clear_bit(F_WRITEFLUSH, &dev.flags)) - wake_up_interruptible(&dev.writeflush); - } - clear_bit(F_WRITING, &dev.flags); - } - - if (test_and_clear_bit(F_WRITEBLOCK, &dev.flags)) - wake_up_interruptible(&dev.writeblock); - break; - - case HIMT_RECORD_DONE: - if (dev.last_recbank == LOBYTE(wMessage)) - break; - dev.last_recbank = LOBYTE(wMessage); - - pack_DARQ_to_DARF(dev.last_recbank); - - if (test_and_clear_bit(F_READBLOCK, &dev.flags)) - wake_up_interruptible(&dev.readblock); - break; - - case HIMT_DSP: - switch (LOBYTE(wMessage)) { -#ifndef MSND_CLASSIC - case HIDSP_PLAY_UNDER: -#endif - case HIDSP_INT_PLAY_UNDER: -/* printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */ - clear_bit(F_WRITING, &dev.flags); - break; - - case HIDSP_INT_RECORD_OVER: -/* printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */ - clear_bit(F_READING, &dev.flags); - break; - - default: -/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", - LOBYTE(wMessage), LOBYTE(wMessage)); */ - break; - } - break; - - case HIMT_MIDI_IN_UCHAR: - if (dev.midi_in_interrupt) - (*dev.midi_in_interrupt)(&dev); - break; - - default: -/* printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */ - break; - } -} - -static irqreturn_t intr(int irq, void *dev_id) -{ - /* Send ack to DSP */ - msnd_inb(dev.io + HP_RXL); - - /* Evaluate queued DSP messages */ - while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) { - register WORD wTmp; - - eval_dsp_msg(readw(dev.pwDSPQData + 2*readw(dev.DSPQ + JQS_wHead))); - - if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize)) - writew(0, dev.DSPQ + JQS_wHead); - else - writew(wTmp, dev.DSPQ + JQS_wHead); - } - return IRQ_HANDLED; -} - -static const struct file_operations dev_fileops = { - .owner = THIS_MODULE, - .read = dev_read, - .write = dev_write, - .unlocked_ioctl = dev_ioctl, - .open = dev_open, - .release = dev_release, - .llseek = noop_llseek, -}; - -static int reset_dsp(void) -{ - int timeout = 100; - - msnd_outb(HPDSPRESET_ON, dev.io + HP_DSPR); - mdelay(1); -#ifndef MSND_CLASSIC - dev.info = msnd_inb(dev.io + HP_INFO); -#endif - msnd_outb(HPDSPRESET_OFF, dev.io + HP_DSPR); - mdelay(1); - while (timeout-- > 0) { - if (msnd_inb(dev.io + HP_CVR) == HP_CVR_DEF) - return 0; - mdelay(1); - } - printk(KERN_ERR LOGNAME ": Cannot reset DSP\n"); - - return -EIO; -} - -static int __init probe_multisound(void) -{ -#ifndef MSND_CLASSIC - char *xv, *rev = NULL; - char *pin = "Pinnacle", *fiji = "Fiji"; - char *pinfiji = "Pinnacle/Fiji"; -#endif - - if (!request_region(dev.io, dev.numio, "probing")) { - printk(KERN_ERR LOGNAME ": I/O port conflict\n"); - return -ENODEV; - } - - if (reset_dsp() < 0) { - release_region(dev.io, dev.numio); - return -ENODEV; - } - -#ifdef MSND_CLASSIC - dev.name = "Classic/Tahiti/Monterey"; - printk(KERN_INFO LOGNAME ": %s, " -#else - switch (dev.info >> 4) { - case 0xf: xv = "<= 1.15"; break; - case 0x1: xv = "1.18/1.2"; break; - case 0x2: xv = "1.3"; break; - case 0x3: xv = "1.4"; break; - default: xv = "unknown"; break; - } - - switch (dev.info & 0x7) { - case 0x0: rev = "I"; dev.name = pin; break; - case 0x1: rev = "F"; dev.name = pin; break; - case 0x2: rev = "G"; dev.name = pin; break; - case 0x3: rev = "H"; dev.name = pin; break; - case 0x4: rev = "E"; dev.name = fiji; break; - case 0x5: rev = "C"; dev.name = fiji; break; - case 0x6: rev = "D"; dev.name = fiji; break; - case 0x7: - rev = "A-B (Fiji) or A-E (Pinnacle)"; - dev.name = pinfiji; - break; - } - printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, " -#endif /* MSND_CLASSIC */ - "I/O 0x%x-0x%x, IRQ %d, memory mapped to %p-%p\n", - dev.name, -#ifndef MSND_CLASSIC - rev, xv, -#endif - dev.io, dev.io + dev.numio - 1, - dev.irq, - dev.base, dev.base + 0x7fff); - - release_region(dev.io, dev.numio); - return 0; -} - -static int init_sma(void) -{ - static int initted; - WORD mastVolLeft, mastVolRight; - unsigned long flags; - -#ifdef MSND_CLASSIC - msnd_outb(dev.memid, dev.io + HP_MEMM); -#endif - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - if (initted) { - mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft); - mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight); - } else - mastVolLeft = mastVolRight = 0; - memset_io(dev.base, 0, 0x8000); - - /* Critical section: bank 1 access */ - spin_lock_irqsave(&dev.lock, flags); - msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS); - memset_io(dev.base, 0, 0x8000); - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - spin_unlock_irqrestore(&dev.lock, flags); - - dev.pwDSPQData = (dev.base + DSPQ_DATA_BUFF); - dev.pwMODQData = (dev.base + MODQ_DATA_BUFF); - dev.pwMIDQData = (dev.base + MIDQ_DATA_BUFF); - - /* Motorola 56k shared memory base */ - dev.SMA = dev.base + SMA_STRUCT_START; - - /* Digital audio play queue */ - dev.DAPQ = dev.base + DAPQ_OFFSET; - msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE); - - /* Digital audio record queue */ - dev.DARQ = dev.base + DARQ_OFFSET; - msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); - - /* MIDI out queue */ - dev.MODQ = dev.base + MODQ_OFFSET; - msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE); - - /* MIDI in queue */ - dev.MIDQ = dev.base + MIDQ_OFFSET; - msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE); - - /* DSP -> host message queue */ - dev.DSPQ = dev.base + DSPQ_OFFSET; - msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE); - - /* Setup some DSP values */ -#ifndef MSND_CLASSIC - writew(1, dev.SMA + SMA_wCurrPlayFormat); - writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize); - writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels); - writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate); -#endif - writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD); - writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft); - writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight); -#ifndef MSND_CLASSIC - writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch); - writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate); -#endif - writew(0x303, dev.SMA + SMA_wCurrInputTagBits); - - initted = 1; - - return 0; -} - -static int __init calibrate_adc(WORD srate) -{ - writew(srate, dev.SMA + SMA_wCalFreqAtoD); - if (dev.calibrate_signal == 0) - writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) - | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags); - else - writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) - & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags); - if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { - schedule_timeout_interruptible(HZ / 3); - return 0; - } - printk(KERN_WARNING LOGNAME ": ADC calibration failed\n"); - - return -EIO; -} - -static int upload_dsp_code(void) -{ - int ret = 0; - - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); -#ifndef HAVE_DSPCODEH - INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE); - if (!INITCODE) { - printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE); - return -EBUSY; - } - - PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE); - if (!PERMCODE) { - printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE); - vfree(INITCODE); - return -EBUSY; - } -#endif - memcpy_toio(dev.base, PERMCODE, PERMCODESIZE); - if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) { - printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n"); - ret = -ENODEV; - goto out; - } -#ifdef HAVE_DSPCODEH - printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n"); -#else - printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n"); -#endif - -out: -#ifndef HAVE_DSPCODEH - vfree(INITCODE); - vfree(PERMCODE); -#endif - - return ret; -} - -#ifdef MSND_CLASSIC -static void reset_proteus(void) -{ - msnd_outb(HPPRORESET_ON, dev.io + HP_PROR); - mdelay(TIME_PRO_RESET); - msnd_outb(HPPRORESET_OFF, dev.io + HP_PROR); - mdelay(TIME_PRO_RESET_DONE); -} -#endif - -static int initialize(void) -{ - int err, timeout; - -#ifdef MSND_CLASSIC - msnd_outb(HPWAITSTATE_0, dev.io + HP_WAIT); - msnd_outb(HPBITMODE_16, dev.io + HP_BITM); - - reset_proteus(); -#endif - if ((err = init_sma()) < 0) { - printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n"); - return err; - } - - if ((err = reset_dsp()) < 0) - return err; - - if ((err = upload_dsp_code()) < 0) { - printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n"); - return err; - } - - timeout = 200; - while (readw(dev.base)) { - mdelay(1); - if (!timeout--) { - printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n"); - return -EIO; - } - } - - mixer_setup(); - - return 0; -} - -static int dsp_full_reset(void) -{ - int rv; - - if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10) - return 0; - - set_bit(F_RESETTING, &dev.flags); - printk(KERN_INFO LOGNAME ": DSP reset\n"); - dsp_halt(NULL); /* Unconditionally halt */ - if ((rv = initialize())) - printk(KERN_WARNING LOGNAME ": DSP reset failed\n"); - force_recsrc(dev.recsrc); - dsp_open(NULL); - clear_bit(F_RESETTING, &dev.flags); - - return rv; -} - -static int __init attach_multisound(void) -{ - int err; - - if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); - return err; - } - if (request_region(dev.io, dev.numio, dev.name) == NULL) { - free_irq(dev.irq, &dev); - return -EBUSY; - } - - err = dsp_full_reset(); - if (err < 0) { - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return err; - } - - if ((err = msnd_register(&dev)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n"); - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return err; - } - - if ((dev.dsp_minor = register_sound_dsp(&dev_fileops, -1)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n"); - msnd_unregister(&dev); - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return dev.dsp_minor; - } - - if ((dev.mixer_minor = register_sound_mixer(&dev_fileops, -1)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n"); - unregister_sound_mixer(dev.mixer_minor); - msnd_unregister(&dev); - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return dev.mixer_minor; - } - - dev.ext_midi_dev = dev.hdr_midi_dev = -1; - - disable_irq(dev.irq); - calibrate_adc(dev.play_sample_rate); -#ifndef MSND_CLASSIC - force_recsrc(SOUND_MASK_IMIX); -#endif - - return 0; -} - -static void __exit unload_multisound(void) -{ - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - unregister_sound_mixer(dev.mixer_minor); - unregister_sound_dsp(dev.dsp_minor); - msnd_unregister(&dev); -} - -#ifndef MSND_CLASSIC - -/* Pinnacle/Fiji Logical Device Configuration */ - -static int __init msnd_write_cfg(int cfg, int reg, int value) -{ - msnd_outb(reg, cfg); - msnd_outb(value, cfg + 1); - if (value != msnd_inb(cfg + 1)) { - printk(KERN_ERR LOGNAME ": msnd_write_cfg: I/O error\n"); - return -EIO; - } - return 0; -} - -static int __init msnd_write_cfg_io0(int cfg, int num, WORD io) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io))) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_io1(int cfg, int num, WORD io) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io))) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_irq(int cfg, int num, WORD irq) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE)) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_mem(int cfg, int num, int mem) -{ - WORD wmem; - - mem >>= 8; - mem &= 0xfff; - wmem = (WORD)mem; - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem))) - return -EIO; - if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT))) - return -EIO; - return 0; -} - -static int __init msnd_activate_logical(int cfg, int num) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE)) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg_io0(cfg, num, io0)) - return -EIO; - if (msnd_write_cfg_io1(cfg, num, io1)) - return -EIO; - if (msnd_write_cfg_irq(cfg, num, irq)) - return -EIO; - if (msnd_write_cfg_mem(cfg, num, mem)) - return -EIO; - if (msnd_activate_logical(cfg, num)) - return -EIO; - return 0; -} - -typedef struct msnd_pinnacle_cfg_device { - WORD io0, io1, irq; - int mem; -} msnd_pinnacle_cfg_t[4]; - -static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device) -{ - int i; - - /* Reset devices if told to */ - if (reset) { - printk(KERN_INFO LOGNAME ": Resetting all devices\n"); - for (i = 0; i < 4; ++i) - if (msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0)) - return -EIO; - } - - /* Configure specified devices */ - for (i = 0; i < 4; ++i) { - - switch (i) { - case 0: /* DSP */ - if (!(device[i].io0 && device[i].irq && device[i].mem)) - continue; - break; - case 1: /* MPU */ - if (!(device[i].io0 && device[i].irq)) - continue; - printk(KERN_INFO LOGNAME - ": Configuring MPU to I/O 0x%x IRQ %d\n", - device[i].io0, device[i].irq); - break; - case 2: /* IDE */ - if (!(device[i].io0 && device[i].io1 && device[i].irq)) - continue; - printk(KERN_INFO LOGNAME - ": Configuring IDE to I/O 0x%x, 0x%x IRQ %d\n", - device[i].io0, device[i].io1, device[i].irq); - break; - case 3: /* Joystick */ - if (!(device[i].io0)) - continue; - printk(KERN_INFO LOGNAME - ": Configuring joystick to I/O 0x%x\n", - device[i].io0); - break; - } - - /* Configure the device */ - if (msnd_write_cfg_logical(cfg, i, device[i].io0, device[i].io1, device[i].irq, device[i].mem)) - return -EIO; - } - - return 0; -} -#endif - -#ifdef MODULE -MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>"); -MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver"); -MODULE_LICENSE("GPL"); - -static int io __initdata = -1; -static int irq __initdata = -1; -static int mem __initdata = -1; -static int write_ndelay __initdata = -1; - -#ifndef MSND_CLASSIC -/* Pinnacle/Fiji non-PnP Config Port */ -static int cfg __initdata = -1; - -/* Extra Peripheral Configuration */ -static int reset __initdata = 0; -static int mpu_io __initdata = 0; -static int mpu_irq __initdata = 0; -static int ide_io0 __initdata = 0; -static int ide_io1 __initdata = 0; -static int ide_irq __initdata = 0; -static int joystick_io __initdata = 0; - -/* If we have the digital daugherboard... */ -static bool digital __initdata = false; -#endif - -static int fifosize __initdata = DEFFIFOSIZE; -static int calibrate_signal __initdata = 0; - -#else /* not a module */ - -static int write_ndelay __initdata = -1; - -#ifdef MSND_CLASSIC -static int io __initdata = CONFIG_MSNDCLAS_IO; -static int irq __initdata = CONFIG_MSNDCLAS_IRQ; -static int mem __initdata = CONFIG_MSNDCLAS_MEM; -#else /* Pinnacle/Fiji */ - -static int io __initdata = CONFIG_MSNDPIN_IO; -static int irq __initdata = CONFIG_MSNDPIN_IRQ; -static int mem __initdata = CONFIG_MSNDPIN_MEM; - -/* Pinnacle/Fiji non-PnP Config Port */ -#ifdef CONFIG_MSNDPIN_NONPNP -# ifndef CONFIG_MSNDPIN_CFG -# define CONFIG_MSNDPIN_CFG 0x250 -# endif -#else -# ifdef CONFIG_MSNDPIN_CFG -# undef CONFIG_MSNDPIN_CFG -# endif -# define CONFIG_MSNDPIN_CFG -1 -#endif -static int cfg __initdata = CONFIG_MSNDPIN_CFG; -/* If not a module, we don't need to bother with reset=1 */ -static int reset; - -/* Extra Peripheral Configuration (Default: Disable) */ -#ifndef CONFIG_MSNDPIN_MPU_IO -# define CONFIG_MSNDPIN_MPU_IO 0 -#endif -static int mpu_io __initdata = CONFIG_MSNDPIN_MPU_IO; - -#ifndef CONFIG_MSNDPIN_MPU_IRQ -# define CONFIG_MSNDPIN_MPU_IRQ 0 -#endif -static int mpu_irq __initdata = CONFIG_MSNDPIN_MPU_IRQ; - -#ifndef CONFIG_MSNDPIN_IDE_IO0 -# define CONFIG_MSNDPIN_IDE_IO0 0 -#endif -static int ide_io0 __initdata = CONFIG_MSNDPIN_IDE_IO0; - -#ifndef CONFIG_MSNDPIN_IDE_IO1 -# define CONFIG_MSNDPIN_IDE_IO1 0 -#endif -static int ide_io1 __initdata = CONFIG_MSNDPIN_IDE_IO1; - -#ifndef CONFIG_MSNDPIN_IDE_IRQ -# define CONFIG_MSNDPIN_IDE_IRQ 0 -#endif -static int ide_irq __initdata = CONFIG_MSNDPIN_IDE_IRQ; - -#ifndef CONFIG_MSNDPIN_JOYSTICK_IO -# define CONFIG_MSNDPIN_JOYSTICK_IO 0 -#endif -static int joystick_io __initdata = CONFIG_MSNDPIN_JOYSTICK_IO; - -/* Have SPDIF (Digital) Daughterboard */ -#ifndef CONFIG_MSNDPIN_DIGITAL -# define CONFIG_MSNDPIN_DIGITAL 0 -#endif -static bool digital __initdata = CONFIG_MSNDPIN_DIGITAL; - -#endif /* MSND_CLASSIC */ - -#ifndef CONFIG_MSND_FIFOSIZE -# define CONFIG_MSND_FIFOSIZE DEFFIFOSIZE -#endif -static int fifosize __initdata = CONFIG_MSND_FIFOSIZE; - -#ifndef CONFIG_MSND_CALSIGNAL -# define CONFIG_MSND_CALSIGNAL 0 -#endif -static int -calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL; -#endif /* MODULE */ - -module_param_hw (io, int, ioport, 0); -module_param_hw (irq, int, irq, 0); -module_param_hw (mem, int, iomem, 0); -module_param (write_ndelay, int, 0); -module_param (fifosize, int, 0); -module_param (calibrate_signal, int, 0); -#ifndef MSND_CLASSIC -module_param (digital, bool, 0); -module_param_hw (cfg, int, ioport, 0); -module_param (reset, int, 0); -module_param_hw (mpu_io, int, ioport, 0); -module_param_hw (mpu_irq, int, irq, 0); -module_param_hw (ide_io0, int, ioport, 0); -module_param_hw (ide_io1, int, ioport, 0); -module_param_hw (ide_irq, int, irq, 0); -module_param_hw (joystick_io, int, ioport, 0); -#endif - -static int __init msnd_init(void) -{ - int err; -#ifndef MSND_CLASSIC - static msnd_pinnacle_cfg_t pinnacle_devs; -#endif /* MSND_CLASSIC */ - - printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version " - VERSION ", Copyright (C) 1998 Andrew Veliath\n"); - - if (io == -1 || irq == -1 || mem == -1) - printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n"); - -#ifdef MSND_CLASSIC - if (io == -1 || - !(io == 0x290 || - io == 0x260 || - io == 0x250 || - io == 0x240 || - io == 0x230 || - io == 0x220 || - io == 0x210 || - io == 0x3e0)) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n"); - return -EINVAL; - } -#else - if (io == -1 || - io < 0x100 || - io > 0x3e0 || - (io % 0x10) != 0) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must within the range 0x100 to 0x3E0 and must be evenly divisible by 0x10\n"); - return -EINVAL; - } -#endif /* MSND_CLASSIC */ - - if (irq == -1 || - !(irq == 5 || - irq == 7 || - irq == 9 || - irq == 10 || - irq == 11 || - irq == 12)) { - printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n"); - return -EINVAL; - } - - if (mem == -1 || - !(mem == 0xb0000 || - mem == 0xc8000 || - mem == 0xd0000 || - mem == 0xd8000 || - mem == 0xe0000 || - mem == 0xe8000)) { - printk(KERN_ERR LOGNAME ": \"mem\" - must be set to " - "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); - return -EINVAL; - } - -#ifdef MSND_CLASSIC - switch (irq) { - case 5: dev.irqid = HPIRQ_5; break; - case 7: dev.irqid = HPIRQ_7; break; - case 9: dev.irqid = HPIRQ_9; break; - case 10: dev.irqid = HPIRQ_10; break; - case 11: dev.irqid = HPIRQ_11; break; - case 12: dev.irqid = HPIRQ_12; break; - } - - switch (mem) { - case 0xb0000: dev.memid = HPMEM_B000; break; - case 0xc8000: dev.memid = HPMEM_C800; break; - case 0xd0000: dev.memid = HPMEM_D000; break; - case 0xd8000: dev.memid = HPMEM_D800; break; - case 0xe0000: dev.memid = HPMEM_E000; break; - case 0xe8000: dev.memid = HPMEM_E800; break; - } -#else - if (cfg == -1) { - printk(KERN_INFO LOGNAME ": Assuming PnP mode\n"); - } else if (cfg != 0x250 && cfg != 0x260 && cfg != 0x270) { - printk(KERN_INFO LOGNAME ": Config port must be 0x250, 0x260 or 0x270 (or unspecified for PnP mode)\n"); - return -EINVAL; - } else { - printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%x\n", cfg); - - /* DSP */ - pinnacle_devs[0].io0 = io; - pinnacle_devs[0].irq = irq; - pinnacle_devs[0].mem = mem; - - /* The following are Pinnacle specific */ - - /* MPU */ - pinnacle_devs[1].io0 = mpu_io; - pinnacle_devs[1].irq = mpu_irq; - - /* IDE */ - pinnacle_devs[2].io0 = ide_io0; - pinnacle_devs[2].io1 = ide_io1; - pinnacle_devs[2].irq = ide_irq; - - /* Joystick */ - pinnacle_devs[3].io0 = joystick_io; - - if (!request_region(cfg, 2, "Pinnacle/Fiji Config")) { - printk(KERN_ERR LOGNAME ": Config port 0x%x conflict\n", cfg); - return -EIO; - } - - if (msnd_pinnacle_cfg_devices(cfg, reset, pinnacle_devs)) { - printk(KERN_ERR LOGNAME ": Device configuration error\n"); - release_region(cfg, 2); - return -EIO; - } - release_region(cfg, 2); - } -#endif /* MSND_CLASSIC */ - - if (fifosize < 16) - fifosize = 16; - - if (fifosize > 1024) - fifosize = 1024; - - set_default_audio_parameters(); -#ifdef MSND_CLASSIC - dev.type = msndClassic; -#else - dev.type = msndPinnacle; -#endif - dev.io = io; - dev.numio = DSP_NUMIO; - dev.irq = irq; - dev.base = ioremap(mem, 0x8000); - dev.fifosize = fifosize * 1024; - dev.calibrate_signal = calibrate_signal ? 1 : 0; - dev.recsrc = 0; - dev.dspq_data_buff = DSPQ_DATA_BUFF; - dev.dspq_buff_size = DSPQ_BUFF_SIZE; - if (write_ndelay == -1) - write_ndelay = CONFIG_MSND_WRITE_NDELAY; - if (write_ndelay) - clear_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); - else - set_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); -#ifndef MSND_CLASSIC - if (digital) - set_bit(F_HAVEDIGITAL, &dev.flags); -#endif - init_waitqueue_head(&dev.writeblock); - init_waitqueue_head(&dev.readblock); - init_waitqueue_head(&dev.writeflush); - msnd_fifo_init(&dev.DAPF); - msnd_fifo_init(&dev.DARF); - spin_lock_init(&dev.lock); - printk(KERN_INFO LOGNAME ": %u byte audio FIFOs (x2)\n", dev.fifosize); - if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n"); - return err; - } - - if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n"); - msnd_fifo_free(&dev.DAPF); - return err; - } - - if ((err = probe_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Probe failed\n"); - msnd_fifo_free(&dev.DAPF); - msnd_fifo_free(&dev.DARF); - return err; - } - - if ((err = attach_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Attach failed\n"); - msnd_fifo_free(&dev.DAPF); - msnd_fifo_free(&dev.DARF); - return err; - } - - return 0; -} - -static void __exit msdn_cleanup(void) -{ - unload_multisound(); - msnd_fifo_free(&dev.DAPF); - msnd_fifo_free(&dev.DARF); -} - -module_init(msnd_init); -module_exit(msdn_cleanup); diff --git a/sound/oss/msnd_pinnacle.h b/sound/oss/msnd_pinnacle.h deleted file mode 100644 index c18d66cbbe3f..000000000000 --- a/sound/oss/msnd_pinnacle.h +++ /dev/null @@ -1,246 +0,0 @@ -/********************************************************************* - * - * msnd_pinnacle.h - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Some parts of this header file were derived from the Turtle Beach - * MultiSound Driver Development Kit. - * - * Copyright (C) 1998 Andrew Veliath - * Copyright (C) 1993 Turtle Beach Systems, Inc. - * - * 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 __MSND_PINNACLE_H -#define __MSND_PINNACLE_H - - -#define DSP_NUMIO 0x08 - -#define IREG_LOGDEVICE 0x07 -#define IREG_ACTIVATE 0x30 -#define LD_ACTIVATE 0x01 -#define LD_DISACTIVATE 0x00 -#define IREG_EECONTROL 0x3F -#define IREG_MEMBASEHI 0x40 -#define IREG_MEMBASELO 0x41 -#define IREG_MEMCONTROL 0x42 -#define IREG_MEMRANGEHI 0x43 -#define IREG_MEMRANGELO 0x44 -#define MEMTYPE_8BIT 0x00 -#define MEMTYPE_16BIT 0x02 -#define MEMTYPE_RANGE 0x00 -#define MEMTYPE_HIADDR 0x01 -#define IREG_IO0_BASEHI 0x60 -#define IREG_IO0_BASELO 0x61 -#define IREG_IO1_BASEHI 0x62 -#define IREG_IO1_BASELO 0x63 -#define IREG_IRQ_NUMBER 0x70 -#define IREG_IRQ_TYPE 0x71 -#define IRQTYPE_HIGH 0x02 -#define IRQTYPE_LOW 0x00 -#define IRQTYPE_LEVEL 0x01 -#define IRQTYPE_EDGE 0x00 - -#define HP_DSPR 0x04 -#define HP_BLKS 0x04 - -#define HPDSPRESET_OFF 2 -#define HPDSPRESET_ON 0 - -#define HPBLKSEL_0 2 -#define HPBLKSEL_1 3 - -#define HIMT_DAT_OFF 0x03 - -#define HIDSP_PLAY_UNDER 0x00 -#define HIDSP_INT_PLAY_UNDER 0x01 -#define HIDSP_SSI_TX_UNDER 0x02 -#define HIDSP_RECQ_OVERFLOW 0x08 -#define HIDSP_INT_RECORD_OVER 0x09 -#define HIDSP_SSI_RX_OVERFLOW 0x0a - -#define HIDSP_MIDI_IN_OVER 0x10 - -#define HIDSP_MIDI_FRAME_ERR 0x11 -#define HIDSP_MIDI_PARITY_ERR 0x12 -#define HIDSP_MIDI_OVERRUN_ERR 0x13 - -#define HIDSP_INPUT_CLIPPING 0x20 -#define HIDSP_MIX_CLIPPING 0x30 -#define HIDSP_DAT_IN_OFF 0x21 - -#define HDEXAR_SET_ANA_IN 0 -#define HDEXAR_CLEAR_PEAKS 1 -#define HDEXAR_IN_SET_POTS 2 -#define HDEXAR_AUX_SET_POTS 3 -#define HDEXAR_CAL_A_TO_D 4 -#define HDEXAR_RD_EXT_DSP_BITS 5 - -#define HDEXAR_SET_SYNTH_IN 4 -#define HDEXAR_READ_DAT_IN 5 -#define HDEXAR_MIC_SET_POTS 6 -#define HDEXAR_SET_DAT_IN 7 - -#define HDEXAR_SET_SYNTH_48 8 -#define HDEXAR_SET_SYNTH_44 9 - -#define TIME_PRO_RESET_DONE 0x028A -#define TIME_PRO_SYSEX 0x001E -#define TIME_PRO_RESET 0x0032 - -#define AGND 0x01 -#define SIGNAL 0x02 - -#define EXT_DSP_BIT_DCAL 0x0001 -#define EXT_DSP_BIT_MIDI_CON 0x0002 - -#define BUFFSIZE 0x8000 -#define HOSTQ_SIZE 0x40 - -#define SRAM_CNTL_START 0x7F00 -#define SMA_STRUCT_START 0x7F40 - -#define DAP_BUFF_SIZE 0x2400 -#define DAR_BUFF_SIZE 0x2000 - -#define DAPQ_STRUCT_SIZE 0x10 -#define DARQ_STRUCT_SIZE 0x10 -#define DAPQ_BUFF_SIZE (3 * 0x10) -#define DARQ_BUFF_SIZE (3 * 0x10) -#define MODQ_BUFF_SIZE 0x400 -#define MIDQ_BUFF_SIZE 0x800 -#define DSPQ_BUFF_SIZE 0x5A0 - -#define DAPQ_DATA_BUFF 0x6C00 -#define DARQ_DATA_BUFF 0x6C30 -#define MODQ_DATA_BUFF 0x6C60 -#define MIDQ_DATA_BUFF 0x7060 -#define DSPQ_DATA_BUFF 0x7860 - -#define DAPQ_OFFSET SRAM_CNTL_START -#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) -#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) -#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) -#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) - -#define MOP_WAVEHDR 0 -#define MOP_EXTOUT 1 -#define MOP_HWINIT 0xfe -#define MOP_NONE 0xff -#define MOP_MAX 1 - -#define MIP_EXTIN 0 -#define MIP_WAVEHDR 1 -#define MIP_HWINIT 0xfe -#define MIP_MAX 1 - -/* Pinnacle/Fiji SMA Common Data */ -#define SMA_wCurrPlayBytes 0x0000 -#define SMA_wCurrRecordBytes 0x0002 -#define SMA_wCurrPlayVolLeft 0x0004 -#define SMA_wCurrPlayVolRight 0x0006 -#define SMA_wCurrInVolLeft 0x0008 -#define SMA_wCurrInVolRight 0x000a -#define SMA_wCurrMHdrVolLeft 0x000c -#define SMA_wCurrMHdrVolRight 0x000e -#define SMA_dwCurrPlayPitch 0x0010 -#define SMA_dwCurrPlayRate 0x0014 -#define SMA_wCurrMIDIIOPatch 0x0018 -#define SMA_wCurrPlayFormat 0x001a -#define SMA_wCurrPlaySampleSize 0x001c -#define SMA_wCurrPlayChannels 0x001e -#define SMA_wCurrPlaySampleRate 0x0020 -#define SMA_wCurrRecordFormat 0x0022 -#define SMA_wCurrRecordSampleSize 0x0024 -#define SMA_wCurrRecordChannels 0x0026 -#define SMA_wCurrRecordSampleRate 0x0028 -#define SMA_wCurrDSPStatusFlags 0x002a -#define SMA_wCurrHostStatusFlags 0x002c -#define SMA_wCurrInputTagBits 0x002e -#define SMA_wCurrLeftPeak 0x0030 -#define SMA_wCurrRightPeak 0x0032 -#define SMA_bMicPotPosLeft 0x0034 -#define SMA_bMicPotPosRight 0x0035 -#define SMA_bMicPotMaxLeft 0x0036 -#define SMA_bMicPotMaxRight 0x0037 -#define SMA_bInPotPosLeft 0x0038 -#define SMA_bInPotPosRight 0x0039 -#define SMA_bAuxPotPosLeft 0x003a -#define SMA_bAuxPotPosRight 0x003b -#define SMA_bInPotMaxLeft 0x003c -#define SMA_bInPotMaxRight 0x003d -#define SMA_bAuxPotMaxLeft 0x003e -#define SMA_bAuxPotMaxRight 0x003f -#define SMA_bInPotMaxMethod 0x0040 -#define SMA_bAuxPotMaxMethod 0x0041 -#define SMA_wCurrMastVolLeft 0x0042 -#define SMA_wCurrMastVolRight 0x0044 -#define SMA_wCalFreqAtoD 0x0046 -#define SMA_wCurrAuxVolLeft 0x0048 -#define SMA_wCurrAuxVolRight 0x004a -#define SMA_wCurrPlay1VolLeft 0x004c -#define SMA_wCurrPlay1VolRight 0x004e -#define SMA_wCurrPlay2VolLeft 0x0050 -#define SMA_wCurrPlay2VolRight 0x0052 -#define SMA_wCurrPlay3VolLeft 0x0054 -#define SMA_wCurrPlay3VolRight 0x0056 -#define SMA_wCurrPlay4VolLeft 0x0058 -#define SMA_wCurrPlay4VolRight 0x005a -#define SMA_wCurrPlay1PeakLeft 0x005c -#define SMA_wCurrPlay1PeakRight 0x005e -#define SMA_wCurrPlay2PeakLeft 0x0060 -#define SMA_wCurrPlay2PeakRight 0x0062 -#define SMA_wCurrPlay3PeakLeft 0x0064 -#define SMA_wCurrPlay3PeakRight 0x0066 -#define SMA_wCurrPlay4PeakLeft 0x0068 -#define SMA_wCurrPlay4PeakRight 0x006a -#define SMA_wCurrPlayPeakLeft 0x006c -#define SMA_wCurrPlayPeakRight 0x006e -#define SMA_wCurrDATSR 0x0070 -#define SMA_wCurrDATRXCHNL 0x0072 -#define SMA_wCurrDATTXCHNL 0x0074 -#define SMA_wCurrDATRXRate 0x0076 -#define SMA_dwDSPPlayCount 0x0078 -#define SMA__size 0x007c - -#ifdef HAVE_DSPCODEH -# include "pndsperm.c" -# include "pndspini.c" -# define PERMCODE pndsperm -# define INITCODE pndspini -# define PERMCODESIZE sizeof(pndsperm) -# define INITCODESIZE sizeof(pndspini) -#else -# ifndef CONFIG_MSNDPIN_INIT_FILE -# define CONFIG_MSNDPIN_INIT_FILE \ - "/etc/sound/pndspini.bin" -# endif -# ifndef CONFIG_MSNDPIN_PERM_FILE -# define CONFIG_MSNDPIN_PERM_FILE \ - "/etc/sound/pndsperm.bin" -# endif -# define PERMCODEFILE CONFIG_MSNDPIN_PERM_FILE -# define INITCODEFILE CONFIG_MSNDPIN_INIT_FILE -# define PERMCODE dspini -# define INITCODE permini -# define PERMCODESIZE sizeof_dspini -# define INITCODESIZE sizeof_permini -#endif -#define LONGNAME "MultiSound (Pinnacle/Fiji)" - -#endif /* __MSND_PINNACLE_H */ diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c deleted file mode 100644 index f0f5b5be6314..000000000000 --- a/sound/oss/opl3.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * sound/oss/opl3.c - * - * A low level driver for Yamaha YM3812 and OPL-3 -chips - * - * - * 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. - * - * - * Changes - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, fixed sound_mem allocs. - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo get rid of check_region, use request_region for - * OPL4, release it on exit, some cleanups. - * - * Status - * Believed to work. Badly needs rewriting a bit to support multiple - * OPL3 devices. - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/delay.h> - -/* - * Major improvements to the FM handling 30AUG92 by Rob Hooft, - * hooft@chem.ruu.nl - */ - -#include "sound_config.h" - -#include "opl3_hw.h" - -#define MAX_VOICE 18 -#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 */ -}; - -struct opl_devinfo -{ - 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 sbi_instrument i_map[SBFM_MAXINSTR]; - struct sbi_instrument *act_i[MAX_VOICE]; - - struct synth_info fm_info; - - int busy; - int model; - unsigned char cmask; - - int is_opl4; -}; - -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 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; -} - -static int opl3_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - struct sbi_instrument ins; - - switch (cmd) { - case SNDCTL_FM_LOAD_INSTR: - printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); - if (copy_from_user(&ins, arg, sizeof(ins))) - return -EFAULT; - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { - printk(KERN_WARNING "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; - if (copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info))) - return -EFAULT; - 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; - } -} - -static int opl3_detect(int ioaddr) -{ - /* - * 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) - { - printk(KERN_ERR "opl3: Only one OPL3 supported.\n"); - return 0; - } - - devc = kzalloc(sizeof(*devc), GFP_KERNEL); - - if (devc == NULL) - { - printk(KERN_ERR "opl3: Can't allocate memory for the device control " - "structure \n "); - return 0; - } - - strcpy(devc->fm_info.name, "OPL2"); - - if (!request_region(ioaddr, 4, devc->fm_info.name)) { - printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr); - goto cleanup_devc; - } - - 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) - { - MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature)); - goto cleanup_region; - } - - 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 (request_region(ioaddr - 8, 2, "OPL4")) /* OPL4 port was free */ - { - int tmp; - - outb((0x02), ioaddr - 8); /* Select OPL4 ID register */ - udelay(10); - tmp = inb(ioaddr - 7); /* Read it */ - udelay(10); - - if (tmp == 0x20) /* OPL4 should return 0x20 here */ - { - detected_model = 4; - outb((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ - udelay(10); - outb((0x1B), ioaddr - 7); /* Write value */ - udelay(10); - } - else - { /* release OPL4 port */ - release_region(ioaddr - 8, 2); - 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 - */ - - opl3_command(ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl3_command(ioaddr, PERCOSSION_REGISTER, 0x00); /* - * Melodic mode. - */ - return 1; -cleanup_region: - release_region(ioaddr, 4); -cleanup_devc: - kfree(devc); - devc = NULL; - return 0; -} - -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; - - devc->v_alloc->map[voice] = 0; - - map = &pv_map[devc->lv_map[voice]]; - - 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; -} - -#define HIHAT 0 -#define CYMBAL 1 -#define TOMTOM 2 -#define SNARE 3 -#define BDRUM 4 -#define UNDEFINED TOMTOM -#define DEFAULT TOMTOM - -static int store_instr(int instr_no, struct sbi_instrument *instr) -{ - 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) -{ - 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; -} - -/* - * The next table looks magical, but it certainly is not. Its values have - * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception - * for i=0. This log-table converts a linear volume-scaling (0..127) to a - * logarithmic scaling as present in the FM-synthesizer chips. so : Volume - * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative - * 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) -{ - int level = (~*regbyte & 0x3f); - - if (main_vol > 127) - main_vol = 127; - volume = (volume * main_vol) / 127; - - if (level) - level += fm_volume_table[volume]; - - if (level > 0x3f) - level = 0x3f; - if (level < 0) - level = 0; - - *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); -} - -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; - - map = &pv_map[devc->lv_map[voice]]; - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[0]; - - if (instr->channel < 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)) - { - 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 - { /* - * 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); - } -} - -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; - - if (voice < 0 || voice >= devc->nr_voice) - return 0; - - map = &pv_map[devc->lv_map[voice]]; - pan = devc->voc[voice].panning; - - if (map->voice_mode == 0) - return 0; - - 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 - */ - - 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); /* - * Note - * off - */ - - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[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; /* - * Cannot play - */ - - voice_mode = map->voice_mode; - - if (voice_mode == 4) - { - int voice_shift; - - 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); - } - else - { - devc->cmask |= (1 << voice_shift); - } - - 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; /* - * 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; - - /* - * 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_to_fnum(freq, &block, &fnum); - - /* - * Play note - */ - - data = fnum & 0xff; /* - * Least significant bits of fnumber - */ - 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); - - return 0; -} - -static void freq_to_fnum (int freq, int *block, int *fnum) -{ - 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 - */ - - f = freq; - - octave = 5; - - if (f == 0) - octave = 0; - else if (f < 261) - { - while (f < 261) - { - octave--; - f <<= 1; - } - } - else if (f > 493) - { - while (f > 493) - { - octave++; - f >>= 1; - } - } - - if (octave > 7) - octave = 7; - - *fnum = freq * (1 << (20 - octave)) / 49716; - *block = octave; -} - -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) - udelay(10); - else - for (i = 0; i < 2; i++) - inb(io_addr); - - outb(((unsigned char) (val & 0xff)), io_addr + 1); - - if (devc->model != 2) - udelay(30); - 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); - - 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); - - opl3_command(pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); - } - - 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) -{ - int i; - - if (devc->busy) - return -EBUSY; - devc->busy = 1; - - 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; - } - - devc->cmask = 0x00; /* - * Just 2 OP mode - */ - if (devc->model == 2) - opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - return 0; -} - -static void opl3_close(int dev) -{ - 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; - - opl3_reset(dev); -} - -static void opl3_hw_control(int dev, unsigned char *event) -{ -} - -static int opl3_load_patch(int dev, int format, const char __user *addr, - int count, int pmgr_flag) -{ - struct sbi_instrument ins; - - if (count <sizeof(ins)) - { - printk(KERN_WARNING "FM Error: Patch record too short\n"); - return -EINVAL; - } - - if (copy_from_user(&ins, addr, sizeof(ins))) - return -EFAULT; - - 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); -} - -static void opl3_panning(int dev, int voice, int value) -{ - - if (voice < 0 || voice >= devc->nr_voice) - return; - - devc->voc[voice].panning = value; -} - -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);} - -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; - - map = &pv_map[devc->lv_map[voice]]; - - if (map->voice_mode == 0) - return; - - /* - * Adjust the amount of vibrato depending the pressure - */ - - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[0]; - - 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 - { - 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) -{ - unsigned char data; - int block, fnum, freq; - struct physical_voice_info *map; - - map = &pv_map[devc->lv_map[voice]]; - - 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 - */ - - 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); - - data = fnum & 0xff; /* - * Least significant bits of fnumber - */ - 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); -} - -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; - } -} - -static void opl3_bender(int dev, int voice, int value) -{ - if (voice < 0 || voice >= devc->nr_voice) - return; - - bend_pitch(dev, voice, value - 8192); -} - -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) - { - 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; - } - - /* - * Insert some kind of priority mechanism here. - */ - - 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. */ -} - -static void opl3_setup_voice(int dev, int voice, int chn) -{ - struct channel_info *info; - - if (voice < 0 || voice >= devc->nr_voice) - return; - - if (chn < 0 || chn > 15) - return; - - info = &synth_devs[dev]->chn_info[chn]; - - 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; -} - -static struct synth_operations opl3_operations = -{ - .owner = THIS_MODULE, - .id = "OPL", - .info = NULL, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_FM, - .synth_subtype = FM_TYPE_ADLIB, - .open = opl3_open, - .close = opl3_close, - .ioctl = opl3_ioctl, - .kill_note = opl3_kill_note, - .start_note = opl3_start_note, - .set_instr = opl3_set_instr, - .reset = opl3_reset, - .hw_control = opl3_hw_control, - .load_patch = opl3_load_patch, - .aftertouch = opl3_aftertouch, - .controller = opl3_controller, - .panning = opl3_panning, - .volume_method = opl3_volume_method, - .bender = opl3_bender, - .alloc_voice = opl3_alloc_voice, - .setup_voice = opl3_setup_voice -}; - -static int opl3_init(int ioaddr, struct module *owner) -{ - int i; - int me; - - if (devc == NULL) - { - printk(KERN_ERR "opl3: Device control structure not initialized.\n"); - return -1; - } - - if ((me = sound_alloc_synthdev()) == -1) - { - printk(KERN_WARNING "opl3: Too many synthesizers\n"); - return -1; - } - - devc->nr_voice = 9; - - 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; - - if (owner) - synth_devs[me]->owner = owner; - - sequencer_init(); - devc->v_alloc = &opl3_operations.alloc; - devc->chn_info = &opl3_operations.chn_info[0]; - - if (devc->model == 2) - { - if (devc->is_opl4) - strcpy(devc->fm_info.name, "Yamaha OPL4/OPL3 FM"); - else - strcpy(devc->fm_info.name, "Yamaha OPL3"); - - 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; - - 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 - { - strcpy(devc->fm_info.name, "Yamaha OPL2"); - 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; - } - conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1); - - for (i = 0; i < SBFM_MAXINSTR; i++) - devc->i_map[i].channel = -1; - - return me; -} - -static int me; - -static int io = -1; - -module_param_hw(io, int, ioport, 0); - -static int __init init_opl3 (void) -{ - printk(KERN_INFO "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)) - { - return -ENODEV; - } - - me = opl3_init(io, THIS_MODULE); - } - - return 0; -} - -static void __exit cleanup_opl3(void) -{ - if (devc && io != -1) - { - if (devc->base) { - release_region(devc->base,4); - if (devc->is_opl4) - release_region(devc->base - 8, 2); - } - kfree(devc); - devc = NULL; - sound_unload_synthdev(me); - } -} - -module_init(init_opl3); -module_exit(cleanup_opl3); - -#ifndef MODULE -static int __init setup_opl3(char *str) -{ - /* io */ - int ints[2]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - - return 1; -} - -__setup("opl3=", setup_opl3); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/opl3_hw.h b/sound/oss/opl3_hw.h deleted file mode 100644 index 8b11c893e869..000000000000 --- a/sound/oss/opl3_hw.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * opl3_hw.h - Definitions of the OPL-3 registers - * - * - * 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. - * - * - * The OPL-3 mode is switched on by writing 0x01, to the offset 5 - * of the right side. - * - * Another special register at the right side is at offset 4. It contains - * a bit mask defining which voices are used as 4 OP voices. - * - * The percussive mode is implemented in the left side only. - * - * With the above exceptions the both sides can be operated independently. - * - * A 4 OP voice can be created by setting the corresponding - * bit at offset 4 of the right side. - * - * For example setting the rightmost bit (0x01) changes the - * first voice on the right side to the 4 OP mode. The fourth - * voice is made inaccessible. - * - * If a voice is set to the 2 OP mode, it works like 2 OP modes - * of the original YM3812 (AdLib). In addition the voice can - * be connected the left, right or both stereo channels. It can - * even be left unconnected. This works with 4 OP voices also. - * - * The stereo connection bits are located in the FEEDBACK_CONNECTION - * register of the voice (0xC0-0xC8). In 4 OP voices these bits are - * in the second half of the voice. - */ - -/* - * Register numbers for the global registers - */ - -#define TEST_REGISTER 0x01 -#define ENABLE_WAVE_SELECT 0x20 - -#define TIMER1_REGISTER 0x02 -#define TIMER2_REGISTER 0x03 -#define TIMER_CONTROL_REGISTER 0x04 /* Left side */ -#define IRQ_RESET 0x80 -#define TIMER1_MASK 0x40 -#define TIMER2_MASK 0x20 -#define TIMER1_START 0x01 -#define TIMER2_START 0x02 - -#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */ -#define RIGHT_4OP_0 0x01 -#define RIGHT_4OP_1 0x02 -#define RIGHT_4OP_2 0x04 -#define LEFT_4OP_0 0x08 -#define LEFT_4OP_1 0x10 -#define LEFT_4OP_2 0x20 - -#define OPL3_MODE_REGISTER 0x05 /* Right side */ -#define OPL3_ENABLE 0x01 -#define OPL4_ENABLE 0x02 - -#define KBD_SPLIT_REGISTER 0x08 /* Left side */ -#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ -#define KEYBOARD_SPLIT 0x40 - -#define PERCOSSION_REGISTER 0xbd /* Left side only */ -#define TREMOLO_DEPTH 0x80 -#define VIBRATO_DEPTH 0x40 -#define PERCOSSION_ENABLE 0x20 -#define BASSDRUM_ON 0x10 -#define SNAREDRUM_ON 0x08 -#define TOMTOM_ON 0x04 -#define CYMBAL_ON 0x02 -#define HIHAT_ON 0x01 - -/* - * Offsets to the register banks for operators. To get the - * register number just add the operator offset to the bank offset - * - * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) - */ -#define AM_VIB 0x20 -#define TREMOLO_ON 0x80 -#define VIBRATO_ON 0x40 -#define SUSTAIN_ON 0x20 -#define KSR 0x10 /* Key scaling rate */ -#define MULTIPLE_MASK 0x0f /* Frequency multiplier */ - - /* - * KSL/Total level (0x40 to 0x55) - */ -#define KSL_LEVEL 0x40 -#define KSL_MASK 0xc0 /* Envelope scaling bits */ -#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ - -/* - * Attack / Decay rate (0x60 to 0x75) - */ -#define ATTACK_DECAY 0x60 -#define ATTACK_MASK 0xf0 -#define DECAY_MASK 0x0f - -/* - * Sustain level / Release rate (0x80 to 0x95) - */ -#define SUSTAIN_RELEASE 0x80 -#define SUSTAIN_MASK 0xf0 -#define RELEASE_MASK 0x0f - -/* - * Wave select (0xE0 to 0xF5) - */ -#define WAVE_SELECT 0xe0 - -/* - * Offsets to the register banks for voices. Just add to the - * voice number to get the register number. - * - * F-Number low bits (0xA0 to 0xA8). - */ -#define FNUM_LOW 0xa0 - -/* - * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) - */ -#define KEYON_BLOCK 0xb0 -#define KEYON_BIT 0x20 -#define BLOCKNUM_MASK 0x1c -#define FNUM_HIGH_MASK 0x03 - -/* - * Feedback / Connection (0xc0 to 0xc8) - * - * These registers have two new bits when the OPL-3 mode - * is selected. These bits controls connecting the voice - * to the stereo channels. For 4 OP voices this bit is - * defined in the second half of the voice (add 3 to the - * register offset). - * - * For 4 OP voices the connection bit is used in the - * both halves (gives 4 ways to connect the operators). - */ -#define FEEDBACK_CONNECTION 0xc0 -#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ -#define CONNECTION_BIT 0x01 -/* - * In the 4 OP mode there is four possible configurations how the - * operators can be connected together (in 2 OP modes there is just - * AM or FM). The 4 OP connection mode is defined by the rightmost - * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves. - * - * First half Second half Mode - * - * +---+ - * v | - * 0 0 >+-1-+--2--3--4--> - * - * - * - * +---+ - * | | - * 0 1 >+-1-+--2-+ - * |-> - * >--3----4-+ - * - * +---+ - * | | - * 1 0 >+-1-+-----+ - * |-> - * >--2--3--4-+ - * - * +---+ - * | | - * 1 1 >+-1-+--+ - * | - * >--2--3-+-> - * | - * >--4----+ - */ -#define STEREO_BITS 0x30 /* OPL-3 only */ -#define VOICE_TO_LEFT 0x10 -#define VOICE_TO_RIGHT 0x20 - -/* - * Definition table for the physical voices - */ - -struct physical_voice_info { - unsigned char voice_num; - unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ - unsigned short ioaddr; /* I/O port (left or right side) */ - unsigned char op[4]; /* Operator offsets */ - }; - -/* - * There is 18 possible 2 OP voices - * (9 in the left and 9 in the right). - * The first OP is the modulator and 2nd is the carrier. - * - * The first three voices in the both sides may be connected - * with another voice to a 4 OP voice. For example voice 0 - * can be connected with voice 3. The operators of voice 3 are - * used as operators 3 and 4 of the new 4 OP voice. - * In this case the 2 OP voice number 0 is the 'first half' and - * voice 3 is the second. - */ - -#define USE_LEFT 0 -#define USE_RIGHT 1 - -static struct physical_voice_info pv_map[18] = -{ -/* No Mode Side OP1 OP2 OP3 OP4 */ -/* --------------------------------------------------- */ - { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */ - { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */ - { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */ - - { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}}, - { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}}, - { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}} -}; -/* - * DMA buffer calls - */ diff --git a/sound/oss/os.h b/sound/oss/os.h deleted file mode 100644 index 0bf89e1d679c..000000000000 --- a/sound/oss/os.h +++ /dev/null @@ -1,45 +0,0 @@ -#define ALLOW_SELECT -#undef NO_INLINE_ASM -#define SHORT_BANNERS -#define MANUAL_PNP -#undef DO_TIMINGS - -#include <linux/module.h> - -#ifdef __KERNEL__ -#include <linux/string.h> -#include <linux/fs.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/param.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <asm/page.h> -#include <linux/vmalloc.h> -#include <linux/uaccess.h> -#include <linux/poll.h> -#include <linux/pci.h> -#endif - -#include <linux/soundcard.h> - -#define FALSE 0 -#define TRUE 1 - -extern int sound_alloc_dma(int chn, char *deviceID); -extern int sound_open_dma(int chn, char *deviceID); -extern void sound_free_dma(int chn); -extern void sound_close_dma(int chn); - -extern void reprogram_timer(void); - -#define USE_AUTOINIT_DMA - -extern void *sound_mem_blocks[1024]; -extern int sound_nblocks; - -#undef PSEUDO_DMA_AUTOINIT -#define ALLOW_BUFFER_MAPPING - -extern const struct file_operations oss_sound_fops; diff --git a/sound/oss/pas2.h b/sound/oss/pas2.h deleted file mode 100644 index d19f757dbd79..000000000000 --- a/sound/oss/pas2.h +++ /dev/null @@ -1,20 +0,0 @@ - -/* From pas_card.c */ -int pas_set_intr(int mask); -int pas_remove_intr(int mask); -unsigned char pas_read(int ioaddr); -void pas_write(unsigned char data, int ioaddr); - -/* From pas_audio.c */ -void pas_pcm_interrupt(unsigned char status, int cause); -void pas_pcm_init(struct address_info *hw_config); - -/* From pas_mixer.c */ -int pas_init_mixer(void); - -/* From pas_midi.c */ -void pas_midi_init(void); -void pas_midi_interrupt(void); - -/* From pas2_mixer.c*/ -void mix_write(unsigned char data, int ioaddr); diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c deleted file mode 100644 index 769fca692d2a..000000000000 --- a/sound/oss/pas2_card.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * sound/oss/pas2_card.c - * - * Detection routine for the Pro Audio Spectrum cards. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "pas2.h" -#include "sb.h" - -static unsigned char dma_bits[] = { - 4, 1, 2, 3, 0, 5, 6, 7 -}; - -static unsigned char irq_bits[] = { - 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 -}; - -static unsigned char sb_irq_bits[] = { - 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, - 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 -}; - -static unsigned char sb_dma_bits[] = { - 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 -}; - -/* - * The Address Translation code is used to convert I/O register addresses to - * be relative to the given base -register - */ - -int pas_translate_code = 0; -static int pas_intr_mask; -static int pas_irq; -static int pas_sb_base; -DEFINE_SPINLOCK(pas_lock); -#ifndef CONFIG_PAS_JOYSTICK -static bool joystick; -#else -static bool joystick = 1; -#endif -#ifdef SYMPHONY_PAS -static bool symphony = 1; -#else -static bool symphony; -#endif -#ifdef BROKEN_BUS_CLOCK -static bool broken_bus_clock = 1; -#else -static bool broken_bus_clock; -#endif - -static struct address_info cfg; -static struct address_info cfg2; - -char pas_model = 0; -static char *pas_model_names[] = { - "", - "Pro AudioSpectrum+", - "CDPC", - "Pro AudioSpectrum 16", - "Pro AudioSpectrum 16D" -}; - -/* - * pas_read() and pas_write() are equivalents of inb and outb - * These routines perform the I/O address translation required - * to support other than the default base address - */ - -unsigned char pas_read(int ioaddr) -{ - return inb(ioaddr + pas_translate_code); -} - -void pas_write(unsigned char data, int ioaddr) -{ - outb((data), ioaddr + pas_translate_code); -} - -/******************* Begin of the Interrupt Handler ********************/ - -static irqreturn_t pasintr(int irq, void *dev_id) -{ - int status; - - status = pas_read(0x0B89); - pas_write(status, 0x0B89); /* Clear interrupt */ - - if (status & 0x08) - { - pas_pcm_interrupt(status, 1); - status &= ~0x08; - } - if (status & 0x10) - { - pas_midi_interrupt(); - status &= ~0x10; - } - return IRQ_HANDLED; -} - -int pas_set_intr(int mask) -{ - if (!mask) - return 0; - - pas_intr_mask |= mask; - - pas_write(pas_intr_mask, 0x0B8B); - return 0; -} - -int pas_remove_intr(int mask) -{ - if (!mask) - return 0; - - pas_intr_mask &= ~mask; - pas_write(pas_intr_mask, 0x0B8B); - - return 0; -} - -/******************* End of the Interrupt handler **********************/ - -/******************* Begin of the Initialization Code ******************/ - -static int __init 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 | (joystick ? 0x40 : 0), 0xF388); - - if (pas_irq < 0 || pas_irq > 15) - { - printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); - hw_config->irq=-1; - ok = 0; - } - else - { - int_ptrs = pas_read(0xF38A); - int_ptrs = (int_ptrs & 0xf0) | irq_bits[pas_irq]; - pas_write(int_ptrs, 0xF38A); - if (!irq_bits[pas_irq]) - { - printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); - hw_config->irq=-1; - ok = 0; - } - else - { - if (request_irq(pas_irq, pasintr, 0, "PAS16",hw_config) < 0) { - printk(KERN_ERR "PAS16: Cannot allocate IRQ %d\n",pas_irq); - hw_config->irq=-1; - ok = 0; - } - } - } - - if (hw_config->dma < 0 || hw_config->dma > 7) - { - printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); - hw_config->dma=-1; - ok = 0; - } - else - { - pas_write(dma_bits[hw_config->dma], 0xF389); - if (!dma_bits[hw_config->dma]) - { - printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); - hw_config->dma=-1; - ok = 0; - } - else - { - if (sound_alloc_dma(hw_config->dma, "PAS16")) - { - printk(KERN_ERR "pas2_card.c: Can't allocate DMA channel\n"); - hw_config->dma=-1; - 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. - */ - - if(symphony) - { - outb((0x05), 0xa8); - outb((0x60), 0xa9); - } - - if(broken_bus_clock) - pas_write(0x01 | 0x10 | 0x20 | 0x04, 0x8388); - else - /* - * pas_write(0x01, 0x8388); - */ - pas_write(0x01 | 0x10 | 0x20, 0x8388); - - 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); - - { - struct address_info *sb_config; - - sb_config = &cfg2; - if (sb_config->io_base) - { - 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(KERN_ERR "PAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); - - if (!sb_irq_bits[sb_config->irq]) - printk(KERN_ERR "PAS16 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); - } - - if (!ok) - printk(KERN_WARNING "PAS16: Driver not enabled\n"); - - return ok; -} - -static int __init detect_pas_hw(struct address_info *hw_config) -{ - 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. - */ - - outb((0xBC), 0x9A01); /* Activate first board */ - outb((hw_config->io_base >> 2), 0x9A01); /* Set base address */ - pas_translate_code = hw_config->io_base - 0x388; - pas_write(1, 0xBF88); /* Select one wait states */ - - board_id = pas_read(0x0B8B); - - 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. - */ - - foo = board_id ^ 0xe0; - - pas_write(foo, 0x0B8B); - foo = pas_read(0x0B8B); - pas_write(board_id, 0x0B8B); - - if (board_id != foo) - return 0; - - pas_model = pas_read(0xFF88); - - return pas_model; -} - -static void __init 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]; - - if (pas_model < 0 || - pas_model >= ARRAY_SIZE(pas_model_names)) { - printk(KERN_ERR "pas2 unrecognized model.\n"); - return; - } - 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_pcm_init(hw_config); - pas_midi_init(); - pas_init_mixer(); - } - } -} - -static inline int __init probe_pas(struct address_info *hw_config) -{ - return detect_pas_hw(hw_config); -} - -static void __exit unload_pas(struct address_info *hw_config) -{ - extern int pas_audiodev; - extern int pas2_mididev; - - if (hw_config->dma>0) - sound_free_dma(hw_config->dma); - if (hw_config->irq>0) - free_irq(hw_config->irq, hw_config); - - if(pas_audiodev!=-1) - sound_unload_mixerdev(audio_devs[pas_audiodev]->mixer_dev); - if(pas2_mididev!=-1) - sound_unload_mididev(pas2_mididev); - if(pas_audiodev!=-1) - sound_unload_audiodev(pas_audiodev); -} - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma16 = -1; /* Set this for modules that need it */ - -static int __initdata sb_io = 0; -static int __initdata sb_irq = -1; -static int __initdata sb_dma = -1; -static int __initdata sb_dma16 = -1; - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param_hw(dma, int, dma, 0); -module_param_hw(dma16, int, dma, 0); - -module_param_hw(sb_io, int, ioport, 0); -module_param_hw(sb_irq, int, irq, 0); -module_param_hw(sb_dma, int, dma, 0); -module_param_hw(sb_dma16, int, dma, 0); - -module_param(joystick, bool, 0); -module_param(symphony, bool, 0); -module_param(broken_bus_clock, bool, 0); - -MODULE_LICENSE("GPL"); - -static int __init init_pas2(void) -{ - printk(KERN_INFO "Pro Audio Spectrum driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma16; - - cfg2.io_base = sb_io; - cfg2.irq = sb_irq; - cfg2.dma = sb_dma; - cfg2.dma2 = sb_dma16; - - if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { - printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); - return -EINVAL; - } - - if (!probe_pas(&cfg)) - return -ENODEV; - attach_pas_card(&cfg); - - return 0; -} - -static void __exit cleanup_pas2(void) -{ - unload_pas(&cfg); -} - -module_init(init_pas2); -module_exit(cleanup_pas2); - -#ifndef MODULE -static int __init setup_pas2(char *str) -{ - /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, sb_dma2 */ - int ints[9]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma16 = ints[4]; - - sb_io = ints[5]; - sb_irq = ints[6]; - sb_dma = ints[7]; - sb_dma16 = ints[8]; - - return 1; -} - -__setup("pas2=", setup_pas2); -#endif diff --git a/sound/oss/pas2_midi.c b/sound/oss/pas2_midi.c deleted file mode 100644 index 1122d10a20c3..000000000000 --- a/sound/oss/pas2_midi.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * sound/oss/pas2_midi.c - * - * The low level driver for the PAS Midi Interface. - */ -/* - * 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. - * - * Bartlomiej Zolnierkiewicz : Added __init to pas_init_mixer() - */ - -#include <linux/init.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "pas2.h" - -extern spinlock_t pas_lock; - -static int midi_busy, input_opened; -static int my_dev; - -int pas2_mididev=-1; - -static unsigned char tmp_queue[256]; -static volatile int qlen; -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) -) -{ - int err; - unsigned long flags; - unsigned char ctrl; - - - if (midi_busy) - return -EBUSY; - - /* - * Reset input and output FIFO pointers - */ - pas_write(0x20 | 0x40, - 0x178b); - - spin_lock_irqsave(&pas_lock, flags); - - if ((err = pas_set_intr(0x10)) < 0) - { - spin_unlock_irqrestore(&pas_lock, flags); - return err; - } - /* - * Enable input available and output FIFO empty interrupts - */ - - ctrl = 0; - input_opened = 0; - midi_input_intr = input; - - 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 - */ - - pas_write(0xff, 0x1B88); - - spin_unlock_irqrestore(&pas_lock, flags); - - midi_busy = 1; - qlen = qhead = qtail = 0; - return 0; -} - -static void pas_midi_close(int dev) -{ - - /* - * Reset FIFO pointers, disable intrs - */ - pas_write(0x20 | 0x40, 0x178b); - - pas_remove_intr(0x10); - midi_busy = 0; -} - -static int dump_to_midi(unsigned char midi_byte) -{ - int fifo_space, x; - - fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f; - - /* - * The MIDI FIFO space register and it's documentation is nonunderstandable. - * There seem to be no way to differentiate between buffer full and buffer - * empty situations. For this reason we don't never write the buffer - * completely full. In this way we can assume that 0 (or is it 15) - * 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); - - return 1; -} - -static int pas_midi_out(int dev, unsigned char midi_byte) -{ - - unsigned long flags; - - /* - * Drain the local queue first - */ - - spin_lock_irqsave(&pas_lock, flags); - - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - spin_unlock_irqrestore(&pas_lock, flags); - - /* - * Output the byte if the local queue is empty. - */ - - if (!qlen) - if (dump_to_midi(midi_byte)) - return 1; - - /* - * Put to the local queue - */ - - if (qlen >= 256) - return 0; /* Local queue full */ - - spin_lock_irqsave(&pas_lock, flags); - - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; - - spin_unlock_irqrestore(&pas_lock, flags); - - return 1; -} - -static int pas_midi_start_read(int dev) -{ - return 0; -} - -static int pas_midi_end_read(int dev) -{ - return 0; -} - -static void pas_midi_kick(int dev) -{ -} - -static int pas_buffer_status(int dev) -{ - return qlen; -} - -#define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations pas_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = pas_midi_open, - .close = pas_midi_close, - .outputc = pas_midi_out, - .start_read = pas_midi_start_read, - .end_read = pas_midi_end_read, - .kick = pas_midi_kick, - .buffer_status = pas_buffer_status, -}; - -void __init pas_midi_init(void) -{ - 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; - pas2_mididev = dev; - sequencer_init(); -} - -void pas_midi_interrupt(void) -{ - unsigned char stat; - int i, incount; - - stat = pas_read(0x1B88); - - if (stat & 0x04) /* Input data available */ - { - 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 */ - } - if (stat & (0x08 | 0x10)) - { - spin_lock(&pas_lock);/* called in irq context */ - - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - spin_unlock(&pas_lock); - } - if (stat & 0x40) - { - printk(KERN_WARNING "MIDI output overrun %x,%x\n", pas_read(0x1B89), stat); - } - pas_write(stat, 0x1B88); /* Acknowledge interrupts */ -} diff --git a/sound/oss/pas2_mixer.c b/sound/oss/pas2_mixer.c deleted file mode 100644 index 50b5bd501247..000000000000 --- a/sound/oss/pas2_mixer.c +++ /dev/null @@ -1,327 +0,0 @@ - -/* - * sound/oss/pas2_mixer.c - * - * Mixer routines for the Pro Audio Spectrum cards. - */ - -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Bartlomiej Zolnierkiewicz : added __init to pas_init_mixer() - */ -#include <linux/init.h> -#include "sound_config.h" - -#include "pas2.h" - -extern int pas_translate_code; -extern char pas_model; -extern int *pas_osp; -extern int pas_audiodev; - -static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ -static int mode_control; - -#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_ALTPCM) - -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV) - -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 */ -}; - -void -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 + pas_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 */ -{ - 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) -{ - mix_write(0x80 | 0x05, 0x078B); - mix_write(new_mode, 0x078B); - - mode_control = new_mode; -} - -static int -pas_mixer_set(int whichDev, unsigned int level) -{ - int left, right, devmask, changed, i, mixer = 0; - - 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)) - { - pas_mixer_set(i, levels[i]); - } - return rec_devices; - break; - - default: - return -EINVAL; - } - - return (levels[whichDev]); -} - -/*****/ - -static void -pas_mixer_reset(void) -{ - int foo; - - for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) - pas_mixer_set(foo, levels[foo]); - - set_mode(0x04 | 0x01); -} - -static int pas_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int level,v ; - int __user *p = (int __user *)arg; - - if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */ - if (get_user(level, p)) - return -EFAULT; - if (level == -1) /* Return current settings */ - level = (mode_control & 0x04); - else { - mode_control &= ~0x04; - if (level) - mode_control |= 0x04; - set_mode(mode_control); - } - level = !!level; - return put_user(level, p); - } - if (cmd == SOUND_MIXER_PRIVATE2) { /* Set enhance bit */ - if (get_user(level, p)) - return -EFAULT; - if (level == -1) { /* Return current settings */ - if (!(mode_control & 0x03)) - level = 0; - else - level = ((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; - level = i; - } - return put_user(level, p); - } - if (cmd == SOUND_MIXER_PRIVATE3) { /* Set mute bit */ - if (get_user(level, p)) - return -EFAULT; - if (level == -1) /* Return current settings */ - level = !(pas_read(0x0B8A) & 0x20); - else { - if (level) - pas_write(pas_read(0x0B8A) & (~0x20), 0x0B8A); - else - pas_write(pas_read(0x0B8A) | 0x20, 0x0B8A); - - level = !(pas_read(0x0B8A) & 0x20); - } - return put_user(level, p); - } - if (((cmd >> 8) & 0xff) == 'M') { - if (get_user(v, p)) - return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - v = pas_mixer_set(cmd & 0xff, v); - } else { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - v = rec_devices; - break; - - case SOUND_MIXER_STEREODEVS: - v = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE); - break; - - case SOUND_MIXER_DEVMASK: - v = SUPPORTED_MIXER_DEVICES; - break; - - case SOUND_MIXER_RECMASK: - v = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES; - break; - - case SOUND_MIXER_CAPS: - v = 0; /* No special capabilities */ - break; - - default: - v = levels[cmd & 0xff]; - break; - } - } - return put_user(v, p); - } - return -EINVAL; -} - -static struct mixer_operations pas_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "PAS16", - .name = "Pro Audio Spectrum 16", - .ioctl = pas_mixer_ioctl -}; - -int __init -pas_init_mixer(void) -{ - int d; - - levels = load_mixer_volumes("PAS16_1", default_levels, 1); - - pas_mixer_reset(); - - if ((d = sound_alloc_mixerdev()) != -1) - { - audio_devs[pas_audiodev]->mixer_dev = d; - mixer_devs[d] = &pas_mixer_operations; - } - return 1; -} diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c deleted file mode 100644 index 474803b52f7d..000000000000 --- a/sound/oss/pas2_pcm.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * pas2_pcm.c Audio routines for PAS16 - * - * - * 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. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Alan Cox : Swatted a double allocation of device bug. Made a few - * more things module options. - * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init() - */ - -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/timex.h> -#include "sound_config.h" - -#include "pas2.h" - -#define PAS_PCM_INTRBITS (0x08) -/* - * Sample buffer timer interrupt enable - */ - -#define PCM_NON 0 -#define PCM_DAC 1 -#define PCM_ADC 2 - -static unsigned long pcm_speed; /* sampling rate */ -static unsigned char pcm_channels = 1; /* channels (1 or 2) */ -static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */ -static unsigned char pcm_filter; /* filter FLAG */ -static unsigned char pcm_mode = PCM_NON; -static unsigned long pcm_count; -static unsigned short pcm_bitsok = 8; /* mask of OK bits */ -static int pcm_busy; -int pas_audiodev = -1; -static int open_mode; - -extern spinlock_t pas_lock; - -static int 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 = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg; - arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo; - } - else - { - foo = (PIT_TICK_RATE + (arg / 2)) / arg; - arg = (PIT_TICK_RATE + (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; -#endif - - spin_lock_irqsave(&pas_lock, flags); - - 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); - - spin_unlock_irqrestore(&pas_lock, flags); - - return pcm_speed; -} - -static int pcm_set_channels(int arg) -{ - - if ((arg != 1) && (arg != 2)) - return pcm_channels; - - 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; -} - -static int pcm_set_bits(int arg) -{ - if (arg == 0) - return pcm_bits; - - if ((arg & pcm_bitsok) != arg) - return pcm_bits; - - if (arg != pcm_bits) - { - pas_write(pas_read(0x8389) ^ 0x04, 0x8389); - - pcm_bits = arg; - } - return pcm_bits; -} - -static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int val, ret; - int __user *p = arg; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_speed(val); - break; - - case SOUND_PCM_READ_RATE: - ret = pcm_speed; - break; - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_channels(val + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_channels(val); - break; - - case SOUND_PCM_READ_CHANNELS: - ret = pcm_channels; - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_bits(val); - break; - - case SOUND_PCM_READ_BITS: - ret = pcm_bits; - break; - - default: - return -EINVAL; - } - return put_user(ret, p); -} - -static void pas_audio_reset(int dev) -{ - pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ -} - -static int pas_audio_open(int dev, int mode) -{ - int err; - unsigned long flags; - - spin_lock_irqsave(&pas_lock, flags); - if (pcm_busy) - { - spin_unlock_irqrestore(&pas_lock, flags); - return -EBUSY; - } - pcm_busy = 1; - spin_unlock_irqrestore(&pas_lock, flags); - - if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) - return err; - - - pcm_count = 0; - open_mode = mode; - - return 0; -} - -static void pas_audio_close(int dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pas_lock, flags); - - pas_audio_reset(dev); - pas_remove_intr(PAS_PCM_INTRBITS); - pcm_mode = PCM_NON; - - pcm_busy = 0; - spin_unlock_irqrestore(&pas_lock, flags); -} - -static void pas_audio_output_block(int dev, unsigned long buf, int count, - int intrflag) -{ - unsigned long flags, cnt; - - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; - - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; - - spin_lock_irqsave(&pas_lock, flags); - - pas_write(pas_read(0xF8A) & ~0x40, - 0xF8A); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - 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); - - pcm_count = count; - } - pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); -#ifdef NO_TRIGGER - pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); -#endif - - pcm_mode = PCM_DAC; - - spin_unlock_irqrestore(&pas_lock, flags); -} - -static void pas_audio_start_input(int dev, unsigned long buf, int count, - int intrflag) -{ - unsigned long flags; - int cnt; - - 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; - - spin_lock_irqsave(&pas_lock, flags); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - 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); - - pcm_count = count; - } - pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); -#ifdef NO_TRIGGER - pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); -#endif - - pcm_mode = PCM_ADC; - - spin_unlock_irqrestore(&pas_lock, flags); -} - -#ifndef NO_TRIGGER -static void pas_audio_trigger(int dev, int state) -{ - unsigned long flags; - - spin_lock_irqsave(&pas_lock, flags); - 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); - - spin_unlock_irqrestore(&pas_lock, flags); -} -#endif - -static int pas_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - pas_audio_reset(dev); - return 0; -} - -static int pas_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - pas_audio_reset(dev); - return 0; -} - -static struct audio_driver pas_audio_driver = -{ - .owner = THIS_MODULE, - .open = pas_audio_open, - .close = pas_audio_close, - .output_block = pas_audio_output_block, - .start_input = pas_audio_start_input, - .ioctl = pas_audio_ioctl, - .prepare_for_input = pas_audio_prepare_for_input, - .prepare_for_output = pas_audio_prepare_for_output, - .halt_io = pas_audio_reset, - .trigger = pas_audio_trigger -}; - -void __init pas_pcm_init(struct address_info *hw_config) -{ - pcm_bitsok = 8; - if (pas_read(0xEF8B) & 0x08) - pcm_bitsok |= 16; - - pcm_set_speed(DSP_DEFAULT_SPEED); - - 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) - printk(KERN_WARNING "PAS16: Too many PCM devices available\n"); -} - -void 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(KERN_WARNING "PAS: Unexpected PCM interrupt\n"); - } - } -} diff --git a/sound/oss/pss.c b/sound/oss/pss.c deleted file mode 100644 index 33c3a442e162..000000000000 --- a/sound/oss/pss.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * sound/oss/pss.c - * - * The low level driver for the Personal Sound System (ECHO ESC614). - * - * - * 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. - * - * - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, clean up. - * - * 98-02-21: Vladimir Michl <vladimir.michl@upol.cz> - * Added mixer device for Beethoven ADSP-16 (master volume, - * bass, treble, synth), only for speakers. - * Fixed bug in pss_write (exchange parameters) - * Fixed config port of SB - * Requested two regions for PSS (PSS mixer, PSS config) - * Modified pss_download_boot - * To probe_pss_mss added test for initialize AD1848 - * 98-05-28: Vladimir Michl <vladimir.michl@upol.cz> - * Fixed computation of mixer volumes - * 04-05-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> - * Added code that allows the user to enable his cdrom and/or - * joystick through the module parameters pss_cdrom_port and - * pss_enable_joystick. pss_cdrom_port takes a port address as its - * argument. pss_enable_joystick takes either a 0 or a non-0 as its - * argument. - * 04-06-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> - * Separated some code into new functions for easier reuse. - * Cleaned up and streamlined new code. Added code to allow a user - * to only use this driver for enabling non-sound components - * through the new module parameter pss_no_sound (flag). Added - * code that would allow a user to decide whether the driver should - * reset the configured hardware settings for the PSS board through - * the module parameter pss_keep_settings (flag). This flag will - * allow a user to free up resources in use by this card if needbe, - * furthermore it allows him to use this driver to just enable the - * emulations and then be unloaded as it is no longer needed. Both - * new settings are only available to this driver if compiled as a - * module. The default settings of all new parameters are set to - * load the driver as it did in previous versions. - * 04-07-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> - * Added module parameter pss_firmware to allow the user to tell - * the driver where the firmware file is located. The default - * setting is the previous hardcoded setting "/etc/sound/pss_synth". - * 00-03-03: Christoph Hellwig <chhellwig@infradead.org> - * Adapted to module_init/module_exit - * 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> - * Added __init to probe_pss(), attach_pss() and probe_pss_mpu() - * 02-Jan-2001: Chris Rankin - * Specify that this module owns the coprocessor - */ - - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/spinlock.h> - -#include "sound_config.h" -#include "sound_firmware.h" - -#include "ad1848.h" -#include "mpu401.h" - -/* - * PSS registers. - */ -#define REG(x) (devc->base+x) -#define PSS_DATA 0 -#define PSS_STATUS 2 -#define PSS_CONTROL 2 -#define PSS_ID 4 -#define PSS_IRQACK 4 -#define PSS_PIO 0x1a - -/* - * Config registers - */ -#define CONF_PSS 0x10 -#define CONF_WSS 0x12 -#define CONF_SB 0x14 -#define CONF_CDROM 0x16 -#define CONF_MIDI 0x18 - -/* - * Status bits. - */ -#define PSS_FLAG3 0x0800 -#define PSS_FLAG2 0x0400 -#define PSS_FLAG1 0x1000 -#define PSS_FLAG0 0x0800 -#define PSS_WRITE_EMPTY 0x8000 -#define PSS_READ_FULL 0x4000 - -/* - * WSS registers - */ -#define WSS_INDEX 4 -#define WSS_DATA 5 - -/* - * WSS status bits - */ -#define WSS_INITIALIZING 0x80 -#define WSS_AUTOCALIBRATION 0x20 - -#define NO_WSS_MIXER -1 - -#include "coproc.h" - -#include "pss_boot.h" - -/* If compiled into kernel, it enable or disable pss mixer */ -#ifdef CONFIG_PSS_MIXER -static bool pss_mixer = 1; -#else -static bool pss_mixer; -#endif - - -struct pss_mixerdata { - unsigned int volume_l; - unsigned int volume_r; - unsigned int bass; - unsigned int treble; - unsigned int synth; -}; - -struct pss_confdata { - int base; - int irq; - int dma; - int *osp; - struct pss_mixerdata mixer; - int ad_mixer_dev; -}; - -static struct pss_confdata pss_data; -static struct pss_confdata *devc = &pss_data; -static DEFINE_SPINLOCK(lock); - -static int pss_initialized; -static int nonstandard_microcode; -static int pss_cdrom_port = -1; /* Parameter for the PSS cdrom port */ -static bool pss_enable_joystick; /* Parameter for enabling the joystick */ -static coproc_operations pss_coproc_operations; - -static void pss_write(struct pss_confdata *devc, int data) -{ - unsigned long i, limit; - - limit = jiffies + HZ/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 && time_before(jiffies, limit); i++) - { - if (inw(REG(PSS_STATUS)) & PSS_WRITE_EMPTY) - { - outw(data, REG(PSS_DATA)); - return; - } - } - printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data); -} - -static int __init 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 (!request_region(devc->base, 0x10, "PSS mixer, SB emulation")) { - printk(KERN_ERR "PSS: I/O port conflict\n"); - return 0; - } - id = inw(REG(PSS_ID)); - if ((id >> 8) != 'E') { - printk(KERN_ERR "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); - release_region(devc->base, 0x10); - return 0; - } - if (!request_region(devc->base + 0x10, 0x9, "PSS config")) { - printk(KERN_ERR "PSS: I/O port conflict\n"); - release_region(devc->base, 0x10); - return 0; - } - return 1; -} - -static int set_irq(struct 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; - - if (irq < 0 || irq > 15) - return 0; - - tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ - - if ((bits = irq_bits[irq]) == 0 && irq != 0) - { - printk(KERN_ERR "PSS: Invalid IRQ %d\n", irq); - return 0; - } - outw(tmp | bits, REG(dev)); - return 1; -} - -static void set_io_base(struct pss_confdata *devc, int dev, int base) -{ - unsigned short tmp = inw(REG(dev)) & 0x003f; - unsigned short bits = (base & 0x0ffc) << 4; - - outw(bits | tmp, REG(dev)); -} - -static int set_dma(struct 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; - - if (dma < 0 || dma > 7) - return 0; - - tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */ - - if ((bits = dma_bits[dma]) == 0 && dma != 4) - { - printk(KERN_ERR "PSS: Invalid DMA %d\n", dma); - return 0; - } - outw(tmp | bits, REG(dev)); - return 1; -} - -static int pss_reset_dsp(struct pss_confdata *devc) -{ - unsigned long i, limit = jiffies + HZ/10; - - outw(0x2000, REG(PSS_CONTROL)); - for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) - inw(REG(PSS_CONTROL)); - outw(0x0000, REG(PSS_CONTROL)); - return 1; -} - -static int pss_put_dspword(struct pss_confdata *devc, unsigned short word) -{ - 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; -} - -static int pss_get_dspword(struct pss_confdata *devc, unsigned short *word) -{ - 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; - } - } - return 0; -} - -static int pss_download_boot(struct pss_confdata *devc, unsigned char *block, - int size, int flags) -{ - int i, val, count; - unsigned long limit; - - if (flags & CPF_FIRST) - { -/*_____ Warn DSP software that a boot is coming */ - outw(0x00fe, REG(PSS_DATA)); - - limit = jiffies + HZ/10; - for (i = 0; i < 32768 && time_before(jiffies, limit); i++) - if (inw(REG(PSS_DATA)) == 0x5500) - break; - - outw(*block++, REG(PSS_DATA)); - pss_reset_dsp(devc); - } - count = 1; - while ((flags&CPF_LAST) || count<size ) - { - int 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("\n"); - printk(KERN_ERR "PSS: Download timeout problems, byte %d=%d\n", count, size); - return 0; - } - } -/*_____ Send the next byte */ - if (count >= size) - { - /* If not data in block send 0xffff */ - outw (0xffff, REG (PSS_DATA)); - } - else - { - /*_____ Send the next byte */ - outw (*block++, REG (PSS_DATA)); - } - count++; - } - - if (flags & CPF_LAST) - { -/*_____ Why */ - outw(0, REG(PSS_DATA)); - - limit = jiffies + HZ/10; - for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) - val = inw(REG(PSS_STATUS)); - - limit = jiffies + HZ/10; - for (i = 0; i < 32768 && time_after_eq(limit, jiffies); 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; -} - -/* Mixer */ -static void set_master_volume(struct pss_confdata *devc, int left, int right) -{ - static unsigned char log_scale[101] = { - 0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, - 0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, - 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, - 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, - 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, - 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, - 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, - 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff - }; - pss_write(devc, 0x0010); - pss_write(devc, log_scale[left] | 0x0000); - pss_write(devc, 0x0010); - pss_write(devc, log_scale[right] | 0x0100); -} - -static void set_synth_volume(struct pss_confdata *devc, int volume) -{ - int vol = ((0x8000*volume)/100L); - pss_write(devc, 0x0080); - pss_write(devc, vol); - pss_write(devc, 0x0081); - pss_write(devc, vol); -} - -static void set_bass(struct pss_confdata *devc, int level) -{ - int vol = (int)(((0xfd - 0xf0) * level)/100L) + 0xf0; - pss_write(devc, 0x0010); - pss_write(devc, vol | 0x0200); -}; - -static void set_treble(struct pss_confdata *devc, int level) -{ - int vol = (((0xfd - 0xf0) * level)/100L) + 0xf0; - pss_write(devc, 0x0010); - pss_write(devc, vol | 0x0300); -}; - -static void pss_mixer_reset(struct pss_confdata *devc) -{ - set_master_volume(devc, 33, 33); - set_bass(devc, 50); - set_treble(devc, 50); - set_synth_volume(devc, 30); - pss_write (devc, 0x0010); - pss_write (devc, 0x0800 | 0xce); /* Stereo */ - - if(pss_mixer) - { - devc->mixer.volume_l = devc->mixer.volume_r = 33; - devc->mixer.bass = 50; - devc->mixer.treble = 50; - devc->mixer.synth = 30; - } -} - -static int set_volume_mono(unsigned __user *p, unsigned int *aleft) -{ - unsigned int left, volume; - if (get_user(volume, p)) - return -EFAULT; - - left = volume & 0xff; - if (left > 100) - left = 100; - *aleft = left; - return 0; -} - -static int set_volume_stereo(unsigned __user *p, - unsigned int *aleft, - unsigned int *aright) -{ - unsigned int left, right, volume; - if (get_user(volume, p)) - return -EFAULT; - - left = volume & 0xff; - if (left > 100) - left = 100; - right = (volume >> 8) & 0xff; - if (right > 100) - right = 100; - *aleft = left; - *aright = right; - return 0; -} - -static int ret_vol_mono(int left) -{ - return ((left << 8) | left); -} - -static int ret_vol_stereo(int left, int right) -{ - return ((right << 8) | left); -} - -static int call_ad_mixer(struct pss_confdata *devc, unsigned int cmd, - void __user *arg) -{ - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev, cmd, arg); - else - return -EINVAL; -} - -static int pss_mixer_ioctl (int dev, unsigned int cmd, void __user *arg) -{ - struct pss_confdata *devc = mixer_devs[dev]->devc; - int cmdf = cmd & 0xff; - - if ((cmdf != SOUND_MIXER_VOLUME) && (cmdf != SOUND_MIXER_BASS) && - (cmdf != SOUND_MIXER_TREBLE) && (cmdf != SOUND_MIXER_SYNTH) && - (cmdf != SOUND_MIXER_DEVMASK) && (cmdf != SOUND_MIXER_STEREODEVS) && - (cmdf != SOUND_MIXER_RECMASK) && (cmdf != SOUND_MIXER_CAPS) && - (cmdf != SOUND_MIXER_RECSRC)) - { - return call_ad_mixer(devc, cmd, arg); - } - - if (((cmd >> 8) & 0xff) != 'M') - return -EINVAL; - - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - { - switch (cmdf) - { - case SOUND_MIXER_RECSRC: - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return call_ad_mixer(devc, cmd, arg); - else - { - int v; - if (get_user(v, (int __user *)arg)) - return -EFAULT; - if (v != 0) - return -EINVAL; - return 0; - } - case SOUND_MIXER_VOLUME: - if (set_volume_stereo(arg, - &devc->mixer.volume_l, - &devc->mixer.volume_r)) - return -EFAULT; - set_master_volume(devc, devc->mixer.volume_l, - devc->mixer.volume_r); - return ret_vol_stereo(devc->mixer.volume_l, - devc->mixer.volume_r); - - case SOUND_MIXER_BASS: - if (set_volume_mono(arg, &devc->mixer.bass)) - return -EFAULT; - set_bass(devc, devc->mixer.bass); - return ret_vol_mono(devc->mixer.bass); - - case SOUND_MIXER_TREBLE: - if (set_volume_mono(arg, &devc->mixer.treble)) - return -EFAULT; - set_treble(devc, devc->mixer.treble); - return ret_vol_mono(devc->mixer.treble); - - case SOUND_MIXER_SYNTH: - if (set_volume_mono(arg, &devc->mixer.synth)) - return -EFAULT; - set_synth_volume(devc, devc->mixer.synth); - return ret_vol_mono(devc->mixer.synth); - - default: - return -EINVAL; - } - } - else - { - int val, and_mask = 0, or_mask = 0; - /* - * Return parameters - */ - switch (cmdf) - { - case SOUND_MIXER_DEVMASK: - if (call_ad_mixer(devc, cmd, arg) == -EINVAL) - break; - and_mask = ~0; - or_mask = SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_STEREODEVS: - if (call_ad_mixer(devc, cmd, arg) == -EINVAL) - break; - and_mask = ~0; - or_mask = SOUND_MASK_VOLUME; - break; - - case SOUND_MIXER_RECMASK: - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return call_ad_mixer(devc, cmd, arg); - break; - - case SOUND_MIXER_CAPS: - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return call_ad_mixer(devc, cmd, arg); - or_mask = SOUND_CAP_EXCL_INPUT; - break; - - case SOUND_MIXER_RECSRC: - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return call_ad_mixer(devc, cmd, arg); - break; - - case SOUND_MIXER_VOLUME: - or_mask = ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r); - break; - - case SOUND_MIXER_BASS: - or_mask = ret_vol_mono(devc->mixer.bass); - break; - - case SOUND_MIXER_TREBLE: - or_mask = ret_vol_mono(devc->mixer.treble); - break; - - case SOUND_MIXER_SYNTH: - or_mask = ret_vol_mono(devc->mixer.synth); - break; - default: - return -EINVAL; - } - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val &= and_mask; - val |= or_mask; - if (put_user(val, (int __user *)arg)) - return -EFAULT; - return val; - } -} - -static struct mixer_operations pss_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "SOUNDPORT", - .name = "PSS-AD1848", - .ioctl = pss_mixer_ioctl -}; - -static void disable_all_emulations(void) -{ - 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)); -} - -static void configure_nonsound_components(void) -{ - /* Configure Joystick port */ - - if(pss_enable_joystick) - { - outw(0x0400, REG(CONF_PSS)); /* 0x0400 enables joystick */ - printk(KERN_INFO "PSS: joystick enabled.\n"); - } - else - { - printk(KERN_INFO "PSS: joystick port not enabled.\n"); - } - - /* Configure CDROM port */ - - if (pss_cdrom_port == -1) { /* If cdrom port enablation wasn't requested */ - printk(KERN_INFO "PSS: CDROM port not enabled.\n"); - } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) { - pss_cdrom_port = -1; - printk(KERN_ERR "PSS: CDROM I/O port conflict.\n"); - } else { - set_io_base(devc, CONF_CDROM, pss_cdrom_port); - printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port); - } -} - -static int __init attach_pss(struct address_info *hw_config) -{ - 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->ad_mixer_dev = NO_WSS_MIXER; - - if (!probe_pss(hw_config)) - return 0; - - id = inw(REG(PSS_ID)) & 0x00ff; - - /* - * Disable all emulations. Will be enabled later (if required). - */ - - disable_all_emulations(); - -#ifdef YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES - if (sound_alloc_dma(hw_config->dma, "PSS")) - { - printk("pss.c: Can't allocate DMA channel.\n"); - release_region(hw_config->io_base, 0x10); - release_region(hw_config->io_base+0x10, 0x9); - return 0; - } - if (!set_irq(devc, CONF_PSS, devc->irq)) - { - printk("PSS: IRQ allocation error.\n"); - release_region(hw_config->io_base, 0x10); - release_region(hw_config->io_base+0x10, 0x9); - return 0; - } - if (!set_dma(devc, CONF_PSS, devc->dma)) - { - printk(KERN_ERR "PSS: DMA allocation error\n"); - release_region(hw_config->io_base, 0x10); - release_region(hw_config->io_base+0x10, 0x9); - return 0; - } -#endif - - configure_nonsound_components(); - pss_initialized = 1; - sprintf(tmp, "ECHO-PSS Rev. %d", id); - conf_printf(tmp, hw_config); - return 1; -} - -static int __init probe_pss_mpu(struct address_info *hw_config) -{ - struct resource *ports; - int timeout; - - if (!pss_initialized) - return 0; - - ports = request_region(hw_config->io_base, 2, "mpu401"); - - if (!ports) { - printk(KERN_ERR "PSS: MPU I/O port conflict\n"); - return 0; - } - set_io_base(devc, CONF_MIDI, hw_config->io_base); - if (!set_irq(devc, CONF_MIDI, hw_config->irq)) { - printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n"); - goto fail; - } - if (!pss_synthLen) { - printk(KERN_ERR "PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - goto fail; - } - if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) { - printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); - goto fail; - } - - /* - * 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 */ - } - - if (!probe_mpu401(hw_config, ports)) - goto fail; - - attach_mpu401(hw_config, THIS_MODULE); /* Slot 1 */ - if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ - midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; - return 1; -fail: - release_region(hw_config->io_base, 2); - return 0; -} - -static int pss_coproc_open(void *dev_info, int sub_device) -{ - switch (sub_device) - { - case COPR_MIDI: - if (pss_synthLen == 0) - { - printk(KERN_ERR "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(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 0; - break; - - default: - break; - } - return 0; -} - -static void pss_coproc_close(void *dev_info, int sub_device) -{ - return; -} - -static void pss_coproc_reset(void *dev_info) -{ - if (pss_synthLen) - if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); - } - nonstandard_microcode = 0; -} - -static int 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(KERN_ERR "PSS: Unable to load microcode block to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - return 0; -} - -static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local) -{ - copr_buffer *buf; - copr_msg *mbuf; - copr_debug_buf dbuf; - unsigned short tmp; - unsigned long flags; - unsigned short *data; - int i, err; - /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - - switch (cmd) - { - case SNDCTL_COPR_RESET: - pss_coproc_reset(dev_info); - return 0; - - case SNDCTL_COPR_LOAD: - buf = vmalloc(sizeof(copr_buffer)); - if (buf == NULL) - return -ENOSPC; - if (copy_from_user(buf, arg, sizeof(copr_buffer))) { - vfree(buf); - return -EFAULT; - } - err = download_boot_block(dev_info, buf); - vfree(buf); - return err; - - case SNDCTL_COPR_SENDMSG: - mbuf = vmalloc(sizeof(copr_msg)); - if (mbuf == NULL) - return -ENOSPC; - if (copy_from_user(mbuf, arg, sizeof(copr_msg))) { - vfree(mbuf); - return -EFAULT; - } - data = (unsigned short *)(mbuf->data); - spin_lock_irqsave(&lock, flags); - for (i = 0; i < mbuf->len; i++) { - if (!pss_put_dspword(devc, *data++)) { - spin_unlock_irqrestore(&lock,flags); - mbuf->len = i; /* feed back number of WORDs sent */ - err = copy_to_user(arg, mbuf, sizeof(copr_msg)); - vfree(mbuf); - return err ? -EFAULT : -EIO; - } - } - spin_unlock_irqrestore(&lock,flags); - vfree(mbuf); - return 0; - - case SNDCTL_COPR_RCVMSG: - err = 0; - mbuf = vmalloc(sizeof(copr_msg)); - if (mbuf == NULL) - return -ENOSPC; - data = (unsigned short *)mbuf->data; - spin_lock_irqsave(&lock, flags); - for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) { - mbuf->len = i; /* feed back number of WORDs read */ - if (!pss_get_dspword(devc, data++)) { - if (i == 0) - err = -EIO; - break; - } - } - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(arg, mbuf, sizeof(copr_msg))) - err = -EFAULT; - vfree(mbuf); - return err; - - case SNDCTL_COPR_RDATA: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d0)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_get_dspword(devc, &tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - dbuf.parm1 = tmp; - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(arg, &dbuf, sizeof(dbuf))) - return -EFAULT; - return 0; - - case SNDCTL_COPR_WDATA: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d1)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - tmp = (unsigned int)dbuf.parm2 & 0xffff; - if (!pss_put_dspword(devc, tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - spin_unlock_irqrestore(&lock,flags); - return 0; - - case SNDCTL_COPR_WCODE: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d3)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - tmp = (unsigned int)dbuf.parm2 & 0x00ff; - if (!pss_put_dspword(devc, tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff; - if (!pss_put_dspword(devc, tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - spin_unlock_irqrestore(&lock,flags); - return 0; - - case SNDCTL_COPR_RCODE: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d2)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */ - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - dbuf.parm1 = tmp << 8; - if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */ - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - dbuf.parm1 |= tmp & 0x00ff; - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(arg, &dbuf, sizeof(dbuf))) - return -EFAULT; - return 0; - - default: - return -EINVAL; - } - return -EINVAL; -} - -static coproc_operations pss_coproc_operations = -{ - "ADSP-2115", - THIS_MODULE, - pss_coproc_open, - pss_coproc_close, - pss_coproc_ioctl, - pss_coproc_reset, - &pss_data -}; - -static int __init probe_pss_mss(struct address_info *hw_config) -{ - volatile int timeout; - struct resource *ports; - int my_mix = -999; /* gcc shut up */ - - if (!pss_initialized) - return 0; - - if (!request_region(hw_config->io_base, 4, "WSS config")) { - printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); - return 0; - } - ports = request_region(hw_config->io_base + 4, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); - release_region(hw_config->io_base, 4); - return 0; - } - set_io_base(devc, CONF_WSS, hw_config->io_base); - if (!set_irq(devc, CONF_WSS, hw_config->irq)) { - printk("PSS: WSS IRQ allocation error.\n"); - goto fail; - } - if (!set_dma(devc, CONF_WSS, hw_config->dma)) { - printk(KERN_ERR "PSS: WSS DMA allocation error\n"); - goto fail; - } - /* - * 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 + WSS_INDEX) & - WSS_INITIALIZING); timeout++) - ; - - outb((0x0b), hw_config->io_base + WSS_INDEX); /* Required by some cards */ - - for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && - (timeout < 100000); timeout++) - ; - - if (!probe_ms_sound(hw_config, ports)) - goto fail; - - devc->ad_mixer_dev = NO_WSS_MIXER; - if (pss_mixer) - { - if ((my_mix = sound_install_mixer (MIXER_DRIVER_VERSION, - "PSS-SPEAKERS and AD1848 (through MSS audio codec)", - &pss_mixer_operations, - sizeof (struct mixer_operations), - devc)) < 0) - { - printk(KERN_ERR "Could not install PSS mixer\n"); - goto fail; - } - } - pss_mixer_reset(devc); - attach_ms_sound(hw_config, ports, THIS_MODULE); /* Slot 0 */ - - if (hw_config->slots[0] != -1) - { - /* The MSS driver installed itself */ - audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; - if (pss_mixer && (num_mixers == (my_mix + 2))) - { - /* The MSS mixer installed */ - devc->ad_mixer_dev = audio_devs[hw_config->slots[0]]->mixer_dev; - } - } - return 1; -fail: - release_region(hw_config->io_base + 4, 4); - release_region(hw_config->io_base, 4); - return 0; -} - -static inline void __exit unload_pss(struct address_info *hw_config) -{ - release_region(hw_config->io_base, 0x10); - release_region(hw_config->io_base+0x10, 0x9); -} - -static inline void __exit unload_pss_mpu(struct address_info *hw_config) -{ - unload_mpu401(hw_config); -} - -static inline void __exit unload_pss_mss(struct address_info *hw_config) -{ - unload_ms_sound(hw_config); -} - - -static struct address_info cfg; -static struct address_info cfg2; -static struct address_info cfg_mpu; - -static int pss_io __initdata = -1; -static int mss_io __initdata = -1; -static int mss_irq __initdata = -1; -static int mss_dma __initdata = -1; -static int mpu_io __initdata = -1; -static int mpu_irq __initdata = -1; -static bool pss_no_sound = 0; /* Just configure non-sound components */ -static bool pss_keep_settings = 1; /* Keep hardware settings at module exit */ -static char *pss_firmware = "/etc/sound/pss_synth"; - -module_param_hw(pss_io, int, ioport, 0); -MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)"); -module_param_hw(mss_io, int, ioport, 0); -MODULE_PARM_DESC(mss_io, "Set WSS (audio) i/o base (0x530, 0x604, 0xE80, 0xF40, or other. Address must end in 0 or 4 and must be from 0x100 to 0xFF4)"); -module_param_hw(mss_irq, int, irq, 0); -MODULE_PARM_DESC(mss_irq, "Set WSS (audio) IRQ (3, 5, 7, 9, 10, 11, 12)"); -module_param_hw(mss_dma, int, dma, 0); -MODULE_PARM_DESC(mss_dma, "Set WSS (audio) DMA (0, 1, 3)"); -module_param_hw(mpu_io, int, ioport, 0); -MODULE_PARM_DESC(mpu_io, "Set MIDI i/o base (0x330 or other. Address must be on 4 location boundaries and must be from 0x100 to 0xFFC)"); -module_param_hw(mpu_irq, int, irq, 0); -MODULE_PARM_DESC(mpu_irq, "Set MIDI IRQ (3, 5, 7, 9, 10, 11, 12)"); -module_param_hw(pss_cdrom_port, int, ioport, 0); -MODULE_PARM_DESC(pss_cdrom_port, "Set the PSS CDROM port i/o base (0x340 or other)"); -module_param(pss_enable_joystick, bool, 0); -MODULE_PARM_DESC(pss_enable_joystick, "Enables the PSS joystick port (1 to enable, 0 to disable)"); -module_param(pss_no_sound, bool, 0); -MODULE_PARM_DESC(pss_no_sound, "Configure sound compoents (0 - no, 1 - yes)"); -module_param(pss_keep_settings, bool, 0); -MODULE_PARM_DESC(pss_keep_settings, "Keep hardware setting at driver unloading (0 - no, 1 - yes)"); -module_param(pss_firmware, charp, 0); -MODULE_PARM_DESC(pss_firmware, "Location of the firmware file (default - /etc/sound/pss_synth)"); -module_param(pss_mixer, bool, 0); -MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble, synth volume). The mixer is not available on all PSS cards."); -MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl"); -MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards)."); -MODULE_LICENSE("GPL"); - - -static int fw_load = 0; -static int pssmpu = 0, pssmss = 0; - -/* - * Load a PSS sound card module - */ - -static int __init init_pss(void) -{ - - if(pss_no_sound) /* If configuring only nonsound components */ - { - cfg.io_base = pss_io; - if(!probe_pss(&cfg)) - return -ENODEV; - printk(KERN_INFO "ECHO-PSS Rev. %d\n", inw(REG(PSS_ID)) & 0x00ff); - printk(KERN_INFO "PSS: loading in no sound mode.\n"); - disable_all_emulations(); - configure_nonsound_components(); - release_region(pss_io, 0x10); - release_region(pss_io + 0x10, 0x9); - return 0; - } - - cfg.io_base = pss_io; - - cfg2.io_base = mss_io; - cfg2.irq = mss_irq; - cfg2.dma = mss_dma; - - cfg_mpu.io_base = mpu_io; - cfg_mpu.irq = mpu_irq; - - if (cfg.io_base == -1 || cfg2.io_base == -1 || cfg2.irq == -1 || cfg.dma == -1) { - printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n"); - return -EINVAL; - } - - if (!pss_synth) { - fw_load = 1; - pss_synthLen = mod_firmware_load(pss_firmware, (void *) &pss_synth); - } - if (!attach_pss(&cfg)) - return -ENODEV; - /* - * Attach stuff - */ - if (probe_pss_mpu(&cfg_mpu)) - pssmpu = 1; - - if (probe_pss_mss(&cfg2)) - pssmss = 1; - - return 0; -} - -static void __exit cleanup_pss(void) -{ - if(!pss_no_sound) - { - if (fw_load) - vfree(pss_synth); - if(pssmss) - unload_pss_mss(&cfg2); - if(pssmpu) - unload_pss_mpu(&cfg_mpu); - unload_pss(&cfg); - } else if (pss_cdrom_port != -1) - release_region(pss_cdrom_port, 2); - - if(!pss_keep_settings) /* Keep hardware settings if asked */ - { - disable_all_emulations(); - printk(KERN_INFO "Resetting PSS sound card configurations.\n"); - } -} - -module_init(init_pss); -module_exit(cleanup_pss); - -#ifndef MODULE -static int __init setup_pss(char *str) -{ - /* io, mss_io, mss_irq, mss_dma, mpu_io, mpu_irq */ - int ints[7]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - pss_io = ints[1]; - mss_io = ints[2]; - mss_irq = ints[3]; - mss_dma = ints[4]; - mpu_io = ints[5]; - mpu_irq = ints[6]; - - return 1; -} - -__setup("pss=", setup_pss); -#endif diff --git a/sound/oss/sb.h b/sound/oss/sb.h deleted file mode 100644 index 77e8891ce333..000000000000 --- a/sound/oss/sb.h +++ /dev/null @@ -1,185 +0,0 @@ -#define DSP_RESET (devc->base + 0x6) -#define DSP_READ (devc->base + 0xA) -#define DSP_WRITE (devc->base + 0xC) -#define DSP_COMMAND (devc->base + 0xC) -#define DSP_STATUS (devc->base + 0xC) -#define DSP_DATA_AVAIL (devc->base + 0xE) -#define DSP_DATA_AVL16 (devc->base + 0xF) -#define MIXER_ADDR (devc->base + 0x4) -#define MIXER_DATA (devc->base + 0x5) -#define OPL3_LEFT (devc->base + 0x0) -#define OPL3_RIGHT (devc->base + 0x2) -#define OPL3_BOTH (devc->base + 0x8) -/* DSP Commands */ - -#define DSP_CMD_SPKON 0xD1 -#define DSP_CMD_SPKOFF 0xD3 -#define DSP_CMD_DMAON 0xD0 -#define DSP_CMD_DMAOFF 0xD4 - -#define IMODE_NONE 0 -#define IMODE_OUTPUT PCM_ENABLE_OUTPUT -#define IMODE_INPUT PCM_ENABLE_INPUT -#define IMODE_INIT 3 -#define IMODE_MIDI 4 - -#define NORMAL_MIDI 0 -#define UART_MIDI 1 - - -/* - * Device models - */ -#define MDL_NONE 0 -#define MDL_SB1 1 /* SB1.0 or 1.5 */ -#define MDL_SB2 2 /* SB2.0 */ -#define MDL_SB201 3 /* SB2.01 */ -#define MDL_SBPRO 4 /* SB Pro */ -#define MDL_SB16 5 /* SB16/32/AWE */ -#define MDL_SBPNP 6 /* SB16/32/AWE PnP */ -#define MDL_JAZZ 10 /* Media Vision Jazz16 */ -#define MDL_SMW 11 /* Logitech SoundMan Wave (Jazz16) */ -#define MDL_ESS 12 /* ESS ES688 and ES1688 */ -#define MDL_AZTECH 13 /* Aztech Sound Galaxy family */ -#define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ -#define MDL_AEDSP 15 /* Audio Excel DSP 16 */ -#define MDL_ESSPCI 16 /* ESS PCI card */ -#define MDL_YMPCI 17 /* Yamaha PCI sb in emulation */ - -#define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ - /* register assignment */ -#define SUBMDL_ALS100 43 /* ALS-100 allows sampling rates of up */ - /* to 48kHz */ - -/* - * Config flags - */ -#define SB_NO_MIDI 0x00000001 -#define SB_NO_MIXER 0x00000002 -#define SB_NO_AUDIO 0x00000004 -#define SB_NO_RECORDING 0x00000008 /* No audio recording */ -#define SB_MIDI_ONLY (SB_NO_AUDIO|SB_NO_MIXER) -#define SB_PCI_IRQ 0x00000010 /* PCI shared IRQ */ - -struct mixer_def { - unsigned int regno: 8; - unsigned int bitoffs:4; - unsigned int nbits:4; -}; - -typedef struct mixer_def mixer_tab[32][2]; -typedef struct mixer_def mixer_ent; - -struct sb_module_options -{ - int esstype; /* ESS chip type */ - int acer; /* Do acer notebook init? */ - int sm_games; /* Logitech soundman games? */ -}; - -typedef struct sb_devc { - int dev; - - /* Hardware parameters */ - int *osp; - int minor, major; - int type; - int model, submodel; - int caps; -# define SBCAP_STEREO 0x00000001 -# define SBCAP_16BITS 0x00000002 - - /* Hardware resources */ - int base; - int irq; - int dma8, dma16; - - int pcibase; /* For ESS Maestro etc */ - - /* State variables */ - int opened; - /* new audio fields for full duplex support */ - int fullduplex; - int duplex; - int speed, bits, channels; - volatile int irq_ok; - volatile int intr_active, irq_mode; - /* duplicate audio fields for full duplex support */ - volatile int intr_active_16, irq_mode_16; - - /* Mixer fields */ - int *levels; - mixer_tab *iomap; - size_t iomap_sz; /* number or records in the iomap table */ - int mixer_caps, recmask, outmask, supported_devices; - int supported_rec_devices, supported_out_devices; - int my_mixerdev; - int sbmixnum; - - /* Audio fields */ - unsigned long trg_buf; - int trigger_bits; - int trg_bytes; - int trg_intrflag; - int trg_restart; - /* duplicate audio fields for full duplex support */ - unsigned long trg_buf_16; - int trigger_bits_16; - int trg_bytes_16; - int trg_intrflag_16; - int trg_restart_16; - - unsigned char tconst; - - /* MIDI fields */ - int my_mididev; - int input_opened; - int midi_broken; - void (*midi_input_intr) (int dev, unsigned char data); - void *midi_irq_cookie; /* IRQ cookie for the midi */ - - spinlock_t lock; - - struct sb_module_options sbmo; /* Module options */ - - } sb_devc; - -/* - * PCI card types - */ - -#define SB_PCI_ESSMAESTRO 1 /* ESS Maestro Legacy */ -#define SB_PCI_YAMAHA 2 /* Yamaha Legacy */ - -/* - * Functions - */ - -int sb_dsp_command (sb_devc *devc, unsigned char val); -int sb_dsp_get_byte(sb_devc * devc); -int sb_dsp_reset (sb_devc *devc); -void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); -unsigned int sb_getmixer (sb_devc *devc, unsigned int port); -int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo); -int sb_dsp_init (struct address_info *hw_config, struct module *owner); -void sb_dsp_unload(struct address_info *hw_config, int sbmpu); -int sb_mixer_init(sb_devc *devc, struct module *owner); -void sb_mixer_unload(sb_devc *devc); -void sb_mixer_set_stereo (sb_devc *devc, int mode); -void smw_mixer_init(sb_devc *devc); -void sb_dsp_midi_init (sb_devc *devc, struct module *owner); -void sb_audio_init (sb_devc *devc, char *name, struct module *owner); -void sb_midi_interrupt (sb_devc *devc); -void sb_chgmixer (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val); -int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right); - -int sb_audio_open(int dev, int mode); -void sb_audio_close(int dev); - -/* From sb_common.c */ -void sb_dsp_disable_midi(int port); -int probe_sbmpu (struct address_info *hw_config, struct module *owner); -void unload_sbmpu (struct address_info *hw_config); - -void unload_sb16(struct address_info *hw_info); -void unload_sb16midi(struct address_info *hw_info); diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c deleted file mode 100644 index dc91072f4d82..000000000000 --- a/sound/oss/sb_audio.c +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * sound/oss/sb_audio.c - * - * Audio routines for Sound Blaster compatible cards. - * - * - * 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. - * - * Changes - * Alan Cox : Formatting and clean ups - * - * Status - * Mostly working. Weird uart bug causing irq storms - * - * Daniel J. Rodriksson: Changes to make sb16 work full duplex. - * Maybe other 16 bit cards in this code could behave - * the same. - * Chris Rankin: Use spinlocks instead of CLI/STI - */ - -#include <linux/spinlock.h> - -#include "sound_config.h" - -#include "sb_mixer.h" -#include "sb.h" - -#include "sb_ess.h" - -int sb_audio_open(int dev, int mode) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - { - printk(KERN_ERR "Sound Blaster: incomplete initialization.\n"); - return -ENXIO; - } - if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) - { - if (mode == OPEN_READ) - return -EPERM; - } - spin_lock_irqsave(&devc->lock, flags); - if (devc->opened) - { - spin_unlock_irqrestore(&devc->lock, flags); - return -EBUSY; - } - if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) - { - if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) - { - spin_unlock_irqrestore(&devc->lock, flags); - return -EBUSY; - } - } - devc->opened = mode; - spin_unlock_irqrestore(&devc->lock, flags); - - devc->irq_mode = IMODE_NONE; - devc->irq_mode_16 = IMODE_NONE; - devc->fullduplex = devc->duplex && - ((mode & OPEN_READ) && (mode & OPEN_WRITE)); - sb_dsp_reset(devc); - - /* At first glance this check isn't enough, some ESS chips might not - * have a RECLEV. However if they don't common_mixer_set will refuse - * cause devc->iomap has no register mapping for RECLEV - */ - if (devc->model == MDL_ESS) ess_mixer_reload (devc, SOUND_MIXER_RECLEV); - - /* The ALS007 seems to require that the DSP be removed from the output */ - /* in order for recording to be activated properly. This is done by */ - /* setting the appropriate bits of the output control register 4ch to */ - /* zero. This code assumes that the output control registers are not */ - /* used anywhere else and therefore the DSP bits are *always* ON for */ - /* output and OFF for sampling. */ - - if (devc->submodel == SUBMDL_ALS007) - { - if (mode & OPEN_READ) - sb_setmixer(devc,ALS007_OUTPUT_CTRL2, - sb_getmixer(devc,ALS007_OUTPUT_CTRL2) & 0xf9); - else - sb_setmixer(devc,ALS007_OUTPUT_CTRL2, - sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); - } - return 0; -} - -void sb_audio_close(int dev) -{ - sb_devc *devc = audio_devs[dev]->devc; - - /* fix things if mmap turned off fullduplex */ - if(devc->duplex - && !devc->fullduplex - && (devc->opened & OPEN_READ) && (devc->opened & OPEN_WRITE)) - swap(audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_in); - - audio_devs[dev]->dmap_out->dma = devc->dma8; - audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ? - devc->dma16 : devc->dma8; - - if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) - sound_close_dma(devc->dma16); - - /* For ALS007, turn DSP output back on if closing the device for read */ - - if ((devc->submodel == SUBMDL_ALS007) && (devc->opened & OPEN_READ)) - { - sb_setmixer(devc,ALS007_OUTPUT_CTRL2, - sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); - } - devc->opened = 0; -} - -static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, - int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex || devc->bits == AFMT_S16_LE) - { - devc->trg_buf = buf; - devc->trg_bytes = nr_bytes; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_OUTPUT; - } - else - { - devc->trg_buf_16 = buf; - devc->trg_bytes_16 = nr_bytes; - devc->trg_intrflag_16 = intrflag; - devc->irq_mode_16 = IMODE_OUTPUT; - } -} - -static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex || devc->bits != AFMT_S16_LE) - { - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; - } - else - { - devc->trg_buf_16 = buf; - devc->trg_bytes_16 = count; - devc->trg_intrflag_16 = intrflag; - devc->irq_mode_16 = IMODE_INPUT; - } -} - -/* - * SB1.x compatible routines - */ - -static void 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; - - spin_lock_irqsave(&devc->lock, flags); - 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(KERN_WARNING "Sound Blaster: unable to start DAC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - devc->intr_active = 1; -} - -static void 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; - - spin_lock_irqsave(&devc->lock, flags); - 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(KERN_ERR "Sound Blaster: unable to start ADC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - - devc->intr_active = 1; -} - -static void sb1_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: - 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_input(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x40)) - sb_dsp_command(devc, devc->tconst); - sb_dsp_command(devc, DSP_CMD_SPKOFF); - spin_unlock_irqrestore(&devc->lock, flags); - - devc->trigger_bits = 0; - return 0; -} - -static int sb1_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x40)) - sb_dsp_command(devc, devc->tconst); - sb_dsp_command(devc, DSP_CMD_SPKON); - spin_unlock_irqrestore(&devc->lock, flags); - devc->trigger_bits = 0; - return 0; -} - -static int sb1_audio_set_speed(int dev, int speed) -{ - int max_speed = 23000; - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - - if (devc->opened & OPEN_READ) - max_speed = 13000; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > max_speed) - speed = max_speed; - - devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - tmp = 256 - devc->tconst; - speed = (1000000 + tmp / 2) / tmp; - - devc->speed = speed; - } - return devc->speed; -} - -static short sb1_audio_set_channels(int dev, short channels) -{ - sb_devc *devc = audio_devs[dev]->devc; - return devc->channels = 1; -} - -static unsigned int sb1_audio_set_bits(int dev, unsigned int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - return devc->bits = 8; -} - -static void sb1_audio_halt_xfer(int dev) -{ - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; - - spin_lock_irqsave(&devc->lock, flags); - sb_dsp_reset(devc); - spin_unlock_irqrestore(&devc->lock, flags); -} - -/* - * SB 2.0 and SB 2.01 compatible routines - */ - -static void 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; - - spin_lock_irqsave(&devc->lock, flags); - 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(KERN_ERR "Sound Blaster: unable to start DAC.\n"); - } - else - printk(KERN_ERR "Sound Blaster: unable to start DAC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - devc->intr_active = 1; -} - -static void 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; - - spin_lock_irqsave(&devc->lock, flags); - 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(KERN_ERR "Sound Blaster: unable to start ADC.\n"); - } - else - printk(KERN_ERR "Sound Blaster: unable to start ADC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - devc->intr_active = 1; -} - -static void 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; -} - -/* - * SB2.01 specific speed setup - */ - -static int sb201_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - int s; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - if (speed > 44100) - speed = 44100; - if (devc->opened & OPEN_READ && speed > 15000) - speed = 15000; - s = speed * devc->channels; - devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - - devc->speed = speed; - } - return devc->speed; -} - -/* - * SB Pro specific routines - */ - -static int 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 */ - - spin_lock_irqsave(&devc->lock, flags); - 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 */ - spin_unlock_irqrestore(&devc->lock, flags); - - devc->trigger_bits = 0; - return 0; -} - -static int 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); - - spin_lock_irqsave(&devc->lock, flags); - 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 */ - spin_unlock_irqrestore(&devc->lock, flags); - } - else - { - spin_unlock_irqrestore(&devc->lock, flags); - tmp = sb_getmixer(devc, 0x0e); - if (devc->channels == 1) - tmp &= ~0x02; - else - tmp |= 0x02; - sb_setmixer(devc, 0x0e, tmp); - } - devc->trigger_bits = 0; - return 0; -} - -static int sbpro_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - if (speed > 44100) - speed = 44100; - if (devc->channels > 1 && speed > 22050) - speed = 22050; - sb201_audio_set_speed(dev, speed); - } - return devc->speed; -} - -static short 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 && devc->channels == 2) - sbpro_audio_set_speed(dev, devc->speed); - } - } - return devc->channels; -} - -static int jazz16_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - int tmp; - int s; - - if (speed < 5000) - speed = 5000; - if (speed > 44100) - speed = 44100; - - s = speed * devc->channels; - - devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff; - - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - - devc->speed = speed; - } - return devc->speed; -} - -/* - * SB16 specific routines - */ - -static int sb16_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - int max_speed = devc->submodel == SUBMDL_ALS100 ? 48000 : 44100; - - if (speed > 0) - { - if (speed < 5000) - speed = 5000; - - if (speed > max_speed) - speed = max_speed; - - devc->speed = speed; - } - return devc->speed; -} - -static unsigned int sb16_audio_set_bits(int dev, unsigned int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (bits != 0) - { - if (bits == AFMT_U8 || bits == AFMT_S16_LE) - devc->bits = bits; - else - devc->bits = AFMT_U8; - } - - return devc->bits; -} - -static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex) - { - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? - devc->dma16 : devc->dma8; - } - else if (devc->bits == AFMT_S16_LE) - { - audio_devs[dev]->dmap_out->dma = devc->dma8; - audio_devs[dev]->dmap_in->dma = devc->dma16; - } - else - { - audio_devs[dev]->dmap_out->dma = devc->dma16; - audio_devs[dev]->dmap_in->dma = devc->dma8; - } - - devc->trigger_bits = 0; - return 0; -} - -static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex) - { - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? - devc->dma16 : devc->dma8; - } - else if (devc->bits == AFMT_S16_LE) - { - audio_devs[dev]->dmap_out->dma = devc->dma8; - audio_devs[dev]->dmap_in->dma = devc->dma16; - } - else - { - audio_devs[dev]->dmap_out->dma = devc->dma16; - audio_devs[dev]->dmap_in->dma = devc->dma8; - } - - devc->trigger_bits = 0; - return 0; -} - -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 bits; - - if (!devc->fullduplex || devc->bits == AFMT_S16_LE) - { - devc->irq_mode = IMODE_OUTPUT; - devc->intr_active = 1; - } - else - { - devc->irq_mode_16 = IMODE_OUTPUT; - devc->intr_active_16 = 1; - } - - /* save value */ - spin_lock_irqsave(&devc->lock, flags); - bits = devc->bits; - if (devc->fullduplex) - devc->bits = (devc->bits == AFMT_S16_LE) ? - AFMT_U8 : AFMT_S16_LE; - spin_unlock_irqrestore(&devc->lock, flags); - - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; - - spin_lock_irqsave(&devc->lock, flags); - - /* 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, (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 real value after all programming */ - devc->bits = bits; - spin_unlock_irqrestore(&devc->lock, flags); -} - - -/* - * This fails on the Cyrix MediaGX. If you don't have the DMA enabled - * before the first sample arrives it locks up. However even if you - * do enable the DMA in time you just get DMA timeouts and missing - * interrupts and stuff, so for now I've not bothered fixing this either. - */ - -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; - - if (!devc->fullduplex || devc->bits != AFMT_S16_LE) - { - devc->irq_mode = IMODE_INPUT; - devc->intr_active = 1; - } - else - { - devc->irq_mode_16 = IMODE_INPUT; - devc->intr_active_16 = 1; - } - - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; - - spin_lock_irqsave(&devc->lock, flags); - - /* 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, (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)); - - spin_unlock_irqrestore(&devc->lock, flags); -} - -static void sb16_audio_trigger(int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - int bits_16 = bits & devc->irq_mode_16; - bits &= devc->irq_mode; - - if (!bits && !bits_16) - sb_dsp_command(devc, 0xd0); /* Halt DMA */ - else - { - if (bits) - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb16_audio_start_input(dev, - devc->trg_buf, - devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb16_audio_output_block(dev, - devc->trg_buf, - devc->trg_bytes, - devc->trg_intrflag); - break; - } - } - if (bits_16) - { - switch (devc->irq_mode_16) - { - case IMODE_INPUT: - sb16_audio_start_input(dev, - devc->trg_buf_16, - devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - - case IMODE_OUTPUT: - sb16_audio_output_block(dev, - devc->trg_buf_16, - devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - } - } - } - - devc->trigger_bits = bits | bits_16; -} - -static unsigned char lbuf8[2048]; -static signed short *lbuf16 = (signed short *)lbuf8; -#define LBUFCOPYSIZE 1024 -static void -sb16_copy_from_user(int dev, - char *localbuf, int localoffs, - const char __user *userbuf, int useroffs, - int max_in, int max_out, - int *used, int *returned, - int len) -{ - sb_devc *devc = audio_devs[dev]->devc; - int i, c, p, locallen; - unsigned char *buf8; - signed short *buf16; - - /* if not duplex no conversion */ - if (!devc->fullduplex) - { - if (copy_from_user(localbuf + localoffs, - userbuf + useroffs, len)) - return; - *used = len; - *returned = len; - } - else if (devc->bits == AFMT_S16_LE) - { - /* 16 -> 8 */ - /* max_in >> 1, max number of samples in ( 16 bits ) */ - /* max_out, max number of samples out ( 8 bits ) */ - /* len, number of samples that will be taken ( 16 bits )*/ - /* c, count of samples remaining in buffer ( 16 bits )*/ - /* p, count of samples already processed ( 16 bits )*/ - len = ( (max_in >> 1) > max_out) ? max_out : (max_in >> 1); - c = len; - p = 0; - buf8 = (unsigned char *)(localbuf + localoffs); - while (c) - { - locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); - /* << 1 in order to get 16 bit samples */ - if (copy_from_user(lbuf16, - userbuf + useroffs + (p << 1), - locallen << 1)) - return; - for (i = 0; i < locallen; i++) - { - buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80; - } - c -= locallen; p += locallen; - } - /* used = ( samples * 16 bits size ) */ - *used = max_in > ( max_out << 1) ? (max_out << 1) : max_in; - /* returned = ( samples * 8 bits size ) */ - *returned = len; - } - else - { - /* 8 -> 16 */ - /* max_in, max number of samples in ( 8 bits ) */ - /* max_out >> 1, max number of samples out ( 16 bits ) */ - /* len, number of samples that will be taken ( 8 bits )*/ - /* c, count of samples remaining in buffer ( 8 bits )*/ - /* p, count of samples already processed ( 8 bits )*/ - len = max_in > (max_out >> 1) ? (max_out >> 1) : max_in; - c = len; - p = 0; - buf16 = (signed short *)(localbuf + localoffs); - while (c) - { - locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); - if (copy_from_user(lbuf8, - userbuf+useroffs + p, - locallen)) - return; - for (i = 0; i < locallen; i++) - { - buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8; - } - c -= locallen; p += locallen; - } - /* used = ( samples * 8 bits size ) */ - *used = len; - /* returned = ( samples * 16 bits size ) */ - *returned = len << 1; - } -} - -static void -sb16_audio_mmap(int dev) -{ - sb_devc *devc = audio_devs[dev]->devc; - devc->fullduplex = 0; -} - -static struct audio_driver sb1_audio_driver = /* SB1.x */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb1_audio_prepare_for_input, - .prepare_for_output = sb1_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb1_audio_trigger, - .set_speed = sb1_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sb1_audio_set_channels -}; - -static struct audio_driver sb20_audio_driver = /* SB2.0 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb1_audio_prepare_for_input, - .prepare_for_output = sb1_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = sb1_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sb1_audio_set_channels -}; - -static struct audio_driver sb201_audio_driver = /* SB2.01 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb1_audio_prepare_for_input, - .prepare_for_output = sb1_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = sb201_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sb1_audio_set_channels -}; - -static struct audio_driver sbpro_audio_driver = /* SB Pro */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sbpro_audio_prepare_for_input, - .prepare_for_output = sbpro_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = sbpro_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sbpro_audio_set_channels -}; - -static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sbpro_audio_prepare_for_input, - .prepare_for_output = sbpro_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = jazz16_audio_set_speed, - .set_bits = sb16_audio_set_bits, - .set_channels = sbpro_audio_set_channels -}; - -static struct audio_driver sb16_audio_driver = /* SB16 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb16_audio_prepare_for_input, - .prepare_for_output = sb16_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .copy_user = sb16_copy_from_user, - .trigger = sb16_audio_trigger, - .set_speed = sb16_audio_set_speed, - .set_bits = sb16_audio_set_bits, - .set_channels = sbpro_audio_set_channels, - .mmap = sb16_audio_mmap -}; - -void sb_audio_init(sb_devc * devc, char *name, struct module *owner) -{ - 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")); - driver = ess_audio_init (devc, &audio_flags, &format_mask); - break; - - case MDL_SB16: - DDB(printk("Will use SB16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - if (devc->dma8 != devc->dma16 && devc->dma16 != -1) - { - audio_flags |= DMA_DUPLEX; - devc->duplex = 1; - } - driver = &sb16_audio_driver; - break; - - default: - DDB(printk("Will use SB Pro driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sbpro_audio_driver; - } - - if (owner) - driver->owner = owner; - - if ((devc->dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - name,driver, sizeof(struct audio_driver), - audio_flags, format_mask, devc, - devc->dma8, - devc->duplex ? devc->dma16 : devc->dma8)) < 0) - { - printk(KERN_ERR "Sound Blaster: unable to install audio.\n"); - return; - } - audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev; - audio_devs[devc->dev]->min_fragment = 5; -} diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c deleted file mode 100644 index 2a92cfe6cfe9..000000000000 --- a/sound/oss/sb_card.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * sound/oss/sb_card.c - * - * Detection routine for the ISA Sound Blaster and compatible sound - * cards. - * - * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this - * software for more info. - * - * This is a complete rewrite of the detection routines. This was - * prompted by the PnP API change during v2.5 and the ugly state the - * code was in. - * - * Copyright (C) by Paul Laufer 2002. Based on code originally by - * Hannu Savolainen which was modified by many others over the - * years. Authors specifically mentioned in the previous version were: - * Daniel Stone, Alessandro Zummo, Jeff Garzik, Arnaldo Carvalho de - * Melo, Daniel Church, and myself. - * - * 02-05-2003 Original Release, Paul Laufer <paul@laufernet.com> - * 02-07-2003 Bug made it into first release. Take two. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/init.h> -#include "sound_config.h" -#include "sb_mixer.h" -#include "sb.h" -#ifdef CONFIG_PNP -#include <linux/pnp.h> -#endif /* CONFIG_PNP */ -#include "sb_card.h" - -MODULE_DESCRIPTION("OSS Soundblaster ISA PnP and legacy sound driver"); -MODULE_LICENSE("GPL"); - -extern void *smw_free; - -static int __initdata mpu_io = 0; -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma16 = -1; -static int __initdata type = 0; /* Can set this to a specific card type */ -static int __initdata esstype = 0; /* ESS chip type */ -static int __initdata acer = 0; /* Do acer notebook init? */ -static int __initdata sm_games = 0; /* Logitech soundman games? */ - -static struct sb_card_config *legacy = NULL; - -#ifdef CONFIG_PNP -static int pnp_registered; -static int __initdata pnp = 1; -/* -static int __initdata uart401 = 0; -*/ -#else -static int __initdata pnp = 0; -#endif - -module_param_hw(io, int, ioport, 000); -MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); -module_param_hw(irq, int, irq, 000); -MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)"); -module_param_hw(dma, int, dma, 000); -MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)"); -module_param_hw(dma16, int, dma, 000); -MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)"); -module_param_hw(mpu_io, int, ioport, 000); -MODULE_PARM_DESC(mpu_io, "MPU base address"); -module_param(type, int, 000); -MODULE_PARM_DESC(type, "You can set this to specific card type (doesn't " \ - "work with pnp)"); -module_param(sm_games, int, 000); -MODULE_PARM_DESC(sm_games, "Enable support for Logitech soundman games " \ - "(doesn't work with pnp)"); -module_param(esstype, int, 000); -MODULE_PARM_DESC(esstype, "ESS chip type (doesn't work with pnp)"); -module_param(acer, int, 000); -MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks "\ - "(doesn't work with pnp)"); - -#ifdef CONFIG_PNP -module_param(pnp, int, 000); -MODULE_PARM_DESC(pnp, "Went set to 0 will disable detection using PnP. "\ - "Default is 1.\n"); -/* Not done yet.... */ -/* -module_param(uart401, int, 000); -MODULE_PARM_DESC(uart401, "When set to 1, will attempt to detect and enable"\ - "the mpu on some clones"); -*/ -#endif /* CONFIG_PNP */ - -/* OSS subsystem card registration shared by PnP and legacy routines */ -static int sb_register_oss(struct sb_card_config *scc, struct sb_module_options *sbmo) -{ - if (!request_region(scc->conf.io_base, 16, "soundblaster")) { - printk(KERN_ERR "sb: ports busy.\n"); - kfree(scc); - return -EBUSY; - } - - if (!sb_dsp_detect(&scc->conf, 0, 0, sbmo)) { - release_region(scc->conf.io_base, 16); - printk(KERN_ERR "sb: Failed DSP Detect.\n"); - kfree(scc); - return -ENODEV; - } - if(!sb_dsp_init(&scc->conf, THIS_MODULE)) { - printk(KERN_ERR "sb: Failed DSP init.\n"); - kfree(scc); - return -ENODEV; - } - if(scc->mpucnf.io_base > 0) { - scc->mpu = 1; - printk(KERN_INFO "sb: Turning on MPU\n"); - if(!probe_sbmpu(&scc->mpucnf, THIS_MODULE)) - scc->mpu = 0; - } - - return 1; -} - -static void sb_unload(struct sb_card_config *scc) -{ - sb_dsp_unload(&scc->conf, 0); - if(scc->mpu) - unload_sbmpu(&scc->mpucnf); - kfree(scc); -} - -/* Register legacy card with OSS subsystem */ -static int __init sb_init_legacy(void) -{ - struct sb_module_options sbmo = {0}; - - if((legacy = kzalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "sb: Error: Could not allocate memory\n"); - return -ENOMEM; - } - - legacy->conf.io_base = io; - legacy->conf.irq = irq; - legacy->conf.dma = dma; - legacy->conf.dma2 = dma16; - legacy->conf.card_subtype = type; - - legacy->mpucnf.io_base = mpu_io; - legacy->mpucnf.irq = -1; - legacy->mpucnf.dma = -1; - legacy->mpucnf.dma2 = -1; - - sbmo.esstype = esstype; - sbmo.sm_games = sm_games; - sbmo.acer = acer; - - return sb_register_oss(legacy, &sbmo); -} - -#ifdef CONFIG_PNP - -/* Populate the OSS subsystem structures with information from PnP */ -static void sb_dev2cfg(struct pnp_dev *dev, struct sb_card_config *scc) -{ - scc->conf.io_base = -1; - scc->conf.irq = -1; - scc->conf.dma = -1; - scc->conf.dma2 = -1; - scc->mpucnf.io_base = -1; - scc->mpucnf.irq = -1; - scc->mpucnf.dma = -1; - scc->mpucnf.dma2 = -1; - - /* All clones layout their PnP tables differently and some use - different logical devices for the MPU */ - if(!strncmp("CTL",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - scc->mpucnf.io_base = pnp_port_start(dev,1); - return; - } - if(!strncmp("tBA",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - return; - } - if(!strncmp("ESS",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - scc->mpucnf.io_base = pnp_port_start(dev,2); - return; - } - if(!strncmp("CMI",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - return; - } - if(!strncmp("RWB",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - return; - } - if(!strncmp("ALS",scc->card_id,3)) { - if(!strncmp("ALS0007",scc->card_id,7)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - } else { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,1); - scc->conf.dma2 = pnp_dma(dev,0); - } - return; - } - if(!strncmp("RTL",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,1); - scc->conf.dma2 = pnp_dma(dev,0); - } -} - -static unsigned int sb_pnp_devices; - -/* Probe callback function for the PnP API */ -static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id) -{ - struct sb_card_config *scc; - struct sb_module_options sbmo = {0}; /* Default to 0 for PnP */ - struct pnp_dev *dev = pnp_request_card_device(card, card_id->devs[0].id, NULL); - - if(!dev){ - return -EBUSY; - } - - if((scc = kzalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "sb: Error: Could not allocate memory\n"); - return -ENOMEM; - } - - printk(KERN_INFO "sb: PnP: Found Card Named = \"%s\", Card PnP id = " \ - "%s, Device PnP id = %s\n", card->card->name, card_id->id, - dev->id->id); - - scc->card_id = card_id->id; - scc->dev_id = dev->id->id; - sb_dev2cfg(dev, scc); - - printk(KERN_INFO "sb: PnP: Detected at: io=0x%x, irq=%d, " \ - "dma=%d, dma16=%d\n", scc->conf.io_base, scc->conf.irq, - scc->conf.dma, scc->conf.dma2); - - pnp_set_card_drvdata(card, scc); - sb_pnp_devices++; - - return sb_register_oss(scc, &sbmo); -} - -static void sb_pnp_remove(struct pnp_card_link *card) -{ - struct sb_card_config *scc = pnp_get_card_drvdata(card); - - if(!scc) - return; - - printk(KERN_INFO "sb: PnP: Removing %s\n", scc->card_id); - - sb_unload(scc); -} - -static struct pnp_card_driver sb_pnp_driver = { - .name = "OSS SndBlstr", /* 16 character limit */ - .id_table = sb_pnp_card_table, - .probe = sb_pnp_probe, - .remove = sb_pnp_remove, -}; -MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table); -#endif /* CONFIG_PNP */ - -static void sb_unregister_all(void) -{ -#ifdef CONFIG_PNP - if (pnp_registered) - pnp_unregister_card_driver(&sb_pnp_driver); -#endif -} - -static int __init sb_init(void) -{ - int lres = 0; - int pres = 0; - - printk(KERN_INFO "sb: Init: Starting Probe...\n"); - - if(io != -1 && irq != -1 && dma != -1) { - printk(KERN_INFO "sb: Probing legacy card with io=%x, "\ - "irq=%d, dma=%d, dma16=%d\n",io, irq, dma, dma16); - lres = sb_init_legacy(); - } else if((io != -1 || irq != -1 || dma != -1) || - (!pnp && (io == -1 && irq == -1 && dma == -1))) - printk(KERN_ERR "sb: Error: At least io, irq, and dma "\ - "must be set for legacy cards.\n"); - -#ifdef CONFIG_PNP - if(pnp) { - int err = pnp_register_card_driver(&sb_pnp_driver); - if (!err) - pnp_registered = 1; - pres = sb_pnp_devices; - } -#endif - printk(KERN_INFO "sb: Init: Done\n"); - - /* If either PnP or Legacy registered a card then return - * success */ - if (pres == 0 && lres <= 0) { - sb_unregister_all(); - return -ENODEV; - } - return 0; -} - -static void __exit sb_exit(void) -{ - printk(KERN_INFO "sb: Unloading...\n"); - - /* Unload legacy card */ - if (legacy) { - printk (KERN_INFO "sb: Unloading legacy card\n"); - sb_unload(legacy); - } - - sb_unregister_all(); - - vfree(smw_free); - smw_free = NULL; -} - -module_init(sb_init); -module_exit(sb_exit); diff --git a/sound/oss/sb_card.h b/sound/oss/sb_card.h deleted file mode 100644 index 5535cff800df..000000000000 --- a/sound/oss/sb_card.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * sound/oss/sb_card.h - * - * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this - * software for more info. - * - * 02-05-2002 Original Release, Paul Laufer <paul@laufernet.com> - */ - -struct sb_card_config { - struct address_info conf; - struct address_info mpucnf; - const char *card_id; - const char *dev_id; - int mpu; -}; - -#ifdef CONFIG_PNP - -/* - * SoundBlaster PnP tables and structures. - */ - -/* Card PnP ID Table */ -static struct pnp_card_device_id sb_pnp_card_table[] = { - /* Sound Blaster 16 */ - {.id = "CTL0024", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0025", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0026", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0027", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0028", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0029", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL002a", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL002b", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL002c", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL00ed", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0086", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster Vibra16S */ - {.id = "CTL0051", .driver_data = 0, .devs = { {.id="CTL0001"}, } }, - /* Sound Blaster Vibra16C */ - {.id = "CTL0070", .driver_data = 0, .devs = { {.id="CTL0001"}, } }, - /* Sound Blaster Vibra16CL */ - {.id = "CTL0080", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster Vibra16CL */ - {.id = "CTL00F0", .driver_data = 0, .devs = { {.id="CTL0043"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0039", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0042", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0043", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0044", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0045", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0046", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0047", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0048", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0054", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL009C", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Createive SB32 PnP */ - {.id = "CTL009F", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL009D", .driver_data = 0, .devs = { {.id="CTL0042"}, } }, - /* Sound Blaster AWE 64 Gold */ - {.id = "CTL009E", .driver_data = 0, .devs = { {.id="CTL0044"}, } }, - /* Sound Blaster AWE 64 Gold */ - {.id = "CTL00B2", .driver_data = 0, .devs = { {.id="CTL0044"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C1", .driver_data = 0, .devs = { {.id="CTL0042"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C3", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C5", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C7", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00E4", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00E9", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* ESS 1868 */ - {.id = "ESS0968", .driver_data = 0, .devs = { {.id="ESS0968"}, } }, - /* ESS 1868 */ - {.id = "ESS1868", .driver_data = 0, .devs = { {.id="ESS1868"}, } }, - /* ESS 1868 */ - {.id = "ESS1868", .driver_data = 0, .devs = { {.id="ESS8611"}, } }, - /* ESS 1869 PnP AudioDrive */ - {.id = "ESS0003", .driver_data = 0, .devs = { {.id="ESS1869"}, } }, - /* ESS 1869 */ - {.id = "ESS1869", .driver_data = 0, .devs = { {.id="ESS1869"}, } }, - /* ESS 1878 */ - {.id = "ESS1878", .driver_data = 0, .devs = { {.id="ESS1878"}, } }, - /* ESS 1879 */ - {.id = "ESS1879", .driver_data = 0, .devs = { {.id="ESS1879"}, } }, - /* CMI 8330 SoundPRO */ - {.id = "CMI0001", .driver_data = 0, .devs = { {.id="@X@0001"}, - {.id="@H@0001"}, - {.id="@@@0001"}, } }, - /* Diamond DT0197H */ - {.id = "RWR1688", .driver_data = 0, .devs = { {.id="@@@0001"}, - {.id="@X@0001"}, - {.id="@H@0001"}, } }, - /* ALS007 */ - {.id = "ALS0007", .driver_data = 0, .devs = { {.id="@@@0001"}, - {.id="@X@0001"}, - {.id="@H@0001"}, } }, - /* ALS100 */ - {.id = "ALS0001", .driver_data = 0, .devs = { {.id="@@@0001"}, - {.id="@X@0001"}, - {.id="@H@0001"}, } }, - /* ALS110 */ - {.id = "ALS0110", .driver_data = 0, .devs = { {.id="@@@1001"}, - {.id="@X@1001"}, - {.id="@H@0001"}, } }, - /* ALS120 */ - {.id = "ALS0120", .driver_data = 0, .devs = { {.id="@@@2001"}, - {.id="@X@2001"}, - {.id="@H@0001"}, } }, - /* ALS200 */ - {.id = "ALS0200", .driver_data = 0, .devs = { {.id="@@@0020"}, - {.id="@X@0030"}, - {.id="@H@0001"}, } }, - /* ALS200 */ - {.id = "RTL3000", .driver_data = 0, .devs = { {.id="@@@2001"}, - {.id="@X@2001"}, - {.id="@H@0001"}, } }, - /* Sound Blaster 16 (Virtual PC 2004) */ - {.id = "tBA03b0", .driver_data = 0, .devs = { {.id="PNPb003"}, } }, - /* -end- */ - {.id = "", } -}; - -#endif diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c deleted file mode 100644 index 3d50fb4236ed..000000000000 --- a/sound/oss/sb_common.c +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * sound/oss/sb_common.c - * - * Common routines for Sound Blaster compatible cards. - * - * - * 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. - * - * - * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts - * for full duplex support ( only sb16 by now ) - * Rolf Fokkens: Added (BETA?) support for ES1887 chips. - * (fokkensr@vertis.nl) Which means: You can adjust the recording levels. - * - * 2000/01/18 - separated sb_card and sb_common - - * Jeff Garzik <jgarzik@pobox.com> - * - * 2000/09/18 - got rid of attach_uart401 - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - * - * 2001/01/26 - replaced CLI/STI with spinlocks - * Chris Rankin <rankinc@zipworld.com.au> - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/slab.h> - -#include "sound_config.h" -#include "sound_firmware.h" - -#include "mpu401.h" - -#include "sb_mixer.h" -#include "sb.h" -#include "sb_ess.h" - -/* - * global module flag - */ - -int sb_be_quiet; - -static sb_devc *detected_devc; /* For communication from probe to init */ -static sb_devc *last_devc; /* For MPU401 initialization */ - -static unsigned char jazz_irq_bits[] = { - 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 -}; - -static unsigned char jazz_dma_bits[] = { - 0, 1, 0, 2, 0, 3, 0, 4 -}; - -void *smw_free; - -/* - * Jazz16 chipset specific control variables - */ - -static int jazz16_base; /* Not detected */ -static unsigned char jazz16_bits; /* I/O relocation bits */ -static DEFINE_SPINLOCK(jazz16_lock); - -/* - * Logitech Soundman Wave specific initialization code - */ - -#ifdef SMW_MIDI0001_INCLUDED -#include "smw-midi0001.h" -#else -static unsigned char *smw_ucode; -static int smw_ucodeLen; - -#endif - -static sb_devc *last_sb; /* Last sb loaded */ - -int 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 && (limit-jiffies)>0; i++) - { - if ((inb(DSP_STATUS) & 0x80) == 0) - { - outb((val), DSP_COMMAND); - return 1; - } - } - printk(KERN_WARNING "Sound Blaster: DSP command(%x) timeout.\n", val); - return 0; -} - -int 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; -} - -static void sb_intr (sb_devc *devc) -{ - int status; - unsigned char src = 0xff; - - if (devc->model == MDL_SB16) - { - src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ - - if (src & 4) /* MPU401 interrupt */ - if(devc->midi_irq_cookie) - uart401intr(devc->irq, devc->midi_irq_cookie); - - if (!(src & 3)) - return; /* Not a DSP interrupt */ - } - if (devc->intr_active && (!devc->fullduplex || (src & 0x01))) - { - 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: - sb_midi_interrupt(devc); - break; - - default: - /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ - ; - } - } - else if (devc->intr_active_16 && (src & 0x02)) - { - switch (devc->irq_mode_16) - { - case IMODE_OUTPUT: - DMAbuf_outputintr(devc->dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr(devc->dev); - break; - - case IMODE_INIT: - break; - - default: - /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ - ; - } - } - /* - * Acknowledge interrupts - */ - - if (src & 0x01) - status = inb(DSP_DATA_AVAIL); - - if (devc->model == MDL_SB16 && src & 0x02) - status = inb(DSP_DATA_AVL16); -} - -static void pci_intr(sb_devc *devc) -{ - int src = inb(devc->pcibase+0x1A); - src&=3; - if(src) - sb_intr(devc); -} - -static irqreturn_t sbintr(int irq, void *dev_id) -{ - sb_devc *devc = dev_id; - - devc->irq_ok = 1; - - switch (devc->model) { - case MDL_ESSPCI: - pci_intr (devc); - break; - - case MDL_ESS: - ess_intr (devc); - break; - default: - sb_intr (devc); - break; - } - return IRQ_HANDLED; -} - -int sb_dsp_reset(sb_devc * devc) -{ - int loopc; - - if (devc->model == MDL_ESS) return ess_dsp_reset (devc); - - /* This is only for non-ESS chips */ - - outb(1, DSP_RESET); - - udelay(10); - outb(0, DSP_RESET); - udelay(30); - - 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 */ - } - - return 1; -} - -static void dsp_get_vers(sb_devc * devc) -{ - int i; - - unsigned long flags; - - DDB(printk("Entered dsp_get_vers()\n")); - spin_lock_irqsave(&devc->lock, flags); - 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; - } - } - } - spin_unlock_irqrestore(&devc->lock, flags); - DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor)); -} - -static int sb16_set_dma_hw(sb_devc * devc) -{ - int bits; - - if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) - { - printk(KERN_ERR "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); - - sb_setmixer(devc, DMA_NR, bits); - return 1; -} - -static void 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(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); - } -} - -static int 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(KERN_ERR "SB16: Invalid IRQ%d\n", level); - return 0; - } - sb_setmixer(devc, IRQ_NR, ival); - return 1; -} - -static void 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; - - 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; - jazz16_base = hw_config->io_base; - - /* - * Magic wake up sequence by writing to 0x201 (aka Joystick port) - */ - spin_lock_irqsave(&jazz16_lock, flags); - outb((0xAF), 0x201); - outb((0x50), 0x201); - outb((bits), 0x201); - spin_unlock_irqrestore(&jazz16_lock, flags); -} - -static int init_Jazz16(sb_devc * devc, struct address_info *hw_config) -{ - 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_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(KERN_ERR "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(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); - return 0; - } - if (hw_config->dma2 < 0) - { - printk(KERN_ERR "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(KERN_ERR "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 = "Jazz16"; - 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 -} - -int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo) -{ - sb_devc sb_info; - sb_devc *devc = &sb_info; - - memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ - - /* Copy module options in place */ - if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options)); - - sb_info.my_mididev = -1; - sb_info.my_mixerdev = -1; - sb_info.dev = -1; - - /* - * Initialize variables - */ - - DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base)); - - spin_lock_init(&devc->lock); - devc->type = hw_config->card_subtype; - - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma8 = hw_config->dma; - - devc->dma16 = -1; - devc->pcibase = pciio; - - if(pci == SB_PCI_ESSMAESTRO) - { - devc->model = MDL_ESSPCI; - devc->caps |= SB_PCI_IRQ; - hw_config->driver_use_1 |= SB_PCI_IRQ; - hw_config->card_subtype = MDL_ESSPCI; - } - - if(pci == SB_PCI_YAMAHA) - { - devc->model = MDL_YMPCI; - devc->caps |= SB_PCI_IRQ; - hw_config->driver_use_1 |= SB_PCI_IRQ; - hw_config->card_subtype = MDL_YMPCI; - - printk("Yamaha PCI mode.\n"); - } - - if (devc->sbmo.acer) - { - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - 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); - spin_unlock_irqrestore(&devc->lock, flags); - } - /* - * Detect the device - */ - - 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->major == 0 && (devc->type == MDL_ESS || devc->type == 0)) - relocate_ess1688(devc); - - if (!sb_dsp_reset(devc)) - { - DDB(printk("SB reset failed\n")); -#ifdef MODULE - printk(KERN_INFO "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; - } - } - } - - if(devc->type == MDL_ESSPCI) - devc->model = MDL_ESSPCI; - - if(devc->type == MDL_YMPCI) - { - printk("YMPCI selected\n"); - devc->model = MDL_YMPCI; - } - - /* - * Save device information for sb_dsp_init() - */ - - - detected_devc = kmemdup(devc, sizeof(sb_devc), GFP_KERNEL); - if (detected_devc == NULL) - { - printk(KERN_ERR "sb: Can't allocate memory for device information\n"); - return 0; - } - MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); - return 1; -} - -int sb_dsp_init(struct address_info *hw_config, struct module *owner) -{ - sb_devc *devc; - char name[100]; - extern int sb_be_quiet; - int mixer22, mixer30; - -/* - * 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) - { - MDB(printk("No detected device\n")); - return 0; - } - devc = detected_devc; - detected_devc = NULL; - - if (devc->base != hw_config->io_base) - { - DDB(printk("I/O port mismatch\n")); - release_region(devc->base, 16); - return 0; - } - /* - * Now continue initialization of the device - */ - - devc->caps = hw_config->driver_use_1; - - if (!((devc->caps & SB_NO_AUDIO) && (devc->caps & SB_NO_MIDI)) && hw_config->irq > 0) - { /* IRQ setup */ - - /* - * ESS PCI cards do shared PCI IRQ stuff. Since they - * will get shared PCI irq lines we must cope. - */ - - int i=(devc->caps&SB_PCI_IRQ)?IRQF_SHARED:0; - - if (request_irq(hw_config->irq, sbintr, i, "soundblaster", devc) < 0) - { - printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); - release_region(devc->base, 16); - return 0; - } - devc->irq_ok = 0; - - if (devc->major == 4) - if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ - { - free_irq(devc->irq, devc); - release_region(devc->base, 16); - return 0; - } - 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 (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(KERN_WARNING "sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); - else - { - DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq)); - } - } - } /* IRQ setup */ - - last_sb = devc; - - 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 */ - switch (devc->model) { - case 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 MDL_ESS: - ess_dsp_init(devc, hw_config); - break; - } - break; - - case 4: - devc->model = hw_config->card_subtype = MDL_SB16; - /* - * ALS007 and ALS100 return DSP version 4.2 and have 2 post-reset !=0 - * registers at 0x3c and 0x4c (output ctrl registers on ALS007) whereas - * a "standard" SB16 doesn't have a register at 0x4c. ALS100 actively - * updates register 0x22 whenever 0x30 changes, as per the SB16 spec. - * Since ALS007 doesn't, this can be used to differentiate the 2 cards. - */ - if ((devc->minor == 2) && sb_getmixer(devc,0x3c) && sb_getmixer(devc,0x4c)) - { - mixer30 = sb_getmixer(devc,0x30); - sb_setmixer(devc,0x22,(mixer22=sb_getmixer(devc,0x22)) & 0x0f); - sb_setmixer(devc,0x30,0xff); - /* ALS100 will force 0x30 to 0xf8 like SB16; ALS007 will allow 0xff. */ - /* Register 0x22 & 0xf0 on ALS100 == 0xf0; on ALS007 it == 0x10. */ - if ((sb_getmixer(devc,0x30) != 0xff) || ((sb_getmixer(devc,0x22) & 0xf0) != 0x10)) - { - devc->submodel = SUBMDL_ALS100; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16 (ALS-100)"; - } - else - { - sb_setmixer(devc,0x3c,0x1f); /* Enable all inputs */ - sb_setmixer(devc,0x4c,0x1f); - sb_setmixer(devc,0x22,mixer22); /* Restore 0x22 to original value */ - devc->submodel = SUBMDL_ALS007; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16 (ALS-007)"; - } - sb_setmixer(devc,0x30,mixer30); - } - else 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(KERN_WARNING "SB16: Bad or missing 16 bit DMA channel\n"); - devc->dma16 = devc->dma8; - } - else - devc->dma16 = hw_config->dma2; - - if(!sb16_set_dma_hw(devc)) { - free_irq(devc->irq, devc); - release_region(hw_config->io_base, 16); - return 0; - } - - devc->caps |= SB_NO_MIDI; - } - - if (!(devc->caps & SB_NO_MIXER)) - if (devc->major == 3 || devc->major == 4) - sb_mixer_init(devc, owner); - - if (!(devc->caps & SB_NO_MIDI)) - sb_dsp_midi_init(devc, owner); - - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; - - sprintf(name, "%s (%d.%02d)", hw_config->name, devc->major, devc->minor); - conf_printf(name, hw_config); - - /* - * Assuming that a sound card is Sound Blaster (compatible) is the most common - * configuration error and the mother of all problems. Usually sound cards - * emulate SB Pro but in addition they have a 16 bit native mode which should be - * 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 (rare ones may have 3.2). */ - { - printk(KERN_INFO "This sound card may not be fully Sound Blaster Pro compatible.\n"); - printk(KERN_INFO "In many cases there is another way to configure OSS so that\n"); - printk(KERN_INFO "it works properly with OSS (for example in 16 bit mode).\n"); - printk(KERN_INFO "Please ignore this message if you _really_ have a SB Pro.\n"); - } - else if (!sb_be_quiet && devc->model == MDL_SBPRO) - { - printk(KERN_INFO "SB DSP version is just %d.%02d which means that your card is\n", devc->major, devc->minor); - printk(KERN_INFO "several years old (8 bit only device) or alternatively the sound driver\n"); - printk(KERN_INFO "is incorrectly configured.\n"); - } - } - hw_config->card_subtype = devc->model; - hw_config->slots[0]=devc->dev; - last_devc = devc; /* For SB MPU detection */ - - if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) - { - if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) - { - printk(KERN_WARNING "Sound Blaster: 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(KERN_WARNING "Sound Blaster: can't allocate 16 bit DMA channel %d.\n", devc->dma16); - } - sb_audio_init(devc, name, owner); - hw_config->slots[0]=devc->dev; - } - else - { - MDB(printk("Sound Blaster: no audio devices found.\n")); - } - return 1; -} - -/* if (sbmpu) below we allow mpu401 to manage the midi devs - otherwise we have to unload them. (Andrzej Krzysztofowicz) */ - -void sb_dsp_unload(struct address_info *hw_config, int sbmpu) -{ - sb_devc *devc; - - devc = audio_devs[hw_config->slots[0]]->devc; - - if (devc && devc->base == hw_config->io_base) - { - if ((devc->model & MDL_ESS) && devc->pcibase) - release_region(devc->pcibase, 8); - - 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)) - { - if (devc->irq > 0) - free_irq(devc->irq, devc); - - sb_mixer_unload(devc); - /* We don't have to do this bit any more the UART401 is its own - master -- Krzysztof Halasa */ - /* But we have to do it, if UART401 is not detected */ - if (!sbmpu) - sound_unload_mididev(devc->my_mididev); - sound_unload_audiodev(devc->dev); - } - kfree(devc); - } - else - release_region(hw_config->io_base, 16); - - kfree(detected_devc); -} - -/* - * Mixer access routines - * - * ES1887 modifications: some mixer registers reside in the - * range above 0xa0. These must be accessed in another way. - */ - -void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) -{ - unsigned long flags; - - if (devc->model == MDL_ESS) { - ess_setmixer (devc, port, value); - return; - } - - spin_lock_irqsave(&devc->lock, flags); - - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - udelay(20); - outb(((unsigned char) (value & 0xff)), MIXER_DATA); - udelay(20); - - spin_unlock_irqrestore(&devc->lock, flags); -} - -unsigned int sb_getmixer(sb_devc * devc, unsigned int port) -{ - unsigned int val; - unsigned long flags; - - if (devc->model == MDL_ESS) return ess_getmixer (devc, port); - - spin_lock_irqsave(&devc->lock, flags); - - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - udelay(20); - val = inb(MIXER_DATA); - udelay(20); - - spin_unlock_irqrestore(&devc->lock, flags); - - return val; -} - -void sb_chgmixer - (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val) -{ - int value; - - value = sb_getmixer(devc, reg); - value = (value & ~mask) | (val & mask); - sb_setmixer(devc, reg, value); -} - -/* - * MPU401 MIDI initialization. - */ - -static void smw_putmem(sb_devc * devc, int base, int addr, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&jazz16_lock, flags); /* NOT the SB card? */ - - outb((addr & 0xff), base + 1); /* Low address bits */ - outb((addr >> 8), base + 2); /* High address bits */ - outb((val), base); /* Data */ - - spin_unlock_irqrestore(&jazz16_lock, flags); -} - -static unsigned char smw_getmem(sb_devc * devc, int base, int addr) -{ - unsigned long flags; - unsigned char val; - - spin_lock_irqsave(&jazz16_lock, flags); /* NOT the SB card? */ - - outb((addr & 0xff), base + 1); /* Low address bits */ - outb((addr >> 8), base + 2); /* High address bits */ - val = inb(base); /* Data */ - - spin_unlock_irqrestore(&jazz16_lock, flags); - return val; -} - -static int 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 - */ - - 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 */ - - mdelay(3); /* Wait at least 1ms */ - - outb((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ - - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem(devc, mp_base, 0, 0x00); - smw_putmem(devc, mp_base, 1, 0xff); - udelay(10); - - if (smw_getmem(devc, mp_base, 0) != 0x00 || smw_getmem(devc, mp_base, 1) != 0xff) - { - DDB(printk("SM 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 - */ - - devc->model = MDL_SMW; - smw_mixer_init(devc); - -#ifdef MODULE - if (!smw_ucode) - { - smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); - smw_free = smw_ucode; - } -#endif - if (smw_ucodeLen > 0) - { - if (smw_ucodeLen != 8192) - { - printk(KERN_ERR "SM 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(KERN_ERR "SM Wave: Microcode verification failed\n"); - return 0; - } - } - control = 0; -#ifdef SMW_SCSI_IRQ - /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * FIXME - make this a module option - * - * 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 */ -#endif - outb((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ - hw_config->name = "SoundMan Wave"; - return 1; -} - -static int 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(KERN_ERR "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(KERN_ERR "Jazz16: Invalid MIDI I/O port %x\n", mpu_base); - return 0; - } - /* - * Magic wake up sequence by writing to 0x201 (aka Joystick port) - */ - spin_lock_irqsave(&jazz16_lock, flags); - outb(0xAF, 0x201); - outb(0x50, 0x201); - outb(bits, 0x201); - spin_unlock_irqrestore(&jazz16_lock, flags); - - hw_config->name = "Jazz16"; - smw_midi_init(devc, hw_config); - - 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_irq_bits[devc->irq] | - (jazz_irq_bits[irq] << 4))) - return 0; - - return 1; -} - -int probe_sbmpu(struct address_info *hw_config, struct module *owner) -{ - sb_devc *devc = last_devc; - int ret; - - if (last_devc == NULL) - return 0; - - last_devc = NULL; - - if (hw_config->io_base <= 0) - { - /* The real vibra16 is fine about this, but we have to go - wipe up after Cyrix again */ - - if(devc->model == MDL_SB16 && devc->minor >= 12) - { - unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; - sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ - } - return 0; - } - -#if defined(CONFIG_SOUND_MPU401) - if (devc->model == MDL_ESS) - { - struct resource *ports; - ports = request_region(hw_config->io_base, 2, "mpu401"); - if (!ports) { - printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - if (!ess_midi_init(devc, hw_config)) { - release_region(hw_config->io_base, 2); - return 0; - } - hw_config->name = "ESS1xxx MPU"; - devc->midi_irq_cookie = NULL; - if (!probe_mpu401(hw_config, ports)) { - release_region(hw_config->io_base, 2); - return 0; - } - attach_mpu401(hw_config, owner); - if (last_sb->irq == -hw_config->irq) - last_sb->midi_irq_cookie = - (void *)(long) hw_config->slots[1]; - return 1; - } -#endif - - switch (devc->model) - { - case MDL_SB16: - if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) - { - printk(KERN_ERR "SB16: Invalid MIDI port %x\n", hw_config->io_base); - return 0; - } - hw_config->name = "Sound Blaster 16"; - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (devc->minor > 12) /* What is Vibra's version??? */ - sb16_set_mpu_port(devc, hw_config); - 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; - - case MDL_YMPCI: - hw_config->name = "Yamaha PCI Legacy"; - printk("Yamaha PCI legacy UART401 check.\n"); - break; - default: - return 0; - } - - ret = probe_uart401(hw_config, owner); - if (ret) - last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; - return ret; -} - -void unload_sbmpu(struct address_info *hw_config) -{ -#if defined(CONFIG_SOUND_MPU401) - if (!strcmp (hw_config->name, "ESS1xxx MPU")) { - unload_mpu401(hw_config); - return; - } -#endif - unload_uart401(hw_config); -} - -EXPORT_SYMBOL(sb_dsp_init); -EXPORT_SYMBOL(sb_dsp_detect); -EXPORT_SYMBOL(sb_dsp_unload); -EXPORT_SYMBOL(sb_be_quiet); -EXPORT_SYMBOL(probe_sbmpu); -EXPORT_SYMBOL(unload_sbmpu); -EXPORT_SYMBOL(smw_free); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c deleted file mode 100644 index 57f7d25a2cd3..000000000000 --- a/sound/oss/sb_ess.c +++ /dev/null @@ -1,1822 +0,0 @@ -#undef FKS_LOGGING -#undef FKS_TEST - -/* - * tabs should be 4 spaces, in vi(m): set tabstop=4 - * - * TODO: consistency speed calculations!! - * cleanup! - * ????: Did I break MIDI support? - * - * History: - * - * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per - * fokkensr@vertis.nl input basis. - * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, - * ES1868, ES1869 and ES1878. Could be used for - * specific handling in the future. All except - * ES1887 and ES1888 and ES688 are handled like - * ES1688. - * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now - * have the "Dec 20" support + RECLEV - * (Jan 2 1999): Preparation for Full Duplex. This means - * Audio 2 is now used for playback when dma16 - * is specified. The next step would be to use - * Audio 1 and Audio 2 at the same time. - * (Jan 9 1999): Put all ESS stuff into sb_ess.[ch], this - * includes both the ESS stuff that has been in - * sb_*[ch] before I touched it and the ESS support - * I added later - * (Jan 23 1999): Full Duplex seems to work. I wrote a small - * test proggy which works OK. Haven't found - * any applications to test it though. So why did - * I bother to create it anyway?? :) Just for - * fun. - * (May 2 1999): I tried to be too smart by "introducing" - * ess_calc_best_speed (). The idea was that two - * dividers could be used to setup a samplerate, - * ess_calc_best_speed () would choose the best. - * This works for playback, but results in - * recording problems for high samplerates. I - * fixed this by removing ess_calc_best_speed () - * and just doing what the documentation says. - * Andy Sloane (Jun 4 1999): Stole some code from ALSA to fix the playback - * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. - * 1879's were previously ignored by this driver; - * added (untested) support for those. - * Cvetan Ivanov (Oct 27 1999): Fixed ess_dsp_init to call ess_set_dma_hw for - * zezo@inet.bg _ALL_ ESS models, not only ES1887 - * - * This files contains ESS chip specifics. It's based on the existing ESS - * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This - * file adds features like: - * - Chip Identification (as shown in /proc/sound) - * - RECLEV support for ES1688 and later - * - 6 bits playback level support chips later than ES1688 - * - Recording level support on a per-device basis for ES1887 - * - Full-Duplex for ES1887 - * - * Full duplex is enabled by specifying dma16. While the normal dma must - * be one of 0, 1 or 3, dma16 can be one of 0, 1, 3 or 5. DMA 5 is a 16 bit - * DMA channel, while the others are 8 bit.. - * - * ESS detection isn't full proof (yet). If it fails an additional module - * parameter esstype can be specified to be one of the following: - * -1, 0, 688, 1688, 1868, 1869, 1788, 1887, 1888 - * -1 means: mimic 2.0 behaviour, - * 0 means: auto detect. - * others: explicitly specify chip - * -1 is default, cause auto detect still doesn't work. - */ - -/* - * About the documentation - * - * I don't know if the chips all are OK, but the documentation is buggy. 'cause - * I don't have all the cips myself, there's a lot I cannot verify. I'll try to - * keep track of my latest insights about his here. If you have additional info, - * please enlighten me (fokkensr@vertis.nl)! - * - * I had the impression that ES1688 also has 6 bit master volume control. The - * documentation about ES1888 (rev C, october '95) claims that ES1888 has - * the following features ES1688 doesn't have: - * - 6 bit master volume - * - Full Duplex - * So ES1688 apparently doesn't have 6 bit master volume control, but the - * ES1688 does have RECLEV control. Makes me wonder: does ES688 have it too? - * Without RECLEV ES688 won't be much fun I guess. - * - * From the ES1888 (rev C, october '95) documentation I got the impression - * that registers 0x68 to 0x6e don't exist which means: no recording volume - * controls. To my surprise the ES888 documentation (1/14/96) claims that - * ES888 does have these record mixer registers, but that ES1888 doesn't have - * 0x69 and 0x6b. So the rest should be there. - * - * I'm trying to get ES1887 Full Duplex. Audio 2 is playback only, while Audio 2 - * is both record and playback. I think I should use Audio 2 for all playback. - * - * The documentation is an adventure: it's close but not fully accurate. I - * found out that after a reset some registers are *NOT* reset, though the - * docs say the would be. Interesting ones are 0x7f, 0x7d and 0x7a. They are - * related to the Audio 2 channel. I also was surprised about the consequences - * of writing 0x00 to 0x7f (which should be done by reset): The ES1887 moves - * into ES1888 mode. This means that it claims IRQ 11, which happens to be my - * ISDN adapter. Needless to say it no longer worked. I now understand why - * after rebooting 0x7f already was 0x05, the value of my choice: the BIOS - * did it. - * - * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is - * described as if it's exactly the same as register 0xa1. This is *NOT* true. - * The description of 0x70 in ES1869 docs is accurate however. - * Well, the assumption about ES1869 was wrong: register 0x70 is very much - * like register 0xa1, except that bit 7 is always 1, whatever you want - * it to be. - * - * When using audio 2 mixer register 0x72 seems te be meaningless. Only 0xa2 - * has effect. - * - * Software reset not being able to reset all registers is great! Especially - * the fact that register 0x78 isn't reset is great when you wanna change back - * to single dma operation (simplex): audio 2 is still operational, and uses - * the same dma as audio 1: your ess changes into a funny echo machine. - * - * Received the news that ES1688 is detected as a ES1788. Did some thinking: - * the ES1887 detection scheme suggests in step 2 to try if bit 3 of register - * 0x64 can be changed. This is inaccurate, first I inverted the * check: "If - * can be modified, it's a 1688", which lead to a correct detection - * of my ES1887. It resulted however in bad detection of 1688 (reported by mail) - * and 1868 (if no PnP detection first): they result in a 1788 being detected. - * I don't have docs on 1688, but I do have docs on 1868: The documentation is - * probably inaccurate in the fact that I should check bit 2, not bit 3. This - * is what I do now. - */ - -/* - * About recognition of ESS chips - * - * The distinction of ES688, ES1688, ES1788, ES1887 and ES1888 is described in - * a (preliminary ??) datasheet on ES1887. Its aim is to identify ES1887, but - * during detection the text claims that "this chip may be ..." when a step - * fails. This scheme is used to distinct between the above chips. - * It appears however that some PnP chips like ES1868 are recognized as ES1788 - * by the ES1887 detection scheme. These PnP chips can be detected in another - * way however: ES1868, ES1869 and ES1878 can be recognized (full proof I think) - * by repeatedly reading mixer register 0x40. This is done by ess_identify in - * sb_common.c. - * This results in the following detection steps: - * - distinct between ES688 and ES1688+ (as always done in this driver) - * if ES688 we're ready - * - try to detect ES1868, ES1869 or ES1878 - * if successful we're ready - * - try to detect ES1888, ES1887 or ES1788 - * if successful we're ready - * - Dunno. Must be 1688. Will do in general - * - * About RECLEV support: - * - * The existing ES1688 support didn't take care of the ES1688+ recording - * levels very well. Whenever a device was selected (recmask) for recording - * its recording level was loud, and it couldn't be changed. The fact that - * internal register 0xb4 could take care of RECLEV, didn't work meaning until - * its value was restored every time the chip was reset; this reset the - * value of 0xb4 too. I guess that's what 4front also had (have?) trouble with. - * - * About ES1887 support: - * - * The ES1887 has separate registers to control the recording levels, for all - * inputs. The ES1887 specific software makes these levels the same as their - * corresponding playback levels, unless recmask says they aren't recorded. In - * the latter case the recording volumes are 0. - * Now recording levels of inputs can be controlled, by changing the playback - * levels. Furthermore several devices can be recorded together (which is not - * possible with the ES1688). - * Besides the separate recording level control for each input, the common - * recording level can also be controlled by RECLEV as described above. - * - * Not only ES1887 have this recording mixer. I know the following from the - * documentation: - * ES688 no - * ES1688 no - * ES1868 no - * ES1869 yes - * ES1878 no - * ES1879 yes - * ES1888 no/yes Contradicting documentation; most recent: yes - * ES1946 yes This is a PCI chip; not handled by this driver - */ - -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> - -#include "sound_config.h" -#include "sb_mixer.h" -#include "sb.h" - -#include "sb_ess.h" - -#define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ -#define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ - -#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ -#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ -#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ -#define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ -#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */ -#define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ -#define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ - -#define SB_CAP_ES18XX_RATE 0x100 - -#define ES1688_CLOCK1 795444 /* 128 - div */ -#define ES1688_CLOCK2 397722 /* 256 - div */ -#define ES18XX_CLOCK1 793800 /* 128 - div */ -#define ES18XX_CLOCK2 768000 /* 256 - div */ - -#ifdef FKS_LOGGING -static void ess_show_mixerregs (sb_devc *devc); -#endif -static int ess_read (sb_devc * devc, unsigned char reg); -static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data); -static void ess_chgmixer - (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val); - -/**************************************************************************** - * * - * ESS audio * - * * - ****************************************************************************/ - -struct ess_command {short cmd; short data;}; - -/* - * Commands for initializing Audio 1 for input (record) - */ -static struct ess_command ess_i08m[] = /* input 8 bit mono */ - { {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; -static struct ess_command ess_i16m[] = /* input 16 bit mono */ - { {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; -static struct ess_command ess_i08s[] = /* input 8 bit stereo */ - { {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; -static struct ess_command ess_i16s[] = /* input 16 bit stereo */ - { {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; - -static struct ess_command *ess_inp_cmds[] = - { ess_i08m, ess_i16m, ess_i08s, ess_i16s }; - - -/* - * Commands for initializing Audio 1 for output (playback) - */ -static struct ess_command ess_o08m[] = /* output 8 bit mono */ - { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; -static struct ess_command ess_o16m[] = /* output 16 bit mono */ - { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; -static struct ess_command ess_o08s[] = /* output 8 bit stereo */ - { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; -static struct ess_command ess_o16s[] = /* output 16 bit stereo */ - { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; - -static struct ess_command *ess_out_cmds[] = - { ess_o08m, ess_o16m, ess_o08s, ess_o16s }; - -static void ess_exec_commands - (sb_devc *devc, struct ess_command *cmdtab[]) -{ - struct ess_command *cmd; - - cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ]; - - while (cmd->cmd != -1) { - ess_write (devc, cmd->cmd, cmd->data); - cmd++; - } -} - -static void ess_change - (sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val) -{ - int value; - - value = ess_read (devc, reg); - value = (value & ~mask) | (val & mask); - ess_write (devc, reg, value); -} - -static void ess_set_output_parms - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (devc->duplex) { - devc->trg_buf_16 = buf; - devc->trg_bytes_16 = nr_bytes; - devc->trg_intrflag_16 = intrflag; - devc->irq_mode_16 = IMODE_OUTPUT; - } else { - devc->trg_buf = buf; - devc->trg_bytes = nr_bytes; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_OUTPUT; - } -} - -static void ess_set_input_parms - (int dev, unsigned long buf, int count, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; -} - -static int ess_calc_div (int clock, int revert, int *speedp, int *diffp) -{ - int divider; - int speed, diff; - int retval; - - speed = *speedp; - divider = (clock + speed / 2) / speed; - retval = revert - divider; - if (retval > revert - 1) { - retval = revert - 1; - divider = revert - retval; - } - /* This line is suggested. Must be wrong I think - *speedp = (clock + divider / 2) / divider; - So I chose the next one */ - - *speedp = clock / divider; - diff = speed - *speedp; - if (diff < 0) diff =-diff; - *diffp = diff; - - return retval; -} - -static int ess_calc_best_speed - (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) -{ - int speed1 = *speedp, speed2 = *speedp; - int div1, div2; - int diff1, diff2; - int retval; - - div1 = ess_calc_div (clock1, rev1, &speed1, &diff1); - div2 = ess_calc_div (clock2, rev2, &speed2, &diff2); - - if (diff1 < diff2) { - *divp = div1; - *speedp = speed1; - retval = 1; - } else { - /* *divp = div2; */ - *divp = 0x80 | div2; - *speedp = speed2; - retval = 2; - } - - return retval; -} - -/* - * Depending on the audiochannel ESS devices can - * have different clock settings. These are made consistent for duplex - * however. - * callers of ess_speed only do an audionum suggestion, which means - * input suggests 1, output suggests 2. This suggestion is only true - * however when doing duplex. - */ -static void ess_common_speed (sb_devc *devc, int *speedp, int *divp) -{ - int diff = 0, div; - - if (devc->duplex) { - /* - * The 0x80 is important for the first audio channel - */ - if (devc->submodel == SUBMDL_ES1888) { - div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); - } else { - div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); - } - } else if(devc->caps & SB_CAP_ES18XX_RATE) { - if (devc->submodel == SUBMDL_ES1888) { - ess_calc_best_speed(397700, 128, 795500, 256, - &div, speedp); - } else { - ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, - &div, speedp); - } - } else { - if (*speedp > 22000) { - div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff); - } else { - div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff); - } - } - *divp = div; -} - -static void ess_speed (sb_devc *devc, int audionum) -{ - int speed; - int div, div2; - - ess_common_speed (devc, &(devc->speed), &div); - -#ifdef FKS_REG_LOGGING -printk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc->speed, div); -#endif - - /* Set filter roll-off to 90% of speed/2 */ - speed = (devc->speed * 9) / 20; - - div2 = 256 - 7160000 / (speed * 82); - - if (!devc->duplex) audionum = 1; - - if (audionum == 1) { - /* Change behaviour of register A1 * - sb_chg_mixer(devc, 0x71, 0x20, 0x20) - * For ES1869 only??? */ - ess_write (devc, 0xa1, div); - ess_write (devc, 0xa2, div2); - } else { - ess_setmixer (devc, 0x70, div); - /* - * FKS: fascinating: 0x72 doesn't seem to work. - */ - ess_write (devc, 0xa2, div2); - ess_setmixer (devc, 0x72, div2); - } -} - -static int ess_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - ess_speed(devc, 1); - - sb_dsp_command(devc, DSP_CMD_SPKOFF); - - ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ - - ess_exec_commands (devc, ess_inp_cmds); - - ess_change (devc, 0xb1, 0xf0, 0x50); - ess_change (devc, 0xb2, 0xf0, 0x50); - - devc->trigger_bits = 0; - return 0; -} - -static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - sb_dsp_reset(devc); - ess_speed(devc, 1); - ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ - ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ - - ess_exec_commands (devc, ess_out_cmds); - - ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable DMA */ - ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable IRQ */ - - sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */ - - devc->trigger_bits = 0; - return 0; -} - -static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned char bits; - -/* FKS: qqq - sb_dsp_reset(devc); -*/ - - /* - * Auto-Initialize: - * DMA mode + demand mode (8 bytes/request, yes I want it all!) - * But leave 16-bit DMA bit untouched! - */ - ess_chgmixer (devc, 0x78, 0xd0, 0xd0); - - ess_speed(devc, 2); - - /* bits 4:3 on ES1887 represent recording source. Keep them! */ - bits = ess_getmixer (devc, 0x7a) & 0x18; - - /* Set stereo/mono */ - if (devc->channels != 1) bits |= 0x02; - - /* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */ - if (devc->bits != AFMT_U8) bits |= 0x05; /* 16 bit */ - - /* Enable DMA, IRQ will be shared (hopefully)*/ - bits |= 0x60; - - ess_setmixer (devc, 0x7a, bits); - - ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */ - - devc->trigger_bits = 0; - return 0; -} - -static int ess_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "ess_audio_prepare_for_output: dma_out=%d,dma_in=%d\n" -, audio_devs[dev]->dmap_out->dma, audio_devs[dev]->dmap_in->dma); -#endif - - if (devc->duplex) { - return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount); - } else { - return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount); - } -} - -static void ess_audio_halt_xfer(int dev) -{ - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; - - spin_lock_irqsave(&devc->lock, flags); - sb_dsp_reset(devc); - spin_unlock_irqrestore(&devc->lock, flags); - - /* - * Audio 2 may still be operational! Creates awful sounds! - */ - if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00); -} - -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; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1; - count--; - - 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_change (devc, 0xb8, 0x0f, 0x0f); /* Go */ - devc->intr_active = 1; -} - -static void ess_audio_output_block_audio1 - (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; - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - 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_change (devc, 0xb8, 0x05, 0x05); /* Go */ - devc->intr_active = 1; -} - -static void ess_audio_output_block_audio2 - (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; - - if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; - count--; - - ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff)); - ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */ - - devc->irq_mode_16 = IMODE_OUTPUT; - devc->intr_active_16 = 1; -} - -static void ess_audio_output_block - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (devc->duplex) { - ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag); - } else { - ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag); - } -} - -/* - * FKS: the if-statements for both bits and bits_16 are quite alike. - * Combine this... - */ -static void ess_audio_trigger(int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - int bits_16 = bits & devc->irq_mode_16; - bits &= devc->irq_mode; - - if (!bits && !bits_16) { - /* FKS oh oh.... wrong?? for dma 16? */ - sb_dsp_command(devc, 0xd0); /* Halt DMA */ - } - - if (bits) { - 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; - } - } - - if (bits_16) { - switch (devc->irq_mode_16) { - case IMODE_INPUT: - ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - - case IMODE_OUTPUT: - ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - } - } - - devc->trigger_bits = bits | bits_16; -} - -static int ess_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - int minspeed, maxspeed, dummydiv; - - if (speed > 0) { - minspeed = (devc->duplex ? 6215 : 5000 ); - maxspeed = (devc->duplex ? 44100 : 48000); - if (speed < minspeed) speed = minspeed; - if (speed > maxspeed) speed = maxspeed; - - ess_common_speed (devc, &speed, &dummydiv); - - devc->speed = speed; - } - return devc->speed; -} - -/* - * FKS: This is a one-on-one copy of sb1_audio_set_bits - */ -static unsigned int ess_audio_set_bits(int dev, unsigned int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (bits != 0) { - if (bits == AFMT_U8 || bits == AFMT_S16_LE) { - devc->bits = bits; - } else { - devc->bits = AFMT_U8; - } - } - - return devc->bits; -} - -/* - * FKS: This is a one-on-one copy of sbpro_audio_set_channels - * (*) Modified it!! - */ -static short ess_audio_set_channels(int dev, short channels) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (channels == 1 || channels == 2) devc->channels = channels; - - return devc->channels; -} - -static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = ess_set_output_parms, - .start_input = ess_set_input_parms, - .prepare_for_input = ess_audio_prepare_for_input, - .prepare_for_output = ess_audio_prepare_for_output, - .halt_io = ess_audio_halt_xfer, - .trigger = ess_audio_trigger, - .set_speed = ess_audio_set_speed, - .set_bits = ess_audio_set_bits, - .set_channels = ess_audio_set_channels -}; - -/* - * ess_audio_init must be called from sb_audio_init - */ -struct audio_driver *ess_audio_init - (sb_devc *devc, int *audio_flags, int *format_mask) -{ - *audio_flags = DMA_AUTOMODE; - *format_mask |= AFMT_S16_LE; - - if (devc->duplex) { - int tmp_dma; - /* - * sb_audio_init thinks dma8 is for playback and - * dma16 is for record. Not now! So swap them. - */ - tmp_dma = devc->dma16; - devc->dma16 = devc->dma8; - devc->dma8 = tmp_dma; - - *audio_flags |= DMA_DUPLEX; - } - - return &ess_audio_driver; -} - -/**************************************************************************** - * * - * ESS common * - * * - ****************************************************************************/ -static void ess_handle_channel - (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode) -{ - if (!intr_active || !flag) return; -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode); -#endif - switch (irq_mode) { - case IMODE_OUTPUT: - DMAbuf_outputintr (dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr (dev); - break; - - case IMODE_INIT: - break; - - default:; - /* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */ - } -} - -/* - * FKS: TODO!!! Finish this! - * - * I think midi stuff uses uart401, without interrupts. - * So IMODE_MIDI isn't a value for devc->irq_mode. - */ -void ess_intr (sb_devc *devc) -{ - int status; - unsigned char src; - - if (devc->submodel == SUBMDL_ES1887) { - src = ess_getmixer (devc, 0x7f) >> 4; - } else { - src = 0xff; - } - -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src); -#endif - ess_handle_channel - ( "Audio 1" - , devc->dev, devc->intr_active , src & 0x01, devc->irq_mode ); - ess_handle_channel - ( "Audio 2" - , devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16); - /* - * Acknowledge interrupts - */ - if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) { - ess_chgmixer (devc, 0x7a, 0x80, 0x00); - } - - if (src & 0x01) { - status = inb(DSP_DATA_AVAIL); - } -} - -static void ess_extended (sb_devc * devc) -{ - /* Enable extended mode */ - - sb_dsp_command(devc, 0xc6); -} - -static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data) -{ -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: write reg %x: %x\n", reg, data); -#endif - /* Write a byte to an extended mode register of ES1688 */ - - if (!sb_dsp_command(devc, reg)) - return 0; - - return sb_dsp_command(devc, data); -} - -static int ess_read (sb_devc * devc, unsigned char reg) -{ - /* Read a byte from an extended mode register of ES1688 */ - - /* Read register command */ - if (!sb_dsp_command(devc, 0xc0)) return -1; - - if (!sb_dsp_command(devc, reg )) return -1; - - return sb_dsp_get_byte(devc); -} - -int ess_dsp_reset(sb_devc * devc) -{ - int loopc; - -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: ess_dsp_reset 1\n"); -ess_show_mixerregs (devc); -#endif - - outb(3, DSP_RESET); /* Reset FIFO too */ - - udelay(10); - outb(0, DSP_RESET); - udelay(30); - - 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 */ - } - ess_extended (devc); - -#ifdef FKS_LOGGING -printk(KERN_INFO "FKS: dsp_reset 2\n"); -ess_show_mixerregs (devc); -#endif - - return 1; -} - -static int ess_irq_bits (int irq) -{ - switch (irq) { - case 2: - case 9: - return 0; - - case 5: - return 1; - - case 7: - return 2; - - case 10: - return 3; - - default: - printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq); - return -1; - } -} - -/* - * Set IRQ configuration register for all ESS models - */ -static int ess_common_set_irq_hw (sb_devc * devc) -{ - int irq_bits; - - if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return 0; - - if (!ess_write (devc, 0xb1, 0x50 | (irq_bits << 2))) { - printk(KERN_ERR "ES1688: Failed to write to IRQ config register\n"); - return 0; - } - return 1; -} - -/* - * I wanna use modern ES1887 mixer irq handling. Funny is the - * fact that my BIOS wants the same. But suppose someone's BIOS - * doesn't do this! - * This is independent of duplex. If there's a 1887 this will - * prevent it from going into 1888 mode. - */ -static void ess_es1887_set_irq_hw (sb_devc * devc) -{ - int irq_bits; - - if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return; - - ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1)); -} - -static int ess_set_irq_hw (sb_devc * devc) -{ - if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc); - - return ess_common_set_irq_hw (devc); -} - -#ifdef FKS_TEST - -/* - * FKS_test: - * for ES1887: 00, 18, non wr bits: 0001 1000 - * for ES1868: 00, b8, non wr bits: 1011 1000 - * for ES1888: 00, f8, non wr bits: 1111 1000 - * for ES1688: 00, f8, non wr bits: 1111 1000 - * + ES968 - */ - -static void FKS_test (sb_devc * devc) -{ - int val1, val2; - val1 = ess_getmixer (devc, 0x64); - ess_setmixer (devc, 0x64, ~val1); - val2 = ess_getmixer (devc, 0x64) ^ ~val1; - ess_setmixer (devc, 0x64, val1); - val1 ^= ess_getmixer (devc, 0x64); -printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff)); -}; -#endif - -static unsigned int ess_identify (sb_devc * devc) -{ - unsigned int val; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - outb(((unsigned char) (0x40 & 0xff)), MIXER_ADDR); - - udelay(20); - val = inb(MIXER_DATA) << 8; - udelay(20); - val |= inb(MIXER_DATA); - udelay(20); - spin_unlock_irqrestore(&devc->lock, flags); - - return val; -} - -/* - * ESS technology describes a detection scheme in their docs. It involves - * fiddling with the bits in certain mixer registers. ess_probe is supposed - * to help. - * - * FKS: tracing shows ess_probe writes wrong value to 0x64. Bit 3 reads 1, but - * should be written 0 only. Check this. - */ -static int ess_probe (sb_devc * devc, int reg, int xorval) -{ - int val1, val2, val3; - - val1 = ess_getmixer (devc, reg); - val2 = val1 ^ xorval; - ess_setmixer (devc, reg, val2); - val3 = ess_getmixer (devc, reg); - ess_setmixer (devc, reg, val1); - - return (val2 == val3); -} - -int ess_init(sb_devc * devc, struct address_info *hw_config) -{ - unsigned char cfg; - int ess_major = 0, ess_minor = 0; - int i; - static char name[100], modelname[10]; - - /* - * Try to detect ESS chips. - */ - - 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; - } - - /* - * This the detection heuristic of ESS technology, though somewhat - * changed to actually make it work. - * This results in the following detection steps: - * - distinct between ES688 and ES1688+ (as always done in this driver) - * if ES688 we're ready - * - try to detect ES1868, ES1869 or ES1878 (ess_identify) - * if successful we're ready - * - try to detect ES1888, ES1887 or ES1788 (aim: detect ES1887) - * if successful we're ready - * - Dunno. Must be 1688. Will do in general - * - * This is the most BETA part of the software: Will the detection - * always work? - */ - devc->model = MDL_ESS; - devc->submodel = ess_minor & 0x0f; - - if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { - char *chip = NULL; - int submodel = -1; - - switch (devc->sbmo.esstype) { - case ESSTYPE_DETECT: - case ESSTYPE_LIKE20: - break; - case 688: - submodel = 0x00; - break; - case 1688: - submodel = 0x08; - break; - case 1868: - submodel = SUBMDL_ES1868; - break; - case 1869: - submodel = SUBMDL_ES1869; - break; - case 1788: - submodel = SUBMDL_ES1788; - break; - case 1878: - submodel = SUBMDL_ES1878; - break; - case 1879: - submodel = SUBMDL_ES1879; - break; - case 1887: - submodel = SUBMDL_ES1887; - break; - case 1888: - submodel = SUBMDL_ES1888; - break; - default: - printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype); - return 0; - } - if (submodel != -1) { - devc->submodel = submodel; - sprintf (modelname, "ES%d", devc->sbmo.esstype); - chip = modelname; - } - if (chip == NULL && (ess_minor & 0x0f) < 8) { - chip = "ES688"; - } -#ifdef FKS_TEST -FKS_test (devc); -#endif - /* - * If Nothing detected yet, and we want 2.0 behaviour... - * Then let's assume it's ES1688. - */ - if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) { - chip = "ES1688"; - } - - if (chip == NULL) { - int type; - - type = ess_identify (devc); - - switch (type) { - case 0x1868: - chip = "ES1868"; - devc->submodel = SUBMDL_ES1868; - break; - case 0x1869: - chip = "ES1869"; - devc->submodel = SUBMDL_ES1869; - break; - case 0x1878: - chip = "ES1878"; - devc->submodel = SUBMDL_ES1878; - break; - case 0x1879: - chip = "ES1879"; - devc->submodel = SUBMDL_ES1879; - break; - default: - if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { - printk ("ess_init: Unrecognized %04x\n", type); - } - } - } -#if 0 - /* - * this one failed: - * the probing of bit 4 is another thought: from ES1788 and up, all - * chips seem to have hardware volume control. Bit 4 is readonly to - * check if a hardware volume interrupt has fired. - * Cause ES688/ES1688 don't have this feature, bit 4 might be writeable - * for these chips. - */ - if (chip == NULL && !ess_probe(devc, 0x64, (1 << 4))) { -#endif - /* - * the probing of bit 2 is my idea. The ES1887 docs want me to probe - * bit 3. This results in ES1688 being detected as ES1788. - * Bit 2 is for "Enable HWV IRQE", but as ES(1)688 chips don't have - * HardWare Volume, I think they don't have this IRQE. - */ - if (chip == NULL && ess_probe(devc, 0x64, (1 << 2))) { - if (ess_probe (devc, 0x70, 0x7f)) { - if (ess_probe (devc, 0x64, (1 << 5))) { - chip = "ES1887"; - devc->submodel = SUBMDL_ES1887; - } else { - chip = "ES1888"; - devc->submodel = SUBMDL_ES1888; - } - } else { - chip = "ES1788"; - devc->submodel = SUBMDL_ES1788; - } - } - if (chip == NULL) { - chip = "ES1688"; - } - - printk(KERN_INFO "ESS chip %s %s%s\n", chip, - (devc->sbmo.esstype == ESSTYPE_DETECT || - devc->sbmo.esstype == ESSTYPE_LIKE20) ? - "detected" : "specified", - devc->sbmo.esstype == ESSTYPE_LIKE20 ? - " (kernel 2.0 compatible)" : ""); - - sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); - } else { - strcpy(name, "Jazz16"); - } - - /* AAS: info stolen from ALSA: these boards have different clocks */ - switch(devc->submodel) { -/* APPARENTLY NOT 1869 AND 1887 - case SUBMDL_ES1869: - case SUBMDL_ES1887: -*/ - case SUBMDL_ES1888: - devc->caps |= SB_CAP_ES18XX_RATE; - break; - } - - hw_config->name = name; - /* FKS: sb_dsp_reset to enable extended mode???? */ - sb_dsp_reset(devc); /* Turn on extended mode */ - - /* - * Enable joystick and OPL3 - */ - cfg = ess_getmixer (devc, 0x40); - ess_setmixer (devc, 0x40, cfg | 0x03); - if (devc->submodel >= 8) { /* ES1688 */ - devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ - } - sb_dsp_reset (devc); - - /* - * This is important! If it's not done, the IRQ probe in sb_dsp_init - * may fail. - */ - return ess_set_irq_hw (devc); -} - -static int ess_set_dma_hw(sb_devc * devc) -{ - unsigned char cfg, dma_bits = 0, dma16_bits; - int dma; - -#ifdef FKS_LOGGING -printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n" -, devc->dma8, devc->dma16, devc->duplex); -#endif - - /* - * FKS: It seems as if this duplex flag isn't set yet. Check it. - */ - dma = devc->dma8; - - if (dma > 3 || dma < 0 || dma == 2) { - dma_bits = 0; - printk(KERN_ERR "ESS1688: Invalid DMA8 %d\n", dma); - return 0; - } else { - /* Extended mode DMA enable */ - cfg = 0x50; - - if (dma == 3) { - dma_bits = 3; - } else { - dma_bits = dma + 1; - } - } - - if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) { - printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n"); - return 0; - } - - if (devc->duplex) { - dma = devc->dma16; - dma16_bits = 0; - - if (dma >= 0) { - switch (dma) { - case 0: - dma_bits = 0x04; - break; - case 1: - dma_bits = 0x05; - break; - case 3: - dma_bits = 0x06; - break; - case 5: - dma_bits = 0x07; - dma16_bits = 0x20; - break; - default: - printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma); - return 0; - } - ess_chgmixer (devc, 0x78, 0x20, dma16_bits); - ess_chgmixer (devc, 0x7d, 0x07, dma_bits); - } - } - return 1; -} - -/* - * This one is called from sb_dsp_init. - * - * Return values: - * 0: Failed - * 1: Succeeded or doesn't apply (not SUBMDL_ES1887) - */ -int ess_dsp_init (sb_devc *devc, struct address_info *hw_config) -{ - /* - * Caller also checks this, but anyway - */ - if (devc->model != MDL_ESS) { - printk (KERN_INFO "ess_dsp_init for non ESS chip\n"); - return 1; - } - /* - * This for ES1887 to run Full Duplex. Actually ES1888 - * is allowed to do so too. I have no idea yet if this - * will work for ES1888 however. - * - * For SB16 having both dma8 and dma16 means enable - * Full Duplex. Let's try this for ES1887 too - * - */ - if (devc->submodel == SUBMDL_ES1887) { - if (hw_config->dma2 != -1) { - devc->dma16 = hw_config->dma2; - } - /* - * devc->duplex initialization is put here, cause - * ess_set_dma_hw needs it. - */ - if (devc->dma8 != devc->dma16 && devc->dma16 != -1) { - devc->duplex = 1; - } - } - if (!ess_set_dma_hw (devc)) { - free_irq(devc->irq, devc); - return 0; - } - return 1; -} - -/**************************************************************************** - * * - * ESS mixer * - * * - ****************************************************************************/ - -#define ES688_RECORDING_DEVICES \ - ( SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD ) -#define ES688_MIXER_DEVICES \ - ( SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE \ - | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME \ - | SOUND_MASK_LINE2 | SOUND_MASK_SPEAKER ) - -#define ES1688_RECORDING_DEVICES \ - ( ES688_RECORDING_DEVICES ) -#define ES1688_MIXER_DEVICES \ - ( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV ) - -#define ES1887_RECORDING_DEVICES \ - ( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH) -#define ES1887_MIXER_DEVICES \ - ( ES1688_MIXER_DEVICES ) - -/* - * Mixer registers of ES1887 - * - * These registers specifically take care of recording levels. To make the - * mapping from playback devices to recording devices every recording - * devices = playback device + ES_REC_MIXER_RECDIFF - */ -#define ES_REC_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1) -#define ES_REC_MIXER_RECDIFF (ES_REC_MIXER_RECBASE - SOUND_MIXER_SYNTH) - -#define ES_REC_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECPCM (SOUND_MIXER_PCM + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE (SOUND_MIXER_LINE + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECMIC (SOUND_MIXER_MIC + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECCD (SOUND_MIXER_CD + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES_REC_MIXER_RECDIFF) - -static mixer_tab es688_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -/* - * The ES1688 specifics... hopefully correct... - * - 6 bit master volume - * I was wrong, ES1888 docs say ES1688 didn't have it. - * - RECLEV control - * These may apply to ES688 too. I have no idea. - */ -static mixer_tab es1688_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -static mixer_tab es1688later_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -/* - * This one is for all ESS chips with a record mixer. - * It's not used (yet) however - */ -static mixer_tab es_rec_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4), -MIX_ENT(ES_REC_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(ES_REC_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4), -MIX_ENT(ES_REC_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4), -MIX_ENT(ES_REC_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4), -MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -/* - * This one is for ES1887. It's little different from es_rec_mix: it - * has 0x7c for PCM playback level. This is because ES1887 uses - * Audio 2 for playback. - */ -static mixer_tab es1887_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x7c, 7, 4, 0x7c, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4), -MIX_ENT(ES_REC_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(ES_REC_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4), -MIX_ENT(ES_REC_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4), -MIX_ENT(ES_REC_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4), -MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -static int ess_has_rec_mixer (int submodel) -{ - switch (submodel) { - case SUBMDL_ES1887: - return 1; - default: - return 0; - } -}; - -#ifdef FKS_LOGGING -static int ess_mixer_mon_regs[] - = { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f - , 0xa1, 0xa2, 0xa4, 0xa5, 0xa8, 0xa9 - , 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb9 - , 0x00}; - -static void ess_show_mixerregs (sb_devc *devc) -{ - int *mp = ess_mixer_mon_regs; - -return; - - while (*mp != 0) { - printk (KERN_INFO "res (%x)=%x\n", *mp, (int)(ess_getmixer (devc, *mp))); - mp++; - } -} -#endif - -void ess_setmixer (sb_devc * devc, unsigned int port, unsigned int value) -{ - unsigned long flags; - -#ifdef FKS_LOGGING -printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value); -#endif - - spin_lock_irqsave(&devc->lock, flags); - if (port >= 0xa0) { - ess_write (devc, port, value); - } else { - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - - udelay(20); - outb(((unsigned char) (value & 0xff)), MIXER_DATA); - udelay(20); - } - spin_unlock_irqrestore(&devc->lock, flags); -} - -unsigned int ess_getmixer (sb_devc * devc, unsigned int port) -{ - unsigned int val; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - - if (port >= 0xa0) { - val = ess_read (devc, port); - } else { - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - - udelay(20); - val = inb(MIXER_DATA); - udelay(20); - } - spin_unlock_irqrestore(&devc->lock, flags); - - return val; -} - -static void ess_chgmixer - (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val) -{ - int value; - - value = ess_getmixer (devc, reg); - value = (value & ~mask) | (val & mask); - ess_setmixer (devc, reg, value); -} - -/* - * ess_mixer_init must be called from sb_mixer_init - */ -void ess_mixer_init (sb_devc * devc) -{ - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - - /* - * Take care of ES1887 specifics... - */ - switch (devc->submodel) { - case SUBMDL_ES1887: - devc->supported_devices = ES1887_MIXER_DEVICES; - devc->supported_rec_devices = ES1887_RECORDING_DEVICES; -#ifdef FKS_LOGGING -printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex); -#endif - if (devc->duplex) { - devc->iomap = &es1887_mix; - devc->iomap_sz = ARRAY_SIZE(es1887_mix); - } else { - devc->iomap = &es_rec_mix; - devc->iomap_sz = ARRAY_SIZE(es_rec_mix); - } - break; - default: - if (devc->submodel < 8) { - devc->supported_devices = ES688_MIXER_DEVICES; - devc->supported_rec_devices = ES688_RECORDING_DEVICES; - devc->iomap = &es688_mix; - devc->iomap_sz = ARRAY_SIZE(es688_mix); - } else { - /* - * es1688 has 4 bits master vol. - * later chips have 6 bits (?) - */ - devc->supported_devices = ES1688_MIXER_DEVICES; - devc->supported_rec_devices = ES1688_RECORDING_DEVICES; - if (devc->submodel < 0x10) { - devc->iomap = &es1688_mix; - devc->iomap_sz = ARRAY_SIZE(es688_mix); - } else { - devc->iomap = &es1688later_mix; - devc->iomap_sz = ARRAY_SIZE(es1688later_mix); - } - } - } -} - -/* - * Changing playback levels at an ESS chip with record mixer means having to - * take care of recording levels of recorded inputs (devc->recmask) too! - */ -int ess_mixer_set(sb_devc *devc, int dev, int left, int right) -{ - if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) { - sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right); - } - return sb_common_mixer_set (devc, dev, left, right); -} - -/* - * After a sb_dsp_reset extended register 0xb4 (RECLEV) is reset too. After - * sb_dsp_reset RECLEV has to be restored. This is where ess_mixer_reload - * helps. - */ -void ess_mixer_reload (sb_devc *devc, int dev) -{ - int left, right, value; - - value = devc->levels[dev]; - left = value & 0x000000ff; - right = (value & 0x0000ff00) >> 8; - - sb_common_mixer_set(devc, dev, left, right); -} - -static int es_rec_set_recmask(sb_devc * devc, int mask) -{ - int i, i_mask, cur_mask, diff_mask; - int value, left, right; - -#ifdef FKS_LOGGING -printk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask); -#endif - /* - * Changing the recmask on an ESS chip with recording mixer means: - * (1) Find the differences - * (2) For "turned-on" inputs: make the recording level the playback level - * (3) For "turned-off" inputs: make the recording level zero - */ - cur_mask = devc->recmask; - diff_mask = (cur_mask ^ mask); - - for (i = 0; i < 32; i++) { - i_mask = (1 << i); - if (diff_mask & i_mask) { /* Difference? (1) */ - if (mask & i_mask) { /* Turn it on (2) */ - value = devc->levels[i]; - left = value & 0x000000ff; - right = (value & 0x0000ff00) >> 8; - } else { /* Turn it off (3) */ - left = 0; - right = 0; - } - sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right); - } - } - return mask; -} - -int ess_set_recmask(sb_devc * devc, int *mask) -{ - /* This applies to ESS chips with record mixers only! */ - - if (ess_has_rec_mixer (devc->submodel)) { - *mask = es_rec_set_recmask (devc, *mask); - return 1; /* Applied */ - } else { - return 0; /* Not applied */ - } -} - -/* - * ess_mixer_reset must be called from sb_mixer_reset - */ -int ess_mixer_reset (sb_devc * devc) -{ - /* - * Separate actions for ESS chips with a record mixer: - */ - if (ess_has_rec_mixer (devc->submodel)) { - switch (devc->submodel) { - case SUBMDL_ES1887: - /* - * Separate actions for ES1887: - * Change registers 7a and 1c to make the record mixer the - * actual recording source. - */ - ess_chgmixer(devc, 0x7a, 0x18, 0x08); - ess_chgmixer(devc, 0x1c, 0x07, 0x07); - break; - } - /* - * Call set_recmask for proper initialization - */ - devc->recmask = devc->supported_rec_devices; - es_rec_set_recmask(devc, 0); - devc->recmask = 0; - - return 1; /* We took care of recmask. */ - } else { - return 0; /* We didn't take care; caller do it */ - } -} - -/**************************************************************************** - * * - * ESS midi * - * * - ****************************************************************************/ - -/* - * FKS: IRQ may be shared. Hm. And if so? Then What? - */ -int ess_midi_init(sb_devc * devc, struct address_info *hw_config) -{ - unsigned char cfg, tmp; - - cfg = ess_getmixer (devc, 0x40) & 0x03; - - if (devc->submodel < 8) { - ess_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) { - ess_setmixer (devc, 0x40, cfg); - return 0; - } - cfg |= tmp << 3; - - tmp = 1; /* MPU enabled without interrupts */ - - /* May be shared: if so the value is -ve */ - - switch (abs(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; - ess_setmixer (devc, 0x40, cfg | 0x03); - - return 1; -} - diff --git a/sound/oss/sb_ess.h b/sound/oss/sb_ess.h deleted file mode 100644 index 38aa072e01f2..000000000000 --- a/sound/oss/sb_ess.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Created: 9-Jan-1999 Rolf Fokkens - */ - -extern void ess_intr - (sb_devc *devc); -extern int ess_dsp_init - (sb_devc *devc, struct address_info *hw_config); - -extern struct audio_driver *ess_audio_init - (sb_devc *devc, int *audio_flags, int *format_mask); -extern int ess_midi_init - (sb_devc *devc, struct address_info *hw_config); -extern void ess_mixer_init - (sb_devc *devc); - -extern int ess_init - (sb_devc *devc, struct address_info *hw_config); -extern int ess_dsp_reset - (sb_devc *devc); - -extern void ess_setmixer - (sb_devc *devc, unsigned int port, unsigned int value); -extern unsigned int ess_getmixer - (sb_devc *devc, unsigned int port); -extern int ess_mixer_set - (sb_devc *devc, int dev, int left, int right); -extern int ess_mixer_reset - (sb_devc *devc); -extern void ess_mixer_reload - (sb_devc * devc, int dev); -extern int ess_set_recmask - (sb_devc *devc, int *mask); - diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c deleted file mode 100644 index 551ee7557b4e..000000000000 --- a/sound/oss/sb_midi.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * sound/oss/sb_midi.c - * - * The low level driver for the Sound Blaster DS chips. - * - * - * 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/spinlock.h> -#include <linux/slab.h> - -#include "sound_config.h" - -#include "sb.h" -#undef SB_TEST_IRQ - -/* - * The DSP channel can be used either for input or output. Variable - * 'sb_irq_mode' will be set when the program calls read or write first time - * after open. Current version doesn't support mode changes without closing - * and reopening the device. Support for this feature may be implemented in a - * future version of this driver. - */ - - -static int 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; - - spin_lock_irqsave(&devc->lock, flags); - if (devc->opened) - { - spin_unlock_irqrestore(&devc->lock, flags); - return -EBUSY; - } - devc->opened = 1; - spin_unlock_irqrestore(&devc->lock, 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_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return; - - spin_lock_irqsave(&devc->lock, flags); - sb_dsp_reset(devc); - devc->intr_active = 0; - devc->input_opened = 0; - devc->opened = 0; - spin_unlock_irqrestore(&devc->lock, flags); -} - -static int sb_midi_out(int dev, unsigned char midi_byte) -{ - sb_devc *devc = midi_devs[dev]->devc; - - if (devc == NULL) - return 1; - - if (devc->midi_broken) - 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) -{ - return 0; -} - -static int sb_midi_end_read(int dev) -{ - sb_devc *devc = midi_devs[dev]->devc; - - if (devc == NULL) - return -ENXIO; - - sb_dsp_reset(devc); - devc->intr_active = 0; - return 0; -} - -static int sb_midi_ioctl(int dev, unsigned cmd, void __user *arg) -{ - return -EINVAL; -} - -void sb_midi_interrupt(sb_devc * devc) -{ - unsigned long flags; - unsigned char data; - - if (devc == NULL) - return; - - spin_lock_irqsave(&devc->lock, flags); - - data = inb(DSP_READ); - if (devc->input_opened) - devc->midi_input_intr(devc->my_mididev, data); - - spin_unlock_irqrestore(&devc->lock, flags); -} - -#define MIDI_SYNTH_NAME "Sound Blaster Midi" -#define MIDI_SYNTH_CAPS 0 -#include "midi_synth.h" - -static struct midi_operations sb_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Sound Blaster", 0, 0, SNDCARD_SB}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = sb_midi_open, - .close = sb_midi_close, - .ioctl = sb_midi_ioctl, - .outputc = sb_midi_out, - .start_read = sb_midi_start_read, - .end_read = sb_midi_end_read, -}; - -void sb_dsp_midi_init(sb_devc * devc, struct module *owner) -{ - int dev; - - if (devc->model < 2) /* No MIDI support for SB 1.x */ - return; - - dev = sound_alloc_mididev(); - - if (dev == -1) - { - printk(KERN_ERR "sb_midi: too many MIDI devices detected\n"); - return; - } - std_midi_synth.midi_dev = devc->my_mididev = dev; - midi_devs[dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL); - if (midi_devs[dev] == NULL) - { - printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n"); - sound_unload_mididev(dev); - return; - } - memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, - sizeof(struct midi_operations)); - - if (owner) - midi_devs[dev]->owner = owner; - - midi_devs[dev]->devc = devc; - - - midi_devs[dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL); - if (midi_devs[dev]->converter == NULL) - { - printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n"); - kfree(midi_devs[dev]); - sound_unload_mididev(dev); - return; - } - memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth, - sizeof(struct synth_operations)); - - midi_devs[dev]->converter->id = "SBMIDI"; - sequencer_init(); -} diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c deleted file mode 100644 index acf7586aeb47..000000000000 --- a/sound/oss/sb_mixer.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * sound/oss/sb_mixer.c - * - * The low level mixer driver for the Sound Blaster compatible cards. - */ -/* - * 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. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] - * Stanislav Voronyi <stas@esc.kharkov.com> : Support for AWE 3DSE device (Jun 7 1999) - */ - -#include <linux/slab.h> - -#include "sound_config.h" - -#define __SB_MIXER_C__ - -#include "sb.h" -#include "sb_mixer.h" - -#include "sb_ess.h" - -#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -/* Same as SB Pro, unless I find otherwise */ -#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES - -#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' - * channel is the COVOX/DisneySoundSource emulation volume control - * on the mixer. It does NOT control speaker volume. Should have own - * mask eventually? - */ -#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ - SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) - -#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ - SOUND_MASK_IMIX) - -/* These are the only devices that are working at the moment. Others could - * be added once they are identified and a method is found to control them. - */ -#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ - SOUND_MASK_PCM | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_VOLUME) - -static mixer_tab sbpro_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) -}; - -static mixer_tab sb16_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), -MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), -MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4), -MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5), -MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), -MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), -MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ -MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), -MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) -}; - -static mixer_tab als007_mix = -{ -MIX_ENT(SOUND_MIXER_VOLUME, 0x62, 7, 4, 0x62, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */ -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) -}; - - -/* SM_GAMES Master volume is lower and PCM & FM volumes - higher than with SB Pro. This improves the - sound quality */ - -static int smg_default_levels[32] = -{ - 0x2020, /* Master Volume */ - 0x4b4b, /* Bass */ - 0x4b4b, /* Treble */ - 0x6464, /* FM */ - 0x6464, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x0000, /* Mic */ - 0x4b4b, /* CD */ - 0x4b4b, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ - 0x4b4b, /* Output gain */ - 0x4040, /* Line1 */ - 0x4040, /* Line2 */ - 0x1515 /* Line3 */ -}; - -static int sb_default_levels[32] = -{ - 0x5a5a, /* Master Volume */ - 0x4b4b, /* Bass */ - 0x4b4b, /* Treble */ - 0x4b4b, /* FM */ - 0x4b4b, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x1010, /* Mic */ - 0x4b4b, /* CD */ - 0x0000, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ - 0x4b4b, /* Output gain */ - 0x4040, /* Line1 */ - 0x4040, /* Line2 */ - 0x1515 /* Line3 */ -}; - -static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = -{ - 0x00, /* SOUND_MIXER_VOLUME */ - 0x00, /* SOUND_MIXER_BASS */ - 0x00, /* SOUND_MIXER_TREBLE */ - 0x40, /* SOUND_MIXER_SYNTH */ - 0x00, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x10, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x04, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00 /* SOUND_MIXER_OGAIN */ -}; - -static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = -{ - 0x00, /* SOUND_MIXER_VOLUME */ - 0x00, /* SOUND_MIXER_BASS */ - 0x00, /* SOUND_MIXER_TREBLE */ - 0x20, /* SOUND_MIXER_SYNTH */ - 0x00, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x08, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x02, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00 /* SOUND_MIXER_OGAIN */ -}; - -static char smw_mix_regs[] = /* Left mixer registers */ -{ - 0x0b, /* SOUND_MIXER_VOLUME */ - 0x0d, /* SOUND_MIXER_BASS */ - 0x0d, /* SOUND_MIXER_TREBLE */ - 0x05, /* SOUND_MIXER_SYNTH */ - 0x09, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x03, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x07, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00, /* SOUND_MIXER_OGAIN */ - 0x00, /* SOUND_MIXER_LINE1 */ - 0x00, /* SOUND_MIXER_LINE2 */ - 0x00 /* SOUND_MIXER_LINE3 */ -}; - -static int sbmixnum = 1; - -static void sb_mixer_reset(sb_devc * devc); - -void sb_mixer_set_stereo(sb_devc * devc, int mode) -{ - sb_chgmixer(devc, OUT_FILTER, STEREO_DAC, (mode ? STEREO_DAC : MONO_DAC)); -} - -static int detect_mixer(sb_devc * devc) -{ - /* Just trust the mixer is there */ - return 1; -} - -static void oss_change_bits(sb_devc *devc, unsigned char *regval, int dev, int chn, int newval) -{ - unsigned char mask; - int shift; - - 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; - - *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) -{ - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; - return devc->levels[dev]; -} - -void smw_mixer_init(sb_devc * devc) -{ - int i; - - 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_rec_devices = devc->supported_devices & - ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); - sb_mixer_reset(devc); -} - -int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right) -{ - int regoffs; - unsigned char val; - - if ((dev < 0) || (dev >= devc->iomap_sz)) - return -EINVAL; - - regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; - - if (regoffs == 0) - return -EINVAL; - - val = sb_getmixer(devc, regoffs); - oss_change_bits(devc, &val, dev, LEFT_CHN, left); - - if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* - * Change register - */ - { - 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 - */ - - val = sb_getmixer(devc, regoffs); /* - * Read the new one - */ - } - oss_change_bits(devc, &val, dev, RIGHT_CHN, right); - - sb_setmixer(devc, regoffs, val); - - return left | (right << 8); -} - -static int smw_mixer_set(sb_devc * devc, int dev, int left, int right) -{ - int reg, val; - - 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: - /* bounds check */ - if (dev < 0 || dev >= ARRAY_SIZE(smw_mix_regs)) - return -EINVAL; - 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) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retval; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if ((dev < 0) || (dev > 31)) - return -EINVAL; - - if (!(devc->supported_devices & (1 << dev))) /* - * Not supported - */ - return -EINVAL; - - /* Differentiate depending on the chipsets */ - switch (devc->model) { - case MDL_SMW: - retval = smw_mixer_set(devc, dev, left, right); - break; - case MDL_ESS: - retval = ess_mixer_set(devc, dev, left, right); - break; - default: - retval = sb_common_mixer_set(devc, dev, left, right); - } - if (retval >= 0) devc->levels[dev] = retval; - - return retval; -} - -/* - * set_recsrc doesn't apply to ES188x - */ -static void set_recsrc(sb_devc * devc, int src) -{ - sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); -} - -static int 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 (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) { - break; - } - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { - /* - * More than one device selected. Drop the - * previous selection - */ - devmask &= ~devc->recmask; - } - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { - /* - * More than one device 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; - - if (devc->submodel == SUBMDL_ALS007) - { - switch (devmask) - { - case SOUND_MASK_LINE: - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE); - break; - case SOUND_MASK_CD: - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD); - break; - case SOUND_MASK_SYNTH: - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH); - break; - default: /* Also takes care of SOUND_MASK_MIC case */ - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC); - break; - } - } - else - { - 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; - } - devc->recmask = devmask; - return devc->recmask; -} - -static int set_outmask(sb_devc * devc, int mask) -{ - int devmask, i; - unsigned char regimage; - - devmask = mask & devc->supported_out_devices; - - switch (devc->model) - { - case MDL_SB16: - if (devc->submodel == SUBMDL_ALS007) - break; - else - { - regimage = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - { - if ((1 << i) & devmask) - { - regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]); - } - sb_setmixer (devc, SB16_OMASK, regimage); - } - } - break; - default: - break; - } - - devc->outmask = devmask; - return devc->outmask; -} - -static int sb_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - sb_devc *devc = mixer_devs[dev]->devc; - int val, ret; - int __user *p = arg; - - /* - * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). - * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) - * or mode==2 put 3DSE state to mode. - */ - if (devc->model == MDL_SB16) { - if (cmd == SOUND_MIXER_AGC) - { - if (get_user(val, p)) - return -EFAULT; - sb_setmixer(devc, 0x43, (~val) & 0x01); - return 0; - } - if (cmd == SOUND_MIXER_3DSE) - { - /* I put here 15, but I don't know the exact version. - At least my 4.13 havn't 3DSE, 4.16 has it. */ - if (devc->minor < 15) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val == 0 || val == 1) - sb_chgmixer(devc, AWE_3DSE, 0x01, val); - else if (val == 2) - { - ret = sb_getmixer(devc, AWE_3DSE)&0x01; - return put_user(ret, p); - } - else - return -EINVAL; - return 0; - } - } - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - { - if (get_user(val, p)) - return -EFAULT; - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - ret = set_recmask(devc, val); - break; - - case SOUND_MIXER_OUTSRC: - ret = set_outmask(devc, val); - break; - - default: - ret = sb_mixer_set(devc, cmd & 0xff, val); - } - } - else switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - ret = devc->recmask; - break; - - case SOUND_MIXER_OUTSRC: - ret = devc->outmask; - break; - - case SOUND_MIXER_DEVMASK: - ret = devc->supported_devices; - break; - - case SOUND_MIXER_STEREODEVS: - ret = devc->supported_devices; - /* The ESS seems to have stereo mic controls */ - if (devc->model == MDL_ESS) - ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); - else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) - ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - break; - - case SOUND_MIXER_RECMASK: - ret = devc->supported_rec_devices; - break; - - case SOUND_MIXER_OUTMASK: - ret = devc->supported_out_devices; - break; - - case SOUND_MIXER_CAPS: - ret = devc->mixer_caps; - break; - - default: - ret = sb_mixer_get(devc, cmd & 0xff); - break; - } - return put_user(ret, p); - } else - return -EINVAL; -} - -static struct mixer_operations sb_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "SB", - .name = "Sound Blaster", - .ioctl = sb_mixer_ioctl -}; - -static struct mixer_operations als007_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "ALS007", - .name = "Avance ALS-007", - .ioctl = sb_mixer_ioctl -}; - -static void sb_mixer_reset(sb_devc * devc) -{ - char name[32]; - int i; - - sprintf(name, "SB_%d", devc->sbmixnum); - - if (devc->sbmo.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]); - - if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) { - set_recmask(devc, SOUND_MASK_MIC); - } -} - -int sb_mixer_init(sb_devc * devc, struct module *owner) -{ - 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_ESSPCI: - case MDL_YMPCI: - 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; - devc->iomap_sz = ARRAY_SIZE(sbpro_mix); - break; - - case MDL_ESS: - ess_mixer_init (devc); - break; - - case MDL_SMW: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = 0; - devc->supported_rec_devices = 0; - devc->iomap = &sbpro_mix; - devc->iomap_sz = ARRAY_SIZE(sbpro_mix); - smw_mixer_init(devc); - break; - - case MDL_SB16: - devc->mixer_caps = 0; - devc->supported_rec_devices = SB16_RECORDING_DEVICES; - devc->supported_out_devices = SB16_OUTFILTER_DEVICES; - if (devc->submodel != SUBMDL_ALS007) - { - devc->supported_devices = SB16_MIXER_DEVICES; - devc->iomap = &sb16_mix; - devc->iomap_sz = ARRAY_SIZE(sb16_mix); - } - else - { - devc->supported_devices = ALS007_MIXER_DEVICES; - devc->iomap = &als007_mix; - devc->iomap_sz = ARRAY_SIZE(als007_mix); - } - break; - - default: - printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model); - return 0; - } - - m = sound_alloc_mixerdev(); - if (m == -1) - return 0; - - mixer_devs[m] = kmalloc(sizeof(struct mixer_operations), GFP_KERNEL); - if (mixer_devs[m] == NULL) - { - printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); - sound_unload_mixerdev(m); - return 0; - } - - if (devc->submodel != SUBMDL_ALS007) - memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations)); - else - memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); - - mixer_devs[m]->devc = devc; - - if (owner) - mixer_devs[m]->owner = owner; - - devc->my_mixerdev = m; - sb_mixer_reset(devc); - return 1; -} - -void sb_mixer_unload(sb_devc *devc) -{ - if (devc->my_mixerdev == -1) - return; - - kfree(mixer_devs[devc->my_mixerdev]); - sound_unload_mixerdev(devc->my_mixerdev); - sbmixnum--; -} diff --git a/sound/oss/sb_mixer.h b/sound/oss/sb_mixer.h deleted file mode 100644 index 4b9425f085e3..000000000000 --- a/sound/oss/sb_mixer.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * sound/oss/sb_mixer.h - * - * Definitions for the SB Pro and SB16 mixers - */ -/* - * 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. - */ - -/* - * Modified: - * Hunyue Yau Jan 6 1994 - * Added defines for the Sound Galaxy NX Pro mixer. - * - * Rolf Fokkens Dec 20 1998 - * Added defines for some ES188x chips. - * - * Rolf Fokkens Dec 27 1998 - * Moved static stuff to sb_mixer.c - * - */ -/* - * Mixer registers - * - * NOTE! RECORD_SRC == IN_FILTER - */ - -/* - * Mixer registers of SB Pro - */ -#define VOC_VOL 0x04 -#define MIC_VOL 0x0A -#define MIC_MIX 0x0A -#define RECORD_SRC 0x0C -#define IN_FILTER 0x0C -#define OUT_FILTER 0x0E -#define MASTER_VOL 0x22 -#define FM_VOL 0x26 -#define CD_VOL 0x28 -#define LINE_VOL 0x2E -#define IRQ_NR 0x80 -#define DMA_NR 0x81 -#define IRQ_STAT 0x82 -#define OPSW 0x3c - -/* - * Additional registers on the SG NX Pro - */ -#define COVOX_VOL 0x42 -#define TREBLE_LVL 0x44 -#define BASS_LVL 0x46 - -#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */ -#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */ -#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */ -#define FILT_OFF (1 << 5) - -#define MONO_DAC 0x00 -#define STEREO_DAC 0x02 - -/* - * Mixer registers of SB16 - */ -#define SB16_OMASK 0x3c -#define SB16_IMASK_L 0x3d -#define SB16_IMASK_R 0x3e - -#define LEFT_CHN 0 -#define RIGHT_CHN 1 - -/* - * 3DSE register of AWE32/64 - */ -#define AWE_3DSE 0x90 - -/* - * Mixer registers of ALS007 - */ -#define ALS007_RECORD_SRC 0x6c -#define ALS007_OUTPUT_CTRL1 0x3c -#define ALS007_OUTPUT_CTRL2 0x4c - -#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ - {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} - -/* - * Recording sources (SB Pro) - */ - -#define SRC__MIC 1 /* Select Microphone recording source */ -#define SRC__CD 3 /* Select CD recording source */ -#define SRC__LINE 7 /* Use Line-in for recording source */ - -/* - * Recording sources for ALS-007 - */ - -#define ALS007_MIC 4 -#define ALS007_LINE 6 -#define ALS007_CD 2 -#define ALS007_SYNTH 7 diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c deleted file mode 100644 index f19da4b47c1d..000000000000 --- a/sound/oss/sequencer.c +++ /dev/null @@ -1,1661 +0,0 @@ -/* - * sound/oss/sequencer.c - * - * The sequencer personality manager. - */ -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Alan Cox : reformatted and fixed a pair of null pointer bugs - */ -#include <linux/kmod.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "midi_ctrl.h" -#include "sleep.h" - -static int sequencer_ok; -static struct sound_timer_operations *tmr; -static int tmr_no = -1; /* Currently selected timer */ -static int pending_timer = -1; /* For timer change operation */ -extern unsigned long seq_time; - -static int obsolete_api_used; -static DEFINE_SPINLOCK(lock); - -/* - * Local counts for number of synth and MIDI devices. These are initialized - * by the sequencer_open. - */ -static int max_mididev; -static int max_synthdev; - -/* - * The seq_mode gives the operating mode of the sequencer: - * 1 = level1 (the default) - * 2 = level2 (extended capabilities) - */ - -#define SEQ_1 1 -#define SEQ_2 2 -static int seq_mode = SEQ_1; - -static DECLARE_WAIT_QUEUE_HEAD(seq_sleeper); -static DECLARE_WAIT_QUEUE_HEAD(midi_sleeper); - -static int midi_opened[MAX_MIDI_DEV]; - -static int midi_written[MAX_MIDI_DEV]; - -static unsigned long prev_input_time; -static int prev_event_time; - -#include "tuning.h" - -#define EV_SZ 8 -#define IEV_SZ 8 - -static unsigned char *queue; -static unsigned char *iqueue; - -static volatile int qhead, qtail, qlen; -static volatile int iqhead, iqtail, iqlen; -static volatile int seq_playing; -static volatile int sequencer_busy; -static int output_threshold; -static long 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); - -#if MAX_SYNTH_DEV > 15 -#error Too many synthesizer devices enabled. -#endif - -int sequencer_read(int dev, struct file *file, char __user *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; - - spin_lock_irqsave(&lock,flags); - - if (!iqlen) - { - spin_unlock_irqrestore(&lock,flags); - if (file->f_flags & O_NONBLOCK) { - return -EAGAIN; - } - - oss_broken_sleep_on(&midi_sleeper, pre_event_timeout); - spin_lock_irqsave(&lock,flags); - if (!iqlen) - { - spin_unlock_irqrestore(&lock,flags); - return 0; - } - } - while (iqlen && c >= ev_len) - { - char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(&(buf)[p], fixit, ev_len)) - return count - c; - p += ev_len; - c -= ev_len; - - spin_lock_irqsave(&lock,flags); - iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; - iqlen--; - } - spin_unlock_irqrestore(&lock,flags); - return count - c; -} - -static void sequencer_midi_output(int dev) -{ - /* - * 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 */ - - spin_lock_irqsave(&lock,flags); - memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); - iqlen++; - iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - wake_up(&midi_sleeper); - spin_unlock_irqrestore(&lock,flags); -} -EXPORT_SYMBOL(seq_copy_to_input); - -static void sequencer_midi_input(int dev, unsigned char data) -{ - unsigned int tstamp; - unsigned char event_rec[4]; - - if (data == 0xfe) /* Ignore active sensing */ - return; - - tstamp = jiffies - seq_time; - - if (tstamp != prev_input_time) - { - tstamp = (tstamp << 8) | SEQ_WAIT; - 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, 4); -} - -void seq_input_event(unsigned char *event_rec, int len) -{ - unsigned long this_time; - - if (seq_mode == SEQ_2) - this_time = tmr->get_time(tmr_no); - else - this_time = jiffies - seq_time; - - if (this_time != prev_input_time) - { - unsigned char tmp_event[8]; - - 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; - - seq_copy_to_input(tmp_event, 8); - prev_input_time = this_time; - } - seq_copy_to_input(event_rec, len); -} -EXPORT_SYMBOL(seq_input_event); - -int sequencer_write(int dev, struct file *file, const char __user *buf, int count) -{ - unsigned char event_rec[EV_SZ], ev_code; - int p = 0, c, ev_size; - int mode = translate_mode(file); - - dev = dev >> 4; - - if (mode == OPEN_READ) - return -EIO; - - c = count; - - while (c >= 4) - { - if (copy_from_user((char *) event_rec, &(buf)[p], 4)) - goto out; - 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, c, 0); - if (err < 0) - return err; - - return err; - } - if (ev_code >= 128) - { - if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) - { - printk(KERN_WARNING "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; - } - if (copy_from_user((char *)&event_rec[4], - &(buf)[p + 4], 4)) - goto out; - - } - else - { - if (seq_mode == SEQ_2) - { - printk(KERN_WARNING "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 err, mode; - int dev = event_rec[2]; - - if (dev >= max_mididev || midi_devs[dev]==NULL) - { - /*printk("Sequencer Error: Nonexistent MIDI device %d\n", dev);*/ - return -ENXIO; - } - mode = translate_mode(file); - - if ((err = midi_devs[dev]->open(dev, mode, - sequencer_midi_input, sequencer_midi_output)) < 0) - { - seq_reset(); - printk(KERN_WARNING "Sequencer Error: Unable to open Midi #%d\n", dev); - return err; - } - midi_opened[dev] = 1; - } - } - if (!seq_queue(event_rec, (file->f_flags & (O_NONBLOCK) ? 1 : 0))) - { - int processed = count - c; - - if (!seq_playing) - seq_startplay(); - - if (!processed && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; - else - return processed; - } - p += ev_size; - c -= ev_size; - } - - if (!seq_playing) - seq_startplay(); -out: - return count; -} - -static int 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 - */ - - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !waitqueue_active(&seq_sleeper)) { - /* - * Sleep until there is enough space on the queue - */ - oss_broken_sleep_on(&seq_sleeper, MAX_SCHEDULE_TIMEOUT); - } - if (qlen >= SEQ_MAX_QUEUE) - { - return 0; /* - * To be sure - */ - } - memcpy(&queue[qtail * EV_SZ], note, EV_SZ); - - qtail = (qtail + 1) % SEQ_MAX_QUEUE; - qlen++; - - return 1; -} - -static int extended_event(unsigned char *q) -{ - int dev = q[2]; - - if (dev < 0 || dev >= max_synthdev) - 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; - - 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) -{ - unsigned short key; - int i; - - 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; - return -1; -} - -static int alloc_voice(int dev, int chn, int note) -{ - unsigned short key; - int voice; - - 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; -} - -static void seq_chn_voice_event(unsigned char *event_rec) -{ -#define dev event_rec[1] -#define cmd event_rec[2] -#define chn event_rec[3] -#define note event_rec[4] -#define parm event_rec[5] - - int voice = -1; - - if ((int) dev > max_synthdev || synth_devs[dev] == NULL) - 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 (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 -#undef note -#undef parm -} - - -static void 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 || 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) - { - if (chn > 15) - break; - - 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) - { - if (chn > 15) - break; - - 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) -{ - 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) - wake_up(&seq_sleeper); - 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) - wake_up(&seq_sleeper); - 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: - parm = (parm << 8 | SEQ_ECHO); - seq_copy_to_input((unsigned char *) &parm, 4); - break; - - default:; - } - - return TIMER_NOT_ARMED; -} - -static void seq_local_event(unsigned char *event_rec) -{ - unsigned char cmd = event_rec[1]; - unsigned int parm = *((unsigned int *) &event_rec[4]); - - switch (cmd) - { - case LOCL_STARTAUDIO: - DMAbuf_start_devices(parm); - break; - - default:; - } -} - -static void seq_sysex_message(unsigned char *event_rec) -{ - unsigned int dev = event_rec[1]; - int i, l = 0; - unsigned char *buf = &event_rec[2]; - - if (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) -{ - /* - * 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) - wake_up(&seq_sleeper); - /* - * 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: /* - * Put a midi character - */ - 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; - 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; -} - -/* called also as timer in irq context */ -static void seq_startplay(void) -{ - int this_one, action; - unsigned long flags; - - while (qlen > 0) - { - - spin_lock_irqsave(&lock,flags); - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - spin_unlock_irqrestore(&lock,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; - } - } - - seq_playing = 0; - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - wake_up(&seq_sleeper); -} - -static void reset_controllers(int dev, unsigned char *controller, int update_dev) -{ - int i; - for (i = 0; i < 128; i++) - controller[i] = ctrl_def_values[i]; -} - -static void setup_mode2(void) -{ - int dev; - - max_synthdev = num_synths; - - 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; - } - } - max_mididev = 0; - seq_mode = SEQ_2; -} - -int sequencer_open(int dev, struct file *file) -{ - int retval, mode, i; - int level, tmp; - - if (!sequencer_ok) - sequencer_init(); - - level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; - - dev = dev >> 4; - mode = translate_mode(file); - - if (!sequencer_ok) - { -/* printk("Sound card: sequencer not initialized\n");*/ - return -ENXIO; - } - if (dev) /* Patch manager device (obsolete) */ - return -ENXIO; - - if(synth_devs[dev] == NULL) - request_module("synth0"); - - if (mode == OPEN_READ) - { - if (!num_midis) - { - /*printk("Sequencer: No MIDI devices. Input not possible\n");*/ - sequencer_busy = 0; - return -ENXIO; - } - } - if (sequencer_busy) - { - return -EBUSY; - } - sequencer_busy = 1; - obsolete_api_used = 0; - - max_mididev = num_midis; - max_synthdev = num_synths; - pre_event_timeout = MAX_SCHEDULE_TIMEOUT; - 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] && 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 (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) - { - sequencer_busy=0; - 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 (synth_devs[i]==NULL) - continue; - - if (!try_module_get(synth_devs[i]->owner)) - continue; - - if ((tmp = synth_devs[i]->open(i, mode)) < 0) - { - printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); - if (synth_devs[i]->midi_dev) - printk(KERN_WARNING "(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; - - prev_input_time = 0; - prev_event_time = 0; - - 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] && midi_devs[i]) - { - if (!try_module_get(midi_devs[i]->owner)) - continue; - - 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 (try_module_get(tmr->owner)) - tmr->open(tmr_no, seq_mode); - } - - init_waitqueue_head(&seq_sleeper); - init_waitqueue_head(&midi_sleeper); - output_threshold = SEQ_MAX_QUEUE / 2; - - return 0; -} - -static void seq_drain_midi_queues(void) -{ - int i, n; - - /* - * Give the Midi drivers time to drain their output queues - */ - - n = 1; - - while (!signal_pending(current) && n) - { - 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) - oss_broken_sleep_on(&seq_sleeper, HZ/10); - } -} - -void sequencer_release(int dev, struct file *file) -{ - int i; - int mode = translate_mode(file); - - dev = dev >> 4; - - /* - * Wait until the queue is empty (if we don't have nonblock) - */ - - if (mode != OPEN_READ && !(file->f_flags & O_NONBLOCK)) - { - while (!signal_pending(current) && qlen > 0) - { - seq_sync(); - oss_broken_sleep_on(&seq_sleeper, 3*HZ); - /* 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]) - { - synth_devs[i]->close(i); - - module_put(synth_devs[i]->owner); - - 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); - module_put(midi_devs[i]->owner); - } - } - - if (seq_mode == SEQ_2) { - tmr->close(tmr_no); - module_put(tmr->owner); - } - - if (obsolete_api_used) - printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm); - sequencer_busy = 0; -} - -static int seq_sync(void) -{ - if (qlen && !seq_playing && !signal_pending(current)) - seq_startplay(); - - if (qlen > 0) - oss_broken_sleep_on(&seq_sleeper, HZ); - return qlen; -} - -static void 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 - */ - - n = 3 * HZ; /* Timeout */ - - spin_lock_irqsave(&lock,flags); - while (n && !midi_devs[dev]->outputc(dev, data)) { - oss_broken_sleep_on(&seq_sleeper, HZ/25); - n--; - } - spin_unlock_irqrestore(&lock,flags); -} - -static void seq_reset(void) -{ - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ - - int i; - int chn; - unsigned long flags; - - sound_stop_timer(); - - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 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); - - 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 - */ - { - /* - * 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; - - spin_lock_irqsave(&lock,flags); - - if (waitqueue_active(&seq_sleeper)) { - /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ - wake_up(&seq_sleeper); - } - spin_unlock_irqrestore(&lock,flags); -} - -static 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 - */ -} - -int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) -{ - int midi_dev, orig_dev, val, err; - int mode = translate_mode(file); - struct synth_info inf; - struct seq_event_rec event_rec; - int __user *p = arg; - - 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); - - case SNDCTL_TMR_SELECT: - if (seq_mode != SEQ_2) - return -EINVAL; - if (get_user(pending_timer, p)) - return -EFAULT; - if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) - { - pending_timer = -1; - return -EINVAL; - } - val = pending_timer; - break; - - case SNDCTL_SEQ_PANIC: - seq_panic(); - return -EINVAL; - - case SNDCTL_SEQ_SYNC: - if (mode == OPEN_READ) - return 0; - while (qlen > 0 && !signal_pending(current)) - seq_sync(); - return qlen ? -EINTR : 0; - - case SNDCTL_SEQ_RESET: - seq_reset(); - return 0; - - case SNDCTL_SEQ_TESTMIDI: - if (__get_user(midi_dev, p)) - return -EFAULT; - if (midi_dev < 0 || midi_dev >= max_mididev || !midi_devs[midi_dev]) - return -ENXIO; - - if (!midi_opened[midi_dev] && - (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; - - case SNDCTL_SEQ_GETINCOUNT: - if (mode == OPEN_WRITE) - return 0; - val = iqlen; - break; - - case SNDCTL_SEQ_GETOUTCOUNT: - if (mode == OPEN_READ) - return 0; - val = SEQ_MAX_QUEUE - qlen; - break; - - case SNDCTL_SEQ_GETTIME: - if (seq_mode == SEQ_2) - return tmr->ioctl(tmr_no, cmd, arg); - val = 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); - - if (get_user(val, p)) - return -EFAULT; - if (val != 0) - return -EINVAL; - val = HZ; - break; - - case SNDCTL_SEQ_RESETSAMPLES: - case SNDCTL_SYNTH_REMOVESAMPLE: - case SNDCTL_SYNTH_CONTROL: - if (get_user(dev, p)) - return -EFAULT; - if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - return synth_devs[dev]->ioctl(dev, cmd, arg); - - case SNDCTL_SEQ_NRSYNTHS: - val = max_synthdev; - break; - - case SNDCTL_SEQ_NRMIDIS: - val = max_mididev; - break; - - case SNDCTL_SYNTH_MEMAVL: - if (get_user(dev, p)) - return -EFAULT; - if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - val = synth_devs[dev]->ioctl(dev, cmd, arg); - break; - - case SNDCTL_FM_4OP_ENABLE: - if (get_user(dev, p)) - return -EFAULT; - if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) - return -ENXIO; - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - synth_devs[dev]->ioctl(dev, cmd, arg); - return 0; - - case SNDCTL_SYNTH_INFO: - if (get_user(dev, &((struct synth_info __user *)arg)->device)) - return -EFAULT; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - return synth_devs[dev]->ioctl(dev, cmd, arg); - - /* Like SYNTH_INFO but returns ID in the name field */ - case SNDCTL_SYNTH_ID: - if (get_user(dev, &((struct synth_info __user *)arg)->device)) - return -EFAULT; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - memcpy(&inf, synth_devs[dev]->info, sizeof(inf)); - strlcpy(inf.name, synth_devs[dev]->id, sizeof(inf.name)); - inf.device = dev; - return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0; - - case SNDCTL_SEQ_OUTOFBAND: - if (copy_from_user(&event_rec, arg, sizeof(event_rec))) - return -EFAULT; - play_event(event_rec.arr); - return 0; - - case SNDCTL_MIDI_INFO: - if (get_user(dev, &((struct midi_info __user *)arg)->device)) - return -EFAULT; - if (dev < 0 || dev >= max_mididev || !midi_devs[dev]) - return -ENXIO; - midi_devs[dev]->info.device = dev; - return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; - - case SNDCTL_SEQ_THRESHOLD: - if (get_user(val, p)) - return -EFAULT; - if (val < 1) - val = 1; - if (val >= SEQ_MAX_QUEUE) - val = SEQ_MAX_QUEUE - 1; - output_threshold = val; - return 0; - - case SNDCTL_MIDI_PRETIME: - if (get_user(val, p)) - return -EFAULT; - if (val < 0) - val = 0; - val = (HZ * val) / 10; - pre_event_timeout = val; - break; - - default: - if (mode == OPEN_READ) - return -EIO; - if (!synth_devs[0]) - return -ENXIO; - if (!(synth_open_mask & (1 << 0))) - return -ENXIO; - if (!synth_devs[0]->ioctl) - return -EINVAL; - return synth_devs[0]->ioctl(0, cmd, arg); - } - return put_user(val, p); -} - -/* No kernel lock - we're using the global irq lock here */ -unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait) -{ - unsigned long flags; - unsigned int mask = 0; - - dev = dev >> 4; - - spin_lock_irqsave(&lock,flags); - /* input */ - poll_wait(file, &midi_sleeper, wait); - if (iqlen) - mask |= POLLIN | POLLRDNORM; - - /* output */ - poll_wait(file, &seq_sleeper, wait); - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - mask |= POLLOUT | POLLWRNORM; - spin_unlock_irqrestore(&lock,flags); - return mask; -} - - -void sequencer_timer(unsigned long dummy) -{ - seq_startplay(); -} -EXPORT_SYMBOL(sequencer_timer); - -int note_to_freq(int note_num) -{ - - /* - * This routine converts a midi note to a frequency (multiplied by 1000) - */ - - int note, octave, note_freq; - static int notes[] = - { - 261632, 277189, 293671, 311132, 329632, 349232, - 369998, 391998, 415306, 440000, 466162, 493880 - }; - -#define BASE_OCTAVE 5 - - octave = note_num / 12; - note = note_num % 12; - - note_freq = notes[note]; - - if (octave < BASE_OCTAVE) - note_freq >>= (BASE_OCTAVE - octave); - else if (octave > BASE_OCTAVE) - note_freq <<= (octave - BASE_OCTAVE); - - /* - * note_freq >>= 1; - */ - - return note_freq; -} -EXPORT_SYMBOL(note_to_freq); - -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; - 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 */ -} -EXPORT_SYMBOL(compute_finetune); - -void sequencer_init(void) -{ - if (sequencer_ok) - return; - queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ); - if (queue == NULL) - { - printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); - return; - } - iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ); - if (iqueue == NULL) - { - printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n"); - vfree(queue); - return; - } - sequencer_ok = 1; -} -EXPORT_SYMBOL(sequencer_init); - -void sequencer_unload(void) -{ - vfree(queue); - vfree(iqueue); - queue = iqueue = NULL; -} diff --git a/sound/oss/sleep.h b/sound/oss/sleep.h deleted file mode 100644 index a20fc925a5ce..000000000000 --- a/sound/oss/sleep.h +++ /dev/null @@ -1,18 +0,0 @@ -#include <linux/wait.h> - -/* - * Do not use. This is a replacement for the old - * "interruptible_sleep_on_timeout" function that has been - * deprecated for ages. All users should instead try to use - * wait_event_interruptible_timeout. - */ - -static inline long -oss_broken_sleep_on(wait_queue_head_t *q, long timeout) -{ - DEFINE_WAIT(wait); - prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE); - timeout = schedule_timeout(timeout); - finish_wait(q, &wait); - return timeout; -} diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h deleted file mode 100644 index 87d8ad4a0340..000000000000 --- a/sound/oss/sound_calls.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * DMA buffer calls - */ - -int DMAbuf_open(int dev, int mode); -int DMAbuf_release(int dev, int mode); -int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock); -int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock); -int DMAbuf_rmchars(int dev, int buff_no, int c); -int DMAbuf_start_output(int dev, int buff_no, int l); -int DMAbuf_move_wrpointer(int dev, int l); -/* int DMAbuf_ioctl(int dev, unsigned int cmd, void __user *arg, int local); */ -void DMAbuf_init(int dev, int dma1, int dma2); -void DMAbuf_deinit(int dev); -int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); -void DMAbuf_inputintr(int dev); -void DMAbuf_outputintr(int dev, int underflow_flag); -struct dma_buffparms; -int DMAbuf_space_in_queue (int dev); -int DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap); -int DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction); -void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap); -unsigned int DMAbuf_poll(struct file *file, int dev, poll_table *wait); -void DMAbuf_start_devices(unsigned int devmask); -void DMAbuf_reset (int dev); -int DMAbuf_sync (int dev); - -/* - * System calls for /dev/dsp and /dev/audio (audio.c) - */ - -int audio_read (int dev, struct file *file, char __user *buf, int count); -int audio_write (int dev, struct file *file, const char __user *buf, int count); -int audio_open (int dev, struct file *file); -void audio_release (int dev, struct file *file); -int audio_ioctl (int dev, struct file *file, - unsigned int cmd, void __user *arg); -void audio_init_devices (void); -void reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording); - -/* - * System calls for the /dev/sequencer - */ - -int sequencer_read (int dev, struct file *file, char __user *buf, int count); -int sequencer_write (int dev, struct file *file, const char __user *buf, int count); -int sequencer_open (int dev, struct file *file); -void sequencer_release (int dev, struct file *file); -int sequencer_ioctl (int dev, struct file *file, unsigned int cmd, void __user *arg); -unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait); - -void sequencer_init (void); -void sequencer_unload (void); -void sequencer_timer(unsigned long dummy); -int note_to_freq(int note_num); -unsigned long compute_finetune(unsigned long base_freq, int bend, int range, - int vibrato_bend); -void seq_input_event(unsigned char *event, int len); -void seq_copy_to_input (unsigned char *event, int len); - -/* - * System calls for the /dev/midi - */ - -int MIDIbuf_read (int dev, struct file *file, char __user *buf, int count); -int MIDIbuf_write (int dev, struct file *file, const char __user *buf, int count); -int MIDIbuf_open (int dev, struct file *file); -void MIDIbuf_release (int dev, struct file *file); -int MIDIbuf_ioctl (int dev, struct file *file, unsigned int cmd, void __user *arg); -unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait); -int MIDIbuf_avail(int dev); - -void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); - - -/* From soundcard.c */ -void request_sound_timer (int count); -void sound_stop_timer(void); -void conf_printf(char *name, struct address_info *hw_config); -void conf_printf2(char *name, int base, int irq, int dma, int dma2); - -/* From sound_timer.c */ -void sound_timer_interrupt(void); -void sound_timer_syncinterval(unsigned int new_usecs); - -/* From midi_synth.c */ -void do_midi_msg (int synthno, unsigned char *msg, int mlen); diff --git a/sound/oss/sound_config.h b/sound/oss/sound_config.h deleted file mode 100644 index 5253b0a70437..000000000000 --- a/sound/oss/sound_config.h +++ /dev/null @@ -1,144 +0,0 @@ -/* sound_config.h - * - * A driver for sound cards, misc. configuration parameters. - */ -/* - * 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. - */ - - -#ifndef _SOUND_CONFIG_H_ -#define _SOUND_CONFIG_H_ - -#include <linux/fs.h> -#include <linux/sound.h> -#include <linux/sched/signal.h> - -#include "os.h" -#include "soundvers.h" - - -#ifndef SND_DEFAULT_ENABLE -#define SND_DEFAULT_ENABLE 1 -#endif - -#ifndef MAX_REALTIME_FACTOR -#define MAX_REALTIME_FACTOR 4 -#endif - -/* - * Use always 64k buffer size. There is no reason to use shorter. - */ -#undef DSP_BUFFSIZE -#define DSP_BUFFSIZE (64*1024) - -#ifndef DSP_BUFFCOUNT -#define DSP_BUFFCOUNT 1 /* 1 is recommended. */ -#endif - -#define FM_MONO 0x388 /* This is the I/O address used by AdLib */ - -#ifndef CONFIG_PAS_BASE -#define CONFIG_PAS_BASE 0x388 -#endif - -/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the - driver. (There is no need to alter this) */ -#define SEQ_MAX_QUEUE 1024 - -#define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */ -/* 128 instruments for general MIDI setup and 16 unassigned */ - -#define SND_NDEVS 256 /* Number of supported devices */ - -#define DSP_DEFAULT_SPEED 8000 - -#define MAX_AUDIO_DEV 5 -#define MAX_MIXER_DEV 5 -#define MAX_SYNTH_DEV 5 -#define MAX_MIDI_DEV 6 -#define MAX_TIMER_DEV 4 - -struct address_info { - int io_base; - int irq; - int dma; - int dma2; - int always_detect; /* 1=Trust me, it's there */ - char *name; - 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 specific. Usually 0 */ - void *memptr; /* Module memory chainer */ - int slots[6]; /* To remember driver slot ids */ -}; - -#define SYNTH_MAX_VOICES 32 - -struct voice_alloc_info { - int max_voice; - int used_voices; - int ptr; /* For device specific use */ - unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ - int timestamp; - int alloc_times[SYNTH_MAX_VOICES]; - }; - -struct channel_info { - int pgm_num; - int bender_value; - int bender_range; - unsigned char controllers[128]; - }; - -/* - * Process wakeup reasons - */ -#define WK_NONE 0x00 -#define WK_WAKEUP 0x01 -#define WK_TIMEOUT 0x02 -#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 -#define OPEN_READWRITE (OPEN_READ|OPEN_WRITE) - -static inline int translate_mode(struct file *file) -{ - if (OPEN_READ == (__force int)FMODE_READ && - OPEN_WRITE == (__force int)FMODE_WRITE) - return (__force int)(file->f_mode & (FMODE_READ | FMODE_WRITE)); - else - return ((file->f_mode & FMODE_READ) ? OPEN_READ : 0) | - ((file->f_mode & FMODE_WRITE) ? OPEN_WRITE : 0); -} - -#include "sound_calls.h" -#include "dev_table.h" - -#ifndef DDB -#define DDB(x) do {} while (0) -#endif - -#ifndef MDB -#ifdef MODULE -#define MDB(x) x -#else -#define MDB(x) -#endif -#endif - -#define TIMER_ARMED 121234 -#define TIMER_NOT_ARMED 1 - -#define MAX_MEM_BLOCKS 1024 - -#endif diff --git a/sound/oss/sound_firmware.h b/sound/oss/sound_firmware.h deleted file mode 100644 index 2be465277ba0..000000000000 --- a/sound/oss/sound_firmware.h +++ /dev/null @@ -1,29 +0,0 @@ -#include <linux/fs.h> - -/** - * mod_firmware_load - load sound driver firmware - * @fn: filename - * @fp: return for the buffer. - * - * Load the firmware for a sound module (up to 128K) into a buffer. - * The buffer is returned in *fp. It is allocated with vmalloc so is - * virtually linear and not DMAable. The caller should free it with - * vfree when finished. - * - * The length of the buffer is returned on a successful load, the - * value zero on a failure. - * - * Caution: This API is not recommended. Firmware should be loaded via - * request_firmware. - */ -static inline int mod_firmware_load(const char *fn, char **fp) -{ - loff_t size; - int err; - - err = kernel_read_file_from_path(fn, (void **)fp, &size, - 131072, READING_FIRMWARE); - if (err < 0) - return 0; - return size; -} diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c deleted file mode 100644 index 3a444a6f10eb..000000000000 --- a/sound/oss/sound_timer.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * sound/oss/sound_timer.c - */ -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - */ -#include <linux/string.h> -#include <linux/spinlock.h> - -#include "sound_config.h" - -static volatile int initialized, opened, tmr_running; -static volatile unsigned int tmr_offs, tmr_ctr; -static volatile unsigned long ticks_offs; -static volatile int curr_tempo, curr_timebase; -static volatile unsigned long curr_ticks; -static volatile unsigned long next_event_time; -static unsigned long prev_event_time; -static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ - -static struct sound_lowlev_timer *tmr; -static DEFINE_SPINLOCK(lock); - -static unsigned long tmr2ticks(int tmr_value) -{ - /* - * Convert timer ticks to MIDI ticks - */ - - unsigned long tmp; - unsigned long scale; - - tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ - scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ - return (tmp + (scale / 2)) / scale; -} - -void reprogram_timer(void) -{ - unsigned long usecs_per_tick; - - /* - * The user is changing the timer rate before setting a timer - * slap, bad bad not allowed. - */ - - if(!tmr) - return; - - 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; - - usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick); -} - -void 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; - usecs_per_tmr = new_usecs; -} -EXPORT_SYMBOL(sound_timer_syncinterval); - -static void tmr_reset(void) -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - spin_unlock_irqrestore(&lock,flags); -} - -static int timer_open(int dev, int mode) -{ - if (opened) - return -EBUSY; - tmr_reset(); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - reprogram_timer(); - return 0; -} - -static void timer_close(int dev) -{ - opened = tmr_running = 0; - tmr->tmr_disable(tmr->dev); -} - -static int 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; -} - -static unsigned long timer_get_time(int dev) -{ - if (!opened) - return 0; - return curr_ticks; -} - -static int timer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int __user *p = arg; - int val; - - switch (cmd) - { - case SNDCTL_TMR_SOURCE: - val = TMR_INTERNAL; - break; - - case SNDCTL_TMR_START: - tmr_reset(); - tmr_running = 1; - return 0; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - - case SNDCTL_TMR_TIMEBASE: - if (get_user(val, p)) - return -EFAULT; - if (val) - { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - val = curr_timebase; - break; - - case SNDCTL_TMR_TEMPO: - if (get_user(val, p)) - return -EFAULT; - 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(); - } - val = curr_tempo; - break; - - case SNDCTL_SEQ_CTRLRATE: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) /* Can't change */ - return -EINVAL; - val = ((curr_tempo * curr_timebase) + 30) / 60; - break; - - case SNDCTL_SEQ_GETTIME: - val = curr_ticks; - break; - - case SNDCTL_TMR_METRONOME: - default: - return -EINVAL; - } - return put_user(val, p); -} - -static void timer_arm(int dev, long time) -{ - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; - - next_event_time = prev_event_time = time; - return; -} - -static struct sound_timer_operations sound_timer = -{ - .owner = THIS_MODULE, - .info = {"Sound Timer", 0}, - .priority = 1, /* Priority */ - .devlink = 0, /* Local device link */ - .open = timer_open, - .close = timer_close, - .event = timer_event, - .get_time = timer_get_time, - .ioctl = timer_ioctl, - .arm_timer = timer_arm -}; - -void sound_timer_interrupt(void) -{ - unsigned long flags; - - if (!opened) - return; - - tmr->tmr_restart(tmr->dev); - - if (!tmr_running) - return; - - spin_lock_irqsave(&lock,flags); - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } - spin_unlock_irqrestore(&lock,flags); -} -EXPORT_SYMBOL(sound_timer_interrupt); - -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; - - n = sound_alloc_timerdev(); - if (n == -1) - n = 0; /* Overwrite the system timer */ - strlcpy(sound_timer.info.name, name, sizeof(sound_timer.info.name)); - sound_timer_devs[n] = &sound_timer; -} -EXPORT_SYMBOL(sound_timer_init); - diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c deleted file mode 100644 index b70c7c8f9c5d..000000000000 --- a/sound/oss/soundcard.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * linux/sound/oss/soundcard.c - * - * Sound card driver for Linux - * - * - * 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. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * integrated sound_switch.c - * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, - * which should disappear in the near future) - * Eric Dumas : devfs support (22-Jan-98) <dumas@linux.eu.org> with - * fixups by C. Scott Ananian <cananian@alumni.princeton.edu> - * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c - * Rob Riggs : Added persistent DMA buffers support (1998/10/17) - * Christoph Hellwig : Some cleanup work (2000/03/01) - */ - - -#include "sound_config.h" -#include <linux/init.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/fcntl.h> -#include <linux/ctype.h> -#include <linux/stddef.h> -#include <linux/kmod.h> -#include <linux/kernel.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/wait.h> -#include <linux/ioport.h> -#include <linux/major.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/mutex.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/device.h> - -/* - * This ought to be moved into include/asm/dma.h - */ -#ifndef valid_dma -#define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4) -#endif - -/* - * Table for permanently allocated memory (used when unloading the module) - */ -void * sound_mem_blocks[MAX_MEM_BLOCKS]; -static DEFINE_MUTEX(soundcard_mutex); -int sound_nblocks = 0; - -/* Persistent DMA buffers */ -#ifdef CONFIG_SOUND_DMAP -int sound_dmap_flag = 1; -#else -int sound_dmap_flag = 0; -#endif - -static char dma_alloc_map[MAX_DMA_CHANNELS]; - -#define DMA_MAP_UNAVAIL 0 -#define DMA_MAP_FREE 1 -#define DMA_MAP_BUSY 2 - - -unsigned long seq_time = 0; /* Time for /dev/sequencer */ -extern struct class *sound_class; - -/* - * Table for configurable mixer volume handling - */ -static mixer_vol_table mixer_vols[MAX_MIXER_DEV]; -static int num_mixer_volumes; - -int *load_mixer_volumes(char *name, int *levels, int present) -{ - int i, n; - - for (i = 0; i < num_mixer_volumes; i++) { - if (strncmp(name, mixer_vols[i].name, 32) == 0) { - if (present) - mixer_vols[i].num = i; - return mixer_vols[i].levels; - } - } - if (num_mixer_volumes >= MAX_MIXER_DEV) { - printk(KERN_ERR "Sound: Too many mixers (%s)\n", name); - return levels; - } - n = num_mixer_volumes++; - - strncpy(mixer_vols[n].name, name, 32); - - 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; -} -EXPORT_SYMBOL(load_mixer_volumes); - -static int set_mixer_levels(void __user * arg) -{ - /* mixer_vol_table is 174 bytes, so IMHO no reason to not allocate it on the stack */ - mixer_vol_table buf; - - if (__copy_from_user(&buf, arg, sizeof(buf))) - return -EFAULT; - load_mixer_volumes(buf.name, buf.levels, 0); - if (__copy_to_user(arg, &buf, sizeof(buf))) - return -EFAULT; - return 0; -} - -static int get_mixer_levels(void __user * arg) -{ - int n; - - if (__get_user(n, (int __user *)(&(((mixer_vol_table __user *)arg)->num)))) - return -EFAULT; - if (n < 0 || n >= num_mixer_volumes) - return -EINVAL; - if (__copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table))) - return -EFAULT; - return 0; -} - -/* 4K page size but our output routines use some slack for overruns */ -#define PROC_BLOCK_SIZE (3*1024) - -static ssize_t sound_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - int dev = iminor(file_inode(file)); - int ret = -EINVAL; - - /* - * The OSS drivers aren't remotely happy without this locking, - * and unless someone fixes them when they are about to bite the - * big one anyway, we might as well bandage here.. - */ - - mutex_lock(&soundcard_mutex); - - switch (dev & 0x0f) { - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = audio_read(dev, file, buf, count); - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - ret = sequencer_read(dev, file, buf, count); - break; - - case SND_DEV_MIDIN: - ret = MIDIbuf_read(dev, file, buf, count); - } - mutex_unlock(&soundcard_mutex); - return ret; -} - -static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - int dev = iminor(file_inode(file)); - int ret = -EINVAL; - - mutex_lock(&soundcard_mutex); - switch (dev & 0x0f) { - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - ret = sequencer_write(dev, file, buf, count); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = audio_write(dev, file, buf, count); - break; - - case SND_DEV_MIDIN: - ret = MIDIbuf_write(dev, file, buf, count); - break; - } - mutex_unlock(&soundcard_mutex); - return ret; -} - -static int sound_open(struct inode *inode, struct file *file) -{ - int dev = iminor(inode); - int retval; - - if ((dev >= SND_NDEVS) || (dev < 0)) { - printk(KERN_ERR "Invalid minor device %d\n", dev); - return -ENXIO; - } - mutex_lock(&soundcard_mutex); - switch (dev & 0x0f) { - case SND_DEV_CTL: - dev >>= 4; - if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { - request_module("mixer%d", dev); - } - retval = -ENXIO; - if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) - break; - - if (!try_module_get(mixer_devs[dev]->owner)) - break; - - retval = 0; - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - retval = sequencer_open(dev, file); - break; - - case SND_DEV_MIDIN: - retval = MIDIbuf_open(dev, file); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - retval = audio_open(dev, file); - break; - - default: - printk(KERN_ERR "Invalid minor device %d\n", dev); - retval = -ENXIO; - } - - mutex_unlock(&soundcard_mutex); - return retval; -} - -static int sound_release(struct inode *inode, struct file *file) -{ - int dev = iminor(inode); - - mutex_lock(&soundcard_mutex); - switch (dev & 0x0f) { - case SND_DEV_CTL: - module_put(mixer_devs[dev >> 4]->owner); - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - sequencer_release(dev, file); - break; - - case SND_DEV_MIDIN: - MIDIbuf_release(dev, file); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - audio_release(dev, file); - break; - - default: - printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); - } - mutex_unlock(&soundcard_mutex); - - return 0; -} - -static int get_mixer_info(int dev, void __user *arg) -{ - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); - strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); - info.modify_counter = mixer_devs[dev]->modify_counter; - if (__copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int get_old_mixer_info(int dev, void __user *arg) -{ - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); - strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) -{ - if (mixdev < 0 || mixdev >= MAX_MIXER_DEV) - return -ENXIO; - /* Try to load the mixer... */ - if (mixer_devs[mixdev] == NULL) { - request_module("mixer%d", mixdev); - } - if (mixdev >= num_mixers || !mixer_devs[mixdev]) - return -ENXIO; - 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 (!mixer_devs[mixdev]->ioctl) - return -EINVAL; - return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); -} - -static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int len = 0, dtype; - int dev = iminor(file_inode(file)); - long ret = -EINVAL; - void __user *p = (void __user *)arg; - - if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { - /* - * Have to validate the address given by the process. - */ - len = _SIOC_SIZE(cmd); - if (len < 1 || len > 65536 || !p) - return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (!access_ok(VERIFY_READ, p, len)) - return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_READ) - if (!access_ok(VERIFY_WRITE, p, len)) - return -EFAULT; - } - if (cmd == OSS_GETVERSION) - return __put_user(SOUND_VERSION, (int __user *)p); - - mutex_lock(&soundcard_mutex); - if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ - (dev & 0x0f) != SND_DEV_CTL) { - dtype = dev & 0x0f; - switch (dtype) { - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, - cmd, p); - break; - default: - ret = sound_mixer_ioctl(dev >> 4, cmd, p); - break; - } - mutex_unlock(&soundcard_mutex); - return ret; - } - - switch (dev & 0x0f) { - case SND_DEV_CTL: - if (cmd == SOUND_MIXER_GETLEVELS) - ret = get_mixer_levels(p); - else if (cmd == SOUND_MIXER_SETLEVELS) - ret = set_mixer_levels(p); - else - ret = sound_mixer_ioctl(dev >> 4, cmd, p); - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - ret = sequencer_ioctl(dev, file, cmd, p); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = audio_ioctl(dev, file, cmd, p); - break; - - case SND_DEV_MIDIN: - ret = MIDIbuf_ioctl(dev, file, cmd, p); - break; - - } - mutex_unlock(&soundcard_mutex); - return ret; -} - -static unsigned int sound_poll(struct file *file, poll_table * wait) -{ - struct inode *inode = file_inode(file); - int dev = iminor(inode); - - switch (dev & 0x0f) { - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_poll(dev, file, wait); - - case SND_DEV_MIDIN: - return MIDIbuf_poll(dev, file, wait); - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return DMAbuf_poll(file, dev >> 4, wait); - } - return 0; -} - -static int sound_mmap(struct file *file, struct vm_area_struct *vma) -{ - int dev_class; - unsigned long size; - struct dma_buffparms *dmap = NULL; - int dev = iminor(file_inode(file)); - - dev_class = dev & 0x0f; - dev >>= 4; - - if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) { - printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); - return -EINVAL; - } - mutex_lock(&soundcard_mutex); - 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(KERN_ERR "Sound: Undefined mmap() access\n"); - mutex_unlock(&soundcard_mutex); - return -EINVAL; - } - - if (dmap == NULL) { - printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); - mutex_unlock(&soundcard_mutex); - return -EIO; - } - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); - mutex_unlock(&soundcard_mutex); - return -EIO; - } - if (dmap->mapping_flags) { - printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); - mutex_unlock(&soundcard_mutex); - return -EIO; - } - if (vma->vm_pgoff != 0) { - printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); - mutex_unlock(&soundcard_mutex); - 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_pfn_range(vma, vma->vm_start, - virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - mutex_unlock(&soundcard_mutex); - return -EAGAIN; - } - - dmap->mapping_flags |= DMA_MAP_MAPPED; - - if( audio_devs[dev]->d->mmap) - audio_devs[dev]->d->mmap(dev); - - memset(dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); - mutex_unlock(&soundcard_mutex); - return 0; -} - -const struct file_operations oss_sound_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = sound_read, - .write = sound_write, - .poll = sound_poll, - .unlocked_ioctl = sound_ioctl, - .mmap = sound_mmap, - .open = sound_open, - .release = sound_release, -}; - -/* - * Create the required special subdevices - */ - -static int create_special_devices(void) -{ - int seq1,seq2; - seq1=register_sound_special(&oss_sound_fops, 1); - if(seq1==-1) - goto bad; - seq2=register_sound_special(&oss_sound_fops, 8); - if(seq2!=-1) - return 0; - unregister_sound_special(1); -bad: - return -1; -} - - -static int dmabuf; -static int dmabug; - -module_param(dmabuf, int, 0444); -module_param(dmabug, int, 0444); - -/* additional minors for compatibility */ -struct oss_minor_dev { - unsigned short minor; - unsigned int enabled; -} dev_list[] = { - { SND_DEV_DSP16 }, - { SND_DEV_AUDIO }, -}; - -static int __init oss_init(void) -{ - int err; - int i, j; - -#ifdef CONFIG_PCI - if(dmabug) - isa_dma_bridge_buggy = dmabug; -#endif - - err = create_special_devices(); - if (err) { - printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); - return err; - } - - /* Protecting the innocent */ - sound_dmap_flag = (dmabuf > 0 ? 1 : 0); - - for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - j = 0; - do { - unsigned short minor = dev_list[i].minor + j * 0x10; - if (!register_sound_special(&oss_sound_fops, minor)) - dev_list[i].enabled = (1 << j); - } while (++j < num_audiodevs); - } - - if (sound_nblocks >= MAX_MEM_BLOCKS - 1) - printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); - - return 0; -} - -static void __exit oss_cleanup(void) -{ - int i, j; - - for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - j = 0; - do { - if (dev_list[i].enabled & (1 << j)) - unregister_sound_special(dev_list[i].minor); - } while (++j < num_audiodevs); - } - - unregister_sound_special(1); - unregister_sound_special(8); - - sound_stop_timer(); - - sequencer_unload(); - - for (i = 0; i < MAX_DMA_CHANNELS; 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]); - -} - -module_init(oss_init); -module_exit(oss_cleanup); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("OSS Sound subsystem"); -MODULE_AUTHOR("Hannu Savolainen, et al."); - - -int sound_alloc_dma(int chn, char *deviceID) -{ - int err; - - if ((err = request_dma(chn, deviceID)) != 0) - return err; - - dma_alloc_map[chn] = DMA_MAP_FREE; - - return 0; -} -EXPORT_SYMBOL(sound_alloc_dma); - -int sound_open_dma(int chn, char *deviceID) -{ - if (!valid_dma(chn)) { - printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); - return 1; - } - - 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]); - return 1; - } - dma_alloc_map[chn] = DMA_MAP_BUSY; - return 0; -} -EXPORT_SYMBOL(sound_open_dma); - -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; -} -EXPORT_SYMBOL(sound_free_dma); - -void sound_close_dma(int chn) -{ - if (dma_alloc_map[chn] != DMA_MAP_BUSY) { - printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); - return; - } - dma_alloc_map[chn] = DMA_MAP_FREE; -} -EXPORT_SYMBOL(sound_close_dma); - -static void do_sequencer_timer(unsigned long dummy) -{ - sequencer_timer(0); -} - - -static DEFINE_TIMER(seq_timer, do_sequencer_timer, 0, 0); - -void request_sound_timer(int count) -{ - 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 < 1) - count = 1; - - seq_timer.expires = (count) + jiffies; - add_timer(&seq_timer); -} - -void sound_stop_timer(void) -{ - del_timer(&seq_timer); -} - -void conf_printf(char *name, struct address_info *hw_config) -{ -#ifndef CONFIG_SOUND_TRACEINIT - return; -#else - 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->dma != -1 || hw_config->dma2 != -1) - { - printk(" dma %d", hw_config->dma); - if (hw_config->dma2 != -1) - printk(",%d", hw_config->dma2); - } - printk("\n"); -#endif -} -EXPORT_SYMBOL(conf_printf); - -void conf_printf2(char *name, int base, int irq, int dma, int dma2) -{ -#ifndef CONFIG_SOUND_TRACEINIT - return; -#else - printk("<%s> at 0x%03x", name, base); - - 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"); -#endif -} -EXPORT_SYMBOL(conf_printf2); - diff --git a/sound/oss/soundvers.h b/sound/oss/soundvers.h deleted file mode 100644 index e9084d2f46a9..000000000000 --- a/sound/oss/soundvers.h +++ /dev/null @@ -1,2 +0,0 @@ -#define SOUND_VERSION_STRING "3.8s2++-971130" -#define SOUND_INTERNAL_VERSION 0x030804 diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c deleted file mode 100644 index 97899352b15f..000000000000 --- a/sound/oss/swarm_cs4297a.c +++ /dev/null @@ -1,2781 +0,0 @@ -/******************************************************************************* -* -* "swarm_cs4297a.c" -- Cirrus Logic-Crystal CS4297a linux audio driver. -* -* Copyright (C) 2001 Broadcom Corporation. -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- adapted from drivers by Thomas Sailer, -* -- but don't bug him; Problems should go to: -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -- adapted from cs4281 PCI driver for cs4297a on -* BCM1250 Synchronous Serial interface -* (Kip Walker, Broadcom Corp.) -* Copyright (C) 2004 Maciej W. Rozycki -* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) -* -* 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. -* -* Module command line parameters: -* none -* -* Supported devices: -* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible -* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible -* /dev/midi simple MIDI UART interface, no ioctl -* -* Modification History -* 08/20/00 trw - silence and no stopping DAC until release -* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop. -* 09/18/00 trw - added 16bit only record with conversion -* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous -* capture/playback rates) -* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin -* libOSSm.so) -* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal) -* 11/03/00 trw - fixed interrupt loss/stutter, added debug. -* 11/10/00 bkz - added __devinit to cs4297a_hw_init() -* 11/10/00 trw - fixed SMP and capture spinlock hang. -* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm. -* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix. -* 12/08/00 trw - added PM support. -* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 -* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident. -* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup. -* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use -* defaultorder-100 as power of 2 for the buffer size. example: -* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. -* -*******************************************************************************/ - -#include <linux/list.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched/signal.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/pci.h> -#include <linux/bitops.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/mutex.h> -#include <linux/kernel.h> - -#include <asm/byteorder.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/uaccess.h> - -#include <asm/sibyte/sb1250_regs.h> -#include <asm/sibyte/sb1250_int.h> -#include <asm/sibyte/sb1250_dma.h> -#include <asm/sibyte/sb1250_scd.h> -#include <asm/sibyte/sb1250_syncser.h> -#include <asm/sibyte/sb1250_mac.h> -#include <asm/sibyte/sb1250.h> - -#include "sleep.h" - -struct cs4297a_state; - -static DEFINE_MUTEX(swarm_cs4297a_mutex); -static void stop_dac(struct cs4297a_state *s); -static void stop_adc(struct cs4297a_state *s); -static void start_dac(struct cs4297a_state *s); -static void start_adc(struct cs4297a_state *s); -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -// --------------------------------------------------------------------- - -#define CS4297a_MAGIC 0xf00beef1 - -// buffer order determines the size of the dma buffer for the driver. -// under Linux, a smaller buffer allows more responsiveness from many of the -// applications (e.g. games). A larger buffer allows some of the apps (esound) -// to not underrun the dma buffer as easily. As default, use 32k (order=3) -// rather than 64k as some of the games work more responsively. -// log base 2( buff sz = 32k). - -// -// Turn on/off debugging compilation by commenting out "#define CSDEBUG" -// -#define CSDEBUG 0 -#if CSDEBUG -#define CSDEBUG_INTERFACE 1 -#else -#undef CSDEBUG_INTERFACE -#endif -// -// cs_debugmask areas -// -#define CS_INIT 0x00000001 // initialization and probe functions -#define CS_ERROR 0x00000002 // tmp debugging bit placeholder -#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other) -#define CS_FUNCTION 0x00000008 // enter/leave functions -#define CS_WAVE_WRITE 0x00000010 // write information for wave -#define CS_WAVE_READ 0x00000020 // read information for wave -#define CS_AC97 0x00000040 // AC97 register access -#define CS_DESCR 0x00000080 // descriptor management -#define CS_OPEN 0x00000400 // all open functions in the driver -#define CS_RELEASE 0x00000800 // all release functions in the driver -#define CS_PARMS 0x00001000 // functional and operational parameters -#define CS_IOCTL 0x00002000 // ioctl (non-mixer) -#define CS_TMP 0x10000000 // tmp debug mask bit - -// -// CSDEBUG is usual mode is set to 1, then use the -// cs_debuglevel and cs_debugmask to turn on or off debugging. -// Debug level of 1 has been defined to be kernel errors and info -// that should be printed on any released driver. -// -#if CSDEBUG -#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;} -#else -#define CS_DBGOUT(mask,level,x) -#endif - -#if CSDEBUG -static unsigned long cs_debuglevel = 4; // levels range from 1-9 -static unsigned long cs_debugmask = CS_INIT /*| CS_IOCTL*/; -module_param(cs_debuglevel, int, 0); -module_param(cs_debugmask, int, 0); -#endif -#define CS_TRUE 1 -#define CS_FALSE 0 - -#define CS_TYPE_ADC 0 -#define CS_TYPE_DAC 1 - -#define SER_BASE (A_SER_BASE_1 + KSEG1) -#define SS_CSR(t) (SER_BASE+t) -#define SS_TXTBL(t) (SER_BASE+R_SER_TX_TABLE_BASE+(t*8)) -#define SS_RXTBL(t) (SER_BASE+R_SER_RX_TABLE_BASE+(t*8)) - -#define FRAME_BYTES 32 -#define FRAME_SAMPLE_BYTES 4 - -/* Should this be variable? */ -#define SAMPLE_BUF_SIZE (16*1024) -#define SAMPLE_FRAME_COUNT (SAMPLE_BUF_SIZE / FRAME_SAMPLE_BYTES) -/* The driver can explode/shrink the frames to/from a smaller sample - buffer */ -#define DMA_BLOAT_FACTOR 1 -#define DMA_DESCR (SAMPLE_FRAME_COUNT / DMA_BLOAT_FACTOR) -#define DMA_BUF_SIZE (DMA_DESCR * FRAME_BYTES) - -/* Use the maxmium count (255 == 5.1 ms between interrupts) */ -#define DMA_INT_CNT ((1 << S_DMA_INT_PKTCNT) - 1) - -/* Figure this out: how many TX DMAs ahead to schedule a reg access */ -#define REG_LATENCY 150 - -#define FRAME_TX_US 20 - -#define SERDMA_NEXTBUF(d,f) (((d)->f+1) % (d)->ringsz) - -static const char invalid_magic[] = - KERN_CRIT "cs4297a: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != CS4297a_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* AC97 registers */ -#define AC97_MASTER_VOL_STEREO 0x0002 /* Line Out */ -#define AC97_PCBEEP_VOL 0x000a /* none */ -#define AC97_PHONE_VOL 0x000c /* TAD Input (mono) */ -#define AC97_MIC_VOL 0x000e /* MIC Input (mono) */ -#define AC97_LINEIN_VOL 0x0010 /* Line Input (stereo) */ -#define AC97_CD_VOL 0x0012 /* CD Input (stereo) */ -#define AC97_AUX_VOL 0x0016 /* Aux Input (stereo) */ -#define AC97_PCMOUT_VOL 0x0018 /* Wave Output (stereo) */ -#define AC97_RECORD_SELECT 0x001a /* */ -#define AC97_RECORD_GAIN 0x001c -#define AC97_GENERAL_PURPOSE 0x0020 -#define AC97_3D_CONTROL 0x0022 -#define AC97_POWER_CONTROL 0x0026 -#define AC97_VENDOR_ID1 0x007c - -struct list_head cs4297a_devs = { &cs4297a_devs, &cs4297a_devs }; - -typedef struct serdma_descr_s { - u64 descr_a; - u64 descr_b; -} serdma_descr_t; - -typedef unsigned long paddr_t; - -typedef struct serdma_s { - unsigned ringsz; - serdma_descr_t *descrtab; - serdma_descr_t *descrtab_end; - paddr_t descrtab_phys; - - serdma_descr_t *descr_add; - serdma_descr_t *descr_rem; - - u64 *dma_buf; // buffer for DMA contents (frames) - paddr_t dma_buf_phys; - u16 *sample_buf; // tmp buffer for sample conversions - u16 *sb_swptr; - u16 *sb_hwptr; - u16 *sb_end; - - dma_addr_t dmaaddr; -// unsigned buforder; // Log base 2 of 'dma_buf' size in bytes.. - unsigned numfrag; // # of 'fragments' in the buffer. - unsigned fragshift; // Log base 2 of fragment size. - unsigned hwptr, swptr; - unsigned total_bytes; // # bytes process since open. - unsigned blocks; // last returned blocks value GETOPTR - unsigned wakeup; // interrupt occurred on block - int count; - unsigned underrun; // underrun flag - unsigned error; // over/underrun - wait_queue_head_t wait; - wait_queue_head_t reg_wait; - // redundant, but makes calculations easier - unsigned fragsize; // 2**fragshift.. - unsigned sbufsz; // 2**buforder. - unsigned fragsamples; - // OSS stuff - unsigned mapped:1; // Buffer mapped in cs4297a_mmap()? - unsigned ready:1; // prog_dmabuf_dac()/adc() successful? - unsigned endcleared:1; - unsigned type:1; // adc or dac buffer (CS_TYPE_XXX) - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; -} serdma_t; - -struct cs4297a_state { - // magic - unsigned int magic; - - struct list_head list; - - // soundcore stuff - int dev_audio; - int dev_mixer; - - // hardware resources - unsigned int irq; - - struct { - unsigned int rx_ovrrn; /* FIFO */ - unsigned int rx_overflow; /* staging buffer */ - unsigned int tx_underrun; - unsigned int rx_bad; - unsigned int rx_good; - } stats; - - // mixer registers - struct { - unsigned short vol[10]; - unsigned int recsrc; - unsigned int modcnt; - unsigned short micpreamp; - } mix; - - // wave stuff - struct properties { - unsigned fmt; - unsigned fmt_original; // original requested format - unsigned channels; - unsigned rate; - } prop_dac, prop_adc; - unsigned conversion:1; // conversion from 16 to 8 bit in progress - unsigned ena; - spinlock_t lock; - struct mutex open_mutex; - struct mutex open_sem_adc; - struct mutex open_sem_dac; - fmode_t open_mode; - wait_queue_head_t open_wait; - wait_queue_head_t open_wait_adc; - wait_queue_head_t open_wait_dac; - - dma_addr_t dmaaddr_sample_buf; - unsigned buforder_sample_buf; // Log base 2 of 'dma_buf' size in bytes.. - - serdma_t dma_dac, dma_adc; - - volatile u16 read_value; - volatile u16 read_reg; - volatile u64 reg_request; -}; - -#if 1 -#define prog_codec(a,b) -#define dealloc_dmabuf(a,b); -#endif - -static int prog_dmabuf_adc(struct cs4297a_state *s) -{ - s->dma_adc.ready = 1; - return 0; -} - - -static int prog_dmabuf_dac(struct cs4297a_state *s) -{ - s->dma_dac.ready = 1; - return 0; -} - -static void clear_advance(void *buf, unsigned bsize, unsigned bptr, - unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *) buf) + bptr, c, x); - bptr = 0; - len -= x; - } - CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO - "cs4297a: clear_advance(): memset %d at 0x%.8x for %d size \n", - (unsigned)c, (unsigned)((char *) buf) + bptr, len)); - memset(((char *) buf) + bptr, c, len); -} - -#if CSDEBUG - -// DEBUG ROUTINES - -#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int) -#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) -#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) -#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) - -static void cs_printioctl(unsigned int x) -{ - unsigned int i; - unsigned char vidx; - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - switch (x) { - case SOUND_MIXER_CS_GETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_GETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGLEVEL:\n")); - break; - case SOUND_MIXER_CS_SETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_SETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGLEVEL:\n")); - break; - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n")); - break; - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n")); - break; - case SNDCTL_DSP_SETDUPLEX: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n")); - break; - case SNDCTL_DSP_GETCAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n")); - break; - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n")); - break; - case SNDCTL_DSP_SPEED: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n")); - break; - case SNDCTL_DSP_STEREO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n")); - break; - case SNDCTL_DSP_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n")); - break; - case SNDCTL_DSP_GETFMTS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n")); - break; - case SNDCTL_DSP_SETFMT: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n")); - break; - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n")); - break; - case SNDCTL_DSP_GETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n")); - break; - case SNDCTL_DSP_SETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n")); - break; - case SNDCTL_DSP_GETOSPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n")); - break; - case SNDCTL_DSP_GETISPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n")); - break; - case SNDCTL_DSP_NONBLOCK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n")); - break; - case SNDCTL_DSP_GETODELAY: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n")); - break; - case SNDCTL_DSP_GETIPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n")); - break; - case SNDCTL_DSP_GETOPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n")); - break; - case SNDCTL_DSP_GETBLKSIZE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n")); - break; - case SNDCTL_DSP_SETFRAGMENT: - CS_DBGOUT(CS_IOCTL, 4, - printk("SNDCTL_DSP_SETFRAGMENT:\n")); - break; - case SNDCTL_DSP_SUBDIVIDE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n")); - break; - case SOUND_PCM_READ_RATE: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n")); - break; - case SOUND_PCM_READ_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_READ_CHANNELS:\n")); - break; - case SOUND_PCM_READ_BITS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n")); - break; - case SOUND_PCM_WRITE_FILTER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_WRITE_FILTER:\n")); - break; - case SNDCTL_DSP_SETSYNCRO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n")); - break; - case SOUND_PCM_READ_FILTER: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n")); - break; - case SOUND_MIXER_PRIVATE1: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n")); - break; - case SOUND_MIXER_PRIVATE2: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n")); - break; - case SOUND_MIXER_PRIVATE3: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n")); - break; - case SOUND_MIXER_PRIVATE4: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n")); - break; - case SOUND_MIXER_PRIVATE5: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n")); - break; - case SOUND_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n")); - break; - case SOUND_OLD_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n")); - break; - - default: - switch (_IOC_NR(x)) { - case SOUND_MIXER_VOLUME: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_VOLUME:\n")); - break; - case SOUND_MIXER_SPEAKER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SPEAKER:\n")); - break; - case SOUND_MIXER_RECLEV: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECLEV:\n")); - break; - case SOUND_MIXER_MIC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_MIC:\n")); - break; - case SOUND_MIXER_SYNTH: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SYNTH:\n")); - break; - case SOUND_MIXER_RECSRC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECSRC:\n")); - break; - case SOUND_MIXER_DEVMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_DEVMASK:\n")); - break; - case SOUND_MIXER_RECMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECMASK:\n")); - break; - case SOUND_MIXER_STEREODEVS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_STEREODEVS:\n")); - break; - case SOUND_MIXER_CAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n")); - break; - default: - i = _IOC_NR(x); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) { - CS_DBGOUT(CS_IOCTL, 4, printk - ("UNKNOWN IOCTL: 0x%.8x NR=%d\n", - x, i)); - } else { - CS_DBGOUT(CS_IOCTL, 4, printk - ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n", - x, i)); - } - break; - } - } -} -#endif - - -static int ser_init(struct cs4297a_state *s) -{ - int i; - - CS_DBGOUT(CS_INIT, 2, - printk(KERN_INFO "cs4297a: Setting up serial parameters\n")); - - __raw_writeq(M_SYNCSER_CMD_RX_RESET | M_SYNCSER_CMD_TX_RESET, SS_CSR(R_SER_CMD)); - - __raw_writeq(M_SYNCSER_MSB_FIRST, SS_CSR(R_SER_MODE)); - __raw_writeq(32, SS_CSR(R_SER_MINFRM_SZ)); - __raw_writeq(32, SS_CSR(R_SER_MAXFRM_SZ)); - - __raw_writeq(1, SS_CSR(R_SER_TX_RD_THRSH)); - __raw_writeq(4, SS_CSR(R_SER_TX_WR_THRSH)); - __raw_writeq(8, SS_CSR(R_SER_RX_RD_THRSH)); - - /* This looks good from experimentation */ - __raw_writeq((M_SYNCSER_TXSYNC_INT | V_SYNCSER_TXSYNC_DLY(0) | M_SYNCSER_TXCLK_EXT | - M_SYNCSER_RXSYNC_INT | V_SYNCSER_RXSYNC_DLY(1) | M_SYNCSER_RXCLK_EXT | M_SYNCSER_RXSYNC_EDGE), - SS_CSR(R_SER_LINE_MODE)); - - /* This looks good from experimentation */ - __raw_writeq(V_SYNCSER_SEQ_COUNT(14) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE, - SS_TXTBL(0)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(15) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_TXTBL(1)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(13) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_TXTBL(2)); - __raw_writeq(V_SYNCSER_SEQ_COUNT( 0) | M_SYNCSER_SEQ_ENABLE | - M_SYNCSER_SEQ_STROBE | M_SYNCSER_SEQ_LAST, SS_TXTBL(3)); - - __raw_writeq(V_SYNCSER_SEQ_COUNT(14) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE, - SS_RXTBL(0)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(15) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_RXTBL(1)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(13) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_RXTBL(2)); - __raw_writeq(V_SYNCSER_SEQ_COUNT( 0) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE | - M_SYNCSER_SEQ_LAST, SS_RXTBL(3)); - - for (i=4; i<16; i++) { - /* Just in case... */ - __raw_writeq(M_SYNCSER_SEQ_LAST, SS_TXTBL(i)); - __raw_writeq(M_SYNCSER_SEQ_LAST, SS_RXTBL(i)); - } - - return 0; -} - -static int init_serdma(serdma_t *dma) -{ - CS_DBGOUT(CS_INIT, 2, - printk(KERN_ERR "cs4297a: desc - %d sbufsize - %d dbufsize - %d\n", - DMA_DESCR, SAMPLE_BUF_SIZE, DMA_BUF_SIZE)); - - /* Descriptors */ - dma->ringsz = DMA_DESCR; - dma->descrtab = kzalloc(dma->ringsz * sizeof(serdma_descr_t), GFP_KERNEL); - if (!dma->descrtab) { - printk(KERN_ERR "cs4297a: kzalloc descrtab failed\n"); - return -1; - } - dma->descrtab_end = dma->descrtab + dma->ringsz; - /* XXX bloddy mess, use proper DMA API here ... */ - dma->descrtab_phys = CPHYSADDR((long)dma->descrtab); - dma->descr_add = dma->descr_rem = dma->descrtab; - - /* Frame buffer area */ - dma->dma_buf = kzalloc(DMA_BUF_SIZE, GFP_KERNEL); - if (!dma->dma_buf) { - printk(KERN_ERR "cs4297a: kzalloc dma_buf failed\n"); - kfree(dma->descrtab); - return -1; - } - dma->dma_buf_phys = CPHYSADDR((long)dma->dma_buf); - - /* Samples buffer area */ - dma->sbufsz = SAMPLE_BUF_SIZE; - dma->sample_buf = kmalloc(dma->sbufsz, GFP_KERNEL); - if (!dma->sample_buf) { - printk(KERN_ERR "cs4297a: kmalloc sample_buf failed\n"); - kfree(dma->descrtab); - kfree(dma->dma_buf); - return -1; - } - dma->sb_swptr = dma->sb_hwptr = dma->sample_buf; - dma->sb_end = (u16 *)((void *)dma->sample_buf + dma->sbufsz); - dma->fragsize = dma->sbufsz >> 1; - - CS_DBGOUT(CS_INIT, 4, - printk(KERN_ERR "cs4297a: descrtab - %08x dma_buf - %x sample_buf - %x\n", - (int)dma->descrtab, (int)dma->dma_buf, - (int)dma->sample_buf)); - - return 0; -} - -static int dma_init(struct cs4297a_state *s) -{ - int i; - - CS_DBGOUT(CS_INIT, 2, - printk(KERN_INFO "cs4297a: Setting up DMA\n")); - - if (init_serdma(&s->dma_adc) || - init_serdma(&s->dma_dac)) - return -1; - - if (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_RX))|| - __raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) { - panic("DMA state corrupted?!"); - } - - /* Initialize now - the descr/buffer pairings will never - change... */ - for (i=0; i<DMA_DESCR; i++) { - s->dma_dac.descrtab[i].descr_a = M_DMA_SERRX_SOP | V_DMA_DSCRA_A_SIZE(1) | - (s->dma_dac.dma_buf_phys + i*FRAME_BYTES); - s->dma_dac.descrtab[i].descr_b = V_DMA_DSCRB_PKT_SIZE(FRAME_BYTES); - s->dma_adc.descrtab[i].descr_a = V_DMA_DSCRA_A_SIZE(1) | - (s->dma_adc.dma_buf_phys + i*FRAME_BYTES); - s->dma_adc.descrtab[i].descr_b = 0; - } - - __raw_writeq((M_DMA_EOP_INT_EN | V_DMA_INT_PKTCNT(DMA_INT_CNT) | - V_DMA_RINGSZ(DMA_DESCR) | M_DMA_TDX_EN), - SS_CSR(R_SER_DMA_CONFIG0_RX)); - __raw_writeq(M_DMA_L2CA, SS_CSR(R_SER_DMA_CONFIG1_RX)); - __raw_writeq(s->dma_adc.descrtab_phys, SS_CSR(R_SER_DMA_DSCR_BASE_RX)); - - __raw_writeq(V_DMA_RINGSZ(DMA_DESCR), SS_CSR(R_SER_DMA_CONFIG0_TX)); - __raw_writeq(M_DMA_L2CA | M_DMA_NO_DSCR_UPDT, SS_CSR(R_SER_DMA_CONFIG1_TX)); - __raw_writeq(s->dma_dac.descrtab_phys, SS_CSR(R_SER_DMA_DSCR_BASE_TX)); - - /* Prep the receive DMA descriptor ring */ - __raw_writeq(DMA_DESCR, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - - __raw_writeq(M_SYNCSER_DMA_RX_EN | M_SYNCSER_DMA_TX_EN, SS_CSR(R_SER_DMA_ENABLE)); - - __raw_writeq((M_SYNCSER_RX_SYNC_ERR | M_SYNCSER_RX_OVERRUN | M_SYNCSER_RX_EOP_COUNT), - SS_CSR(R_SER_INT_MASK)); - - /* Enable the rx/tx; let the codec warm up to the sync and - start sending good frames before the receive FIFO is - enabled */ - __raw_writeq(M_SYNCSER_CMD_TX_EN, SS_CSR(R_SER_CMD)); - udelay(1000); - __raw_writeq(M_SYNCSER_CMD_RX_EN | M_SYNCSER_CMD_TX_EN, SS_CSR(R_SER_CMD)); - - /* XXXKW is this magic? (the "1" part) */ - while ((__raw_readq(SS_CSR(R_SER_STATUS)) & 0xf1) != 1) - ; - - CS_DBGOUT(CS_INIT, 4, - printk(KERN_INFO "cs4297a: status: %08x\n", - (unsigned int)(__raw_readq(SS_CSR(R_SER_STATUS)) & 0xffffffff))); - - return 0; -} - -static int serdma_reg_access(struct cs4297a_state *s, u64 data) -{ - serdma_t *d = &s->dma_dac; - u64 *data_p; - unsigned swptr; - unsigned long flags; - serdma_descr_t *descr; - - if (s->reg_request) { - printk(KERN_ERR "cs4297a: attempt to issue multiple reg_access\n"); - return -1; - } - - if (s->ena & FMODE_WRITE) { - /* Since a writer has the DSP open, we have to mux the - request in */ - s->reg_request = data; - oss_broken_sleep_on(&s->dma_dac.reg_wait, MAX_SCHEDULE_TIMEOUT); - /* XXXKW how can I deal with the starvation case where - the opener isn't writing? */ - } else { - /* Be safe when changing ring pointers */ - spin_lock_irqsave(&s->lock, flags); - if (d->hwptr != d->swptr) { - printk(KERN_ERR "cs4297a: reg access found bookkeeping error (hw/sw = %d/%d\n", - d->hwptr, d->swptr); - spin_unlock_irqrestore(&s->lock, flags); - return -1; - } - swptr = d->swptr; - d->hwptr = d->swptr = (d->swptr + 1) % d->ringsz; - spin_unlock_irqrestore(&s->lock, flags); - - descr = &d->descrtab[swptr]; - data_p = &d->dma_buf[swptr * 4]; - *data_p = cpu_to_be64(data); - __raw_writeq(1, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); - CS_DBGOUT(CS_DESCR, 4, - printk(KERN_INFO "cs4297a: add_tx %p (%x -> %x)\n", - data_p, swptr, d->hwptr)); - } - - CS_DBGOUT(CS_FUNCTION, 6, - printk(KERN_INFO "cs4297a: serdma_reg_access()-\n")); - - return 0; -} - -//**************************************************************************** -// "cs4297a_read_ac97" -- Reads an AC97 register -//**************************************************************************** -static int cs4297a_read_ac97(struct cs4297a_state *s, u32 offset, - u32 * value) -{ - CS_DBGOUT(CS_AC97, 1, - printk(KERN_INFO "cs4297a: read reg %2x\n", offset)); - if (serdma_reg_access(s, (0xCLL << 60) | (1LL << 47) | ((u64)(offset & 0x7F) << 40))) - return -1; - - oss_broken_sleep_on(&s->dma_adc.reg_wait, MAX_SCHEDULE_TIMEOUT); - *value = s->read_value; - CS_DBGOUT(CS_AC97, 2, - printk(KERN_INFO "cs4297a: rdr reg %x -> %x\n", s->read_reg, s->read_value)); - - return 0; -} - - -//**************************************************************************** -// "cs4297a_write_ac97()"-- writes an AC97 register -//**************************************************************************** -static int cs4297a_write_ac97(struct cs4297a_state *s, u32 offset, - u32 value) -{ - CS_DBGOUT(CS_AC97, 1, - printk(KERN_INFO "cs4297a: write reg %2x -> %04x\n", offset, value)); - return (serdma_reg_access(s, (0xELL << 60) | ((u64)(offset & 0x7F) << 40) | ((value & 0xffff) << 12))); -} - -static void stop_dac(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4297a: stop_dac():\n")); - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_WRITE; -#if 0 - /* XXXKW what do I really want here? My theory for now is - that I just flip the "ena" bit, and the interrupt handler - will stop processing the xmit channel */ - __raw_writeq((s->ena & FMODE_READ) ? M_SYNCSER_DMA_RX_EN : 0, - SS_CSR(R_SER_DMA_ENABLE)); -#endif - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void start_dac(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: start_dac()+\n")); - spin_lock_irqsave(&s->lock, flags); - if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || - (s->dma_dac.count > 0 - && s->dma_dac.ready))) { - s->ena |= FMODE_WRITE; - /* XXXKW what do I really want here? My theory for - now is that I just flip the "ena" bit, and the - interrupt handler will start processing the xmit - channel */ - - CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO - "cs4297a: start_dac(): start dma\n")); - - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4297a: start_dac()-\n")); -} - - -static void stop_adc(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4297a: stop_adc()+\n")); - - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_READ; - - if (s->conversion == 1) { - s->conversion = 0; - s->prop_adc.fmt = s->prop_adc.fmt_original; - } - /* Nothing to do really, I need to keep the DMA going - XXXKW when do I get here, and is there more I should do? */ - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4297a: stop_adc()-\n")); -} - - -static void start_adc(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: start_adc()+\n")); - - if (!(s->ena & FMODE_READ) && - (s->dma_adc.mapped || s->dma_adc.count <= - (signed) (s->dma_adc.sbufsz - 2 * s->dma_adc.fragsize)) - && s->dma_adc.ready) { - if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { - // - // now only use 16 bit capture, due to truncation issue - // in the chip, noticeable distortion occurs. - // allocate buffer and then convert from 16 bit to - // 8 bit for the user buffer. - // - s->prop_adc.fmt_original = s->prop_adc.fmt; - if (s->prop_adc.fmt & AFMT_S8) { - s->prop_adc.fmt &= ~AFMT_S8; - s->prop_adc.fmt |= AFMT_S16_LE; - } - if (s->prop_adc.fmt & AFMT_U8) { - s->prop_adc.fmt &= ~AFMT_U8; - s->prop_adc.fmt |= AFMT_U16_LE; - } - // - // prog_dmabuf_adc performs a stop_adc() but that is - // ok since we really haven't started the DMA yet. - // - prog_codec(s, CS_TYPE_ADC); - - prog_dmabuf_adc(s); - s->conversion = 1; - } - spin_lock_irqsave(&s->lock, flags); - s->ena |= FMODE_READ; - /* Nothing to do really, I am probably already - DMAing... XXXKW when do I get here, and is there - more I should do? */ - spin_unlock_irqrestore(&s->lock, flags); - - CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO - "cs4297a: start_adc(): start adc\n")); - } - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: start_adc()-\n")); - -} - - -// call with spinlock held! -static void cs4297a_update_ptr(struct cs4297a_state *s, int intflag) -{ - int good_diff, diff, diff2; - u64 *data_p, data; - u32 *s_ptr; - unsigned hwptr; - u32 status; - serdma_t *d; - serdma_descr_t *descr; - - // update ADC pointer - status = intflag ? __raw_readq(SS_CSR(R_SER_STATUS)) : 0; - - if ((s->ena & FMODE_READ) || (status & (M_SYNCSER_RX_EOP_COUNT))) { - d = &s->dma_adc; - hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - - d->descrtab_phys) / sizeof(serdma_descr_t)); - - if (s->ena & FMODE_READ) { - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: upd_rcv sw->hw->hw %x/%x/%x (int-%d)n", - d->swptr, d->hwptr, hwptr, intflag)); - /* Number of DMA buffers available for software: */ - diff2 = diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; - d->hwptr = hwptr; - good_diff = 0; - s_ptr = (u32 *)&(d->dma_buf[d->swptr*4]); - descr = &d->descrtab[d->swptr]; - while (diff2--) { - u64 data = be64_to_cpu(*(u64 *)s_ptr); - u64 descr_a; - u16 left, right; - descr_a = descr->descr_a; - descr->descr_a &= ~M_DMA_SERRX_SOP; - if ((descr_a & M_DMA_DSCRA_A_ADDR) != CPHYSADDR((long)s_ptr)) { - printk(KERN_ERR "cs4297a: RX Bad address (read)\n"); - } - if (((data & 0x9800000000000000) != 0x9800000000000000) || - (!(descr_a & M_DMA_SERRX_SOP)) || - (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { - s->stats.rx_bad++; - printk(KERN_DEBUG "cs4297a: RX Bad attributes (read)\n"); - continue; - } - s->stats.rx_good++; - if ((data >> 61) == 7) { - s->read_value = (data >> 12) & 0xffff; - s->read_reg = (data >> 40) & 0x7f; - wake_up(&d->reg_wait); - } - if (d->count && (d->sb_hwptr == d->sb_swptr)) { - s->stats.rx_overflow++; - printk(KERN_DEBUG "cs4297a: RX overflow\n"); - continue; - } - good_diff++; - left = ((be32_to_cpu(s_ptr[1]) & 0xff) << 8) | - ((be32_to_cpu(s_ptr[2]) >> 24) & 0xff); - right = (be32_to_cpu(s_ptr[2]) >> 4) & 0xffff; - *d->sb_hwptr++ = cpu_to_be16(left); - *d->sb_hwptr++ = cpu_to_be16(right); - if (d->sb_hwptr == d->sb_end) - d->sb_hwptr = d->sample_buf; - descr++; - if (descr == d->descrtab_end) { - descr = d->descrtab; - s_ptr = (u32 *)s->dma_adc.dma_buf; - } else { - s_ptr += 8; - } - } - d->total_bytes += good_diff * FRAME_SAMPLE_BYTES; - d->count += good_diff * FRAME_SAMPLE_BYTES; - if (d->count > d->sbufsz) { - printk(KERN_ERR "cs4297a: bogus receive overflow!!\n"); - } - d->swptr = (d->swptr + diff) % d->ringsz; - __raw_writeq(diff, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - if (d->mapped) { - if (d->count >= (signed) d->fragsize) - wake_up(&d->wait); - } else { - if (d->count > 0) { - CS_DBGOUT(CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4297a: update count -> %d\n", d->count)); - wake_up(&d->wait); - } - } - } else { - /* Receive is going even if no one is - listening (for register accesses and to - avoid FIFO overrun) */ - diff2 = diff = (hwptr + d->ringsz - d->hwptr) % d->ringsz; - if (!diff) { - printk(KERN_ERR "cs4297a: RX full or empty?\n"); - } - - descr = &d->descrtab[d->swptr]; - data_p = &d->dma_buf[d->swptr*4]; - - /* Force this to happen at least once; I got - here because of an interrupt, so there must - be a buffer to process. */ - do { - data = be64_to_cpu(*data_p); - if ((descr->descr_a & M_DMA_DSCRA_A_ADDR) != CPHYSADDR((long)data_p)) { - printk(KERN_ERR "cs4297a: RX Bad address %d (%llx %lx)\n", d->swptr, - (long long)(descr->descr_a & M_DMA_DSCRA_A_ADDR), - (long)CPHYSADDR((long)data_p)); - } - if (!(data & (1LL << 63)) || - !(descr->descr_a & M_DMA_SERRX_SOP) || - (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { - s->stats.rx_bad++; - printk(KERN_DEBUG "cs4297a: RX Bad attributes\n"); - } else { - s->stats.rx_good++; - if ((data >> 61) == 7) { - s->read_value = (data >> 12) & 0xffff; - s->read_reg = (data >> 40) & 0x7f; - wake_up(&d->reg_wait); - } - } - descr->descr_a &= ~M_DMA_SERRX_SOP; - descr++; - d->swptr++; - data_p += 4; - if (descr == d->descrtab_end) { - descr = d->descrtab; - d->swptr = 0; - data_p = d->dma_buf; - } - __raw_writeq(1, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - } while (--diff); - d->hwptr = hwptr; - - CS_DBGOUT(CS_DESCR, 6, - printk(KERN_INFO "cs4297a: hw/sw %x/%x\n", d->hwptr, d->swptr)); - } - - CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", - (unsigned)s, d->hwptr, - d->total_bytes, d->count)); - } - - /* XXXKW worry about s->reg_request -- there is a starvation - case if s->ena has FMODE_WRITE on, but the client isn't - doing writes */ - - // update DAC pointer - // - // check for end of buffer, means that we are going to wait for another interrupt - // to allow silence to fill the fifos on the part, to keep pops down to a minimum. - // - if (s->ena & FMODE_WRITE) { - serdma_t *d = &s->dma_dac; - hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - d->descrtab_phys) / sizeof(serdma_descr_t)); - diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; - CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): hw/hw/sw %x/%x/%x diff %d count %d\n", - d->hwptr, hwptr, d->swptr, diff, d->count)); - d->hwptr = hwptr; - /* XXXKW stereo? conversion? Just assume 2 16-bit samples for now */ - d->total_bytes += diff * FRAME_SAMPLE_BYTES; - if (d->mapped) { - d->count += diff * FRAME_SAMPLE_BYTES; - if (d->count >= d->fragsize) { - d->wakeup = 1; - wake_up(&d->wait); - if (d->count > d->sbufsz) - d->count &= d->sbufsz - 1; - } - } else { - d->count -= diff * FRAME_SAMPLE_BYTES; - if (d->count <= 0) { - // - // fill with silence, and do not shut down the DAC. - // Continue to play silence until the _release. - // - CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): memset %d at 0x%.8x for %d size \n", - (unsigned)(s->prop_dac.fmt & - (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, - (unsigned)d->dma_buf, - d->ringsz)); - memset(d->dma_buf, 0, d->ringsz * FRAME_BYTES); - if (d->count < 0) { - d->underrun = 1; - s->stats.tx_underrun++; - d->count = 0; - CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): underrun\n")); - } - } else if (d->count <= - (signed) d->fragsize - && !d->endcleared) { - /* XXXKW what is this for? */ - clear_advance(d->dma_buf, - d->sbufsz, - d->swptr, - d->fragsize, - 0); - d->endcleared = 1; - } - if ( (d->count <= (signed) d->sbufsz/2) || intflag) - { - CS_DBGOUT(CS_WAVE_WRITE, 4, - printk(KERN_INFO - "cs4297a: update count -> %d\n", d->count)); - wake_up(&d->wait); - } - } - CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", - (unsigned) s, d->hwptr, - d->total_bytes, d->count)); - } -} - -static int mixer_ioctl(struct cs4297a_state *s, unsigned int cmd, - unsigned long arg) -{ - // Index to mixer_src[] is value of AC97 Input Mux Select Reg. - // Value of array member is recording source Device ID Mask. - static const unsigned int mixer_src[8] = { - SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1, - SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0 - }; - - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - static const unsigned mixreg[] = { - AC97_PCMOUT_VOL, - AC97_AUX_VOL, - AC97_CD_VOL, - AC97_LINEIN_VOL - }; - unsigned char l, r, rl, rr, vidx; - unsigned char attentbl[11] = - { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 }; - unsigned temp1; - int i, val; - - VALIDATE_STATE(s); - CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO - "cs4297a: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n", - (unsigned) s, cmd)); -#if CSDEBUG - cs_printioctl(cmd); -#endif -#if CSDEBUG_INTERFACE - - if ((cmd == SOUND_MIXER_CS_GETDBGMASK) || - (cmd == SOUND_MIXER_CS_SETDBGMASK) || - (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || - (cmd == SOUND_MIXER_CS_SETDBGLEVEL)) - { - switch (cmd) { - - case SOUND_MIXER_CS_GETDBGMASK: - return put_user(cs_debugmask, - (unsigned long *) arg); - - case SOUND_MIXER_CS_GETDBGLEVEL: - return put_user(cs_debuglevel, - (unsigned long *) arg); - - case SOUND_MIXER_CS_SETDBGMASK: - if (get_user(val, (unsigned long *) arg)) - return -EFAULT; - cs_debugmask = val; - return 0; - - case SOUND_MIXER_CS_SETDBGLEVEL: - if (get_user(val, (unsigned long *) arg)) - return -EFAULT; - cs_debuglevel = val; - return 0; - default: - CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4297a: mixer_ioctl(): ERROR unknown debug cmd\n")); - return 0; - } - } -#endif - - if (cmd == SOUND_MIXER_PRIVATE1) { - return -EINVAL; - } - if (cmd == SOUND_MIXER_PRIVATE2) { - // enable/disable/query spatializer - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != -1) { - temp1 = (val & 0x3f) >> 2; - cs4297a_write_ac97(s, AC97_3D_CONTROL, temp1); - cs4297a_read_ac97(s, AC97_GENERAL_PURPOSE, - &temp1); - cs4297a_write_ac97(s, AC97_GENERAL_PURPOSE, - temp1 | 0x2000); - } - cs4297a_read_ac97(s, AC97_3D_CONTROL, &temp1); - return put_user((temp1 << 2) | 3, (int *) arg); - } - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "CS4297a", sizeof(info.id)); - strlcpy(info.name, "Crystal CS4297a", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user((void *) arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "CS4297a", sizeof(info.id)); - strlcpy(info.name, "Crystal CS4297a", sizeof(info.name)); - if (copy_to_user((void *) arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *) arg); - - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - // If ioctl has only the SIOC_READ bit(bit 31) - // on, process the only-read commands. - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source - cs4297a_read_ac97(s, AC97_RECORD_SELECT, - &temp1); - return put_user(mixer_src[temp1 & 7], (int *) arg); - - case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device - return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, - (int *) arg); - - case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source - return put_user(SOUND_MASK_LINE | SOUND_MASK_VOLUME, - (int *) arg); - - case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo - return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, - (int *) arg); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) - return -EINVAL; - return put_user(s->mix.vol[vidx - 1], (int *) arg); - } - } - // If ioctl doesn't have both the SIOC_READ and - // the SIOC_WRITE bit set, return invalid. - if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE)) - return -EINVAL; - - // Increment the count of volume writes. - s->mix.modcnt++; - - // Isolate the command; it must be a write. - switch (_IOC_NR(cmd)) { - - case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source - if (get_user(val, (int *) arg)) - return -EFAULT; - i = hweight32(val); // i = # bits on in val. - if (i != 1) // One & only 1 bit must be on. - return 0; - for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) { - if (val == mixer_src[i]) { - temp1 = (i << 8) | i; - cs4297a_write_ac97(s, - AC97_RECORD_SELECT, - temp1); - return 0; - } - } - return 0; - - case SOUND_MIXER_VOLUME: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; // Max soundcard.h vol is 100. - if (l < 6) { - rl = 63; - l = 0; - } else - rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten. - - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; // Max right volume is 100, too - if (r < 6) { - rr = 63; - r = 0; - } else - rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation. - - if ((rl > 60) && (rr > 60)) // If both l & r are 'low', - temp1 = 0x8000; // turn on the mute bit. - else - temp1 = 0; - - temp1 |= (rl << 8) | rr; - - cs4297a_write_ac97(s, AC97_MASTER_VOL_STEREO, temp1); - cs4297a_write_ac97(s, AC97_PHONE_VOL, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[8] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[8] = val; -#endif - return put_user(s->mix.vol[8], (int *) arg); - - case SOUND_MIXER_SPEAKER: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 3) { - rl = 0; - l = 0; - } else { - rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15. - l = (rl * 13 + 5) / 2; - } - - if (rl < 3) { - temp1 = 0x8000; - rl = 0; - } else - temp1 = 0; - rl = 15 - rl; // Convert volume to attenuation. - temp1 |= rl << 1; - cs4297a_write_ac97(s, AC97_PCBEEP_VOL, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[6] = l << 8; -#else - s->mix.vol[6] = val; -#endif - return put_user(s->mix.vol[6], (int *) arg); - - case SOUND_MIXER_RECLEV: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15. - rr = (r * 2 - 5) / 13; - if (rl < 3 && rr < 3) - temp1 = 0x8000; - else - temp1 = 0; - - temp1 = temp1 | (rl << 8) | rr; - cs4297a_write_ac97(s, AC97_RECORD_GAIN, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[7] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[7] = val; -#endif - return put_user(s->mix.vol[7], (int *) arg); - - case SOUND_MIXER_MIC: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 1) { - l = 0; - rl = 0; - } else { - rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31. - l = (rl * 16 + 4) / 5; - } - cs4297a_read_ac97(s, AC97_MIC_VOL, &temp1); - temp1 &= 0x40; // Isolate 20db gain bit. - if (rl < 3) { - temp1 |= 0x8000; - rl = 0; - } - rl = 31 - rl; // Convert volume to attenuation. - temp1 |= rl; - cs4297a_write_ac97(s, AC97_MIC_VOL, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[5] = val << 8; -#else - s->mix.vol[5] = val; -#endif - return put_user(s->mix.vol[5], (int *) arg); - - - case SOUND_MIXER_SYNTH: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (get_user(val, (int *) arg)) - return -EFAULT; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63. - rr = (r * 2 - 11) / 3; - if (rl < 3) // If l is low, turn on - temp1 = 0x0080; // the mute bit. - else - temp1 = 0; - - rl = 63 - rl; // Convert vol to attenuation. -// writel(temp1 | rl, s->pBA0 + FMLVC); - if (rr < 3) // If rr is low, turn on - temp1 = 0x0080; // the mute bit. - else - temp1 = 0; - rr = 63 - rr; // Convert vol to attenuation. -// writel(temp1 | rr, s->pBA0 + FMRVC); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[4] = (r << 8) | l; -#else - s->mix.vol[4] = val; -#endif - return put_user(s->mix.vol[4], (int *) arg); - - - default: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: mixer_ioctl(): default\n")); - - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) - return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 1) { - l = 0; - rl = 31; - } else - rl = (attentbl[(l * 10) / 100]) >> 1; - - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - if (r < 1) { - r = 0; - rr = 31; - } else - rr = (attentbl[(r * 10) / 100]) >> 1; - if ((rl > 30) && (rr > 30)) - temp1 = 0x8000; - else - temp1 = 0; - temp1 = temp1 | (rl << 8) | rr; - cs4297a_write_ac97(s, mixreg[vidx - 1], temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[vidx - 1] = val; -#endif - return put_user(s->mix.vol[vidx - 1], (int *) arg); - } -} - - -// --------------------------------------------------------------------- - -static int cs4297a_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct cs4297a_state *s=NULL; - struct list_head *entry; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, - printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); - - mutex_lock(&swarm_cs4297a_mutex); - list_for_each(entry, &cs4297a_devs) - { - s = list_entry(entry, struct cs4297a_state, list); - if(s->dev_mixer == minor) - break; - } - if (!s) - { - CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, - printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); - - mutex_unlock(&swarm_cs4297a_mutex); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, - printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); - mutex_unlock(&swarm_cs4297a_mutex); - - return nonseekable_open(inode, file); -} - - -static int cs4297a_release_mixdev(struct inode *inode, struct file *file) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - - VALIDATE_STATE(s); - return 0; -} - - -static int cs4297a_ioctl_mixdev(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ret; - mutex_lock(&swarm_cs4297a_mutex); - ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, - arg); - mutex_unlock(&swarm_cs4297a_mutex); - return ret; -} - - -// ****************************************************************************************** -// Mixer file operations struct. -// ****************************************************************************************** -static const struct file_operations cs4297a_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .unlocked_ioctl = cs4297a_ioctl_mixdev, - .open = cs4297a_open_mixdev, - .release = cs4297a_release_mixdev, -}; - -// --------------------------------------------------------------------- - - -static int drain_adc(struct cs4297a_state *s, int nonblock) -{ - /* This routine serves no purpose currently - any samples - sitting in the receive queue will just be processed by the - background consumer. This would be different if DMA - actually stopped when there were no clients. */ - return 0; -} - -static int drain_dac(struct cs4297a_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned hwptr; - unsigned tmo; - int count; - - if (s->dma_dac.mapped) - return 0; - if (nonblock) - return -EBUSY; - add_wait_queue(&s->dma_dac.wait, &wait); - while ((count = __raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) || - (s->dma_dac.count > 0)) { - if (!signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - /* XXXKW is this calculation working? */ - tmo = ((count * FRAME_TX_US) * HZ) / 1000000; - schedule_timeout(tmo + 1); - } else { - /* XXXKW do I care if there is a signal pending? */ - } - } - spin_lock_irqsave(&s->lock, flags); - /* Reset the bookkeeping */ - hwptr = (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); - s->dma_dac.hwptr = s->dma_dac.swptr = hwptr; - spin_unlock_irqrestore(&s->lock, flags); - remove_wait_queue(&s->dma_dac.wait, &wait); - __set_current_state(TASK_RUNNING); - return 0; -} - - -// --------------------------------------------------------------------- - -static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count, - loff_t * ppos) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - ssize_t ret; - unsigned long flags; - int cnt, count_fr, cnt_by; - unsigned copied = 0; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, - printk(KERN_INFO "cs4297a: cs4297a_read()+ %d \n", count)); - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; -// -// "count" is the amount of bytes to read (from app), is decremented each loop -// by the amount of bytes that have been returned to the user buffer. -// "cnt" is the running total of each read from the buffer (changes each loop) -// "buffer" points to the app's buffer -// "ret" keeps a running total of the amount of bytes that have been copied -// to the user buffer. -// "copied" is the total bytes copied into the user buffer for each loop. -// - while (count > 0) { - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - "_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n", - count, s->dma_adc.count, - s->dma_adc.swptr, s->dma_adc.hwptr)); - spin_lock_irqsave(&s->lock, flags); - - /* cnt will be the number of available samples (16-bit - stereo); it starts out as the maxmimum consequetive - samples */ - cnt = (s->dma_adc.sb_end - s->dma_adc.sb_swptr) / 2; - count_fr = s->dma_adc.count / FRAME_SAMPLE_BYTES; - - // dma_adc.count is the current total bytes that have not been read. - // if the amount of unread bytes from the current sw pointer to the - // end of the buffer is greater than the current total bytes that - // have not been read, then set the "cnt" (unread bytes) to the - // amount of unread bytes. - - if (count_fr < cnt) - cnt = count_fr; - cnt_by = cnt * FRAME_SAMPLE_BYTES; - spin_unlock_irqrestore(&s->lock, flags); - // - // if we are converting from 8/16 then we need to copy - // twice the number of 16 bit bytes then 8 bit bytes. - // - if (s->conversion) { - if (cnt_by > (count * 2)) { - cnt = (count * 2) / FRAME_SAMPLE_BYTES; - cnt_by = count * 2; - } - } else { - if (cnt_by > count) { - cnt = count / FRAME_SAMPLE_BYTES; - cnt_by = count; - } - } - // - // "cnt" NOW is the smaller of the amount that will be read, - // and the amount that is requested in this read (or partial). - // if there are no bytes in the buffer to read, then start the - // ADC and wait for the interrupt handler to wake us up. - // - if (cnt <= 0) { - - // start up the dma engine and then continue back to the top of - // the loop when wake up occurs. - start_adc(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - oss_broken_sleep_on(&s->dma_adc.wait, MAX_SCHEDULE_TIMEOUT); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - // there are bytes in the buffer to read. - // copy from the hw buffer over to the user buffer. - // user buffer is designated by "buffer" - // virtual address to copy from is dma_buf+swptr - // the "cnt" is the number of bytes to read. - - CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO - "_read() copy_to cnt=%d count=%d ", cnt_by, count)); - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - " .sbufsz=%d .count=%d buffer=0x%.8x ret=%d\n", - s->dma_adc.sbufsz, s->dma_adc.count, - (unsigned) buffer, ret)); - - if (copy_to_user (buffer, ((void *)s->dma_adc.sb_swptr), cnt_by)) - return ret ? ret : -EFAULT; - copied = cnt_by; - - /* Return the descriptors */ - spin_lock_irqsave(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: upd_rcv sw->hw %x/%x\n", s->dma_adc.swptr, s->dma_adc.hwptr)); - s->dma_adc.count -= cnt_by; - s->dma_adc.sb_swptr += cnt * 2; - if (s->dma_adc.sb_swptr == s->dma_adc.sb_end) - s->dma_adc.sb_swptr = s->dma_adc.sample_buf; - spin_unlock_irqrestore(&s->lock, flags); - count -= copied; - buffer += copied; - ret += copied; - start_adc(s); - } - CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, - printk(KERN_INFO "cs4297a: cs4297a_read()- %d\n", ret)); - return ret; -} - - -static ssize_t cs4297a_write(struct file *file, const char *buffer, - size_t count, loff_t * ppos) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr, hwptr; - int cnt; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, - printk(KERN_INFO "cs4297a: cs4297a_write()+ count=%d\n", - count)); - VALIDATE_STATE(s); - - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - while (count > 0) { - serdma_t *d = &s->dma_dac; - int copy_cnt; - u32 *s_tmpl; - u32 *t_tmpl; - u32 left, right; - int swap = (s->prop_dac.fmt == AFMT_S16_LE) || (s->prop_dac.fmt == AFMT_U16_LE); - - /* XXXXXX this is broken for BLOAT_FACTOR */ - spin_lock_irqsave(&s->lock, flags); - if (d->count < 0) { - d->count = 0; - d->swptr = d->hwptr; - } - if (d->underrun) { - d->underrun = 0; - hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - d->descrtab_phys) / sizeof(serdma_descr_t)); - d->swptr = d->hwptr = hwptr; - } - swptr = d->swptr; - cnt = d->sbufsz - (swptr * FRAME_SAMPLE_BYTES); - /* Will this write fill up the buffer? */ - if (d->count + cnt > d->sbufsz) - cnt = d->sbufsz - d->count; - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - start_dac(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - oss_broken_sleep_on(&d->wait, MAX_SCHEDULE_TIMEOUT); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - if (copy_from_user(d->sample_buf, buffer, cnt)) - return ret ? ret : -EFAULT; - - copy_cnt = cnt; - s_tmpl = (u32 *)d->sample_buf; - t_tmpl = (u32 *)(d->dma_buf + (swptr * 4)); - - /* XXXKW assuming 16-bit stereo! */ - do { - u32 tmp; - - t_tmpl[0] = cpu_to_be32(0x98000000); - - tmp = be32_to_cpu(s_tmpl[0]); - left = tmp & 0xffff; - right = tmp >> 16; - if (swap) { - left = swab16(left); - right = swab16(right); - } - t_tmpl[1] = cpu_to_be32(left >> 8); - t_tmpl[2] = cpu_to_be32(((left & 0xff) << 24) | - (right << 4)); - - s_tmpl++; - t_tmpl += 8; - copy_cnt -= 4; - } while (copy_cnt); - - /* Mux in any pending read/write accesses */ - if (s->reg_request) { - *(u64 *)(d->dma_buf + (swptr * 4)) |= - cpu_to_be64(s->reg_request); - s->reg_request = 0; - wake_up(&s->dma_dac.reg_wait); - } - - CS_DBGOUT(CS_WAVE_WRITE, 4, - printk(KERN_INFO - "cs4297a: copy in %d to swptr %x\n", cnt, swptr)); - - swptr = (swptr + (cnt/FRAME_SAMPLE_BYTES)) % d->ringsz; - __raw_writeq(cnt/FRAME_SAMPLE_BYTES, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); - spin_lock_irqsave(&s->lock, flags); - d->swptr = swptr; - d->count += cnt; - d->endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_dac(s); - } - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, - printk(KERN_INFO "cs4297a: cs4297a_write()- %d\n", ret)); - return ret; -} - - -static unsigned int cs4297a_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - unsigned long flags; - unsigned int mask = 0; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4297a: cs4297a_poll()+\n")); - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4297a: cs4297a_poll() wait on FMODE_WRITE\n")); - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4297a: cs4297a_poll() wait on FMODE_READ\n")); - if(!s->dma_dac.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= - (signed) s->dma_dac.fragsize) { - if (s->dma_dac.wakeup) - mask |= POLLOUT | POLLWRNORM; - else - mask = 0; - s->dma_dac.wakeup = 0; - } - } else { - if ((signed) (s->dma_dac.sbufsz/2) >= s->dma_dac.count) - mask |= POLLOUT | POLLWRNORM; - } - } else if (file->f_mode & FMODE_READ) { - if (s->dma_adc.mapped) { - if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } else { - if (s->dma_adc.count > 0) - mask |= POLLIN | POLLRDNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4297a: cs4297a_poll()- 0x%.8x\n", - mask)); - return mask; -} - - -static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* XXXKW currently no mmap support */ - return -EINVAL; - return 0; -} - - -static int cs4297a_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - - CS_DBGOUT(CS_FUNCTION|CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): file=0x%.8x cmd=0x%.8x\n", - (unsigned) file, cmd)); -#if CSDEBUG - cs_printioctl(cmd); -#endif - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): SOUND_VERSION=0x%.8x\n", - SOUND_VERSION)); - return put_user(SOUND_VERSION, (int *) arg); - - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SYNC\n")); - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, - 0 /*file->f_flags & O_NONBLOCK */ - ); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, - (int *) arg); - - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_RESET\n")); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.count = s->dma_dac.total_bytes = - s->dma_dac.blocks = s->dma_dac.wakeup = 0; - s->dma_dac.swptr = s->dma_dac.hwptr = - (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.count = s->dma_adc.total_bytes = - s->dma_adc.blocks = s->dma_dac.wakeup = 0; - s->dma_adc.swptr = s->dma_adc.hwptr = - (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - - s->dma_adc.descrtab_phys) / sizeof(serdma_descr_t)); - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SPEED val=%d -> 48000\n", val)); - val = 48000; - return put_user(val, (int *) arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_STEREO val=%d\n", val)); - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - s->prop_adc.channels = val ? 2 : 1; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - s->prop_dac.channels = val ? 2 : 1; - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_CHANNELS val=%d\n", - val)); - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - s->prop_adc.channels = 2; - else - s->prop_adc.channels = 1; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - s->prop_dac.channels = 2; - else - s->prop_dac.channels = 1; - } - } - - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.channels; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.channels; - - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETFMTS: // Returns a mask - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_GETFMT val=0x%.8x\n", - AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8)); - return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8, (int *) arg); - - case SNDCTL_DSP_SETFMT: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SETFMT val=0x%.8x\n", - val)); - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val != AFMT_S16_LE - && val != AFMT_U16_LE && val != AFMT_S8 - && val != AFMT_U8) - val = AFMT_U8; - s->prop_adc.fmt = val; - s->prop_adc.fmt_original = s->prop_adc.fmt; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val != AFMT_S16_LE - && val != AFMT_U16_LE && val != AFMT_S8 - && val != AFMT_U8) - val = AFMT_U8; - s->prop_dac.fmt = val; - s->prop_dac.fmt_original = s->prop_dac.fmt; - } - } else { - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.fmt_original; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.fmt_original; - } - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SETFMT return val=0x%.8x\n", - val)); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_POST\n")); - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & s->ena & FMODE_READ) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & s->ena & FMODE_WRITE) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, (int *) arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready - && (ret = prog_dmabuf_adc(s))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready - && (ret = prog_dmabuf_dac(s))) - return ret; - start_dac(s); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s))) - return val; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - abinfo.fragsize = s->dma_dac.fragsize; - if (s->dma_dac.mapped) - abinfo.bytes = s->dma_dac.sbufsz; - else - abinfo.bytes = - s->dma_dac.sbufsz - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n", - abinfo.fragsize,abinfo.bytes,abinfo.fragstotal, - abinfo.fragments)); - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s))) - return val; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - if (s->conversion) { - abinfo.fragsize = s->dma_adc.fragsize / 2; - abinfo.bytes = s->dma_adc.count / 2; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = - abinfo.bytes >> (s->dma_adc.fragshift - 1); - } else { - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = - abinfo.bytes >> s->dma_adc.fragshift; - } - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if(!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - cinfo.bytes = s->dma_adc.total_bytes; - if (s->dma_adc.mapped) { - cinfo.blocks = - (cinfo.bytes >> s->dma_adc.fragshift) - - s->dma_adc.blocks; - s->dma_adc.blocks = - cinfo.bytes >> s->dma_adc.fragshift; - } else { - if (s->conversion) { - cinfo.blocks = - s->dma_adc.count / - 2 >> (s->dma_adc.fragshift - 1); - } else - cinfo.blocks = - s->dma_adc.count >> s->dma_adc. - fragshift; - } - if (s->conversion) - cinfo.ptr = s->dma_adc.hwptr / 2; - else - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize - 1; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - cinfo.bytes = s->dma_dac.total_bytes; - if (s->dma_dac.mapped) { - cinfo.blocks = - (cinfo.bytes >> s->dma_dac.fragshift) - - s->dma_dac.blocks; - s->dma_dac.blocks = - cinfo.bytes >> s->dma_dac.fragshift; - } else { - cinfo.blocks = - s->dma_dac.count >> s->dma_dac.fragshift; - } - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize - 1; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac(s))) - return val; - return put_user(s->dma_dac.fragsize, (int *) arg); - } - if ((val = prog_dmabuf_adc(s))) - return val; - if (s->conversion) - return put_user(s->dma_adc.fragsize / 2, - (int *) arg); - else - return put_user(s->dma_adc.fragsize, (int *) arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *) arg)) - return -EFAULT; - return 0; // Say OK, but do nothing. - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) - || (file->f_mode & FMODE_WRITE - && s->dma_dac.subdivision)) return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - else if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - if (file->f_mode & FMODE_READ) - return put_user(s->prop_adc.rate, (int *) arg); - else if (file->f_mode & FMODE_WRITE) - return put_user(s->prop_dac.rate, (int *) arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user(s->prop_adc.channels, (int *) arg); - else if (file->f_mode & FMODE_WRITE) - return put_user(s->prop_dac.channels, (int *) arg); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return - put_user( - (s->prop_adc. - fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, - (int *) arg); - else if (file->f_mode & FMODE_WRITE) - return - put_user( - (s->prop_dac. - fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, - (int *) arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - return mixer_ioctl(s, cmd, arg); -} - -static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) -{ - int ret; - - mutex_lock(&swarm_cs4297a_mutex); - ret = cs4297a_ioctl(file, cmd, arg); - mutex_unlock(&swarm_cs4297a_mutex); - - return ret; -} - -static int cs4297a_release(struct inode *inode, struct file *file) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - - CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO - "cs4297a: cs4297a_release(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n", - (unsigned) inode, (unsigned) file, file->f_mode)); - VALIDATE_STATE(s); - - if (file->f_mode & FMODE_WRITE) { - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_sem_dac); - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - s->open_mode &= ~FMODE_WRITE; - mutex_unlock(&s->open_sem_dac); - wake_up(&s->open_wait_dac); - } - if (file->f_mode & FMODE_READ) { - drain_adc(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_sem_adc); - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - s->open_mode &= ~FMODE_READ; - mutex_unlock(&s->open_sem_adc); - wake_up(&s->open_wait_adc); - } - return 0; -} - -static int cs4297a_locked_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct cs4297a_state *s=NULL; - struct list_head *entry; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4297a: cs4297a_open(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n", - (unsigned) inode, (unsigned) file, file->f_mode)); - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4297a: status = %08x\n", (int)__raw_readq(SS_CSR(R_SER_STATUS_DEBUG)))); - - list_for_each(entry, &cs4297a_devs) - { - s = list_entry(entry, struct cs4297a_state, list); - - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - if (entry == &cs4297a_devs) - return -ENODEV; - if (!s) { - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4297a: cs4297a_open(): Error - unable to find audio state struct\n")); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - - // wait for device to become free - if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) { - CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO - "cs4297a: cs4297a_open(): Error - must open READ and/or WRITE\n")); - return -ENODEV; - } - if (file->f_mode & FMODE_WRITE) { - if (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX)) != 0) { - printk(KERN_ERR "cs4297a: TX pipe needs to drain\n"); - while (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) - ; - } - - mutex_lock(&s->open_sem_dac); - while (s->open_mode & FMODE_WRITE) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem_dac); - return -EBUSY; - } - mutex_unlock(&s->open_sem_dac); - oss_broken_sleep_on(&s->open_wait_dac, MAX_SCHEDULE_TIMEOUT); - - if (signal_pending(current)) { - printk("open - sig pending\n"); - return -ERESTARTSYS; - } - mutex_lock(&s->open_sem_dac); - } - } - if (file->f_mode & FMODE_READ) { - mutex_lock(&s->open_sem_adc); - while (s->open_mode & FMODE_READ) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem_adc); - return -EBUSY; - } - mutex_unlock(&s->open_sem_adc); - oss_broken_sleep_on(&s->open_wait_adc, MAX_SCHEDULE_TIMEOUT); - - if (signal_pending(current)) { - printk("open - sig pending\n"); - return -ERESTARTSYS; - } - mutex_lock(&s->open_sem_adc); - } - } - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - if (file->f_mode & FMODE_READ) { - s->prop_adc.fmt = AFMT_S16_BE; - s->prop_adc.fmt_original = s->prop_adc.fmt; - s->prop_adc.channels = 2; - s->prop_adc.rate = 48000; - s->conversion = 0; - s->ena &= ~FMODE_READ; - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = 0; - mutex_unlock(&s->open_sem_adc); - - if (prog_dmabuf_adc(s)) { - CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR - "cs4297a: adc Program dmabufs failed.\n")); - cs4297a_release(inode, file); - return -ENOMEM; - } - } - if (file->f_mode & FMODE_WRITE) { - s->prop_dac.fmt = AFMT_S16_BE; - s->prop_dac.fmt_original = s->prop_dac.fmt; - s->prop_dac.channels = 2; - s->prop_dac.rate = 48000; - s->conversion = 0; - s->ena &= ~FMODE_WRITE; - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = 0; - mutex_unlock(&s->open_sem_dac); - - if (prog_dmabuf_dac(s)) { - CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR - "cs4297a: dac Program dmabufs failed.\n")); - cs4297a_release(inode, file); - return -ENOMEM; - } - } - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, - printk(KERN_INFO "cs4297a: cs4297a_open()- 0\n")); - return nonseekable_open(inode, file); -} - -static int cs4297a_open(struct inode *inode, struct file *file) -{ - int ret; - - mutex_lock(&swarm_cs4297a_mutex); - ret = cs4297a_open(inode, file); - mutex_unlock(&swarm_cs4297a_mutex); - - return ret; -} - -// ****************************************************************************************** -// Wave (audio) file operations struct. -// ****************************************************************************************** -static const struct file_operations cs4297a_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cs4297a_read, - .write = cs4297a_write, - .poll = cs4297a_poll, - .unlocked_ioctl = cs4297a_unlocked_ioctl, - .mmap = cs4297a_mmap, - .open = cs4297a_open, - .release = cs4297a_release, -}; - -static void cs4297a_interrupt(int irq, void *dev_id) -{ - struct cs4297a_state *s = (struct cs4297a_state *) dev_id; - u32 status; - - status = __raw_readq(SS_CSR(R_SER_STATUS_DEBUG)); - - CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO - "cs4297a: cs4297a_interrupt() HISR=0x%.8x\n", status)); - -#if 0 - /* XXXKW what check *should* be done here? */ - if (!(status & (M_SYNCSER_RX_EOP_COUNT | M_SYNCSER_RX_OVERRUN | M_SYNCSER_RX_SYNC_ERR))) { - status = __raw_readq(SS_CSR(R_SER_STATUS)); - printk(KERN_ERR "cs4297a: unexpected interrupt (status %08x)\n", status); - return; - } -#endif - - if (status & M_SYNCSER_RX_SYNC_ERR) { - status = __raw_readq(SS_CSR(R_SER_STATUS)); - printk(KERN_ERR "cs4297a: rx sync error (status %08x)\n", status); - return; - } - - if (status & M_SYNCSER_RX_OVERRUN) { - int newptr, i; - s->stats.rx_ovrrn++; - printk(KERN_ERR "cs4297a: receive FIFO overrun\n"); - - /* Fix things up: get the receive descriptor pool - clean and give them back to the hardware */ - while (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_RX))) - ; - newptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - - s->dma_adc.descrtab_phys) / sizeof(serdma_descr_t)); - for (i=0; i<DMA_DESCR; i++) { - s->dma_adc.descrtab[i].descr_a &= ~M_DMA_SERRX_SOP; - } - s->dma_adc.swptr = s->dma_adc.hwptr = newptr; - s->dma_adc.count = 0; - s->dma_adc.sb_swptr = s->dma_adc.sb_hwptr = s->dma_adc.sample_buf; - __raw_writeq(DMA_DESCR, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - } - - spin_lock(&s->lock); - cs4297a_update_ptr(s,CS_TRUE); - spin_unlock(&s->lock); - - CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO - "cs4297a: cs4297a_interrupt()-\n")); -} - -#if 0 -static struct initvol { - int mixch; - int vol; -} initvol[] __initdata = { - - {SOUND_MIXER_WRITE_VOLUME, 0x4040}, - {SOUND_MIXER_WRITE_PCM, 0x4040}, - {SOUND_MIXER_WRITE_SYNTH, 0x4040}, - {SOUND_MIXER_WRITE_CD, 0x4040}, - {SOUND_MIXER_WRITE_LINE, 0x4040}, - {SOUND_MIXER_WRITE_LINE1, 0x4040}, - {SOUND_MIXER_WRITE_RECLEV, 0x0000}, - {SOUND_MIXER_WRITE_SPEAKER, 0x4040}, - {SOUND_MIXER_WRITE_MIC, 0x0000} -}; -#endif - -static int __init cs4297a_init(void) -{ - struct cs4297a_state *s; - u32 pwr, id; - mm_segment_t fs; - int rval; - u64 cfg; - int mdio_val; - - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO - "cs4297a: cs4297a_init_module()+ \n")); - - mdio_val = __raw_readq(KSEG1 + A_MAC_REGISTER(2, R_MAC_MDIO)) & - (M_MAC_MDIO_DIR|M_MAC_MDIO_OUT); - - /* Check syscfg for synchronous serial on port 1 */ - cfg = __raw_readq(KSEG1 + A_SCD_SYSTEM_CFG); - if (!(cfg & M_SYS_SER1_ENABLE)) { - __raw_writeq(cfg | M_SYS_SER1_ENABLE, KSEG1+A_SCD_SYSTEM_CFG); - cfg = __raw_readq(KSEG1 + A_SCD_SYSTEM_CFG); - if (!(cfg & M_SYS_SER1_ENABLE)) { - printk(KERN_INFO "cs4297a: serial port 1 not configured for synchronous operation\n"); - return -1; - } - - printk(KERN_INFO "cs4297a: serial port 1 switching to synchronous operation\n"); - - /* Force the codec (on SWARM) to reset by clearing - GENO, preserving MDIO (no effect on CSWARM) */ - __raw_writeq(mdio_val, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO)); - udelay(10); - } - - /* Now set GENO */ - __raw_writeq(mdio_val | M_MAC_GENC, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO)); - /* Give the codec some time to finish resetting (start the bit clock) */ - udelay(100); - - if (!(s = kzalloc(sizeof(struct cs4297a_state), GFP_KERNEL))) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4297a: probe() no memory for state struct.\n")); - return -1; - } - s->magic = CS4297a_MAGIC; - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->dma_adc.reg_wait); - init_waitqueue_head(&s->dma_dac.reg_wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->open_wait_adc); - init_waitqueue_head(&s->open_wait_dac); - mutex_init(&s->open_sem_adc); - mutex_init(&s->open_sem_dac); - spin_lock_init(&s->lock); - - s->irq = K_INT_SER_1; - - if (request_irq - (s->irq, cs4297a_interrupt, 0, "Crystal CS4297a", s)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, - printk(KERN_ERR "cs4297a: irq %u in use\n", s->irq)); - goto err_irq; - } - if ((s->dev_audio = register_sound_dsp(&cs4297a_audio_fops, -1)) < - 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4297a: probe() register_sound_dsp() failed.\n")); - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&cs4297a_mixer_fops, -1)) < - 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4297a: probe() register_sound_mixer() failed.\n")); - goto err_dev2; - } - - if (ser_init(s) || dma_init(s)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4297a: ser_init failed.\n")); - goto err_dev3; - } - - do { - udelay(4000); - rval = cs4297a_read_ac97(s, AC97_POWER_CONTROL, &pwr); - } while (!rval && (pwr != 0xf)); - - if (!rval) { - char *sb1250_duart_present; - - fs = get_fs(); - set_fs(KERNEL_DS); -#if 0 - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val); - for (i = 0; i < ARRAY_SIZE(initvol); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val); - } -// cs4297a_write_ac97(s, 0x18, 0x0808); -#else - // cs4297a_write_ac97(s, 0x5e, 0x180); - cs4297a_write_ac97(s, 0x02, 0x0808); - cs4297a_write_ac97(s, 0x18, 0x0808); -#endif - set_fs(fs); - - list_add(&s->list, &cs4297a_devs); - - cs4297a_read_ac97(s, AC97_VENDOR_ID1, &id); - - sb1250_duart_present = symbol_get(sb1250_duart_present); - if (sb1250_duart_present) - sb1250_duart_present[1] = 0; - - printk(KERN_INFO "cs4297a: initialized (vendor id = %x)\n", id); - - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: cs4297a_init_module()-\n")); - - return 0; - } - - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - free_irq(s->irq, s); - err_irq: - kfree(s); - - printk(KERN_INFO "cs4297a: initialization failed\n"); - - return -1; -} - -static void __exit cs4297a_cleanup(void) -{ - /* - XXXKW - disable_irq, free_irq - drain DMA queue - disable DMA - disable TX/RX - free memory - */ - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: cleanup_cs4297a() finished\n")); -} - -// --------------------------------------------------------------------- - -MODULE_AUTHOR("Kip Walker, Broadcom Corp."); -MODULE_DESCRIPTION("Cirrus Logic CS4297a Driver for Broadcom SWARM board"); - -// --------------------------------------------------------------------- - -module_init(cs4297a_init); -module_exit(cs4297a_cleanup); diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c deleted file mode 100644 index d17019d25b99..000000000000 --- a/sound/oss/sys_timer.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * sound/oss/sys_timer.c - * - * The default timer for the Level 2 sequencer interface - * Uses the (1/HZ sec) timer of kernel. - */ -/* - * 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. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow) - */ -#include <linux/spinlock.h> -#include "sound_config.h" - -static volatile int opened, tmr_running; -static volatile unsigned int tmr_offs, tmr_ctr; -static volatile unsigned long ticks_offs; -static volatile int curr_tempo, curr_timebase; -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 DEFINE_SPINLOCK(lock); -static DEFINE_TIMER(def_tmr, poll_def_tmr, 0, 0); - -static unsigned long -tmr2ticks(int tmr_value) -{ - /* - * Convert timer ticks to MIDI ticks - */ - - unsigned long tmp; - unsigned long scale; - - /* tmr_value (ticks per sec) * - 1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */ - tmp = tmr_value * (1000000 / HZ); - scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ - return (tmp + scale / 2) / scale; -} - -static void -poll_def_tmr(unsigned long dummy) -{ - if (!opened) - return; - def_tmr.expires = (1) + jiffies; - add_timer(&def_tmr); - - if (!tmr_running) - return; - - spin_lock(&lock); - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - - if (curr_ticks >= next_event_time) { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } - - spin_unlock(&lock); -} - -static void -tmr_reset(void) -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - spin_unlock_irqrestore(&lock,flags); -} - -static int -def_tmr_open(int dev, int mode) -{ - if (opened) - return -EBUSY; - - tmr_reset(); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - { - def_tmr.expires = (1) + jiffies; - add_timer(&def_tmr); - } - - return 0; -} - -static void -def_tmr_close(int dev) -{ - opened = tmr_running = 0; - del_timer(&def_tmr); -} - -static int -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; - - 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:; - } - - return TIMER_NOT_ARMED; -} - -static unsigned long -def_tmr_get_time(int dev) -{ - if (!opened) - return 0; - - return curr_ticks; -} - -/* same as sound_timer.c:timer_ioctl!? */ -static int def_tmr_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int __user *p = arg; - int val; - - switch (cmd) { - case SNDCTL_TMR_SOURCE: - return __put_user(TMR_INTERNAL, p); - - case SNDCTL_TMR_START: - tmr_reset(); - tmr_running = 1; - return 0; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - - case SNDCTL_TMR_TIMEBASE: - if (__get_user(val, p)) - return -EFAULT; - if (val) { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - return __put_user(curr_timebase, p); - - case SNDCTL_TMR_TEMPO: - if (__get_user(val, p)) - return -EFAULT; - 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 __put_user(curr_tempo, p); - - case SNDCTL_SEQ_CTRLRATE: - if (__get_user(val, p)) - return -EFAULT; - if (val != 0) /* Can't change */ - return -EINVAL; - val = ((curr_tempo * curr_timebase) + 30) / 60; - return __put_user(val, p); - - case SNDCTL_SEQ_GETTIME: - return __put_user(curr_ticks, p); - - case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - - default:; - } - return -EINVAL; -} - -static void -def_tmr_arm(int dev, long time) -{ - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; - - next_event_time = prev_event_time = time; - - return; -} - -struct sound_timer_operations default_sound_timer = -{ - .owner = THIS_MODULE, - .info = {"System clock", 0}, - .priority = 0, /* Priority */ - .devlink = 0, /* Local device link */ - .open = def_tmr_open, - .close = def_tmr_close, - .event = def_tmr_event, - .get_time = def_tmr_get_time, - .ioctl = def_tmr_ioctl, - .arm_timer = def_tmr_arm -}; diff --git a/sound/oss/trix.c b/sound/oss/trix.c deleted file mode 100644 index a57bc635d758..000000000000 --- a/sound/oss/trix.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * sound/oss/trix.c - * - * Low level driver for the MediaTrix AudioTrix Pro - * (MT-0002-PC Control 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. - * - * Changes - * Alan Cox Modularisation, cleanup. - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo Got rid of attach_uart401 - */ - -#include <linux/init.h> -#include <linux/module.h> - -#include "sound_config.h" -#include "sb.h" -#include "sound_firmware.h" - -#include "ad1848.h" -#include "mpu401.h" - -#include "trix_boot.h" - -static int mpu; - -static bool joystick; - -static unsigned char trix_read(int addr) -{ - 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) -{ - 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) -{ - int i = 0, n = trix_boot_len; - - if (trix_boot_len == 0) - return; - - 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 */ - - 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) -{ - unsigned char addr_bits; - - if (trix_read(0x15) != 0x71) /* No ASIC signature */ - { - MDB(printk(KERN_ERR "No AudioTrix ASIC signature found\n")); - return 0; - } - - /* - * 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; -} - -/* - * Probe and attach routines for the Windows Sound System mode of - * AudioTrix Pro - */ - -static int __init init_trix_wss(struct address_info *hw_config) -{ - static unsigned char dma_bits[4] = { - 1, 2, 0, 3 - }; - struct resource *ports; - int config_port = hw_config->io_base + 0; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; - u8 config, bits; - int ret; - - switch(hw_config->irq) { - case 7: - bits = 8; - break; - case 9: - bits = 0x10; - break; - case 10: - bits = 0x18; - break; - case 11: - bits = 0x20; - break; - default: - printk(KERN_ERR "AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); - return 0; - } - - switch (dma1) { - case 0: - case 1: - case 3: - break; - default: - printk(KERN_ERR "AudioTrix: Bad WSS DMA %d\n", dma1); - return 0; - } - - switch (dma2) { - case -1: - case 0: - case 1: - case 3: - break; - default: - printk(KERN_ERR "AudioTrix: Bad capture DMA %d\n", dma2); - 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. - */ - ports = request_region(hw_config->io_base + 4, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if (!request_region(hw_config->io_base, 4, "MSS config")) { - printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - release_region(hw_config->io_base + 4, 4); - return 0; - } - - if (!trix_set_wss_port(hw_config)) - goto fail; - - config = inb(hw_config->io_base + 3); - - if ((config & 0x3f) != 0x00) - { - MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x\n", hw_config->io_base)); - goto fail; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (dma1 == 0 && config & 0x80) - { - printk(KERN_ERR "AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); - goto fail; - } - if (hw_config->irq > 9 && config & 0x80) - { - printk(KERN_ERR "AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); - goto fail; - } - - ret = ad1848_detect(ports, NULL, hw_config->osp); - if (!ret) - goto fail; - - if (joystick==1) - trix_write(0x15, 0x80); - - /* - * Set the IRQ and DMA addresses. - */ - - outb((bits | 0x40), config_port); - - if (dma2 == -1 || dma2 == dma1) - { - 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", ports, - hw_config->irq, - dma1, - dma2, - 0, - hw_config->osp, - THIS_MODULE); - - 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 */ - } - return 1; - -fail: - release_region(hw_config->io_base, 4); - release_region(hw_config->io_base + 4, 4); - return 0; -} - -static int __init probe_trix_sb(struct address_info *hw_config) -{ - - int tmp; - unsigned char conf; - extern int sb_be_quiet; - int old_quiet; - static signed char irq_translate[] = { - -1, -1, -1, 0, 1, 2, -1, 3 - }; - - if (trix_boot_len == 0) - return 0; /* No boot code -> no fun */ - - 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; - - if (!request_region(hw_config->io_base, 16, "soundblaster")) { - printk(KERN_ERR "AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); - 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); - - hw_config->name = "AudioTrix SB"; - if (!sb_dsp_detect(hw_config, 0, 0, NULL)) { - release_region(hw_config->io_base, 16); - return 0; - } - - 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; - - sb_dsp_init(hw_config, THIS_MODULE); - - sb_be_quiet = old_quiet; - return 1; -} - -static int __init probe_trix_mpu(struct address_info *hw_config) -{ - unsigned char conf; - static int irq_bits[] = { - -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 - }; - - if (hw_config->irq > 9) - { - printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - if (irq_bits[hw_config->irq] == -1) - { - printk(KERN_ERR "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); - hw_config->name = "AudioTrix Pro"; - return probe_uart401(hw_config, THIS_MODULE); -} - -static void __exit unload_trix_wss(struct address_info *hw_config) -{ - int dma2 = hw_config->dma2; - - if (dma2 == -1) - dma2 = hw_config->dma; - - 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); - sound_unload_audiodev(hw_config->slots[0]); -} - -static inline void __exit unload_trix_mpu(struct address_info *hw_config) -{ - unload_uart401(hw_config); -} - -static inline void __exit unload_trix_sb(struct address_info *hw_config) -{ - sb_dsp_unload(hw_config, mpu); -} - -static struct address_info cfg; -static struct address_info cfg2; -static struct address_info cfg_mpu; - -static int sb; -static int fw_load; - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; /* Set this for modules that need it */ -static int __initdata sb_io = -1; -static int __initdata sb_dma = -1; -static int __initdata sb_irq = -1; -static int __initdata mpu_io = -1; -static int __initdata mpu_irq = -1; - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param_hw(dma, int, dma, 0); -module_param_hw(dma2, int, dma, 0); -module_param_hw(sb_io, int, ioport, 0); -module_param_hw(sb_dma, int, dma, 0); -module_param_hw(sb_irq, int, irq, 0); -module_param_hw(mpu_io, int, ioport, 0); -module_param_hw(mpu_irq, int, irq, 0); -module_param(joystick, bool, 0); - -static int __init init_trix(void) -{ - printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - cfg2.io_base = sb_io; - cfg2.irq = sb_irq; - cfg2.dma = sb_dma; - - cfg_mpu.io_base = mpu_io; - cfg_mpu.irq = mpu_irq; - - if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { - printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); - return -EINVAL; - } - - if (cfg2.io_base != -1 && (cfg2.irq == -1 || cfg2.dma == -1)) { - printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); - return -EINVAL; - } - if (cfg_mpu.io_base != -1 && cfg_mpu.irq == -1) { - printk(KERN_INFO "CONFIG_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 (!request_region(0x390, 2, "AudioTrix")) { - printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); - return -ENODEV; - } - - if (!init_trix_wss(&cfg)) { - release_region(0x390, 2); - return -ENODEV; - } - - /* - * We must attach in the right order to get the firmware - * loaded up in time. - */ - - if (cfg2.io_base != -1) { - sb = probe_trix_sb(&cfg2); - } - - if (cfg_mpu.io_base != -1) - mpu = probe_trix_mpu(&cfg_mpu); - - return 0; -} - -static void __exit cleanup_trix(void) -{ - if (fw_load) - vfree(trix_boot); - if (sb) - unload_trix_sb(&cfg2); - if (mpu) - unload_trix_mpu(&cfg_mpu); - unload_trix_wss(&cfg); -} - -module_init(init_trix); -module_exit(cleanup_trix); - -#ifndef MODULE -static int __init setup_trix (char *str) -{ - /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, mpu_io, mpu_irq */ - int ints[9]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - sb_io = ints[5]; - sb_irq = ints[6]; - sb_dma = ints[6]; - mpu_io = ints[7]; - mpu_irq = ints[8]; - - return 1; -} - -__setup("trix=", setup_trix); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h deleted file mode 100644 index a73e3dd39f9a..000000000000 --- a/sound/oss/tuning.h +++ /dev/null @@ -1,23 +0,0 @@ -static unsigned short semitone_tuning[24] = -{ -/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, -/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, -/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755 -}; - -static unsigned short cent_tuning[100] = -{ -/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, -/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, -/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, -/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, -/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, -/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, -/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, -/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, -/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, -/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, -/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, -/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, -/* 96 */ 10570, 10576, 10582, 10589 -}; diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c deleted file mode 100644 index 83dcc85b8688..000000000000 --- a/sound/oss/uart401.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * sound/oss/uart401.c - * - * MPU-401 UART driver (formerly uart401_midi.c) - * - * - * 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. - * - * Changes: - * Alan Cox Reformatted, removed sound_mem usage, use normal Linux - * interrupt allocation. Protect against bogus unload - * Fixed to allow IRQ > 15 - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo got rid of check_region - * - * Status: - * Untested - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "mpu401.h" - -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; - spinlock_t lock; -}; - -#define DATAPORT (devc->base) -#define COMDPORT (devc->base+1) -#define STATPORT (devc->base+1) - -static int uart401_status(struct uart401_devc *devc) -{ - 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(struct uart401_devc *devc, unsigned char cmd) -{ - outb((cmd), COMDPORT); -} - -static int uart401_read(struct uart401_devc *devc) -{ - return inb(DATAPORT); -} - -static void uart401_write(struct uart401_devc *devc, unsigned char byte) -{ - outb((byte), DATAPORT); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static int reset_uart401(struct uart401_devc *devc); -static void enter_uart_mode(struct uart401_devc *devc); - -static void uart401_input_loop(struct uart401_devc *devc) -{ - int work_limit=30000; - - while (input_avail(devc) && --work_limit) - { - 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); - } - if(work_limit==0) - printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base); -} - -irqreturn_t uart401intr(int irq, void *dev_id) -{ - struct uart401_devc *devc = dev_id; - - if (devc == NULL) - { - printk(KERN_ERR "uart401: bad devc\n"); - return IRQ_NONE; - } - - if (input_avail(devc)) - uart401_input_loop(devc); - return IRQ_HANDLED; -} - -static int -uart401_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - if (devc->opened) - return -EBUSY; - - /* Flush the UART */ - - while (input_avail(devc)) - uart401_read(devc); - - devc->midi_input_intr = input; - devc->opened = mode; - enter_uart_mode(devc); - devc->disabled = 0; - - return 0; -} - -static void uart401_close(int dev) -{ - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - reset_uart401(devc); - devc->opened = 0; -} - -static int uart401_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - if (devc->disabled) - return 1; - /* - * Test for input since pending input seems to block the output. - */ - - spin_lock_irqsave(&devc->lock,flags); - if (input_avail(devc)) - uart401_input_loop(devc); - - spin_unlock_irqrestore(&devc->lock,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(KERN_WARNING "uart401: 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 inline int uart401_start_read(int dev) -{ - return 0; -} - -static inline int uart401_end_read(int dev) -{ - return 0; -} - -static inline void uart401_kick(int dev) -{ -} - -static inline int uart401_buffer_status(int dev) -{ - return 0; -} - -#define MIDI_SYNTH_NAME "MPU-401 UART" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static const struct midi_operations uart401_operations = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = uart401_open, - .close = uart401_close, - .outputc = uart401_out, - .start_read = uart401_start_read, - .end_read = uart401_end_read, - .kick = uart401_kick, - .buffer_status = uart401_buffer_status, -}; - -static void enter_uart_mode(struct uart401_devc *devc) -{ - int ok, timeout; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - 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; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int reset_uart401(struct uart401_devc *devc) -{ - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - devc->input_byte = 0; - uart401_cmd(devc, MPU_RESET); - - /* - * 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; - } - } - } - - /* Flush input before enabling interrupts */ - if (ok) - uart401_input_loop(devc); - else - DDB(printk("Reset UART401 failed - No hardware detected.\n")); - - return ok; -} - -int probe_uart401(struct address_info *hw_config, struct module *owner) -{ - struct uart401_devc *devc; - char *name = "MPU-401 (UART) MIDI"; - int ok = 0; - unsigned long flags; - - DDB(printk("Entered probe_uart401()\n")); - - /* Default to "not found" */ - hw_config->slots[4] = -1; - - if (!request_region(hw_config->io_base, 4, "MPU-401 UART")) { - printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base); - return 0; - } - - devc = kmalloc(sizeof(struct uart401_devc), GFP_KERNEL); - if (!devc) { - printk(KERN_WARNING "uart401: Can't allocate memory\n"); - goto cleanup_region; - } - - 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; - spin_lock_init(&devc->lock); - - spin_lock_irqsave(&devc->lock,flags); - ok = reset_uart401(devc); - spin_unlock_irqrestore(&devc->lock,flags); - - if (!ok) - goto cleanup_devc; - - if (hw_config->name) - name = hw_config->name; - - if (devc->irq < 0) { - devc->share_irq = 1; - devc->irq *= -1; - } else - devc->share_irq = 0; - - if (!devc->share_irq) - if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) { - printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); - devc->share_irq = 1; - } - devc->my_dev = sound_alloc_mididev(); - enter_uart_mode(devc); - - if (devc->my_dev == -1) { - printk(KERN_INFO "uart401: Too many midi devices detected\n"); - goto cleanup_irq; - } - conf_printf(name, hw_config); - midi_devs[devc->my_dev] = kmemdup(&uart401_operations, - sizeof(struct midi_operations), - GFP_KERNEL); - if (!midi_devs[devc->my_dev]) { - printk(KERN_ERR "uart401: Failed to allocate memory\n"); - goto cleanup_unload_mididev; - } - - if (owner) - midi_devs[devc->my_dev]->owner = owner; - - midi_devs[devc->my_dev]->devc = devc; - midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth, - sizeof(struct synth_operations), - GFP_KERNEL); - - if (!midi_devs[devc->my_dev]->converter) { - printk(KERN_WARNING "uart401: Failed to allocate memory\n"); - goto cleanup_midi_devs; - } - strcpy(midi_devs[devc->my_dev]->info.name, name); - midi_devs[devc->my_dev]->converter->id = "UART401"; - midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev; - - if (owner) - midi_devs[devc->my_dev]->converter->owner = owner; - - hw_config->slots[4] = devc->my_dev; - sequencer_init(); - devc->opened = 0; - return 1; -cleanup_midi_devs: - kfree(midi_devs[devc->my_dev]); -cleanup_unload_mididev: - sound_unload_mididev(devc->my_dev); -cleanup_irq: - if (!devc->share_irq) - free_irq(devc->irq, devc); -cleanup_devc: - kfree(devc); -cleanup_region: - release_region(hw_config->io_base, 4); - return 0; -} - -void unload_uart401(struct address_info *hw_config) -{ - struct uart401_devc *devc; - int n=hw_config->slots[4]; - - /* Not set up */ - if(n==-1 || midi_devs[n]==NULL) - return; - - /* Not allocated (erm ??) */ - - devc = midi_devs[hw_config->slots[4]]->devc; - if (devc == NULL) - return; - - reset_uart401(devc); - release_region(hw_config->io_base, 4); - - if (!devc->share_irq) - free_irq(devc->irq, devc); - kfree(midi_devs[devc->my_dev]->converter); - kfree(midi_devs[devc->my_dev]); - kfree(devc); - - /* This kills midi_devs[x] */ - sound_unload_mididev(hw_config->slots[4]); -} - -EXPORT_SYMBOL(probe_uart401); -EXPORT_SYMBOL(unload_uart401); -EXPORT_SYMBOL(uart401intr); - -static struct address_info cfg_mpu; - -static int io = -1; -static int irq = -1; - -module_param_hw(io, int, ioport, 0444); -module_param_hw(irq, int, irq, 0444); - - -static int __init init_uart401(void) -{ - cfg_mpu.irq = irq; - cfg_mpu.io_base = io; - - /* Can be loaded either for module use or to provide functions - to others */ - if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) { - printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); - if (!probe_uart401(&cfg_mpu, THIS_MODULE)) - return -ENODEV; - } - - return 0; -} - -static void __exit cleanup_uart401(void) -{ - if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) - unload_uart401(&cfg_mpu); -} - -module_init(init_uart401); -module_exit(cleanup_uart401); - -#ifndef MODULE -static int __init setup_uart401(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} - -__setup("uart401=", setup_uart401); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c deleted file mode 100644 index eda32d7eddbd..000000000000 --- a/sound/oss/uart6850.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * sound/oss/uart6850.c - * - * - * 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. - * 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. - * - * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now - * uses native linux resources - * Christoph Hellwig: Adapted to module_init/module_exit - * Jeff Garzik: Made it work again, in theory - * FIXME: If the request_irq() succeeds, the probe succeeds. Ug. - * - * Status: Testing required (no shit -jgarzik) - * - * - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/spinlock.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" - -static int uart6850_base = 0x330; - -static int *uart6850_osp; - -#define DATAPORT (uart6850_base) -#define COMDPORT (uart6850_base+1) -#define STATPORT (uart6850_base+1) - -static int uart6850_status(void) -{ - return inb(STATPORT); -} - -#define input_avail() (uart6850_status()&INPUT_AVAIL) -#define output_ready() (uart6850_status()&OUTPUT_READY) - -static void uart6850_cmd(unsigned char cmd) -{ - outb(cmd, COMDPORT); -} - -static int uart6850_read(void) -{ - return inb(DATAPORT); -} - -static void uart6850_write(unsigned char byte) -{ - outb(byte, DATAPORT); -} - -#define OUTPUT_READY 0x02 /* Mask for data ready Bit */ -#define INPUT_AVAIL 0x01 /* Mask for Data Send Ready Bit */ - -#define UART_RESET 0x95 -#define UART_MODE_ON 0x03 - -static int uart6850_opened; -static int uart6850_irq; -static int uart6850_detected; -static int my_dev; -static DEFINE_SPINLOCK(lock); - -static void (*midi_input_intr) (int dev, unsigned char data); -static void poll_uart6850(unsigned long dummy); - - -static DEFINE_TIMER(uart6850_timer, poll_uart6850, 0, 0); - -static void uart6850_input_loop(void) -{ - int count = 10; - - 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--; - } - } -} - -static irqreturn_t m6850intr(int irq, void *dev_id) -{ - if (input_avail()) - uart6850_input_loop(); - return IRQ_HANDLED; -} - -/* - * It looks like there is no input interrupts in the UART mode. Let's try - * polling. - */ - -static void poll_uart6850(unsigned long dummy) -{ - unsigned long flags; - - if (!(uart6850_opened & OPEN_READ)) - return; /* Device has been closed */ - - spin_lock_irqsave(&lock,flags); - if (input_avail()) - uart6850_input_loop(); - - uart6850_timer.expires = 1 + jiffies; - add_timer(&uart6850_timer); - - /* - * Come back later - */ - - spin_unlock_irqrestore(&lock,flags); -} - -static int 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; - } - - uart6850_cmd(UART_RESET); - uart6850_input_loop(); - midi_input_intr = input; - uart6850_opened = mode; - poll_uart6850(0); /* - * Enable input polling - */ - - return 0; -} - -static void uart6850_close(int dev) -{ - uart6850_cmd(UART_MODE_ON); - del_timer(&uart6850_timer); - uart6850_opened = 0; -} - -static int uart6850_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - - /* - * Test for input since pending input seems to block the output. - */ - - spin_lock_irqsave(&lock,flags); - - if (input_avail()) - uart6850_input_loop(); - - spin_unlock_irqrestore(&lock,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(); timeout--); /* - * Wait - */ - if (!output_ready()) - { - printk(KERN_WARNING "Midi6850: Timeout\n"); - return 0; - } - uart6850_write(midi_byte); - return 1; -} - -static inline int uart6850_command(int dev, unsigned char *midi_byte) -{ - return 1; -} - -static inline int uart6850_start_read(int dev) -{ - return 0; -} - -static inline int uart6850_end_read(int dev) -{ - return 0; -} - -static inline void uart6850_kick(int dev) -{ -} - -static inline int uart6850_buffer_status(int dev) -{ - return 0; /* - * No data in buffers - */ -} - -#define MIDI_SYNTH_NAME "6850 UART Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations uart6850_operations = -{ - .owner = THIS_MODULE, - .info = {"6850 UART", 0, 0, SNDCARD_UART6850}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = uart6850_open, - .close = uart6850_close, - .outputc = uart6850_out, - .start_read = uart6850_start_read, - .end_read = uart6850_end_read, - .kick = uart6850_kick, - .command = uart6850_command, - .buffer_status = uart6850_buffer_status -}; - - -static void __init attach_uart6850(struct address_info *hw_config) -{ - int ok, timeout; - unsigned long flags; - - if (!uart6850_detected) - return; - - 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; - - spin_lock_irqsave(&lock,flags); - - for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* - * Wait - */ - uart6850_cmd(UART_MODE_ON); - ok = 1; - spin_unlock_irqrestore(&lock,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 inline int reset_uart6850(void) -{ - uart6850_read(); - return 1; /* - * OK - */ -} - -static int __init probe_uart6850(struct address_info *hw_config) -{ - int ok; - - uart6850_osp = hw_config->osp; - uart6850_base = hw_config->io_base; - uart6850_irq = hw_config->irq; - - if (request_irq(uart6850_irq, m6850intr, 0, "MIDI6850", NULL) < 0) - return 0; - - ok = reset_uart6850(); - uart6850_detected = ok; - return ok; -} - -static void __exit unload_uart6850(struct address_info *hw_config) -{ - free_irq(hw_config->irq, NULL); - sound_unload_mididev(hw_config->slots[4]); -} - -static struct address_info cfg_mpu; - -static int __initdata io = -1; -static int __initdata irq = -1; - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); - -static int __init init_uart6850(void) -{ - cfg_mpu.io_base = io; - cfg_mpu.irq = irq; - - if (cfg_mpu.io_base == -1 || cfg_mpu.irq == -1) { - printk(KERN_INFO "uart6850: irq and io must be set.\n"); - return -EINVAL; - } - - if (probe_uart6850(&cfg_mpu)) - return -ENODEV; - attach_uart6850(&cfg_mpu); - - return 0; -} - -static void __exit cleanup_uart6850(void) -{ - unload_uart6850(&cfg_mpu); -} - -module_init(init_uart6850); -module_exit(cleanup_uart6850); - -#ifndef MODULE -static int __init setup_uart6850(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} -__setup("uart6850=", setup_uart6850); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/ulaw.h b/sound/oss/ulaw.h deleted file mode 100644 index 0ff8c0a3bda0..000000000000 --- a/sound/oss/ulaw.h +++ /dev/null @@ -1,69 +0,0 @@ -static unsigned char ulaw_dsp[] = { - 3, 7, 11, 15, 19, 23, 27, 31, - 35, 39, 43, 47, 51, 55, 59, 63, - 66, 68, 70, 72, 74, 76, 78, 80, - 82, 84, 86, 88, 90, 92, 94, 96, - 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, - 113, 114, 114, 115, 115, 116, 116, 117, - 117, 118, 118, 119, 119, 120, 120, 121, - 121, 121, 122, 122, 122, 122, 123, 123, - 123, 123, 124, 124, 124, 124, 125, 125, - 125, 125, 125, 125, 126, 126, 126, 126, - 126, 126, 126, 126, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 253, 249, 245, 241, 237, 233, 229, 225, - 221, 217, 213, 209, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 174, 172, 170, 168, 166, 164, 162, 160, - 158, 157, 156, 155, 154, 153, 152, 151, - 150, 149, 148, 147, 146, 145, 144, 143, - 143, 142, 142, 141, 141, 140, 140, 139, - 139, 138, 138, 137, 137, 136, 136, 135, - 135, 135, 134, 134, 134, 134, 133, 133, - 133, 133, 132, 132, 132, 132, 131, 131, - 131, 131, 131, 131, 130, 130, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, -}; - -static unsigned char dsp_ulaw[] = { - 0, 0, 0, 0, 0, 1, 1, 1, - 1, 2, 2, 2, 2, 3, 3, 3, - 3, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, - 7, 8, 8, 8, 8, 9, 9, 9, - 9, 10, 10, 10, 10, 11, 11, 11, - 11, 12, 12, 12, 12, 13, 13, 13, - 13, 14, 14, 14, 14, 15, 15, 15, - 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, - 23, 24, 24, 25, 25, 26, 26, 27, - 27, 28, 28, 29, 29, 30, 30, 31, - 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 47, 49, 51, 53, 55, 57, 59, 61, - 63, 66, 70, 74, 78, 84, 92, 104, - 254, 231, 219, 211, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 175, 174, 173, 172, 171, 170, 169, 168, - 167, 166, 165, 164, 163, 162, 161, 160, - 159, 159, 158, 158, 157, 157, 156, 156, - 155, 155, 154, 154, 153, 153, 152, 152, - 151, 151, 150, 150, 149, 149, 148, 148, - 147, 147, 146, 146, 145, 145, 144, 144, - 143, 143, 143, 143, 142, 142, 142, 142, - 141, 141, 141, 141, 140, 140, 140, 140, - 139, 139, 139, 139, 138, 138, 138, 138, - 137, 137, 137, 137, 136, 136, 136, 136, - 135, 135, 135, 135, 134, 134, 134, 134, - 133, 133, 133, 133, 132, 132, 132, 132, - 131, 131, 131, 131, 130, 130, 130, 130, - 129, 129, 129, 129, 128, 128, 128, 128, -}; diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c deleted file mode 100644 index fc0ba276cc8f..000000000000 --- a/sound/oss/v_midi.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * sound/oss/v_midi.c - * - * The low level driver for the Sound Blaster DS chips. - * - * - * Copyright (C) by Hannu Savolainen 1993-1996 - * - * USS/Lite 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. - * ?? - * - * Changes - * Alan Cox Modularisation, changed memory allocations - * Christoph Hellwig Adapted to module_init/module_exit - * - * Status - * Untested - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "v_midi.h" - -static vmidi_devc *v_devc[2] = { NULL, NULL}; -static int midi1,midi2; -static void *midi_mem = NULL; - -/* - * The DSP channel can be used either for input or output. Variable - * 'sb_irq_mode' will be set when the program calls read or write first time - * after open. Current version doesn't support mode changes without closing - * and reopening the device. Support for this feature may be implemented in a - * future version of this driver. - */ - - -static int v_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return -ENXIO; - - spin_lock_irqsave(&devc->lock,flags); - if (devc->opened) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -EBUSY; - } - devc->opened = 1; - spin_unlock_irqrestore(&devc->lock,flags); - - devc->intr_active = 1; - - if (mode & OPEN_READ) - { - devc->input_opened = 1; - devc->midi_input_intr = input; - } - - return 0; -} - -static void v_midi_close (int dev) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return; - - spin_lock_irqsave(&devc->lock,flags); - devc->intr_active = 0; - devc->input_opened = 0; - devc->opened = 0; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int v_midi_out (int dev, unsigned char midi_byte) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - vmidi_devc *pdevc; - - if (devc == NULL) - return -ENXIO; - - pdevc = midi_devs[devc->pair_mididev]->devc; - if (pdevc->input_opened > 0){ - if (MIDIbuf_avail(pdevc->my_mididev) > 500) - return 0; - pdevc->midi_input_intr (pdevc->my_mididev, midi_byte); - } - return 1; -} - -static inline int v_midi_start_read (int dev) -{ - return 0; -} - -static int v_midi_end_read (int dev) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - if (devc == NULL) - return -ENXIO; - - devc->intr_active = 0; - return 0; -} - -/* why -EPERM and not -EINVAL?? */ - -static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg) -{ - return -EPERM; -} - - -#define MIDI_SYNTH_NAME "Loopback MIDI" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT - -#include "midi_synth.h" - -static struct midi_operations v_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = v_midi_open, - .close = v_midi_close, - .ioctl = v_midi_ioctl, - .outputc = v_midi_out, - .start_read = v_midi_start_read, - .end_read = v_midi_end_read, -}; - -static struct midi_operations v_midi_operations2 = -{ - .owner = THIS_MODULE, - .info = {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = v_midi_open, - .close = v_midi_close, - .ioctl = v_midi_ioctl, - .outputc = v_midi_out, - .start_read = v_midi_start_read, - .end_read = v_midi_end_read, -}; - -/* - * We kmalloc just one of these - it makes life simpler and the code - * cleaner and the memory handling far more efficient - */ - -struct vmidi_memory -{ - /* Must be first */ - struct midi_operations m_ops[2]; - struct synth_operations s_ops[2]; - struct vmidi_devc v_ops[2]; -}; - -static void __init attach_v_midi (struct address_info *hw_config) -{ - struct vmidi_memory *m; - /* printk("Attaching v_midi device.....\n"); */ - - midi1 = sound_alloc_mididev(); - if (midi1 == -1) - { - printk(KERN_ERR "v_midi: Too many midi devices detected\n"); - return; - } - - m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL); - if (m == NULL) - { - printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n"); - sound_unload_mididev(midi1); - return; - } - - midi_mem = m; - - midi_devs[midi1] = &m->m_ops[0]; - - - midi2 = sound_alloc_mididev(); - if (midi2 == -1) - { - printk (KERN_ERR "v_midi: Too many midi devices detected\n"); - kfree(m); - sound_unload_mididev(midi1); - return; - } - - midi_devs[midi2] = &m->m_ops[1]; - - /* printk("VMIDI1: %d VMIDI2: %d\n",midi1,midi2); */ - - /* for MIDI-1 */ - v_devc[0] = &m->v_ops[0]; - memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations, - sizeof (struct midi_operations)); - - v_devc[0]->my_mididev = midi1; - v_devc[0]->pair_mididev = midi2; - v_devc[0]->opened = v_devc[0]->input_opened = 0; - v_devc[0]->intr_active = 0; - v_devc[0]->midi_input_intr = NULL; - spin_lock_init(&v_devc[0]->lock); - - midi_devs[midi1]->devc = v_devc[0]; - - midi_devs[midi1]->converter = &m->s_ops[0]; - std_midi_synth.midi_dev = midi1; - memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); - midi_devs[midi1]->converter->id = "V_MIDI 1"; - - /* for MIDI-2 */ - v_devc[1] = &m->v_ops[1]; - - memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2, - sizeof (struct midi_operations)); - - v_devc[1]->my_mididev = midi2; - v_devc[1]->pair_mididev = midi1; - v_devc[1]->opened = v_devc[1]->input_opened = 0; - v_devc[1]->intr_active = 0; - v_devc[1]->midi_input_intr = NULL; - spin_lock_init(&v_devc[1]->lock); - - midi_devs[midi2]->devc = v_devc[1]; - midi_devs[midi2]->converter = &m->s_ops[1]; - - std_midi_synth.midi_dev = midi2; - memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); - midi_devs[midi2]->converter->id = "V_MIDI 2"; - - sequencer_init(); - /* printk("Attached v_midi device\n"); */ -} - -static inline int __init probe_v_midi(struct address_info *hw_config) -{ - return(1); /* always OK */ -} - - -static void __exit unload_v_midi(struct address_info *hw_config) -{ - sound_unload_mididev(midi1); - sound_unload_mididev(midi2); - kfree(midi_mem); -} - -static struct address_info cfg; /* dummy */ - -static int __init init_vmidi(void) -{ - printk("MIDI Loopback device driver\n"); - if (!probe_v_midi(&cfg)) - return -ENODEV; - attach_v_midi(&cfg); - - return 0; -} - -static void __exit cleanup_vmidi(void) -{ - unload_v_midi(&cfg); -} - -module_init(init_vmidi); -module_exit(cleanup_vmidi); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/v_midi.h b/sound/oss/v_midi.h deleted file mode 100644 index 08e2185ee816..000000000000 --- a/sound/oss/v_midi.h +++ /dev/null @@ -1,14 +0,0 @@ -typedef struct vmidi_devc { - int dev; - - /* State variables */ - int opened; - spinlock_t lock; - - /* MIDI fields */ - int my_mididev; - int pair_mididev; - int input_opened; - int intr_active; - void (*midi_input_intr) (int dev, unsigned char data); - } vmidi_devc; diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c deleted file mode 100644 index 92ca5bee1860..000000000000 --- a/sound/oss/vidc.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * linux/drivers/sound/vidc.c - * - * Copyright (C) 1997-2000 by Russell King <rmk@arm.linux.org.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * VIDC20 audio driver. - * - * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA - * engine. The DMA transfers fixed-format (16-bit little-endian linear) - * samples to the VIDC20, which then transfers this data serially to the - * DACs. The samplerate is controlled by the VIDC. - * - * We currently support a mixer device, but it is currently non-functional. - */ - -#include <linux/gfp.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> - -#include <mach/hardware.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/hardware/iomd.h> -#include <asm/irq.h> - -#include "sound_config.h" -#include "vidc.h" - -#ifndef _SIOC_TYPE -#define _SIOC_TYPE(x) _IOC_TYPE(x) -#endif -#ifndef _SIOC_NR -#define _SIOC_NR(x) _IOC_NR(x) -#endif - -#define VIDC_SOUND_CLOCK (250000) -#define VIDC_SOUND_CLOCK_EXT (176400) - -/* - * When using SERIAL SOUND mode (external DAC), the number of physical - * channels is fixed at 2. - */ -static int vidc_busy; -static int vidc_adev; -static int vidc_audio_rate; -static char vidc_audio_format; -static char vidc_audio_channels; - -static unsigned char vidc_level_l[SOUND_MIXER_NRDEVICES] = { - 85, /* master */ - 50, /* bass */ - 50, /* treble */ - 0, /* synth */ - 75, /* pcm */ - 0, /* speaker */ - 100, /* ext line */ - 0, /* mic */ - 100, /* CD */ - 0, -}; - -static unsigned char vidc_level_r[SOUND_MIXER_NRDEVICES] = { - 85, /* master */ - 50, /* bass */ - 50, /* treble */ - 0, /* synth */ - 75, /* pcm */ - 0, /* speaker */ - 100, /* ext line */ - 0, /* mic */ - 100, /* CD */ - 0, -}; - -static unsigned int vidc_audio_volume_l; /* left PCM vol, 0 - 65536 */ -static unsigned int vidc_audio_volume_r; /* right PCM vol, 0 - 65536 */ - -extern void vidc_update_filler(int bits, int channels); -extern int softoss_dev; - -static void -vidc_mixer_set(int mdev, unsigned int level) -{ - unsigned int lev_l = level & 0x007f; - unsigned int lev_r = (level & 0x7f00) >> 8; - unsigned int mlev_l, mlev_r; - - if (lev_l > 100) - lev_l = 100; - if (lev_r > 100) - lev_r = 100; - -#define SCALE(lev,master) ((lev) * (master) * 65536 / 10000) - - mlev_l = vidc_level_l[SOUND_MIXER_VOLUME]; - mlev_r = vidc_level_r[SOUND_MIXER_VOLUME]; - - switch (mdev) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_PCM: - vidc_level_l[mdev] = lev_l; - vidc_level_r[mdev] = lev_r; - - vidc_audio_volume_l = SCALE(lev_l, mlev_l); - vidc_audio_volume_r = SCALE(lev_r, mlev_r); -/*printk("VIDC: PCM vol %05X %05X\n", vidc_audio_volume_l, vidc_audio_volume_r);*/ - break; - } -#undef SCALE -} - -static int vidc_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - unsigned int val; - unsigned int mdev; - - if (_SIOC_TYPE(cmd) != 'M') - return -EINVAL; - - mdev = _SIOC_NR(cmd); - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - if (get_user(val, (unsigned int __user *)arg)) - return -EFAULT; - - if (mdev < SOUND_MIXER_NRDEVICES) - vidc_mixer_set(mdev, val); - else - return -EINVAL; - } - - /* - * Return parameters - */ - switch (mdev) { - case SOUND_MIXER_RECSRC: - val = 0; - break; - - case SOUND_MIXER_DEVMASK: - val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_STEREODEVS: - val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_RECMASK: - val = 0; - break; - - case SOUND_MIXER_CAPS: - val = 0; - break; - - default: - if (mdev < SOUND_MIXER_NRDEVICES) - val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8; - else - return -EINVAL; - } - - return put_user(val, (unsigned int __user *)arg) ? -EFAULT : 0; -} - -static unsigned int vidc_audio_set_format(int dev, unsigned int fmt) -{ - switch (fmt) { - default: - fmt = AFMT_S16_LE; - case AFMT_U8: - case AFMT_S8: - case AFMT_S16_LE: - vidc_audio_format = fmt; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - case AFMT_QUERY: - break; - } - return vidc_audio_format; -} - -#define my_abs(i) ((i)<0 ? -(i) : (i)) - -static int vidc_audio_set_speed(int dev, int rate) -{ - if (rate) { - unsigned int hwctrl, hwrate, hwrate_ext, rate_int, rate_ext; - unsigned int diff_int, diff_ext; - unsigned int newsize, new2size; - - hwctrl = 0x00000003; - - /* Using internal clock */ - hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; - if (hwrate < 3) - hwrate = 3; - if (hwrate > 255) - hwrate = 255; - - /* Using exernal clock */ - hwrate_ext = (((VIDC_SOUND_CLOCK_EXT * 2) / rate) + 1) >> 1; - if (hwrate_ext < 3) - hwrate_ext = 3; - if (hwrate_ext > 255) - hwrate_ext = 255; - - rate_int = VIDC_SOUND_CLOCK / hwrate; - rate_ext = VIDC_SOUND_CLOCK_EXT / hwrate_ext; - - /* Chose between external and internal clock */ - diff_int = my_abs(rate_ext-rate); - diff_ext = my_abs(rate_int-rate); - if (diff_ext < diff_int) { - /*printk("VIDC: external %d %d %d\n", rate, rate_ext, hwrate_ext);*/ - hwrate=hwrate_ext; - hwctrl=0x00000002; - /* Allow roughly 0.4% tolerance */ - if (diff_ext > (rate/256)) - rate=rate_ext; - } else { - /*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/ - hwctrl=0x00000003; - /* Allow roughly 0.4% tolerance */ - if (diff_int > (rate/256)) - rate=rate_int; - } - - vidc_writel(0xb0000000 | (hwrate - 2)); - vidc_writel(0xb1000000 | hwctrl); - - newsize = (10000 / hwrate) & ~3; - if (newsize < 208) - newsize = 208; - if (newsize > 4096) - newsize = 4096; - for (new2size = 128; new2size < newsize; new2size <<= 1); - if (new2size - newsize > newsize - (new2size >> 1)) - new2size >>= 1; - if (new2size > 4096) { - printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n", - newsize, new2size); - new2size = 4096; - } - /*printk("VIDC: dma size %d\n", new2size);*/ - dma_bufsize = new2size; - vidc_audio_rate = rate; - } - return vidc_audio_rate; -} - -static short vidc_audio_set_channels(int dev, short channels) -{ - switch (channels) { - default: - channels = 2; - case 1: - case 2: - vidc_audio_channels = channels; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - case 0: - break; - } - return vidc_audio_channels; -} - -/* - * Open the device - */ -static int vidc_audio_open(int dev, int mode) -{ - /* This audio device does not have recording capability */ - if (mode == OPEN_READ) - return -EPERM; - - if (vidc_busy) - return -EBUSY; - - vidc_busy = 1; - return 0; -} - -/* - * Close the device - */ -static void vidc_audio_close(int dev) -{ - vidc_busy = 0; -} - -/* - * Output a block via DMA to sound device. - * - * We just set the DMA start and count; the DMA interrupt routine - * will take care of formatting the samples (via the appropriate - * vidc_filler routine), and flag via vidc_audio_dma_interrupt when - * more data is required. - */ -static void -vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - - local_irq_save(flags); - dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; - dma_count = total_count; - local_irq_restore(flags); -} - -static void -vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag) -{ -} - -static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - return -EINVAL; -} - -static irqreturn_t vidc_audio_dma_interrupt(void) -{ - DMAbuf_outputintr(vidc_adev, 1); - return IRQ_HANDLED; -} - -/* - * Prepare for outputting samples. - * - * Each buffer that will be passed will be `bsize' bytes long, - * with a total of `bcount' buffers. - */ -static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - struct audio_operations *adev = audio_devs[dev]; - - dma_interrupt = NULL; - adev->dmap_out->flags |= DMA_NODMA; - - return 0; -} - -/* - * Stop our current operation. - */ -static void vidc_audio_reset(int dev) -{ - dma_interrupt = NULL; -} - -static int vidc_audio_local_qlen(int dev) -{ - return /*dma_count !=*/ 0; -} - -static void vidc_audio_trigger(int dev, int enable_bits) -{ - struct audio_operations *adev = audio_devs[dev]; - - if (enable_bits & PCM_ENABLE_OUTPUT) { - if (!(adev->dmap_out->flags & DMA_ACTIVE)) { - unsigned long flags; - - local_irq_save(flags); - - /* prevent recusion */ - adev->dmap_out->flags |= DMA_ACTIVE; - - dma_interrupt = vidc_audio_dma_interrupt; - vidc_sound_dma_irq(0, NULL); - iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR); - - local_irq_restore(flags); - } - } -} - -static struct audio_driver vidc_audio_driver = -{ - .owner = THIS_MODULE, - .open = vidc_audio_open, - .close = vidc_audio_close, - .output_block = vidc_audio_output_block, - .start_input = vidc_audio_start_input, - .prepare_for_input = vidc_audio_prepare_for_input, - .prepare_for_output = vidc_audio_prepare_for_output, - .halt_io = vidc_audio_reset, - .local_qlen = vidc_audio_local_qlen, - .trigger = vidc_audio_trigger, - .set_speed = vidc_audio_set_speed, - .set_bits = vidc_audio_set_format, - .set_channels = vidc_audio_set_channels -}; - -static struct mixer_operations vidc_mixer_operations = { - .owner = THIS_MODULE, - .id = "VIDC", - .name = "VIDCsound", - .ioctl = vidc_mixer_ioctl -}; - -void vidc_update_filler(int format, int channels) -{ -#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) - - switch (TYPE(format, channels)) { - default: - case TYPE(AFMT_U8, 1): - vidc_filler = vidc_fill_1x8_u; - break; - - case TYPE(AFMT_U8, 2): - vidc_filler = vidc_fill_2x8_u; - break; - - case TYPE(AFMT_S8, 1): - vidc_filler = vidc_fill_1x8_s; - break; - - case TYPE(AFMT_S8, 2): - vidc_filler = vidc_fill_2x8_s; - break; - - case TYPE(AFMT_S16_LE, 1): - vidc_filler = vidc_fill_1x16_s; - break; - - case TYPE(AFMT_S16_LE, 2): - vidc_filler = vidc_fill_2x16_s; - break; - } -} - -static void __init attach_vidc(struct address_info *hw_config) -{ - char name[32]; - int i, adev; - - sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype); - conf_printf(name, hw_config); - memset(dma_buf, 0, sizeof(dma_buf)); - - adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name, - &vidc_audio_driver, sizeof(vidc_audio_driver), - DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, - NULL, hw_config->dma, hw_config->dma2); - - if (adev < 0) - goto audio_failed; - - /* - * 1024 bytes => 64 buffers - */ - audio_devs[adev]->min_fragment = 10; - audio_devs[adev]->mixer_dev = num_mixers; - - audio_devs[adev]->mixer_dev = - sound_install_mixer(MIXER_DRIVER_VERSION, - name, &vidc_mixer_operations, - sizeof(vidc_mixer_operations), NULL); - - if (audio_devs[adev]->mixer_dev < 0) - goto mixer_failed; - - for (i = 0; i < 2; i++) { - dma_buf[i] = get_zeroed_page(GFP_KERNEL); - if (!dma_buf[i]) { - printk(KERN_ERR "%s: can't allocate required buffers\n", - name); - goto mem_failed; - } - dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]); - } - - if (sound_alloc_dma(hw_config->dma, hw_config->name)) { - printk(KERN_ERR "%s: DMA %d is in use\n", name, hw_config->dma); - goto dma_failed; - } - - if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, - hw_config->name, &dma_start)) { - printk(KERN_ERR "%s: IRQ %d is in use\n", name, hw_config->irq); - goto irq_failed; - } - vidc_adev = adev; - vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); - - return; - -irq_failed: - sound_free_dma(hw_config->dma); -dma_failed: -mem_failed: - for (i = 0; i < 2; i++) - free_page(dma_buf[i]); - sound_unload_mixerdev(audio_devs[adev]->mixer_dev); -mixer_failed: - sound_unload_audiodev(adev); -audio_failed: - return; -} - -static int __init probe_vidc(struct address_info *hw_config) -{ - hw_config->irq = IRQ_DMAS0; - hw_config->dma = DMA_VIRTUAL_SOUND; - hw_config->dma2 = -1; - hw_config->card_subtype = 16; - hw_config->name = "VIDC20"; - return 1; -} - -static void __exit unload_vidc(struct address_info *hw_config) -{ - int i, adev = vidc_adev; - - vidc_adev = -1; - - free_irq(hw_config->irq, &dma_start); - sound_free_dma(hw_config->dma); - - if (adev >= 0) { - sound_unload_mixerdev(audio_devs[adev]->mixer_dev); - sound_unload_audiodev(adev); - for (i = 0; i < 2; i++) - free_page(dma_buf[i]); - } -} - -static struct address_info cfg; - -static int __init init_vidc(void) -{ - if (probe_vidc(&cfg) == 0) - return -ENODEV; - - attach_vidc(&cfg); - - return 0; -} - -static void __exit cleanup_vidc(void) -{ - unload_vidc(&cfg); -} - -module_init(init_vidc); -module_exit(cleanup_vidc); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("VIDC20 audio driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h deleted file mode 100644 index 0d1424751ecd..000000000000 --- a/sound/oss/vidc.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/drivers/sound/vidc.h - * - * Copyright (C) 1997 Russell King <rmk@arm.linux.org.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * VIDC sound function prototypes - */ - -/* vidc_fill.S */ - -/* - * Filler routines for different channels and sample sizes - */ - -extern unsigned long vidc_fill_1x8_u(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x8_u(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_1x8_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x8_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_1x16_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x16_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); - -/* - * DMA Interrupt handler - */ - -extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref); - -/* - * Filler routine pointer - */ - -extern unsigned long (*vidc_filler) (unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); - -/* - * Virtual DMA buffer exhausted - */ - -extern irqreturn_t (*dma_interrupt) (void); - -/* - * Virtual DMA buffer addresses - */ - -extern unsigned long dma_start, dma_count, dma_bufsize; -extern unsigned long dma_buf[2], dma_pbuf[2]; - -/* vidc_synth.c */ - -extern void vidc_synth_init(struct address_info *hw_config); -extern void vidc_synth_exit(struct address_info *hw_config); -extern int vidc_synth_get_volume(void); -extern int vidc_synth_set_volume(int vol); diff --git a/sound/oss/vidc_fill.S b/sound/oss/vidc_fill.S deleted file mode 100644 index bed34921d176..000000000000 --- a/sound/oss/vidc_fill.S +++ /dev/null @@ -1,218 +0,0 @@ -/* - * linux/drivers/sound/vidc_fill.S - * - * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Filler routines for DMA buffers - */ -#include <linux/linkage.h> -#include <asm/assembler.h> -#include <mach/hardware.h> -#include <asm/hardware/iomd.h> - - .text - -ENTRY(vidc_fill_1x8_u) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldrb r4, [r0], #1 - eor r4, r4, #0x80 - and r4, ip, r4, lsl #8 - orr r4, r4, r4, lsl #16 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_2x8_u) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldr r4, [r0], #2 - and r5, r4, ip - and r4, ip, r4, lsl #8 - orr r4, r4, r5, lsl #16 - orr r4, r4, r4, lsr #8 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_1x8_s) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldrb r4, [r0], #1 - and r4, ip, r4, lsl #8 - orr r4, r4, r4, lsl #16 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_2x8_s) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldr r4, [r0], #2 - and r5, r4, ip - and r4, ip, r4, lsl #8 - orr r4, r4, r5, lsl #16 - orr r4, r4, r4, lsr #8 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_1x16_s) - mov ip, #0xff00 - orr ip, ip, ip, lsr #8 -1: cmp r0, r1 - bge vidc_clear - ldr r5, [r0], #2 - and r4, r5, ip - orr r4, r4, r4, lsl #16 - str r4, [r2], #4 - cmp r0, r1 - addlt r0, r0, #2 - andlt r4, r5, ip, lsl #16 - orrlt r4, r4, r4, lsr #16 - strlt r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_2x16_s) - mov ip, #0xff00 - orr ip, ip, ip, lsr #8 -1: cmp r0, r1 - bge vidc_clear - ldr r4, [r0], #4 - str r4, [r2], #4 - cmp r0, r1 - ldrlt r4, [r0], #4 - strlt r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_noaudio) - mov r0, #0 - mov r1, #0 -2: mov r4, #0 - mov r5, #0 -1: cmp r2, r3 - stmltia r2!, {r0, r1, r4, r5} - blt 1b - mov pc, lr - -ENTRY(vidc_clear) - mov r0, #0 - mov r1, #0 - tst r2, #4 - str r0, [r2], #4 - tst r2, #8 - stmia r2!, {r0, r1} - b 2b - -/* - * Call filler routines with: - * r0 = phys address - * r1 = phys end - * r2 = buffer - * Returns: - * r0 = new buffer address - * r2 = new buffer finish - * r4 = corrupted - * r5 = corrupted - * ip = corrupted - */ - -ENTRY(vidc_sound_dma_irq) - stmfd sp!, {r4 - r8, lr} - ldr r8, =dma_start - ldmia r8, {r0, r1, r2, r3, r4, r5} - teq r1, #0 - adreq r4, vidc_fill_noaudio - moveq r7, #1 << 31 - movne r7, #0 - mov ip, #IOMD_BASE & 0xff000000 - orr ip, ip, #IOMD_BASE & 0x00ff0000 - ldrb r6, [ip, #IOMD_SD0ST] - tst r6, #DMA_ST_OFL @ Check for overrun - eorne r6, r6, #DMA_ST_AB - tst r6, #DMA_ST_AB - moveq r2, r3 @ DMAing A, update B - add r3, r2, r5 @ End of DMA buffer - add r1, r1, r0 @ End of virtual DMA buffer - mov lr, pc - mov pc, r4 @ Call fill routine (uses r4, ip) - sub r1, r1, r0 @ Remaining length - stmia r8, {r0, r1} - mov r0, #0 - tst r2, #4 @ Round buffer up to 4 words - strne r0, [r2], #4 - tst r2, #8 - strne r0, [r2], #4 - strne r0, [r2], #4 - sub r2, r2, #16 - mov r2, r2, lsl #20 - movs r2, r2, lsr #20 - orreq r2, r2, #1 << 30 @ Set L bit - orr r2, r2, r7 - ldmdb r8, {r3, r4, r5} - tst r6, #DMA_ST_AB - mov ip, #IOMD_BASE & 0xff000000 - orr ip, ip, #IOMD_BASE & 0x00ff0000 - streq r4, [ip, #IOMD_SD0CURB] - strne r5, [ip, #IOMD_SD0CURA] - streq r2, [ip, #IOMD_SD0ENDB] - strne r2, [ip, #IOMD_SD0ENDA] - ldr lr, [ip, #IOMD_SD0ST] - tst lr, #DMA_ST_OFL - bne 1f - tst r6, #DMA_ST_AB - strne r4, [ip, #IOMD_SD0CURB] - streq r5, [ip, #IOMD_SD0CURA] - strne r2, [ip, #IOMD_SD0ENDB] - streq r2, [ip, #IOMD_SD0ENDA] -1: teq r7, #0 - mov r0, #0x10 - strneb r0, [ip, #IOMD_SD0CR] - ldmfd sp!, {r4 - r8, lr} - mov r0, #1 @ IRQ_HANDLED - teq r1, #0 @ If we have no more - movne pc, lr - teq r3, #0 - movne pc, r3 @ Call interrupt routine - mov pc, lr - - .data - .globl dma_interrupt -dma_interrupt: - .long 0 @ r3 - .globl dma_pbuf -dma_pbuf: - .long 0 @ r4 - .long 0 @ r5 - .globl dma_start -dma_start: - .long 0 @ r0 - .globl dma_count -dma_count: - .long 0 @ r1 - .globl dma_buf -dma_buf: - .long 0 @ r2 - .long 0 @ r3 - .globl vidc_filler -vidc_filler: - .long vidc_fill_noaudio @ r4 - .globl dma_bufsize -dma_bufsize: - .long 0x1000 @ r5 diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c deleted file mode 100644 index 4f0c3a232e41..000000000000 --- a/sound/oss/waveartist.c +++ /dev/null @@ -1,2043 +0,0 @@ -/* - * linux/sound/oss/waveartist.c - * - * The low level driver for the RWA010 Rockwell Wave Artist - * codec chip used in the Rebel.com NetWinder. - * - * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) - * and Pat Beirne (patb@corel.ca) - * - * - * Copyright (C) by Rebel.com 1998-1999 - * - * RWA010 specs received under NDA from Rockwell - * - * 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. - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> - * Added __init to waveartist_init() - */ - -/* Debugging */ -#define DEBUG_CMD 1 -#define DEBUG_OUT 2 -#define DEBUG_IN 4 -#define DEBUG_INTR 8 -#define DEBUG_MIXER 16 -#define DEBUG_TRIGGER 32 - -#define debug_flg (0) - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/bitops.h> - - -#include "sound_config.h" -#include "waveartist.h" - -#ifdef CONFIG_ARM -#include <mach/hardware.h> -#include <asm/mach-types.h> -#endif - -#ifndef NO_DMA -#define NO_DMA 255 -#endif - -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH |\ - SOUND_MASK_PCM |\ - SOUND_MASK_LINE |\ - SOUND_MASK_MIC |\ - SOUND_MASK_LINE1 |\ - SOUND_MASK_RECLEV |\ - SOUND_MASK_VOLUME |\ - SOUND_MASK_IMIX) - -static unsigned short levels[SOUND_MIXER_NRDEVICES] = { - 0x5555, /* Master Volume */ - 0x0000, /* Bass */ - 0x0000, /* Treble */ - 0x2323, /* Synth (FM) */ - 0x4b4b, /* PCM */ - 0x6464, /* PC Speaker */ - 0x0000, /* Ext Line */ - 0x0000, /* Mic */ - 0x0000, /* CD */ - 0x6464, /* Recording monitor */ - 0x0000, /* SB PCM (ALT PCM) */ - 0x0000, /* Recording level */ - 0x6464, /* Input gain */ - 0x6464, /* Output gain */ - 0x0000, /* Line1 (Aux1) */ - 0x0000, /* Line2 (Aux2) */ - 0x0000, /* Line3 (Aux3) */ - 0x0000, /* Digital1 */ - 0x0000, /* Digital2 */ - 0x0000, /* Digital3 */ - 0x0000, /* Phone In */ - 0x6464, /* Phone Out */ - 0x0000, /* Video */ - 0x0000, /* Radio */ - 0x0000 /* Monitor */ -}; - -struct wavnc_info { - struct address_info hw; /* hardware */ - char *chip_name; - - int xfer_count; - int audio_mode; - int open_mode; - int audio_flags; - int record_dev; - int playback_dev; - int dev_no; - - /* Mixer parameters */ - const struct waveartist_mixer_info *mix; - - unsigned short *levels; /* cache of volume settings */ - int recmask; /* currently enabled recording device! */ - -#ifdef CONFIG_ARCH_NETWINDER - signed int slider_vol; /* hardware slider volume */ - unsigned int handset_detect :1; - unsigned int telephone_detect:1; - unsigned int no_autoselect :1;/* handset/telephone autoselects a path */ - unsigned int spkr_mute_state :1;/* set by ioctl or autoselect */ - unsigned int line_mute_state :1;/* set by ioctl or autoselect */ - unsigned int use_slider :1;/* use slider setting for o/p vol */ -#endif -}; - -/* - * This is the implementation specific mixer information. - */ -struct waveartist_mixer_info { - unsigned int supported_devs; /* Supported devices */ - unsigned int recording_devs; /* Recordable devies */ - unsigned int stereo_devs; /* Stereo devices */ - - unsigned int (*select_input)(struct wavnc_info *, unsigned int, - unsigned char *, unsigned char *); - int (*decode_mixer)(struct wavnc_info *, int, - unsigned char, unsigned char); - int (*get_mixer)(struct wavnc_info *, int); -}; - -struct wavnc_port_info { - int open_mode; - int speed; - int channels; - int audio_format; -}; - -static int nr_waveartist_devs; -static struct wavnc_info adev_info[MAX_AUDIO_DEV]; -static DEFINE_SPINLOCK(waveartist_lock); - -#ifndef CONFIG_ARCH_NETWINDER -#define machine_is_netwinder() 0 -#else -static struct timer_list vnc_timer; -static void vnc_configure_mixer(struct wavnc_info *devc, - unsigned int input_mask); -static int vnc_private_ioctl(int dev, unsigned int cmd, int __user *arg); -static void vnc_slider_tick(unsigned long data); -#endif - -static inline void -waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set) -{ - unsigned int ctlr_port = hw->io_base + CTLR; - - clear = ~clear & inb(ctlr_port); - - outb(clear | set, ctlr_port); -} - -/* Toggle IRQ acknowledge line - */ -static inline void -waveartist_iack(struct wavnc_info *devc) -{ - unsigned int ctlr_port = devc->hw.io_base + CTLR; - int old_ctlr; - - old_ctlr = inb(ctlr_port) & ~IRQ_ACK; - - outb(old_ctlr | IRQ_ACK, ctlr_port); - outb(old_ctlr, ctlr_port); -} - -static inline int -waveartist_sleep(int timeout_ms) -{ - unsigned int timeout = msecs_to_jiffies(timeout_ms*100); - return schedule_timeout_interruptible(timeout); -} - -static int -waveartist_reset(struct wavnc_info *devc) -{ - struct address_info *hw = &devc->hw; - unsigned int timeout, res = -1; - - waveartist_set_ctlr(hw, -1, RESET); - waveartist_sleep(2); - waveartist_set_ctlr(hw, RESET, 0); - - timeout = 500; - do { - mdelay(2); - - if (inb(hw->io_base + STATR) & CMD_RF) { - res = inw(hw->io_base + CMDR); - if (res == 0x55aa) - break; - } - } while (--timeout); - - if (timeout == 0) { - printk(KERN_WARNING "WaveArtist: reset timeout "); - if (res != (unsigned int)-1) - printk("(res=%04X)", res); - printk("\n"); - return 1; - } - return 0; -} - -/* Helper function to send and receive words - * from WaveArtist. It handles all the handshaking - * and can send or receive multiple words. - */ -static int -waveartist_cmd(struct wavnc_info *devc, - int nr_cmd, unsigned int *cmd, - int nr_resp, unsigned int *resp) -{ - unsigned int io_base = devc->hw.io_base; - unsigned int timed_out = 0; - unsigned int i; - - if (debug_flg & DEBUG_CMD) { - printk("waveartist_cmd: cmd="); - - for (i = 0; i < nr_cmd; i++) - printk("%04X ", cmd[i]); - - printk("\n"); - } - - if (inb(io_base + STATR) & CMD_RF) { - int old_data; - - /* flush the port - */ - - old_data = inw(io_base + CMDR); - - if (debug_flg & DEBUG_CMD) - printk("flushed %04X...", old_data); - - udelay(10); - } - - for (i = 0; !timed_out && i < nr_cmd; i++) { - int count; - - for (count = 5000; count; count--) - if (inb(io_base + STATR) & CMD_WE) - break; - - if (!count) - timed_out = 1; - else - outw(cmd[i], io_base + CMDR); - } - - for (i = 0; !timed_out && i < nr_resp; i++) { - int count; - - for (count = 5000; count; count--) - if (inb(io_base + STATR) & CMD_RF) - break; - - if (!count) - timed_out = 1; - else - resp[i] = inw(io_base + CMDR); - } - - if (debug_flg & DEBUG_CMD) { - if (!timed_out) { - printk("waveartist_cmd: resp="); - - for (i = 0; i < nr_resp; i++) - printk("%04X ", resp[i]); - - printk("\n"); - } else - printk("waveartist_cmd: timed out\n"); - } - - return timed_out ? 1 : 0; -} - -/* - * Send one command word - */ -static inline int -waveartist_cmd1(struct wavnc_info *devc, unsigned int cmd) -{ - return waveartist_cmd(devc, 1, &cmd, 0, NULL); -} - -/* - * Send one command, receive one word - */ -static inline unsigned int -waveartist_cmd1_r(struct wavnc_info *devc, unsigned int cmd) -{ - unsigned int ret; - - waveartist_cmd(devc, 1, &cmd, 1, &ret); - - return ret; -} - -/* - * Send a double command, receive one - * word (and throw it away) - */ -static inline int -waveartist_cmd2(struct wavnc_info *devc, unsigned int cmd, unsigned int arg) -{ - unsigned int vals[2]; - - vals[0] = cmd; - vals[1] = arg; - - return waveartist_cmd(devc, 2, vals, 1, vals); -} - -/* - * Send a triple command - */ -static inline int -waveartist_cmd3(struct wavnc_info *devc, unsigned int cmd, - unsigned int arg1, unsigned int arg2) -{ - unsigned int vals[3]; - - vals[0] = cmd; - vals[1] = arg1; - vals[2] = arg2; - - return waveartist_cmd(devc, 3, vals, 0, NULL); -} - -static int -waveartist_getrev(struct wavnc_info *devc, char *rev) -{ - unsigned int temp[2]; - unsigned int cmd = WACMD_GETREV; - - waveartist_cmd(devc, 1, &cmd, 2, temp); - - rev[0] = temp[0] >> 8; - rev[1] = temp[0] & 255; - rev[2] = '\0'; - - return temp[0]; -} - -static void waveartist_halt_output(int dev); -static void waveartist_halt_input(int dev); -static void waveartist_halt(int dev); -static void waveartist_trigger(int dev, int state); - -static int -waveartist_open(int dev, int mode) -{ - struct wavnc_info *devc; - struct wavnc_port_info *portc; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (struct wavnc_info *) audio_devs[dev]->devc; - portc = (struct wavnc_port_info *) audio_devs[dev]->portc; - - spin_lock_irqsave(&waveartist_lock, flags); - if (portc->open_mode || (devc->open_mode & mode)) { - spin_unlock_irqrestore(&waveartist_lock, flags); - return -EBUSY; - } - - devc->audio_mode = 0; - devc->open_mode |= mode; - portc->open_mode = mode; - waveartist_trigger(dev, 0); - - if (mode & OPEN_READ) - devc->record_dev = dev; - if (mode & OPEN_WRITE) - devc->playback_dev = dev; - spin_unlock_irqrestore(&waveartist_lock, flags); - - return 0; -} - -static void -waveartist_close(int dev) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned long flags; - - spin_lock_irqsave(&waveartist_lock, flags); - - waveartist_halt(dev); - - devc->audio_mode = 0; - devc->open_mode &= ~portc->open_mode; - portc->open_mode = 0; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - unsigned int count = __count; - - if (debug_flg & DEBUG_OUT) - printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", - buf, count); - /* - * 16 bit data - */ - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) - count >>= 1; - - if (portc->channels > 1) - count >>= 1; - - count -= 1; - - if (devc->audio_mode & PCM_ENABLE_OUTPUT && - audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - count == devc->xfer_count) { - devc->audio_mode |= PCM_ENABLE_OUTPUT; - return; /* - * Auto DMA mode on. No need to react - */ - } - - spin_lock_irqsave(&waveartist_lock, flags); - - /* - * set sample count - */ - waveartist_cmd2(devc, WACMD_OUTPUTSIZE, count); - - devc->xfer_count = count; - devc->audio_mode |= PCM_ENABLE_OUTPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - unsigned int count = __count; - - if (debug_flg & DEBUG_IN) - printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", - buf, count); - - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - count >>= 1; - - if (portc->channels > 1) - count >>= 1; - - count -= 1; - - if (devc->audio_mode & PCM_ENABLE_INPUT && - audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - count == devc->xfer_count) { - devc->audio_mode |= PCM_ENABLE_INPUT; - return; /* - * Auto DMA mode on. No need to react - */ - } - - spin_lock_irqsave(&waveartist_lock, flags); - - /* - * set sample count - */ - waveartist_cmd2(devc, WACMD_INPUTSIZE, count); - - devc->xfer_count = count; - devc->audio_mode |= PCM_ENABLE_INPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static int -waveartist_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - return -EINVAL; -} - -static unsigned int -waveartist_get_speed(struct wavnc_port_info *portc) -{ - unsigned int speed; - - /* - * program the speed, channels, bits - */ - if (portc->speed == 8000) - speed = 0x2E71; - else if (portc->speed == 11025) - speed = 0x4000; - else if (portc->speed == 22050) - speed = 0x8000; - else if (portc->speed == 44100) - speed = 0x0; - else { - /* - * non-standard - just calculate - */ - speed = portc->speed << 16; - - speed = (speed / 44100) & 65535; - } - - return speed; -} - -static unsigned int -waveartist_get_bits(struct wavnc_port_info *portc) -{ - unsigned int bits; - - if (portc->audio_format == AFMT_S16_LE) - bits = 1; - else if (portc->audio_format == AFMT_S8) - bits = 0; - else - bits = 2; //default AFMT_U8 - - return bits; -} - -static int -waveartist_prepare_for_input(int dev, int bsize, int bcount) -{ - unsigned long flags; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned int speed, bits; - - if (devc->audio_mode) - return 0; - - speed = waveartist_get_speed(portc); - bits = waveartist_get_bits(portc); - - spin_lock_irqsave(&waveartist_lock, flags); - - if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk(KERN_WARNING "waveartist: error setting the " - "record format to %d\n", portc->audio_format); - - if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk(KERN_WARNING "waveartist: error setting record " - "to %d channels\n", portc->channels); - - /* - * write cmd SetSampleSpeedTimeConstant - */ - if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk(KERN_WARNING "waveartist: error setting the record " - "speed to %dHz.\n", portc->speed); - - if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk(KERN_WARNING "waveartist: error setting the record " - "data path to 0x%X\n", 1); - - if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk(KERN_WARNING "waveartist: error setting the record " - "format to %d\n", portc->audio_format); - - devc->xfer_count = 0; - spin_unlock_irqrestore(&waveartist_lock, flags); - waveartist_halt_input(dev); - - if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n", - inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n", - inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n", - inb(devc->hw.io_base + IRQSTAT)); - } - - return 0; -} - -static int -waveartist_prepare_for_output(int dev, int bsize, int bcount) -{ - unsigned long flags; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned int speed, bits; - - /* - * program the speed, channels, bits - */ - speed = waveartist_get_speed(portc); - bits = waveartist_get_bits(portc); - - spin_lock_irqsave(&waveartist_lock, flags); - - if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && - waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk(KERN_WARNING "waveartist: error setting the playback " - "speed to %dHz.\n", portc->speed); - - if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk(KERN_WARNING "waveartist: error setting the playback " - "to %d channels\n", portc->channels); - - if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk(KERN_WARNING "waveartist: error setting the playback " - "data path to 0x%X\n", 0); - - if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk(KERN_WARNING "waveartist: error setting the playback " - "format to %d\n", portc->audio_format); - - devc->xfer_count = 0; - spin_unlock_irqrestore(&waveartist_lock, flags); - waveartist_halt_output(dev); - - if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); - } - - return 0; -} - -static void -waveartist_halt(int dev) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - struct wavnc_info *devc; - - if (portc->open_mode & OPEN_WRITE) - waveartist_halt_output(dev); - - if (portc->open_mode & OPEN_READ) - waveartist_halt_input(dev); - - devc = (struct wavnc_info *) audio_devs[dev]->devc; - devc->audio_mode = 0; -} - -static void -waveartist_halt_input(int dev) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&waveartist_lock, flags); - - /* - * Stop capture - */ - waveartist_cmd1(devc, WACMD_INPUTSTOP); - - devc->audio_mode &= ~PCM_ENABLE_INPUT; - - /* - * Clear interrupt by toggling - * the IRQ_ACK bit in CTRL - */ - if (inb(devc->hw.io_base + STATR) & IRQ_REQ) - waveartist_iack(devc); - -// devc->audio_mode &= ~PCM_ENABLE_INPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_halt_output(int dev) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&waveartist_lock, flags); - - waveartist_cmd1(devc, WACMD_OUTPUTSTOP); - - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - - /* - * Clear interrupt by toggling - * the IRQ_ACK bit in CTRL - */ - if (inb(devc->hw.io_base + STATR) & IRQ_REQ) - waveartist_iack(devc); - -// devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_trigger(int dev, int state) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned long flags; - - if (debug_flg & DEBUG_TRIGGER) { - printk("wavnc: audio trigger "); - if (state & PCM_ENABLE_INPUT) - printk("in "); - if (state & PCM_ENABLE_OUTPUT) - printk("out"); - printk("\n"); - } - - spin_lock_irqsave(&waveartist_lock, flags); - - state &= devc->audio_mode; - - if (portc->open_mode & OPEN_READ && - state & PCM_ENABLE_INPUT) - /* - * enable ADC Data Transfer to PC - */ - waveartist_cmd1(devc, WACMD_INPUTSTART); - - if (portc->open_mode & OPEN_WRITE && - state & PCM_ENABLE_OUTPUT) - /* - * enable DAC data transfer from PC - */ - waveartist_cmd1(devc, WACMD_OUTPUTSTART); - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static int -waveartist_set_speed(int dev, int arg) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - - if (arg <= 0) - return portc->speed; - - if (arg < 5000) - arg = 5000; - if (arg > 44100) - arg = 44100; - - portc->speed = arg; - return portc->speed; - -} - -static short -waveartist_set_channels(int dev, short arg) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - - if (arg != 1 && arg != 2) - return portc->channels; - - portc->channels = arg; - return arg; -} - -static unsigned int -waveartist_set_bits(int dev, unsigned int arg) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - - if (arg == 0) - return portc->audio_format; - - if ((arg != AFMT_U8) && (arg != AFMT_S16_LE) && (arg != AFMT_S8)) - arg = AFMT_U8; - - portc->audio_format = arg; - - return arg; -} - -static struct audio_driver waveartist_audio_driver = { - .owner = THIS_MODULE, - .open = waveartist_open, - .close = waveartist_close, - .output_block = waveartist_output_block, - .start_input = waveartist_start_input, - .ioctl = waveartist_ioctl, - .prepare_for_input = waveartist_prepare_for_input, - .prepare_for_output = waveartist_prepare_for_output, - .halt_io = waveartist_halt, - .halt_input = waveartist_halt_input, - .halt_output = waveartist_halt_output, - .trigger = waveartist_trigger, - .set_speed = waveartist_set_speed, - .set_bits = waveartist_set_bits, - .set_channels = waveartist_set_channels -}; - - -static irqreturn_t -waveartist_intr(int irq, void *dev_id) -{ - struct wavnc_info *devc = dev_id; - int irqstatus, status; - - spin_lock(&waveartist_lock); - irqstatus = inb(devc->hw.io_base + IRQSTAT); - status = inb(devc->hw.io_base + STATR); - - if (debug_flg & DEBUG_INTR) - printk("waveartist_intr: stat=%02x, irqstat=%02x\n", - status, irqstatus); - - if (status & IRQ_REQ) /* Clear interrupt */ - waveartist_iack(devc); - else - printk(KERN_WARNING "waveartist: unexpected interrupt\n"); - - if (irqstatus & 0x01) { - int temp = 1; - - /* PCM buffer done - */ - if ((status & DMA0) && (devc->audio_mode & PCM_ENABLE_OUTPUT)) { - DMAbuf_outputintr(devc->playback_dev, 1); - temp = 0; - } - if ((status & DMA1) && (devc->audio_mode & PCM_ENABLE_INPUT)) { - DMAbuf_inputintr(devc->record_dev); - temp = 0; - } - if (temp) //default: - printk(KERN_WARNING "waveartist: Unknown interrupt\n"); - } - if (irqstatus & 0x2) - // We do not use SB mode natively... - printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); - spin_unlock(&waveartist_lock); - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------------------- - * Mixer stuff - */ -struct mix_ent { - unsigned char reg_l; - unsigned char reg_r; - unsigned char shift; - unsigned char max; -}; - -static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = { - { 2, 6, 1, 7 }, /* SOUND_MIXER_VOLUME */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_BASS */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_TREBLE */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_SYNTH */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_PCM */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_SPEAKER */ - { 0, 4, 6, 31 }, /* SOUND_MIXER_LINE */ - { 2, 6, 4, 3 }, /* SOUND_MIXER_MIC */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_CD */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_IMIX */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_ALTPCM */ -#if 0 - { 3, 7, 0, 10 }, /* SOUND_MIXER_RECLEV */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_IGAIN */ -#else - { 0, 0, 0, 0 }, /* SOUND_MIXER_RECLEV */ - { 3, 7, 0, 7 }, /* SOUND_MIXER_IGAIN */ -#endif - { 0, 0, 0, 0 }, /* SOUND_MIXER_OGAIN */ - { 0, 4, 1, 31 }, /* SOUND_MIXER_LINE1 */ - { 1, 5, 6, 31 }, /* SOUND_MIXER_LINE2 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_LINE3 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL1 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL2 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL3 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEIN */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEOUT */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_VIDEO */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_RADIO */ - { 0, 0, 0, 0 } /* SOUND_MIXER_MONITOR */ -}; - -static void -waveartist_mixer_update(struct wavnc_info *devc, int whichDev) -{ - unsigned int lev_left, lev_right; - - lev_left = devc->levels[whichDev] & 0xff; - lev_right = devc->levels[whichDev] >> 8; - - if (lev_left > 100) - lev_left = 100; - if (lev_right > 100) - lev_right = 100; - -#define SCALE(lev,max) ((lev) * (max) / 100) - - if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT) - whichDev = SOUND_MIXER_VOLUME; - - if (mix_devs[whichDev].reg_l || mix_devs[whichDev].reg_r) { - const struct mix_ent *mix = mix_devs + whichDev; - unsigned int mask, left, right; - - mask = mix->max << mix->shift; - lev_left = SCALE(lev_left, mix->max) << mix->shift; - lev_right = SCALE(lev_right, mix->max) << mix->shift; - - /* read left setting */ - left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | - mix->reg_l << 8); - - /* read right setting */ - right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | - mix->reg_r << 8); - - left = (left & ~mask) | (lev_left & mask); - right = (right & ~mask) | (lev_right & mask); - - /* write left,right back */ - waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); - } else { - switch(whichDev) { - case SOUND_MIXER_PCM: - waveartist_cmd3(devc, WACMD_SET_LEVEL, - SCALE(lev_left, 32767), - SCALE(lev_right, 32767)); - break; - - case SOUND_MIXER_SYNTH: - waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL, - SCALE(lev_left, 32767), - SCALE(lev_right, 32767)); - break; - } - } -} - -/* - * Set the ADC MUX to the specified values. We do NOT do any - * checking of the values passed, since we assume that the - * relevant *_select_input function has done that for us. - */ -static void -waveartist_set_adc_mux(struct wavnc_info *devc, char left_dev, - char right_dev) -{ - unsigned int reg_08, reg_09; - - reg_08 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0800); - reg_09 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0900); - - reg_08 = (reg_08 & ~0x3f) | right_dev << 3 | left_dev; - - waveartist_cmd3(devc, WACMD_SET_MIXER, reg_08, reg_09); -} - -/* - * Decode a recording mask into a mixer selection as follows: - * - * OSS Source WA Source Actual source - * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) - * SOUND_MASK_LINE Line Line in - * SOUND_MASK_LINE1 Aux 1 Aux 1 in - * SOUND_MASK_LINE2 Aux 2 Aux 2 in - * SOUND_MASK_MIC Mic Microphone - */ -static unsigned int -waveartist_select_input(struct wavnc_info *devc, unsigned int recmask, - unsigned char *dev_l, unsigned char *dev_r) -{ - unsigned int recdev = ADC_MUX_NONE; - - if (recmask & SOUND_MASK_IMIX) { - recmask = SOUND_MASK_IMIX; - recdev = ADC_MUX_MIXER; - } else if (recmask & SOUND_MASK_LINE2) { - recmask = SOUND_MASK_LINE2; - recdev = ADC_MUX_AUX2; - } else if (recmask & SOUND_MASK_LINE1) { - recmask = SOUND_MASK_LINE1; - recdev = ADC_MUX_AUX1; - } else if (recmask & SOUND_MASK_LINE) { - recmask = SOUND_MASK_LINE; - recdev = ADC_MUX_LINE; - } else if (recmask & SOUND_MASK_MIC) { - recmask = SOUND_MASK_MIC; - recdev = ADC_MUX_MIC; - } - - *dev_l = *dev_r = recdev; - - return recmask; -} - -static int -waveartist_decode_mixer(struct wavnc_info *devc, int dev, - unsigned char lev_l, - unsigned char lev_r) -{ - switch (dev) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_SYNTH: - case SOUND_MIXER_PCM: - case SOUND_MIXER_LINE: - case SOUND_MIXER_MIC: - case SOUND_MIXER_IGAIN: - case SOUND_MIXER_LINE1: - case SOUND_MIXER_LINE2: - devc->levels[dev] = lev_l | lev_r << 8; - break; - - case SOUND_MIXER_IMIX: - break; - - default: - dev = -EINVAL; - break; - } - - return dev; -} - -static int waveartist_get_mixer(struct wavnc_info *devc, int dev) -{ - return devc->levels[dev]; -} - -static const struct waveartist_mixer_info waveartist_mixer = { - .supported_devs = SUPPORTED_MIXER_DEVICES | SOUND_MASK_IGAIN, - .recording_devs = SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | - SOUND_MASK_IMIX, - .stereo_devs = (SUPPORTED_MIXER_DEVICES | SOUND_MASK_IGAIN) & ~ - (SOUND_MASK_SPEAKER | SOUND_MASK_IMIX), - .select_input = waveartist_select_input, - .decode_mixer = waveartist_decode_mixer, - .get_mixer = waveartist_get_mixer, -}; - -static void -waveartist_set_recmask(struct wavnc_info *devc, unsigned int recmask) -{ - unsigned char dev_l, dev_r; - - recmask &= devc->mix->recording_devs; - - /* - * If more than one recording device selected, - * disable the device that is currently in use. - */ - if (hweight32(recmask) > 1) - recmask &= ~devc->recmask; - - /* - * Translate the recording device mask into - * the ADC multiplexer settings. - */ - devc->recmask = devc->mix->select_input(devc, recmask, - &dev_l, &dev_r); - - waveartist_set_adc_mux(devc, dev_l, dev_r); -} - -static int -waveartist_set_mixer(struct wavnc_info *devc, int dev, unsigned int level) -{ - unsigned int lev_left = level & 0x00ff; - unsigned int lev_right = (level & 0xff00) >> 8; - - if (lev_left > 100) - lev_left = 100; - if (lev_right > 100) - lev_right = 100; - - /* - * Mono devices have their right volume forced to their - * left volume. (from ALSA driver OSS emulation). - */ - if (!(devc->mix->stereo_devs & (1 << dev))) - lev_right = lev_left; - - dev = devc->mix->decode_mixer(devc, dev, lev_left, lev_right); - - if (dev >= 0) - waveartist_mixer_update(devc, dev); - - return dev < 0 ? dev : 0; -} - -static int -waveartist_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; - int ret = 0, val, nr; - - /* - * All SOUND_MIXER_* ioctls use type 'M' - */ - if (((cmd >> 8) & 255) != 'M') - return -ENOIOCTLCMD; - -#ifdef CONFIG_ARCH_NETWINDER - if (machine_is_netwinder()) { - ret = vnc_private_ioctl(dev, cmd, arg); - if (ret != -ENOIOCTLCMD) - return ret; - else - ret = 0; - } -#endif - - nr = cmd & 0xff; - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - if (get_user(val, (int __user *)arg)) - return -EFAULT; - - switch (nr) { - case SOUND_MIXER_RECSRC: - waveartist_set_recmask(devc, val); - break; - - default: - ret = -EINVAL; - if (nr < SOUND_MIXER_NRDEVICES && - devc->mix->supported_devs & (1 << nr)) - ret = waveartist_set_mixer(devc, nr, val); - } - } - - if (ret == 0 && _SIOC_DIR(cmd) & _SIOC_READ) { - ret = -EINVAL; - - switch (nr) { - case SOUND_MIXER_RECSRC: - ret = devc->recmask; - break; - - case SOUND_MIXER_DEVMASK: - ret = devc->mix->supported_devs; - break; - - case SOUND_MIXER_STEREODEVS: - ret = devc->mix->stereo_devs; - break; - - case SOUND_MIXER_RECMASK: - ret = devc->mix->recording_devs; - break; - - case SOUND_MIXER_CAPS: - ret = SOUND_CAP_EXCL_INPUT; - break; - - default: - if (nr < SOUND_MIXER_NRDEVICES) - ret = devc->mix->get_mixer(devc, nr); - break; - } - - if (ret >= 0) - ret = put_user(ret, (int __user *)arg) ? -EFAULT : 0; - } - - return ret; -} - -static struct mixer_operations waveartist_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "WaveArtist", - .name = "WaveArtist", - .ioctl = waveartist_mixer_ioctl -}; - -static void -waveartist_mixer_reset(struct wavnc_info *devc) -{ - int i; - - if (debug_flg & DEBUG_MIXER) - printk("%s: mixer_reset\n", devc->hw.name); - - /* - * reset mixer cmd - */ - waveartist_cmd1(devc, WACMD_RST_MIXER); - - /* - * set input for ADC to come from 'quiet' - * turn on default modes - */ - waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836); - - /* - * set mixer input select to none, RX filter gains 0 dB - */ - waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00); - - /* - * set bit 0 reg 2 to 1 - unmute MonoOut - */ - waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800); - - /* set default input device = internal mic - * current recording device = none - */ - waveartist_set_recmask(devc, 0); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - waveartist_mixer_update(devc, i); -} - -static int __init waveartist_init(struct wavnc_info *devc) -{ - struct wavnc_port_info *portc; - char rev[3], dev_name[64]; - int my_dev; - - if (waveartist_reset(devc)) - return -ENODEV; - - sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name); - - if (waveartist_getrev(devc, rev)) { - strcat(dev_name, " rev. "); - strcat(dev_name, rev); - } - strcat(dev_name, ")"); - - conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, - devc->hw.dma, devc->hw.dma2); - - portc = kzalloc(sizeof(struct wavnc_port_info), GFP_KERNEL); - if (portc == NULL) - goto nomem; - - my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, - &waveartist_audio_driver, sizeof(struct audio_driver), - devc->audio_flags, AFMT_U8 | AFMT_S16_LE | AFMT_S8, - devc, devc->hw.dma, devc->hw.dma2); - - if (my_dev < 0) - goto free; - - audio_devs[my_dev]->portc = portc; - - waveartist_mixer_reset(devc); - - /* - * clear any pending interrupt - */ - waveartist_iack(devc); - - if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { - printk(KERN_ERR "%s: IRQ %d in use\n", - devc->hw.name, devc->hw.irq); - goto uninstall; - } - - if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { - printk(KERN_ERR "%s: Can't allocate DMA%d\n", - devc->hw.name, devc->hw.dma); - goto uninstall_irq; - } - - if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) - if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { - printk(KERN_ERR "%s: can't allocate DMA%d\n", - devc->hw.name, devc->hw.dma2); - goto uninstall_dma; - } - - waveartist_set_ctlr(&devc->hw, 0, DMA1_IE | DMA0_IE); - - audio_devs[my_dev]->mixer_dev = - sound_install_mixer(MIXER_DRIVER_VERSION, - dev_name, - &waveartist_mixer_operations, - sizeof(struct mixer_operations), - devc); - - return my_dev; - -uninstall_dma: - sound_free_dma(devc->hw.dma); - -uninstall_irq: - free_irq(devc->hw.irq, devc); - -uninstall: - sound_unload_audiodev(my_dev); - -free: - kfree(portc); - -nomem: - return -1; -} - -static int __init probe_waveartist(struct address_info *hw_config) -{ - struct wavnc_info *devc = &adev_info[nr_waveartist_devs]; - - if (nr_waveartist_devs >= MAX_AUDIO_DEV) { - printk(KERN_WARNING "waveartist: too many audio devices\n"); - return 0; - } - - if (!request_region(hw_config->io_base, 15, hw_config->name)) { - printk(KERN_WARNING "WaveArtist: I/O port conflict\n"); - return 0; - } - - if (hw_config->irq > 15 || hw_config->irq < 0) { - release_region(hw_config->io_base, 15); - printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n", - hw_config->irq); - return 0; - } - - if (hw_config->dma != 3) { - release_region(hw_config->io_base, 15); - printk(KERN_WARNING "WaveArtist: Bad DMA %d\n", - hw_config->dma); - return 0; - } - - hw_config->name = "WaveArtist"; - devc->hw = *hw_config; - devc->open_mode = 0; - devc->chip_name = "RWA-010"; - - return 1; -} - -static void __init -attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix) -{ - struct wavnc_info *devc = &adev_info[nr_waveartist_devs]; - - /* - * 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). - */ - devc->hw = *hw; - devc->hw.irq = (hw->irq > 0) ? hw->irq : 0; - devc->open_mode = 0; - devc->playback_dev = 0; - devc->record_dev = 0; - devc->audio_flags = DMA_AUTOMODE; - devc->levels = levels; - - if (hw->dma != hw->dma2 && hw->dma2 != NO_DMA) - devc->audio_flags |= DMA_DUPLEX; - - devc->mix = mix; - devc->dev_no = waveartist_init(devc); - - if (devc->dev_no < 0) - release_region(hw->io_base, 15); - else { -#ifdef CONFIG_ARCH_NETWINDER - if (machine_is_netwinder()) { - setup_timer(&vnc_timer, vnc_slider_tick, - nr_waveartist_devs); - mod_timer(&vnc_timer, jiffies); - - vnc_configure_mixer(devc, 0); - - devc->no_autoselect = 1; - } -#endif - nr_waveartist_devs += 1; - } -} - -static void __exit unload_waveartist(struct address_info *hw) -{ - struct wavnc_info *devc = NULL; - int i; - - for (i = 0; i < nr_waveartist_devs; i++) - if (hw->io_base == adev_info[i].hw.io_base) { - devc = adev_info + i; - break; - } - - if (devc != NULL) { - int mixer; - -#ifdef CONFIG_ARCH_NETWINDER - if (machine_is_netwinder()) - del_timer(&vnc_timer); -#endif - - release_region(devc->hw.io_base, 15); - - waveartist_set_ctlr(&devc->hw, DMA1_IE|DMA0_IE, 0); - - if (devc->hw.irq >= 0) - free_irq(devc->hw.irq, devc); - - sound_free_dma(devc->hw.dma); - - if (devc->hw.dma != devc->hw.dma2 && - devc->hw.dma2 != NO_DMA) - sound_free_dma(devc->hw.dma2); - - mixer = audio_devs[devc->dev_no]->mixer_dev; - - if (mixer >= 0) - sound_unload_mixerdev(mixer); - - if (devc->dev_no >= 0) - sound_unload_audiodev(devc->dev_no); - - nr_waveartist_devs -= 1; - - for (; i < nr_waveartist_devs; i++) - adev_info[i] = adev_info[i + 1]; - } else - printk(KERN_WARNING "waveartist: can't find device " - "to unload\n"); -} - -#ifdef CONFIG_ARCH_NETWINDER - -/* - * Rebel.com Netwinder specifics... - */ - -#include <asm/hardware/dec21285.h> - -#define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec - -#define MIXER_PRIVATE3_RESET 0x53570000 -#define MIXER_PRIVATE3_READ 0x53570001 -#define MIXER_PRIVATE3_WRITE 0x53570002 - -#define VNC_MUTE_INTERNAL_SPKR 0x01 //the sw mute on/off control bit -#define VNC_MUTE_LINE_OUT 0x10 -#define VNC_PHONE_DETECT 0x20 -#define VNC_HANDSET_DETECT 0x40 -#define VNC_DISABLE_AUTOSWITCH 0x80 - -static inline void -vnc_mute_spkr(struct wavnc_info *devc) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&nw_gpio_lock, flags); - nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE); - raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); -} - -static void -vnc_mute_lout(struct wavnc_info *devc) -{ - unsigned int left, right; - - left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL); - right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x400); - - if (devc->line_mute_state) { - left &= ~1; - right &= ~1; - } else { - left |= 1; - right |= 1; - } - waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); - -} - -static int -vnc_volume_slider(struct wavnc_info *devc) -{ - static signed int old_slider_volume; - unsigned long flags; - signed int volume = 255; - - *CSR_TIMER1_LOAD = 0x00ffffff; - - spin_lock_irqsave(&waveartist_lock, flags); - - outb(0xFF, 0x201); - *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; - - while (volume && (inb(0x201) & 0x01)) - volume--; - - *CSR_TIMER1_CNTL = 0; - - spin_unlock_irqrestore(&waveartist_lock,flags); - - volume = 0x00ffffff - *CSR_TIMER1_VALUE; - - -#ifndef REVERSE - volume = 150 - (volume >> 5); -#else - volume = (volume >> 6) - 25; -#endif - - if (volume < 0) - volume = 0; - - if (volume > 100) - volume = 100; - - /* - * slider quite often reads +-8, so debounce this random noise - */ - if (abs(volume - old_slider_volume) > 7) { - old_slider_volume = volume; - - if (debug_flg & DEBUG_MIXER) - printk(KERN_DEBUG "Slider volume: %d.\n", volume); - } - - return old_slider_volume; -} - -/* - * Decode a recording mask into a mixer selection on the NetWinder - * as follows: - * - * OSS Source WA Source Actual source - * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) - * SOUND_MASK_LINE Line Line in - * SOUND_MASK_LINE1 Left Mic Handset - * SOUND_MASK_PHONEIN Left Aux Telephone microphone - * SOUND_MASK_MIC Right Mic Builtin microphone - */ -static unsigned int -netwinder_select_input(struct wavnc_info *devc, unsigned int recmask, - unsigned char *dev_l, unsigned char *dev_r) -{ - unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE; - - if (recmask & SOUND_MASK_IMIX) { - recmask = SOUND_MASK_IMIX; - recdev_l = ADC_MUX_MIXER; - recdev_r = ADC_MUX_MIXER; - } else if (recmask & SOUND_MASK_LINE) { - recmask = SOUND_MASK_LINE; - recdev_l = ADC_MUX_LINE; - recdev_r = ADC_MUX_LINE; - } else if (recmask & SOUND_MASK_LINE1) { - recmask = SOUND_MASK_LINE1; - waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ - recdev_l = ADC_MUX_MIC; - recdev_r = ADC_MUX_NONE; - } else if (recmask & SOUND_MASK_PHONEIN) { - recmask = SOUND_MASK_PHONEIN; - waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ - recdev_l = ADC_MUX_AUX1; - recdev_r = ADC_MUX_NONE; - } else if (recmask & SOUND_MASK_MIC) { - recmask = SOUND_MASK_MIC; - waveartist_cmd1(devc, WACMD_SET_MONO | 0x100); /* right */ - recdev_l = ADC_MUX_NONE; - recdev_r = ADC_MUX_MIC; - } - - *dev_l = recdev_l; - *dev_r = recdev_r; - - return recmask; -} - -static int -netwinder_decode_mixer(struct wavnc_info *devc, int dev, unsigned char lev_l, - unsigned char lev_r) -{ - switch (dev) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_SYNTH: - case SOUND_MIXER_PCM: - case SOUND_MIXER_LINE: - case SOUND_MIXER_IGAIN: - devc->levels[dev] = lev_l | lev_r << 8; - break; - - case SOUND_MIXER_MIC: /* right mic only */ - devc->levels[SOUND_MIXER_MIC] &= 0xff; - devc->levels[SOUND_MIXER_MIC] |= lev_l << 8; - break; - - case SOUND_MIXER_LINE1: /* left mic only */ - devc->levels[SOUND_MIXER_MIC] &= 0xff00; - devc->levels[SOUND_MIXER_MIC] |= lev_l; - dev = SOUND_MIXER_MIC; - break; - - case SOUND_MIXER_PHONEIN: /* left aux only */ - devc->levels[SOUND_MIXER_LINE1] = lev_l; - dev = SOUND_MIXER_LINE1; - break; - - case SOUND_MIXER_IMIX: - case SOUND_MIXER_PHONEOUT: - break; - - default: - dev = -EINVAL; - break; - } - return dev; -} - -static int netwinder_get_mixer(struct wavnc_info *devc, int dev) -{ - int levels; - - switch (dev) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_SYNTH: - case SOUND_MIXER_PCM: - case SOUND_MIXER_LINE: - case SOUND_MIXER_IGAIN: - levels = devc->levels[dev]; - break; - - case SOUND_MIXER_MIC: /* builtin mic: right mic only */ - levels = devc->levels[SOUND_MIXER_MIC] >> 8; - levels |= levels << 8; - break; - - case SOUND_MIXER_LINE1: /* handset mic: left mic only */ - levels = devc->levels[SOUND_MIXER_MIC] & 0xff; - levels |= levels << 8; - break; - - case SOUND_MIXER_PHONEIN: /* phone mic: left aux1 only */ - levels = devc->levels[SOUND_MIXER_LINE1] & 0xff; - levels |= levels << 8; - break; - - default: - levels = 0; - } - - return levels; -} - -/* - * Waveartist specific mixer information. - */ -static const struct waveartist_mixer_info netwinder_mixer = { - .supported_devs = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | - SOUND_MASK_PCM | SOUND_MASK_SPEAKER | - SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_IMIX | SOUND_MASK_LINE1 | - SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT| - SOUND_MASK_IGAIN, - - .recording_devs = SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_IMIX | SOUND_MASK_LINE1 | - SOUND_MASK_PHONEIN, - - .stereo_devs = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | - SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_IMIX | SOUND_MASK_IGAIN, - - .select_input = netwinder_select_input, - .decode_mixer = netwinder_decode_mixer, - .get_mixer = netwinder_get_mixer, -}; - -static void -vnc_configure_mixer(struct wavnc_info *devc, unsigned int recmask) -{ - if (!devc->no_autoselect) { - if (devc->handset_detect) { - recmask = SOUND_MASK_LINE1; - devc->spkr_mute_state = devc->line_mute_state = 1; - } else if (devc->telephone_detect) { - recmask = SOUND_MASK_PHONEIN; - devc->spkr_mute_state = devc->line_mute_state = 1; - } else { - /* unless someone has asked for LINE-IN, - * we default to MIC - */ - if ((devc->recmask & SOUND_MASK_LINE) == 0) - devc->recmask = SOUND_MASK_MIC; - devc->spkr_mute_state = devc->line_mute_state = 0; - } - vnc_mute_spkr(devc); - vnc_mute_lout(devc); - - if (recmask != devc->recmask) - waveartist_set_recmask(devc, recmask); - } -} - -static int -vnc_slider(struct wavnc_info *devc) -{ - signed int slider_volume; - unsigned int temp, old_hs, old_td; - - /* - * read the "buttons" state. - * Bit 4 = 0 means handset present - * Bit 5 = 1 means phone offhook - */ - temp = inb(0x201); - - old_hs = devc->handset_detect; - old_td = devc->telephone_detect; - - devc->handset_detect = !(temp & 0x10); - devc->telephone_detect = !!(temp & 0x20); - - if (!devc->no_autoselect && - (old_hs != devc->handset_detect || - old_td != devc->telephone_detect)) - vnc_configure_mixer(devc, devc->recmask); - - slider_volume = vnc_volume_slider(devc); - - /* - * If we're using software controlled volume, and - * the slider moves by more than 20%, then we - * switch back to slider controlled volume. - */ - if (abs(devc->slider_vol - slider_volume) > 20) - devc->use_slider = 1; - - /* - * use only left channel - */ - temp = levels[SOUND_MIXER_VOLUME] & 0xFF; - - if (slider_volume != temp && devc->use_slider) { - devc->slider_vol = slider_volume; - - waveartist_set_mixer(devc, SOUND_MIXER_VOLUME, - slider_volume | slider_volume << 8); - - return 1; - } - - return 0; -} - -static void -vnc_slider_tick(unsigned long data) -{ - int next_timeout; - - if (vnc_slider(adev_info + data)) - next_timeout = 5; // mixer reported change - else - next_timeout = VNC_TIMER_PERIOD; - - mod_timer(&vnc_timer, jiffies + next_timeout); -} - -static int -vnc_private_ioctl(int dev, unsigned int cmd, int __user * arg) -{ - struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; - int val; - - switch (cmd) { - case SOUND_MIXER_PRIVATE1: - { - u_int prev_spkr_mute, prev_line_mute, prev_auto_state; - int val; - - if (get_user(val, arg)) - return -EFAULT; - - /* check if parameter is logical */ - if (val & ~(VNC_MUTE_INTERNAL_SPKR | - VNC_MUTE_LINE_OUT | - VNC_DISABLE_AUTOSWITCH)) - return -EINVAL; - - prev_auto_state = devc->no_autoselect; - prev_spkr_mute = devc->spkr_mute_state; - prev_line_mute = devc->line_mute_state; - - devc->no_autoselect = (val & VNC_DISABLE_AUTOSWITCH) ? 1 : 0; - devc->spkr_mute_state = (val & VNC_MUTE_INTERNAL_SPKR) ? 1 : 0; - devc->line_mute_state = (val & VNC_MUTE_LINE_OUT) ? 1 : 0; - - if (prev_spkr_mute != devc->spkr_mute_state) - vnc_mute_spkr(devc); - - if (prev_line_mute != devc->line_mute_state) - vnc_mute_lout(devc); - - if (prev_auto_state != devc->no_autoselect) - vnc_configure_mixer(devc, devc->recmask); - - return 0; - } - - case SOUND_MIXER_PRIVATE2: - if (get_user(val, arg)) - return -EFAULT; - - switch (val) { -#define VNC_SOUND_PAUSE 0x53 //to pause the DSP -#define VNC_SOUND_RESUME 0x57 //to unpause the DSP - case VNC_SOUND_PAUSE: - waveartist_cmd1(devc, 0x16); - break; - - case VNC_SOUND_RESUME: - waveartist_cmd1(devc, 0x18); - break; - - default: - return -EINVAL; - } - return 0; - - /* private ioctl to allow bulk access to waveartist */ - case SOUND_MIXER_PRIVATE3: - { - unsigned long flags; - int mixer_reg[15], i, val; - - if (get_user(val, arg)) - return -EFAULT; - if (copy_from_user(mixer_reg, (void *)val, sizeof(mixer_reg))) - return -EFAULT; - - switch (mixer_reg[14]) { - case MIXER_PRIVATE3_RESET: - waveartist_mixer_reset(devc); - break; - - case MIXER_PRIVATE3_WRITE: - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[0], mixer_reg[4]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[1], mixer_reg[5]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[2], mixer_reg[6]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[3], mixer_reg[7]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[8], mixer_reg[9]); - - waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[10], mixer_reg[11]); - waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[12], mixer_reg[13]); - break; - - case MIXER_PRIVATE3_READ: - spin_lock_irqsave(&waveartist_lock, flags); - - for (i = 0x30; i < 14 << 8; i += 1 << 8) - waveartist_cmd(devc, 1, &i, 1, mixer_reg + (i >> 8)); - - spin_unlock_irqrestore(&waveartist_lock, flags); - - if (copy_to_user((void *)val, mixer_reg, sizeof(mixer_reg))) - return -EFAULT; - break; - - default: - return -EINVAL; - } - return 0; - } - - /* read back the state from PRIVATE1 */ - case SOUND_MIXER_PRIVATE4: - val = (devc->spkr_mute_state ? VNC_MUTE_INTERNAL_SPKR : 0) | - (devc->line_mute_state ? VNC_MUTE_LINE_OUT : 0) | - (devc->handset_detect ? VNC_HANDSET_DETECT : 0) | - (devc->telephone_detect ? VNC_PHONE_DETECT : 0) | - (devc->no_autoselect ? VNC_DISABLE_AUTOSWITCH : 0); - - return put_user(val, arg) ? -EFAULT : 0; - } - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - /* - * special case for master volume: if we - * received this call - switch from hw - * volume control to a software volume - * control, till the hw volume is modified - * to signal that user wants to be back in - * hardware... - */ - if ((cmd & 0xff) == SOUND_MIXER_VOLUME) - devc->use_slider = 0; - - /* speaker output */ - if ((cmd & 0xff) == SOUND_MIXER_SPEAKER) { - unsigned int val, l, r; - - if (get_user(val, arg)) - return -EFAULT; - - l = val & 0x7f; - r = (val & 0x7f00) >> 8; - val = (l + r) / 2; - devc->levels[SOUND_MIXER_SPEAKER] = val | (val << 8); - devc->spkr_mute_state = (val <= 50); - vnc_mute_spkr(devc); - return 0; - } - } - - return -ENOIOCTLCMD; -} - -#endif - -static struct address_info cfg; - -static int attached; - -static int __initdata io = 0; -static int __initdata irq = 0; -static int __initdata dma = 0; -static int __initdata dma2 = 0; - - -static int __init init_waveartist(void) -{ - const struct waveartist_mixer_info *mix; - - if (!io && machine_is_netwinder()) { - /* - * The NetWinder WaveArtist is at a fixed address. - * If the user does not supply an address, use the - * well-known parameters. - */ - io = 0x250; - irq = 12; - dma = 3; - dma2 = 7; - } - - mix = &waveartist_mixer; -#ifdef CONFIG_ARCH_NETWINDER - if (machine_is_netwinder()) - mix = &netwinder_mixer; -#endif - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - if (!probe_waveartist(&cfg)) - return -ENODEV; - - attach_waveartist(&cfg, mix); - attached = 1; - - return 0; -} - -static void __exit cleanup_waveartist(void) -{ - if (attached) - unload_waveartist(&cfg); -} - -module_init(init_waveartist); -module_exit(cleanup_waveartist); - -#ifndef MODULE -static int __init setup_waveartist(char *str) -{ - /* io, irq, dma, dma2 */ - int ints[5]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - - return 1; -} -__setup("waveartist=", setup_waveartist); -#endif - -MODULE_DESCRIPTION("Rockwell WaveArtist RWA-010 sound driver"); -module_param_hw(io, int, ioport, 0); /* IO base */ -module_param_hw(irq, int, irq, 0); /* IRQ */ -module_param_hw(dma, int, dma, 0); /* DMA */ -module_param_hw(dma2, int, dma, 0); /* DMA2 */ -MODULE_LICENSE("GPL"); diff --git a/sound/oss/waveartist.h b/sound/oss/waveartist.h deleted file mode 100644 index dac4ca910d95..000000000000 --- a/sound/oss/waveartist.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * linux/sound/oss/waveartist.h - * - * def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder - */ - -//registers -#define CMDR 0 -#define DATR 2 -#define CTLR 4 -#define STATR 5 -#define IRQSTAT 12 - -//bit defs -//reg STATR -#define CMD_WE 0x80 -#define CMD_RF 0x40 -#define DAT_WE 0x20 -#define DAT_RF 0x10 - -#define IRQ_REQ 0x08 -#define DMA1 0x04 -#define DMA0 0x02 - -//bit defs -//reg CTLR -#define CMD_WEIE 0x80 -#define CMD_RFIE 0x40 -#define DAT_WEIE 0x20 -#define DAT_RFIE 0x10 - -#define RESET 0x08 -#define DMA1_IE 0x04 -#define DMA0_IE 0x02 -#define IRQ_ACK 0x01 - -//commands - -#define WACMD_SYSTEMID 0x00 -#define WACMD_GETREV 0x00 -#define WACMD_INPUTFORMAT 0x10 //0-8S, 1-16S, 2-8U -#define WACMD_INPUTCHANNELS 0x11 //1-Mono, 2-Stereo -#define WACMD_INPUTSPEED 0x12 //sampling rate -#define WACMD_INPUTDMA 0x13 //0-8bit, 1-16bit, 2-PIO -#define WACMD_INPUTSIZE 0x14 //samples to interrupt -#define WACMD_INPUTSTART 0x15 //start ADC -#define WACMD_INPUTPAUSE 0x16 //pause ADC -#define WACMD_INPUTSTOP 0x17 //stop ADC -#define WACMD_INPUTRESUME 0x18 //resume ADC -#define WACMD_INPUTPIO 0x19 //PIO ADC - -#define WACMD_OUTPUTFORMAT 0x20 //0-8S, 1-16S, 2-8U -#define WACMD_OUTPUTCHANNELS 0x21 //1-Mono, 2-Stereo -#define WACMD_OUTPUTSPEED 0x22 //sampling rate -#define WACMD_OUTPUTDMA 0x23 //0-8bit, 1-16bit, 2-PIO -#define WACMD_OUTPUTSIZE 0x24 //samples to interrupt -#define WACMD_OUTPUTSTART 0x25 //start ADC -#define WACMD_OUTPUTPAUSE 0x26 //pause ADC -#define WACMD_OUTPUTSTOP 0x27 //stop ADC -#define WACMD_OUTPUTRESUME 0x28 //resume ADC -#define WACMD_OUTPUTPIO 0x29 //PIO ADC - -#define WACMD_GET_LEVEL 0x30 -#define WACMD_SET_LEVEL 0x31 -#define WACMD_SET_MIXER 0x32 -#define WACMD_RST_MIXER 0x33 -#define WACMD_SET_MONO 0x34 - -/* - * Definitions for left/right recording input mux - */ -#define ADC_MUX_NONE 0 -#define ADC_MUX_MIXER 1 -#define ADC_MUX_LINE 2 -#define ADC_MUX_AUX2 3 -#define ADC_MUX_AUX1 4 -#define ADC_MUX_MIC 5 - -/* - * Definitions for mixer gain settings - */ -#define MIX_GAIN_LINE 0 /* line in */ -#define MIX_GAIN_AUX1 1 /* aux1 */ -#define MIX_GAIN_AUX2 2 /* aux2 */ -#define MIX_GAIN_XMIC 3 /* crossover mic */ -#define MIX_GAIN_MIC 4 /* normal mic */ -#define MIX_GAIN_PREMIC 5 /* preamp mic */ -#define MIX_GAIN_OUT 6 /* output */ -#define MIX_GAIN_MONO 7 /* mono in */ - -int wa_sendcmd(unsigned int cmd); -int wa_writecmd(unsigned int cmd, unsigned int arg); |