mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 15:44:13 +08:00
sound: Retire OSS
Since no complaints have been raised after disabling the build of OSS
(Open Sound System) by the commit 31cbee6a56
("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>
This commit is contained in:
parent
3f1185d6c9
commit
727dede0ba
@ -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.
|
@ -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
|
@ -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
|
@ -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.
|
||||
|
@ -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
|
@ -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)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
@ -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/
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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.
|
@ -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>
|
||||
|
@ -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.
|
@ -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)".
|
@ -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.
|
@ -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! ;)
|
||||
|
||||
|
@ -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)
|
@ -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>
|
@ -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)
|
||||
_/ _/_/_/_/
|
||||
_/
|
||||
_/ _/
|
||||
_/_/
|
||||
===========================================================
|
@ -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>
|
@ -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.
|
11
MAINTAINERS
11
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
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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.
|
@ -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
|
||||
|
@ -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
|
@ -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
|
3062
sound/oss/ad1848.c
3062
sound/oss/ad1848.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
@ -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
|
1373
sound/oss/aedsp16.c
1373
sound/oss/aedsp16.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
1268
sound/oss/dmabuf.c
1268
sound/oss/dmabuf.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
@ -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);
|
||||
|
@ -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
|
@ -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);
|
||||
|
1804
sound/oss/mpu401.c
1804
sound/oss/mpu401.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
413
sound/oss/msnd.c
413
sound/oss/msnd.c
@ -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
|
278
sound/oss/msnd.h
278
sound/oss/msnd.h
@ -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 */
|
@ -1,3 +0,0 @@
|
||||
/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */
|
||||
#define MSND_CLASSIC
|
||||
#include "msnd_pinnacle.c"
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
@ -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 */
|
1255
sound/oss/opl3.c
1255
sound/oss/opl3.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
*/
|
@ -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;
|
@ -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);
|
@ -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
|
@ -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 */
|
||||
}
|
@ -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;
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
1270
sound/oss/pss.c
1270
sound/oss/pss.c
File diff suppressed because it is too large
Load Diff
185
sound/oss/sb.h
185
sound/oss/sb.h
@ -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);
|
1097
sound/oss/sb_audio.c
1097
sound/oss/sb_audio.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
@ -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
|
File diff suppressed because it is too large
Load Diff
1822
sound/oss/sb_ess.c
1822
sound/oss/sb_ess.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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();
|
||||
}
|
@ -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--;
|
||||
}
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
@ -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);
|
@ -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
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -1,2 +0,0 @@
|
||||
#define SOUND_VERSION_STRING "3.8s2++-971130"
|
||||
#define SOUND_INTERNAL_VERSION 0x030804
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
};
|
525
sound/oss/trix.c
525
sound/oss/trix.c
@ -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");
|
@ -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
|
||||
};
|
@ -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");
|
@ -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");
|
@ -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,
|
||||
};
|
@ -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");
|
@ -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;
|
557
sound/oss/vidc.c
557
sound/oss/vidc.c
@ -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");
|
@ -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);
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
Loading…
Reference in New Issue
Block a user