more scheduled OSS driver removal

This patch contains the scheduled removal of OSS drivers that:
- have ALSA drivers for the same hardware without known regressions and
- whose Kconfig options have been removed in 2.6.20.

Signed-off-by: Adrian Bunk <bunk@stusta.de>
Acked-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Adrian Bunk 2007-07-15 23:39:01 -07:00 committed by Linus Torvalds
parent 786d7e1612
commit b5d425c97f
63 changed files with 4 additions and 31106 deletions

View file

@ -119,13 +119,6 @@ Who: Adrian Bunk <bunk@stusta.de>
---------------------------
What: drivers depending on OSS_OBSOLETE_DRIVER
When: options in 2.6.20, code in 2.6.22
Why: OSS drivers with ALSA replacements
Who: Adrian Bunk <bunk@stusta.de>
---------------------------
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.

View file

@ -238,16 +238,9 @@ and is between 256 and 4096 characters. It is defined in the file
Disable PIN 1 of APIC timer
Can be useful to work around chipset bugs.
ad1816= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2>
See also Documentation/sound/oss/AD1816.
ad1848= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2>,<type>
adlib= [HW,OSS]
Format: <io>
advansys= [HW,SCSI]
See header of drivers/scsi/advansys.c.
@ -1206,9 +1199,6 @@ and is between 256 and 4096 characters. It is defined in the file
opl3= [HW,OSS]
Format: <io>
opl3sa2= [HW,OSS] Format:
<io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
oprofile.timer= [HW]
Use timer interrupt instead of performance counters

View file

@ -1,84 +0,0 @@
Documentation for the AD1816(A) sound driver
============================================
Installation:
-------------
To get your AD1816(A) based sound card work, you'll have to enable support for
experimental code ("Prompt for development and/or incomplete code/drivers")
and isapnp ("Plug and Play support", "ISA Plug and Play support"). Enable
"Sound card support", "OSS modules support" and "Support for AD1816(A) based
cards (EXPERIMENTAL)" in the sound configuration menu, too. Now build, install
and reboot the new kernel as usual.
Features:
---------
List of features supported by this driver:
- full-duplex support
- supported audio formats: unsigned 8bit, signed 16bit little endian,
signed 16bit big endian, µ-law, A-law
- supported channels: mono and stereo
- supported recording sources: Master, CD, Line, Line1, Line2, Mic
- supports phat 3d stereo circuit (Line 3)
Supported cards:
----------------
The following cards are known to work with this driver:
- Terratec Base 1
- Terratec Base 64
- HP Kayak
- Acer FX-3D
- SY-1816
- Highscreen Sound-Boostar 32 Wave 3D
- Highscreen Sound-Boostar 16
- AVM Apex Pro card
- (Aztech SC-16 3D)
- (Newcom SC-16 3D)
- (Terratec EWS64S)
Cards listed in brackets are not supported reliable. If you have such a card
you should add the extra parameter:
options=1
when loading the ad1816 module via modprobe.
Troubleshooting:
----------------
First of all you should check, if the driver has been loaded
properly.
If loading of the driver succeeds, but playback/capture fails, check
if you used the correct values for irq, dma and dma2 when loading the module.
If one of them is wrong you usually get the following error message:
Nov 6 17:06:13 tek01 kernel: Sound: DMA (output) timed out - IRQ/DRQ config error?
If playback/capture is too fast or to slow, you should have a look at
the clock chip of your sound card. The AD1816 was designed for a 33MHz
oscillator, however most sound card manufacturer use slightly
different oscillators as they are cheaper than 33MHz oscillators. If
you have such a card you have to adjust the ad1816_clockfreq parameter
above. For example: For a card using a 32.875MHz oscillator use
ad1816_clockfreq=32875 instead of ad1816_clockfreq=33000.
Updates, bugfixes and bugreports:
--------------------------------
As the driver is still experimental and under development, you should
watch out for updates. Updates of the driver are available on the
Internet from one of my home pages:
http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
or:
http://www.tu-darmstadt.de/~tek01/projects/linux.html
Bugreports, bugfixes and related questions should be sent via E-Mail to:
tek@rbg.informatik.tu-darmstadt.de
Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
Christoph Hellwig <hch@infradead.org>
Last modified: 2000/09/20

View file

@ -1,280 +0,0 @@
=======================================================
Documentation for the NeoMagic 256AV/256ZX sound driver
=======================================================
You're looking at version 1.1 of the driver. (Woohoo!) It has been
successfully tested against the following laptop models:
Sony Z505S/Z505SX/Z505DX/Z505RX
Sony F150, F160, F180, F250, F270, F280, PCG-F26
Dell Latitude CPi, CPt (various submodels)
There are a few caveats, which is why you should read the entirety of
this document first.
This driver was developed without any support or assistance from
NeoMagic. There is no warranty, expressed, implied, or otherwise. It
is free software in the public domain; feel free to use it, sell it,
give it to your best friends, even claim that you wrote it (but why?!)
but don't go whining to me, NeoMagic, Sony, Dell, or anyone else
when it blows up your computer.
Version 1.1 contains a change to try and detect non-AC97 versions of
the hardware, and not install itself appropriately. It should also
reinitialize the hardware on an APM resume event, assuming that APM
was configured into your kernel.
============
Installation
============
Enable the sound drivers, the OSS sound drivers, and then the NM256
driver. The NM256 driver *must* be configured as a module (it won't
give you any other choice).
Next, do the usual "make modules" and "make modules_install".
Finally, insmod the soundcore, sound and nm256 modules.
When the nm256 driver module is loaded, you should see a couple of
confirmation messages in the kernel logfile indicating that it found
the device (the device does *not* use any I/O ports or DMA channels).
Now try playing a wav file, futz with the CD-ROM if you have one, etc.
The NM256 is entirely a PCI-based device, and all the necessary
information is automatically obtained from the card. It can only be
configured as a module in a vain attempt to prevent people from
hurting themselves. It works correctly if it shares an IRQ with
another device (it normally shares IRQ 9 with the builtin eepro100
ethernet on the Sony Z505 laptops).
It does not run the card in any sort of compatibility mode. It will
not work on laptops that have the SB16-compatible, AD1848-compatible
or CS4232-compatible codec/mixer; you will want to use the appropriate
compatible OSS driver with these chipsets. I cannot provide any
assistance with machines using the SB16, AD1848 or CS4232 compatible
versions. (The driver now attempts to detect the mixer version, and
will refuse to load if it believes the hardware is not
AC97-compatible.)
The sound support is very basic, but it does include simultaneous
playback and record capability. The mixer support is also quite
simple, although this is in keeping with the rather limited
functionality of the chipset.
There is no hardware synthesizer available, as the Losedows OPL-3 and
MIDI support is done via hardware emulation.
Only three recording devices are available on the Sony: the
microphone, the CD-ROM input, and the volume device (which corresponds
to the stereo output). (Other devices may be available on other
models of laptops.) The Z505 series does not have a builtin CD-ROM,
so of course the CD-ROM input doesn't work. It does work on laptops
with a builtin CD-ROM drive.
The mixer device does not appear to have any tone controls, at least
on the Z505 series. The mixer module checks for tone controls in the
AC97 mixer, and will enable them if they are available.
==============
Known problems
==============
* There are known problems with PCMCIA cards and the eepro100 ethernet
driver on the Z505S/Z505SX/Z505DX. Keep reading.
* There are also potential problems with using a virtual X display, and
also problems loading the module after the X server has been started.
Keep reading.
* The volume control isn't anywhere near linear. Sorry. This will be
fixed eventually, when I get sufficiently annoyed with it. (I doubt
it will ever be fixed now, since I've never gotten sufficiently
annoyed with it and nobody else seems to care.)
* There are reports that the CD-ROM volume is very low. Since I do not
have a CD-ROM equipped laptop, I cannot test this (it's kinda hard to
do remotely).
* Only 8 fixed-rate speeds are supported. This is mainly a chipset
limitation. It may be possible to support other speeds in the future.
* There is no support for the telephone mixer/codec. There is support
for a phonein/phoneout device in the mixer driver; whether or not
it does anything is anyone's guess. (Reports on this would be
appreciated. You'll have to figure out how to get the phone to
go off-hook before it'll work, tho.)
* This driver was not written with any cooperation or support from
NeoMagic. If you have any questions about this, see their website
for their official stance on supporting open source drivers.
============
Video memory
============
The NeoMagic sound engine uses a portion of the display memory to hold
the sound buffer. (Crazy, eh?) The NeoMagic video BIOS sets up a
special pointer at the top of video RAM to indicate where the top of
the audio buffer should be placed.
At the present time XFree86 is apparently not aware of this. It will
thus write over either the pointer or the sound buffer with abandon.
(Accelerated-X seems to do a better job here.)
This implies a few things:
* Sometimes the NM256 driver has to guess at where the buffer
should be placed, especially if the module is loaded after the
X server is started. It's usually correct, but it will consistently
fail on the Sony F250.
* Virtual screens greater than 1024x768x16 under XFree86 are
problematic on laptops with only 2.5MB of screen RAM. This
includes all of the 256AV-equipped laptops. (Virtual displays
may or may not work on the 256ZX, which has at least 4MB of
video RAM.)
If you start having problems with random noise being output either
constantly (this is the usual symptom on the F250), or when windows
are moved around (this is the usual symptom when using a virtual
screen), the best fix is to
* Don't use a virtual frame buffer.
* Make sure you load the NM256 module before the X server is
started.
On the F250, it is possible to force the driver to load properly even
after the XFree86 server is started by doing:
insmod nm256 buffertop=0x25a800
This forces the audio buffers to the correct offset in screen RAM.
One user has reported a similar problem on the Sony F270, although
others apparently aren't seeing any problems. His suggested command
is
insmod nm256 buffertop=0x272800
=================
Official WWW site
=================
The official site for the NM256 driver is:
http://www.uglx.org/sony.html
You should always be able to get the latest version of the driver there,
and the driver will be supported for the foreseeable future.
==============
Z505RX and IDE
==============
There appears to be a problem with the IDE chipset on the Z505RX; one
of the symptoms is that sound playback periodically hangs (when the
disk is accessed). The user reporting the problem also reported that
enabling all of the IDE chipset workarounds in the kernel solved the
problem, tho obviously only one of them should be needed--if someone
can give me more details I would appreciate it.
==============================
Z505S/Z505SX on-board Ethernet
==============================
If you're using the on-board Ethernet Pro/100 ethernet support on the Z505
series, I strongly encourage you to download the latest eepro100 driver from
Donald Becker's site:
ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/test/eepro100.c
There was a reported problem on the Z505SX that if the ethernet
interface is disabled and reenabled while the sound driver is loaded,
the machine would lock up. I have included a workaround that is
working satisfactorily. However, you may occasionally see a message
about "Releasing interrupts, over 1000 bad interrupts" which indicates
that the workaround is doing its job.
==================================
PCMCIA and the Z505S/Z505SX/Z505DX
==================================
There is also a known problem with the Sony Z505S and Z505SX hanging
if a PCMCIA card is inserted while the ethernet driver is loaded, or
in some cases if the laptop is suspended. This is caused by tons of
spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges.
There is currently no fix for the problem that works in every case.
The only known workarounds are to disable the ethernet interface
before inserting or removing a PCMCIA card, or with some cards
disabling the PCMCIA card before ejecting it will also help the
problem with the laptop hanging when the card is ejected.
One user has reported that setting the tcic's cs_irq to some value
other than 9 (like 11) fixed the problem. This doesn't work on my
Z505S, however--changing the value causes the cardmgr to stop seeing
card insertions and removals, cards don't seem to work correctly, and
I still get hangs if a card is inserted when the kernel is booted.
Using the latest ethernet driver and pcmcia package allows me to
insert an Adaptec 1480A SlimScsi card without the laptop hanging,
although I still have to shut down the card before ejecting or
powering down the laptop. However, similar experiments with a DE-660
ethernet card still result in hangs when the card is inserted. I am
beginning to think that the interrupts are CardBus-related, since the
Adaptec card is a CardBus card, and the DE-660 is not; however, I
don't have any other CardBus cards to test with.
======
Thanks
======
First, I want to thank everyone (except NeoMagic of course) for their
generous support and encouragement. I'd like to list everyone's name
here that replied during the development phase, but the list is
amazingly long.
I will be rather unfair and single out a few people, however:
Justin Maurer, for being the first random net.person to try it,
and for letting me login to his Z505SX to get it working there
Edi Weitz for trying out several different versions, and giving
me a lot of useful feedback
Greg Rumple for letting me login remotely to get the driver
functional on the 256ZX, for his assistance on tracking
down all sorts of random stuff, and for trying out Accel-X
Zach Brown, for the initial AC97 mixer interface design
Jeff Garzik, for various helpful suggestions on the AC97
interface
"Mr. Bumpy" for feedback on the Z505RX
Bill Nottingham, for generous assistance in getting the mixer ID
code working
=================
Previous versions
=================
Versions prior to 0.3 (aka `noname') had problems with weird artifacts
in the output and failed to set the recording rate properly. These
problems have long since been fixed.
Versions prior to 0.5 had problems with clicks in the output when
anything other than 16-bit stereo sound was being played, and also had
periodic clicks when recording.
Version 0.7 first incorporated support for the NM256ZX chipset, which
is found on some Dell Latitude laptops (the CPt, and apparently
some CPi models as well). It also included the generic AC97
mixer module.
Version 0.75 renamed all the functions and files with slightly more
generic names.
Note that previous versions of this document claimed that recording was
8-bit only; it actually has been working for 16-bits all along.

View file

@ -1,210 +0,0 @@
Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o)
---------------------------------------------------------------
Scott Murray, scott@spiteful.org
January 7, 2001
NOTE: All trade-marked terms mentioned below are properties of their
respective owners.
Supported Devices
-----------------
This driver is for PnP soundcards based on the following Yamaha audio
controller chipsets:
YMF711 aka OPL3-SA2
YMF715 and YMF719 aka OPL3-SA3
Up until recently (December 2000), I'd thought the 719 to be a
different chipset, the OPL3-SAx. After an email exhange with
Yamaha, however, it turns out that the 719 is just a re-badged
715, and the chipsets are identical. The chipset detection code
has been updated to reflect this.
Anyways, all of these chipsets implement the following devices:
OPL3 FM synthesizer
Soundblaster Pro
Microsoft/Windows Sound System
MPU401 MIDI interface
Note that this driver uses the MSS device, and to my knowledge these
chipsets enforce an either/or situation with the Soundblaster Pro
device and the MSS device. Since the MSS device has better
capabilities, I have implemented the driver to use it.
Mixer Channels
--------------
Older versions of this driver (pre-December 2000) had two mixers,
an OPL3-SA2 or SA3 mixer and a MSS mixer. The OPL3-SA[23] mixer
device contained a superset of mixer channels consisting of its own
channels and all of the MSS mixer channels. To simplify the driver
considerably, and to partition functionality better, the OPL3-SA[23]
mixer device now contains has its own specific mixer channels. They
are:
Volume - Hardware master volume control
Bass - SA3 only, now supports left and right channels
Treble - SA3 only, now supports left and right channels
Microphone - Hardware microphone input volume control
Digital1 - Yamaha 3D enhancement "Wide" mixer
All other mixer channels (e.g. "PCM", "CD", etc.) now have to be
controlled via the "MS Sound System (CS4231)" mixer. To facilitate
this, the mixer device creation order has been switched so that
the MSS mixer is created first. This allows accessing the majority
of the useful mixer channels even via single mixer-aware tools
such as "aumix".
Plug 'n Play
------------
In previous kernels (2.2.x), some configuration was required to
get the driver to talk to the card. Being the new millennium and
all, the 2.4.x kernels now support auto-configuration if ISA PnP
support is configured in. Theoretically, the driver even supports
having more than one card in this case.
With the addition of PnP support to the driver, two new parameters
have been added to control it:
isapnp - set to 0 to disable ISA PnP card detection
multiple - set to 0 to disable multiple PnP card detection
Optional Parameters
-------------------
Recent (December 2000) additions to the driver (based on a patch
provided by Peter Englmaier) are two new parameters:
ymode - Set Yamaha 3D enhancement mode:
0 = Desktop/Normal 5-12 cm speakers
1 = Notebook PC (1) 3 cm speakers
2 = Notebook PC (2) 1.5 cm speakers
3 = Hi-Fi 16-38 cm speakers
loopback - Set A/D input source. Useful for echo cancellation:
0 = Mic Right channel (default)
1 = Mono output loopback
The ymode parameter has been tested and does work. The loopback
parameter, however, is untested. Any feedback on its usefulness
would be appreciated.
Manual Configuration
--------------------
If for some reason you decide not to compile ISA PnP support into
your kernel, or disabled the driver's usage of it by setting the
isapnp parameter as discussed above, then you will need to do some
manual configuration. 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.
I personally use isapnp and modules, and do not have access to a PnP
BIOS machine to test. If you have such a beast, configuring the
driver to be built into the kernel should just work (thanks to work
done by David Luyer <luyer@ucs.uwa.edu.au>). You will still need
to specify settings, which can be done by adding:
opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>
to the kernel command line. For example:
opl3sa2=0x370,5,0,1,0x530,0x330
If you are instead using the isapnp tools (as most people have been
before Linux 2.4.x), follow the directions in their documentation to
produce a configuration file. Here is the relevant excerpt I used to
use for my SA3 card from my isapnp.conf:
(CONFIGURE YMH0800/-1 (LD 0
# NOTE: IO 0 is for the unused SoundBlaster part of the chipset.
(IO 0 (BASE 0x0220))
(IO 1 (BASE 0x0530))
(IO 2 (BASE 0x0388))
(IO 3 (BASE 0x0330))
(IO 4 (BASE 0x0370))
(INT 0 (IRQ 5 (MODE +E)))
(DMA 0 (CHANNEL 0))
(DMA 1 (CHANNEL 1))
Here, note that:
Port Acceptable Range Purpose
---- ---------------- -------
IO 0 0x0220 - 0x0280 SB base address, unused.
IO 1 0x0530 - 0x0F48 MSS base address
IO 2 0x0388 - 0x03F8 OPL3 base address
IO 3 0x0300 - 0x0334 MPU base address
IO 4 0x0100 - 0x0FFE card's own base address for its control I/O ports
The IRQ and DMA values can be any that are considered acceptable for a
MSS. Assuming you've got isapnp all happy, then you should be able to
do something like the following (which matches up with the isapnp
configuration above):
modprobe mpu401
modprobe ad1848
modprobe opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=5 dma=0 dma2=1
modprobe opl3 io=0x388
See the section "Automatic Module Loading" below for how to set up
/etc/modprobe.conf to automate this.
An important thing to remember that the opl3sa2 module's io argument is
for it's own control port, which handles the card's master mixer for
volume (on all cards), and bass and treble (on SA3 cards).
Troubleshooting
---------------
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 opl3sa2 module, 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 still cannot get the module to load, look at the contents of
your system log file, usually /var/log/messages. If you see the
message "opl3sa2: Unknown Yamaha audio controller version", then you
have a different chipset version than I've encountered so far. Look
for all messages in the log file that start with "opl3sa2: " and see
if they provide any clues. If you do not see the chipset version
message, and none of the other messages present in the system log are
helpful, email me some details and I'll try my best to help.
Automatic Module Loading
------------------------
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 modprobe.conf file:
# Sound
alias sound-slot-0 opl3sa2
options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
options opl3 io=0x388
That's all it currently takes to get an OPL3-SA3 card working on my
system. Once again, if you have any other problems, email me at the
address listed above.
Scott

View file

@ -1,43 +0,0 @@
Running sound cards on VIA chipsets
o There are problems with VIA chipsets and sound cards that appear to
lock the hardware solidly. Test programs under DOS have verified the
problem exists on at least some (but apparently not all) VIA boards
o VIA have so far failed to bother to answer support mail on the subject
so if you are a VIA engineer feeling aggrieved as you read this
document go chase your own people. If there is a workaround please
let us know so we can implement it.
Certain patterns of ISA DMA access used for most PC sound cards cause the
VIA chipsets to lock up. From the collected reports this appears to cover a
wide range of boards. Some also lock up with sound cards under Win* as well.
Linux implements a workaround providing your chipset is PCI and you compiled
with PCI Quirks enabled. If so you will see a message
"Activating ISA DMA bug workarounds"
during booting. If you have a VIA PCI chipset that hangs when you use the
sound and is not generating this message even with PCI quirks enabled
please report the information to the linux-kernel list (see REPORTING-BUGS).
If you are one of the tiny number of unfortunates with a 486 ISA/VLB VIA
chipset board you need to do the following to build a special kernel for
your board
edit linux/include/asm-i386/dma.h
change
#define isa_dma_bridge_buggy (0)
to
#define isa_dma_bridge_buggy (1)
and rebuild a kernel without PCI quirk support.
Other than this particular glitch the VIA [M]VP* chipsets appear to work
perfectly with Linux.

View file

@ -1,138 +0,0 @@
Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio
controller chips (2001/05/11)
The cs46xx audio driver supports the DSP line of Cirrus controllers.
Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280
products. This driver uses the generic ac97_codec driver for AC97 codec
support.
Features:
Full Duplex Playback/Capture supported from 8k-48k.
16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
APM/PM - 2.2.x PM is enabled and functional. APM can also
be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
definition.
DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg
(defaultorder=11). DMA capture buffer size is fixed at a single 4k page as
two 2k fragments.
MMAP seems to work well with QuakeIII, and test XMMS plugin.
Myth2 works, but the polling logic is not fully correct, but is functional.
The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested
with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o). This
audio driver must be loaded prior to the joystick driver to enable the
DSP task image supporting the joystick device.
Limitations:
SPDIF is currently not supported.
Primary codec support only. No secondary codec support is implemented.
NOTES:
Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
and has been tested.
Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR
to disable the external amplifier.
VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
the external amplifier for the "back" speakers, since we do not
support the secondary codec then this external amp is not
turned on. The primary codec external amplifier is supported but
note that the AC97 EAPD bit is inverted logic (amp_voyetra()).
DMA buffer size - there are issues with many of the Linux applications
concerning the optimal buffer size. Several applications request a
certain fragment size and number and then do not verify that the driver
has the ability to support the requested configuration.
SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and
number of fragments. Some applications exit if an error is returned
on this particular ioctl. Therefore, in alignment with the other OSS audio
drivers, no error is returned when a SETFRAGs IOCTL is received, but the
values passed from the app are not used in any buffer calculation
(ossfragshift/ossmaxfrags are not used).
Use the "defaultorder=N" module parameter to change the buffer size if
you have an application that requires a specific number of fragments
or a specific buffer size (see below).
Debug Interface
---------------
There is an ioctl debug interface to allow runtime modification of the
debug print levels. This debug interface code can be disabled from the
compilation process with commenting the following define:
#define CSDEBUG_INTERFACE 1
There is also a debug print methodolgy to select printf statements from
different areas of the driver. A debug print level is also used to allow
additional printfs to be active. Comment out the following line in the
driver to disable compilation of the CS_DBGOUT print statements:
#define CSDEBUG 1
Please see the definitions for cs_debuglevel and cs_debugmask for additional
information on the debug levels and sections.
There is also a csdbg executable to allow runtime manipulation of these
parameters. for a copy email: twoller@crystal.cirrus.com
MODULE_PARMS definitions
------------------------
module_param(defaultorder, ulong, 0);
defaultorder=N
where N is a value from 1 to 12
The buffer order determines the size of the dma buffer for the driver.
under Linux, a smaller buffer allows more responsiveness from many of the
applications (e.g. games). A larger buffer allows some of the apps (esound)
to not underrun the dma buffer as easily. As default, use 32k (order=3)
rather than 64k as some of the games work more responsively.
(2^N) * PAGE_SIZE = allocated buffer size
module_param(cs_debuglevel, ulong, 0644);
module_param(cs_debugmask, ulong, 0644);
cs_debuglevel=N
cs_debugmask=0xMMMMMMMM
where N is a value from 0 (no debug printfs), to 9 (maximum)
0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source).
module_param(hercules_egpio_disable, ulong, 0);
hercules_egpio_disable=N
where N is a 0 (enable egpio), or a 1 (disable egpio support)
module_param(initdelay, ulong, 0);
initdelay=N
This value is used to determine the millescond delay during the initialization
code prior to powering up the PLL. On laptops this value can be used to
assist with errors on resume, mostly with IBM laptops. Basically, if the
system is booted under battery power then the mdelay()/udelay() functions fail to
properly delay the required time. Also, if the system is booted under AC power
and then the power removed, the mdelay()/udelay() functions will not delay properly.
module_param(powerdown, ulong, 0);
powerdown=N
where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown)
module_param(external_amp, bool, 0);
external_amp=1
if N is set to 1, then force enabling the EAPD support in the primary AC97 codec.
override the detection logic and force the external amp bit in the AC97 0x26 register
to be reset (0). EAPD should be 0 for powerup, and 1 for powerdown. The VTB Santa Cruz
card has inverted logic, so there is a special function for these cards.
module_param(thinkpad, bool, 0);
thinkpad=1
if N is set to 1, then force enabling the clkrun functionality.
Currently, when the part is being used, then clkrun is disabled for the entire system,
but re-enabled when the driver is released or there is no outstanding open count.

View file

@ -194,13 +194,6 @@ M: jes@trained-monkey.org
L: linux-acenic@sunsite.dk
S: Maintained
ACI MIXER DRIVER
P: Robert Siemer
M: Robert.Siemer@gmx.de
L: linux-sound@vger.kernel.org
W: http://www.stud.uni-karlsruhe.de/~uh1b/
S: Maintained
IPS SCSI RAID DRIVER
P: Adaptec OEM Raid Solutions
M: aacraid@adaptec.com
@ -272,21 +265,6 @@ L: linux-acpi@vger.kernel.org
W: http://acpi.sourceforge.net/
S: Supported
AD1816 SOUND DRIVER
P: Thorsten Knabe
M: Thorsten Knabe <linux@thorsten-knabe.de>
W: http://linux.thorsten-knabe.de
S: Maintained
AD1889 SOUND DRIVER
P: Kyle McMartin
M: kyle@parisc-linux.org
P: Thibaut Varene
M: T-Bone@parisc-linux.org
W: http://wiki.parisc-linux.org/AD1889
L: parisc-linux@lists.parisc-linux.org
S: Maintained
ADM1025 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
@ -1404,13 +1382,6 @@ M: raisch@de.ibm.com
L: general@lists.openfabrics.org
S: Supported
EMU10K1 SOUND DRIVER
P: James Courtier-Dutton
M: James@superbug.demon.co.uk
L: emu10k1-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/emu10k1/
S: Maintained
EMULEX LPFC FC SCSI DRIVER
P: James Smart
M: james.smart@emulex.com
@ -2730,12 +2701,6 @@ L: osst-users@lists.sourceforge.net
L: linux-scsi@vger.kernel.org
S: Maintained
OPL3-SA2, SA3, and SAx DRIVER
P: Zwane Mwaikambo
M: zwane@arm.linux.org.uk
L: linux-sound@vger.kernel.org
S: Maintained
OPROFILE
P: Philippe Elie
M: phil.el@wanadoo.fr

View file

@ -18,20 +18,15 @@ obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.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_ADLIB) += adlib_card.o opl3.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_AD1816) += ad1816.o
obj-$(CONFIG_SOUND_AD1889) += ad1889.o ac97_codec.o
obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
@ -40,24 +35,16 @@ endif
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o
obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
obj-$(CONFIG_SOUND_BT878) += btaudio.o
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
ifeq ($(CONFIG_MIDI_EMU10K1),y)
obj-$(CONFIG_SOUND_EMU10K1) += sound.o
endif
obj-$(CONFIG_SOUND_EMU10K1) += emu10k1/
obj-$(CONFIG_DMASOUND) += dmasound/
# Declare multi-part drivers.

View file

@ -1,432 +0,0 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include "ac97.h"
/* Flag for mono controls. */
#define MO 0
/* And for stereo. */
#define ST 1
/* Whether or not the bits in the channel are inverted. */
#define INV 1
#define NINV 0
static struct ac97_chn_desc {
int ac97_regnum;
int oss_channel;
int maxval;
int is_stereo;
int oss_mask;
int recordNum;
u16 regmask;
int is_inverted;
} mixerRegs[] = {
{ AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME, 0x3f, ST, SOUND_MASK_VOLUME, 5, 0x0000, INV },
{ AC97_MASTER_VOL_MONO, SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000, INV },
{ AC97_MASTER_TONE, SOUND_MIXER_TREBLE, 0x0f, MO, SOUND_MASK_TREBLE, -1, 0x00ff, INV },
{ AC97_MASTER_TONE, SOUND_MIXER_BASS, 0x0f, MO, SOUND_MASK_BASS, -1, 0xff00, INV },
{ AC97_PCBEEP_VOL, SOUND_MIXER_SPEAKER, 0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e, INV },
{ AC97_PHONE_VOL, SOUND_MIXER_PHONEIN, 0x1f, MO, SOUND_MASK_PHONEIN, 7, 0x0000, INV },
{ AC97_MIC_VOL, SOUND_MIXER_MIC, 0x1f, MO, SOUND_MASK_MIC, 0, 0x0000, INV },
{ AC97_LINEIN_VOL, SOUND_MIXER_LINE, 0x1f, ST, SOUND_MASK_LINE, 4, 0x0000, INV },
{ AC97_CD_VOL, SOUND_MIXER_CD, 0x1f, ST, SOUND_MASK_CD, 1, 0x0000, INV },
{ AC97_VIDEO_VOL, SOUND_MIXER_VIDEO, 0x1f, ST, SOUND_MASK_VIDEO, 2, 0x0000, INV },
{ AC97_AUX_VOL, SOUND_MIXER_LINE1, 0x1f, ST, SOUND_MASK_LINE1, 3, 0x0000, INV },
{ AC97_PCMOUT_VOL, SOUND_MIXER_PCM, 0x1f, ST, SOUND_MASK_PCM, -1, 0x0000, INV },
{ AC97_RECORD_GAIN, SOUND_MIXER_IGAIN, 0x0f, ST, SOUND_MASK_IGAIN, -1, 0x0000, NINV },
{ -1, -1, 0xff, 0, 0, -1, 0x0000, 0 },
};
static struct ac97_chn_desc *
ac97_find_chndesc (struct ac97_hwint *dev, int oss_channel)
{
int x;
for (x = 0; mixerRegs[x].oss_channel != -1; x++) {
if (mixerRegs[x].oss_channel == oss_channel)
return mixerRegs + x;
}
return NULL;
}
static inline int
ac97_is_valid_channel (struct ac97_hwint *dev, struct ac97_chn_desc *chn)
{
return (dev->last_written_mixer_values[chn->ac97_regnum / 2]
!= AC97_REG_UNSUPPORTED);
}
int
ac97_init (struct ac97_hwint *dev)
{
int x;
int reg0;
/* Clear out the arrays of cached values. */
for (x = 0; x < AC97_REG_CNT; x++)
dev->last_written_mixer_values[x] = AC97_REGVAL_UNKNOWN;
for (x = 0; x < SOUND_MIXER_NRDEVICES; x++)
dev->last_written_OSS_values[x] = AC97_REGVAL_UNKNOWN;
/* Clear the device masks. */
dev->mixer_devmask = 0;
dev->mixer_stereomask = 0;
dev->mixer_recmask = 0;
/* ??? Do a "standard reset" via register 0? */
/* Hardware-dependent reset. */
if (dev->reset_device (dev))
return -1;
/* Check the mixer device capabilities. */
reg0 = dev->read_reg (dev, AC97_RESET);
if (reg0 < 0)
return -1;
/* Check for support for treble/bass controls. */
if (! (reg0 & 4)) {
dev->last_written_mixer_values[AC97_MASTER_TONE / 2]
= AC97_REG_UNSUPPORTED;
}
/* ??? There may be other tests here? */
/* Fill in the device masks. */
for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
if (ac97_is_valid_channel (dev, mixerRegs + x)) {
dev->mixer_devmask |= mixerRegs[x].oss_mask;
if (mixerRegs[x].is_stereo)
dev->mixer_stereomask |= mixerRegs[x].oss_mask;
if (mixerRegs[x].recordNum != -1)
dev->mixer_recmask |= mixerRegs[x].oss_mask;
}
}
return 0;
}
/* Return the contents of register REG; use the cache if the value in it
is valid. Returns a negative error code on failure. */
static int
ac97_get_register (struct ac97_hwint *dev, u8 reg)
{
if (reg > 127 || (reg & 1))
return -EINVAL;
/* See if it's in the cache, or if it's just plain invalid. */
switch (dev->last_written_mixer_values[reg / 2]) {
case AC97_REG_UNSUPPORTED:
return -EINVAL;
break;
case AC97_REGVAL_UNKNOWN:
dev->last_written_mixer_values[reg / 2] = dev->read_reg (dev, reg);
break;
default:
break;
}
return dev->last_written_mixer_values[reg / 2];
}
/* Write VALUE to AC97 register REG, and cache its value in the last-written
cache. Returns a negative error code on failure, or 0 on success. */
int
ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value)
{
if (reg > 127 || (reg & 1))
return -EINVAL;
if (dev->last_written_mixer_values[reg / 2] == AC97_REG_UNSUPPORTED)
return -EINVAL;
else {
int res = dev->write_reg (dev, reg, value);
if (res >= 0) {
dev->last_written_mixer_values[reg / 2] = value;
return 0;
}
else
return res;
}
}
/* Scale VALUE (a value fro 0 to MAXVAL) to a value from 0-100. If
IS_STEREO is set, VALUE is a stereo value; the left channel value
is in the lower 8 bits, and the right channel value is in the upper
8 bits.
A negative error code is returned on failure, or the unsigned
scaled value on success. */
static int
ac97_scale_to_oss_val (int value, int maxval, int is_stereo, int inv)
{
/* Muted? */
if (value & AC97_MUTE)
return 0;
if (is_stereo)
return (ac97_scale_to_oss_val (value & 255, maxval, 0, inv) << 8)
| (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
else {
int i;
/* Inverted. */
if (inv)
value = maxval - value;
i = (value * 100 + (maxval / 2)) / maxval;
if (i > 100)
i = 100;
if (i < 0)
i = 0;
return i;
}
}
static int
ac97_scale_from_oss_val (int value, int maxval, int is_stereo, int inv)
{
if (is_stereo)
return (ac97_scale_from_oss_val (value & 255, maxval, 0, inv) << 8)
| (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
else {
int i = ((value & 255) * maxval + 50) / 100;
if (inv)
i = maxval - i;
if (i < 0)
i = 0;
if (i > maxval)
i = maxval;
return i;
}
}
static int
ac97_set_mixer (struct ac97_hwint *dev, int oss_channel, u16 oss_value)
{
int scaled_value;
struct ac97_chn_desc *channel = ac97_find_chndesc (dev, oss_channel);
int result;
if (channel == NULL)
return -ENODEV;
if (! ac97_is_valid_channel (dev, channel))
return -ENODEV;
scaled_value = ac97_scale_from_oss_val (oss_value, channel->maxval,
channel->is_stereo,
channel->is_inverted);
if (scaled_value < 0)
return scaled_value;
if (channel->regmask != 0) {
int mv;
int oldval = ac97_get_register (dev, channel->ac97_regnum);
if (oldval < 0)
return oldval;
for (mv = channel->regmask; ! (mv & 1); mv >>= 1)
scaled_value <<= 1;
scaled_value &= channel->regmask;
scaled_value |= (oldval & ~channel->regmask);
}
result = ac97_put_register (dev, channel->ac97_regnum, scaled_value);
if (result == 0)
dev->last_written_OSS_values[oss_channel] = oss_value;
return result;
}
static int
ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel)
{
struct ac97_chn_desc *channel = ac97_find_chndesc (dev, oss_channel);
int regval;
if (channel == NULL)
return -ENODEV;
if (! ac97_is_valid_channel (dev, channel))
return -ENODEV;
regval = ac97_get_register (dev, channel->ac97_regnum);
if (regval < 0)
return regval;
if (channel->regmask != 0) {
int mv;
regval &= channel->regmask;
for (mv = channel->regmask; ! (mv & 1); mv >>= 1)
regval >>= 1;
}
return ac97_scale_to_oss_val (regval, channel->maxval,
channel->is_stereo,
channel->is_inverted);
}
static int
ac97_get_recmask (struct ac97_hwint *dev)
{
int recReg = ac97_get_register (dev, AC97_RECORD_SELECT);
if (recReg < 0)
return recReg;
else {
int x;
for (x = 0; mixerRegs[x].ac97_regnum >= 0; x++) {
if (mixerRegs[x].recordNum == (recReg & 7))
return mixerRegs[x].oss_mask;
}
return -ENODEV;
}
}
static int
ac97_set_recmask (struct ac97_hwint *dev, int oss_recmask)
{
int x;
if (oss_recmask == 0)
oss_recmask = SOUND_MIXER_MIC;
for (x = 0; mixerRegs[x].ac97_regnum >= 0; x++) {
if ((mixerRegs[x].recordNum >= 0)
&& (oss_recmask & mixerRegs[x].oss_mask))
break;
}
if (mixerRegs[x].ac97_regnum < 0)
return -ENODEV;
else {
int regval = (mixerRegs[x].recordNum << 8) | mixerRegs[x].recordNum;
int res = ac97_put_register (dev, AC97_RECORD_SELECT, regval);
if (res == 0)
return ac97_get_recmask (dev);
else
return res;
}
}
/* Set the mixer DEV to the list of values in VALUE_LIST. Return 0 on
success, or a negative error code. */
int
ac97_set_values (struct ac97_hwint *dev,
struct ac97_mixer_value_list *value_list)
{
int x;
for (x = 0; value_list[x].oss_channel != -1; x++) {
int chnum = value_list[x].oss_channel;
struct ac97_chn_desc *chent = ac97_find_chndesc (dev, chnum);
if (chent != NULL) {
u16 val;
int res;
if (chent->is_stereo)
val = (value_list[x].value.stereo.right << 8)
| value_list[x].value.stereo.left;
else {
/* We do this so the returned value looks OK in the
mixer app. It's not necessary otherwise. */
val = (value_list[x].value.mono << 8)
| value_list[x].value.mono;
}
res = ac97_set_mixer (dev, chnum, val);
if (res < 0)
return res;
}
else
return -ENODEV;
}
return 0;
}
int
ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, void __user *arg)
{
int ret;
switch (cmd) {
case SOUND_MIXER_READ_RECSRC:
ret = ac97_get_recmask (dev);
break;
case SOUND_MIXER_WRITE_RECSRC:
{
if (get_user (ret, (int __user *) arg))
ret = -EFAULT;
else
ret = ac97_set_recmask (dev, ret);
}
break;
case SOUND_MIXER_READ_CAPS:
ret = SOUND_CAP_EXCL_INPUT;
break;
case SOUND_MIXER_READ_DEVMASK:
ret = dev->mixer_devmask;
break;
case SOUND_MIXER_READ_RECMASK:
ret = dev->mixer_recmask;
break;
case SOUND_MIXER_READ_STEREODEVS:
ret = dev->mixer_stereomask;
break;
default:
/* Read or write request. */
ret = -EINVAL;
if (_IOC_TYPE (cmd) == 'M') {
int dir = _SIOC_DIR (cmd);
int channel = _IOC_NR (cmd);
if (channel >= 0 && channel < SOUND_MIXER_NRDEVICES) {
ret = 0;
if (dir & _SIOC_WRITE) {
int val;
if (get_user (val, (int __user *) arg) == 0)
ret = ac97_set_mixer (dev, channel, val);
else
ret = -EFAULT;
}
if (ret >= 0 && (dir & _SIOC_READ)) {
if (dev->last_written_OSS_values[channel]
== AC97_REGVAL_UNKNOWN)
dev->last_written_OSS_values[channel]
= ac97_get_mixer_scaled (dev, channel);
ret = dev->last_written_OSS_values[channel];
}
}
}
break;
}
if (ret < 0)
return ret;
else
return put_user(ret, (int __user *) arg);
}
EXPORT_SYMBOL(ac97_init);
EXPORT_SYMBOL(ac97_set_values);
EXPORT_SYMBOL(ac97_put_register);
EXPORT_SYMBOL(ac97_mixer_ioctl);
MODULE_LICENSE("GPL");
/*
* Local variables:
* c-basic-offset: 4
* End:
*/

View file

@ -1,201 +0,0 @@
/*
* ac97.h
*
* definitions for the AC97, Intel's Audio Codec 97 Spec
* also includes support for a generic AC97 interface
*/
#ifndef _AC97_H_
#define _AC97_H_
#include "sound_config.h"
#include "sound_calls.h"
#define AC97_RESET 0x0000 //
#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out
#define AC97_HEADPHONE_VOL 0x0004 //
#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output
#define AC97_MASTER_TONE 0x0008 //
#define AC97_PCBEEP_VOL 0x000a // none
#define AC97_PHONE_VOL 0x000c // TAD Input (mono)
#define AC97_MIC_VOL 0x000e // MIC Input (mono)
#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo)
#define AC97_CD_VOL 0x0012 // CD Input (stereo)
#define AC97_VIDEO_VOL 0x0014 // none
#define AC97_AUX_VOL 0x0016 // Aux Input (stereo)
#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo)
#define AC97_RECORD_SELECT 0x001a //
#define AC97_RECORD_GAIN 0x001c
#define AC97_RECORD_GAIN_MIC 0x001e
#define AC97_GENERAL_PURPOSE 0x0020
#define AC97_3D_CONTROL 0x0022
#define AC97_MODEM_RATE 0x0024
#define AC97_POWER_CONTROL 0x0026
/* registers 0x0028 - 0x0058 are reserved */
/* AC'97 2.0 */
#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */
#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */
#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */
#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */
#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */
#define AC97_PCM_LR_ADC_RATE 0x0032 /* PCM LR DAC Rate */
#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */
#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */
#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */
#define AC97_RESERVED_3A 0x003A /* Reserved */
/* range 0x3c-0x58 - MODEM */
/* registers 0x005a - 0x007a are vendor reserved */
#define AC97_VENDOR_ID1 0x007c
#define AC97_VENDOR_ID2 0x007e
/* volume control bit defines */
#define AC97_MUTE 0x8000
#define AC97_MICBOOST 0x0040
#define AC97_LEFTVOL 0x3f00
#define AC97_RIGHTVOL 0x003f
/* record mux defines */
#define AC97_RECMUX_MIC 0x0000
#define AC97_RECMUX_CD 0x0101
#define AC97_RECMUX_VIDEO 0x0202 /* not used */
#define AC97_RECMUX_AUX 0x0303
#define AC97_RECMUX_LINE 0x0404
#define AC97_RECMUX_STEREO_MIX 0x0505
#define AC97_RECMUX_MONO_MIX 0x0606
#define AC97_RECMUX_PHONE 0x0707
/* general purpose register bit defines */
#define AC97_GP_LPBK 0x0080 /* Loopback mode */
#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */
#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */
#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */
#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */
#define AC97_GP_LD 0x1000 /* Loudness 1=on */
#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */
#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */
#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */
/* powerdown control and status bit defines */
/* status */
#define AC97_PWR_MDM 0x0010 /* Modem section ready */
#define AC97_PWR_REF 0x0008 /* Vref nominal */
#define AC97_PWR_ANL 0x0004 /* Analog section ready */
#define AC97_PWR_DAC 0x0002 /* DAC section ready */
#define AC97_PWR_ADC 0x0001 /* ADC section ready */
/* control */
#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */
#define AC97_PWR_PR1 0x0200 /* DAC powerdown */
#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */
#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */
#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */
#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */
#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */
#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */
/* useful power states */
#define AC97_PWR_D0 0x0000 /* everything on */
#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */
/* Total number of defined registers. */
#define AC97_REG_CNT 64
/* Generic AC97 mixer interface. */
/* Structure describing access to the hardware. */
struct ac97_hwint
{
/* Perform any hardware-specific reset and initialization. Returns
0 on success, or a negative error code. */
int (*reset_device) (struct ac97_hwint *dev);
/* Returns the contents of the specified register REG. The caller
should check to see if the desired contents are available in
the cache first, if applicable. Returns a positive unsigned value
representing the contents of the register, or a negative error
code. */
int (*read_reg) (struct ac97_hwint *dev, u8 reg);
/* Writes VALUE to register REG. Returns 0 on success, or a
negative error code. */
int (*write_reg) (struct ac97_hwint *dev, u8 reg, u16 value);
/* Hardware-specific information. */
void *driver_private;
/* Three OSS masks. */
int mixer_devmask;
int mixer_stereomask;
int mixer_recmask;
/* The mixer cache. The indices correspond to the AC97 hardware register
number / 2, since the register numbers are always an even number.
Unknown values are set to -1; unsupported registers contain a
-2. */
int last_written_mixer_values[AC97_REG_CNT];
/* A cache of values written via OSS; we need these so we can return
the values originally written by the user.
Why the original user values? Because the real-world hardware
has less precision, and some existing applications assume that
they will get back the exact value that they wrote (aumix).
A -1 value indicates that no value has been written to this mixer
channel via OSS. */
int last_written_OSS_values[SOUND_MIXER_NRDEVICES];
};
/* Values stored in the register cache. */
#define AC97_REGVAL_UNKNOWN -1
#define AC97_REG_UNSUPPORTED -2
struct ac97_mixer_value_list
{
/* Mixer channel to set. List is terminated by a value of -1. */
int oss_channel;
/* The scaled value to set it to; values generally range from 0-100. */
union {
struct {
u8 left, right;
} stereo;
u8 mono;
} value;
};
/* Initialize the ac97 mixer by resetting it. */
extern int ac97_init (struct ac97_hwint *dev);
/* Sets the mixer DEV to the values in VALUE_LIST. Returns 0 on success,
or a negative error code. */
extern int ac97_set_values (struct ac97_hwint *dev,
struct ac97_mixer_value_list *value_list);
/* Writes the specified VALUE to the AC97 register REG in the mixer.
Takes care of setting the last-written cache as well. */
extern int ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value);
/* Default ioctl. */
extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
void __user * arg);
#endif
/*
* Local variables:
* c-basic-offset: 4
* End:
*/

View file

@ -1,712 +0,0 @@
/*
* Audio Command Interface (ACI) driver (sound/aci.c)
*
* ACI is a protocol used to communicate with the microcontroller on
* some sound cards produced by miro, e.g. the miroSOUND PCM12 and
* PCM20. The ACI has been developed for miro by Norberto Pellicci
* <pellicci@home.com>. Special thanks to both him and miro for
* providing the ACI specification.
*
* The main function of the ACI is to control the mixer and to get a
* product identification. On the PCM20, ACI also controls the radio
* tuner on this card, this is supported in the Video for Linux
* miropcm20 driver.
* -
* This is a fullfeatured implementation. Unsupported features
* are bugs... (:
*
* It is not longer necessary to load the mad16 module first. The
* user is currently responsible to set the mad16 mixer correctly.
*
* To toggle the solo mode for full duplex operation just use the OSS
* record switch for the pcm ('wave') controller. Robert
* -
*
* Revision history:
*
* 1995-11-10 Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
* First version written.
* 1995-12-31 Markus Kuhn
* Second revision, general code cleanup.
* 1996-05-16 Hannu Savolainen
* Integrated with other parts of the driver.
* 1996-05-28 Markus Kuhn
* Initialize CS4231A mixer, make ACI first mixer,
* use new private mixer API for solo mode.
* 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
* Small modification to export ACI functions and
* complete modularisation.
* 2000-06-20 Robert Siemer <Robert.Siemer@gmx.de>
* Don't initialize the CS4231A mixer anymore, so the code is
* working again, and other small changes to fit in todays
* kernels.
* 2000-08-26 Robert Siemer
* Clean up and rewrite for 2.4.x. Maybe it's SMP safe now... (:
* ioctl bugfix, and integration of solo-mode into OSS-API,
* added (OSS-limited) equalizer support, return value bugfix,
* changed param aci_reset to reset, new params: ide, wss.
* 2001-04-20 Robert Siemer
* even more cleanups...
* 2001-10-08 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* Get rid of check_region, .bss optimizations, use set_current_state
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "sound_config.h"
int aci_port; /* as determined by bit 4 in the OPTi 929 MC4 register */
static int aci_idcode[2]; /* manufacturer and product ID */
int aci_version; /* ACI firmware version */
EXPORT_SYMBOL(aci_port);
EXPORT_SYMBOL(aci_version);
#include "aci.h"
static int aci_solo; /* status bit of the card that can't be *
* checked with ACI versions prior to 0xb0 */
static int aci_amp; /* status bit for power-amp/line-out level
but I have no docs about what is what... */
static int aci_micpreamp=3; /* microphone preamp-level that can't be *
* checked with ACI versions prior to 0xb0 */
static int mixer_device;
static struct mutex aci_mutex;
#ifdef MODULE
static int reset;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer.");
#else
static int reset = 1;
#endif
static int ide=-1;
module_param(ide, int, 0);
MODULE_PARM_DESC(ide,"1 enable, 0 disable ide-port - untested"
" default: do nothing");
static int wss=-1;
module_param(wss, int, 0);
MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested"
" default: do nothing; for PCM1-pro only");
#ifdef DEBUG
static void print_bits(unsigned char c)
{
int j;
printk(KERN_DEBUG "aci: ");
for (j=7; j>=0; j--) {
printk("%d", (c >> j) & 0x1);
}
printk("\n");
}
#endif
/*
* This busy wait code normally requires less than 15 loops and
* practically always less than 100 loops on my i486/DX2 66 MHz.
*
* Warning: Waiting on the general status flag after reseting the MUTE
* function can take a VERY long time, because the PCM12 does some kind
* of fade-in effect. For this reason, access to the MUTE function has
* not been implemented at all.
*
* - The OSS interface has no mute option. It takes about 3 seconds to
* fade-in on my PCM20. busy_wait() handles it great now... Robert
*/
static int busy_wait(void)
{
#define MINTIME 500
long timeout;
unsigned char byte;
for (timeout = 1; timeout <= MINTIME+30; timeout++) {
if (((byte=inb(BUSY_REGISTER)) & 1) == 0) {
if (timeout >= MINTIME)
printk(KERN_DEBUG "aci: Got READYFLAG in round %ld.\n", timeout-MINTIME);
return byte;
}
if (timeout >= MINTIME) {
long out=10*HZ;
switch (timeout-MINTIME) {
case 0 ... 9:
out /= 10;
case 10 ... 19:
out /= 10;
case 20 ... 30:
out /= 10;
default:
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(out);
break;
}
}
}
printk(KERN_WARNING "aci: busy_wait() time out.\n");
return -EBUSY;
}
/* The four ACI command types are fucked up. [-:
* implied is: 1w - special case for INIT
* write is: 2w1r
* read is: x(1w1r) where x is 1 or 2 (1 CHECK_SIG, 1 CHECK_STER,
* 1 VERSION, 2 IDCODE)
* the command is only in the first write, rest is protocol overhead
*
* indexed is technically a write and used for STATUS
* and the special case for TUNE is: 3w1r
*
* Here the new general sheme: TUNE --> aci_rw_cmd(x, y, z)
* indexed and write --> aci_rw_cmd(x, y, -1)
* implied and read (x=1) --> aci_rw_cmd(x, -1, -1)
*
* Read (x>=2) is not implemented (only used during initialization).
* Use aci_idcode[2] and aci_version... Robert
*/
/* Some notes for error detection: theoretically it is possible.
* But it doubles the I/O-traffic from ww(r) to wwwrw(r) in the normal
* case and doesn't seem to be designed for that... Robert
*/
static inline int aci_rawwrite(unsigned char byte)
{
if (busy_wait() >= 0) {
#ifdef DEBUG
printk(KERN_DEBUG "aci_rawwrite(%d)\n", byte);
#endif
outb(byte, COMMAND_REGISTER);
return 0;
} else
return -EBUSY;
}
static inline int aci_rawread(void)
{
unsigned char byte;
if (busy_wait() >= 0) {
byte=inb(STATUS_REGISTER);
#ifdef DEBUG
printk(KERN_DEBUG "%d = aci_rawread()\n", byte);
#endif
return byte;
} else
return -EBUSY;
}
int aci_rw_cmd(int write1, int write2, int write3)
{
int write[] = {write1, write2, write3};
int read = -EINTR, i;
if (mutex_lock_interruptible(&aci_mutex))
goto out;
for (i=0; i<3; i++) {
if (write[i]< 0 || write[i] > 255)
break;
else {
read = aci_rawwrite(write[i]);
if (read < 0)
goto out_up;
}
}
read = aci_rawread();
out_up: mutex_unlock(&aci_mutex);
out: return read;
}
EXPORT_SYMBOL(aci_rw_cmd);
static int setvolume(int __user *arg,
unsigned char left_index, unsigned char right_index)
{
int vol, ret, uservol, buf;
__get_user(uservol, arg);
/* left channel */
vol = uservol & 0xff;
if (vol > 100)
vol = 100;
vol = SCALE(100, 0x20, vol);
if ((buf=aci_write_cmd(left_index, 0x20 - vol))<0)
return buf;
ret = SCALE(0x20, 100, vol);
/* right channel */
vol = (uservol >> 8) & 0xff;
if (vol > 100)
vol = 100;
vol = SCALE(100, 0x20, vol);
if ((buf=aci_write_cmd(right_index, 0x20 - vol))<0)
return buf;
ret |= SCALE(0x20, 100, vol) << 8;
__put_user(ret, arg);
return 0;
}
static int getvolume(int __user *arg,
unsigned char left_index, unsigned char right_index)
{
int vol;
int buf;
/* left channel */
if ((buf=aci_indexed_cmd(ACI_STATUS, left_index))<0)
return buf;
vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
/* right channel */
if ((buf=aci_indexed_cmd(ACI_STATUS, right_index))<0)
return buf;
vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
__put_user(vol, arg);
return 0;
}
/* The equalizer is somewhat strange on the ACI. From -12dB to +12dB
* write: 0xff..down.to..0x80==0x00..up.to..0x7f
*/
static inline unsigned int eq_oss2aci(unsigned int vol)
{
int boost=0;
unsigned int ret;
if (vol > 100)
vol = 100;
if (vol > 50) {
vol -= 51;
boost=1;
}
if (boost)
ret=SCALE(49, 0x7e, vol)+1;
else
ret=0xff - SCALE(50, 0x7f, vol);
return ret;
}
static inline unsigned int eq_aci2oss(unsigned int vol)
{
if (vol < 0x80)
return SCALE(0x7f, 50, vol) + 50;
else
return SCALE(0x7f, 50, 0xff-vol);
}
static int setequalizer(int __user *arg,
unsigned char left_index, unsigned char right_index)
{
int buf;
unsigned int vol;
__get_user(vol, arg);
/* left channel */
if ((buf=aci_write_cmd(left_index, eq_oss2aci(vol & 0xff)))<0)
return buf;
/* right channel */
if ((buf=aci_write_cmd(right_index, eq_oss2aci((vol>>8) & 0xff)))<0)
return buf;
/* the ACI equalizer is more precise */
return 0;
}
static int getequalizer(int __user *arg,
unsigned char left_index, unsigned char right_index)
{
int buf;
unsigned int vol;
/* left channel */
if ((buf=aci_indexed_cmd(ACI_STATUS, left_index))<0)
return buf;
vol = eq_aci2oss(buf);
/* right channel */
if ((buf=aci_indexed_cmd(ACI_STATUS, right_index))<0)
return buf;
vol |= eq_aci2oss(buf) << 8;
__put_user(vol, arg);
return 0;
}
static int aci_mixer_ioctl (int dev, unsigned int cmd, void __user * arg)
{
int vol, buf;
int __user *p = arg;
switch (cmd) {
case SOUND_MIXER_WRITE_VOLUME:
return setvolume(p, 0x01, 0x00);
case SOUND_MIXER_WRITE_CD:
return setvolume(p, 0x3c, 0x34);
case SOUND_MIXER_WRITE_MIC:
return setvolume(p, 0x38, 0x30);
case SOUND_MIXER_WRITE_LINE:
return setvolume(p, 0x39, 0x31);
case SOUND_MIXER_WRITE_SYNTH:
return setvolume(p, 0x3b, 0x33);
case SOUND_MIXER_WRITE_PCM:
return setvolume(p, 0x3a, 0x32);
case MIXER_WRITE(SOUND_MIXER_RADIO): /* fall through */
case SOUND_MIXER_WRITE_LINE1: /* AUX1 or radio */
return setvolume(p, 0x3d, 0x35);
case SOUND_MIXER_WRITE_LINE2: /* AUX2 */
return setvolume(p, 0x3e, 0x36);
case SOUND_MIXER_WRITE_BASS: /* set band one and two */
if (aci_idcode[1]=='C') {
if ((buf=setequalizer(p, 0x48, 0x40)) ||
(buf=setequalizer(p, 0x49, 0x41)));
return buf;
}
break;
case SOUND_MIXER_WRITE_TREBLE: /* set band six and seven */
if (aci_idcode[1]=='C') {
if ((buf=setequalizer(p, 0x4d, 0x45)) ||
(buf=setequalizer(p, 0x4e, 0x46)));
return buf;
}
break;
case SOUND_MIXER_WRITE_IGAIN: /* MIC pre-amp */
if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
__get_user(vol, p);
vol = vol & 0xff;
if (vol > 100)
vol = 100;
vol = SCALE(100, 3, vol);
if ((buf=aci_write_cmd(ACI_WRITE_IGAIN, vol))<0)
return buf;
aci_micpreamp = vol;
vol = SCALE(3, 100, vol);
vol |= (vol << 8);
__put_user(vol, p);
return 0;
}
break;
case SOUND_MIXER_WRITE_OGAIN: /* Power-amp/line-out level */
if (aci_idcode[1]=='A' || aci_idcode[1]=='B') {
__get_user(buf, p);
buf = buf & 0xff;
if (buf > 50)
vol = 1;
else
vol = 0;
if ((buf=aci_write_cmd(ACI_SET_POWERAMP, vol))<0)
return buf;
aci_amp = vol;
if (aci_amp)
buf = (100 || 100<<8);
else
buf = 0;
__put_user(buf, p);
return 0;
}
break;
case SOUND_MIXER_WRITE_RECSRC:
/* handle solo mode control */
__get_user(buf, p);
/* unset solo when RECSRC for PCM is requested */
if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
vol = !(buf & SOUND_MASK_PCM);
if ((buf=aci_write_cmd(ACI_SET_SOLOMODE, vol))<0)
return buf;
aci_solo = vol;
}
buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
SOUND_MASK_SYNTH| SOUND_MASK_LINE2);
if (aci_idcode[1] == 'C') /* PCM20 radio */
buf |= SOUND_MASK_RADIO;
else
buf |= SOUND_MASK_LINE1;
if (!aci_solo)
buf |= SOUND_MASK_PCM;
__put_user(buf, p);
return 0;
case SOUND_MIXER_READ_DEVMASK:
buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD |
SOUND_MASK_MIC | SOUND_MASK_LINE |
SOUND_MASK_SYNTH | SOUND_MASK_PCM |
SOUND_MASK_LINE2);
switch (aci_idcode[1]) {
case 'C': /* PCM20 radio */
buf |= (SOUND_MASK_RADIO | SOUND_MASK_IGAIN |
SOUND_MASK_BASS | SOUND_MASK_TREBLE);
break;
case 'B': /* PCM12 */
buf |= (SOUND_MASK_LINE1 | SOUND_MASK_IGAIN |
SOUND_MASK_OGAIN);
break;
case 'A': /* PCM1-pro */
buf |= (SOUND_MASK_LINE1 | SOUND_MASK_OGAIN);
break;
default:
buf |= SOUND_MASK_LINE1;
}
__put_user(buf, p);
return 0;
case SOUND_MIXER_READ_STEREODEVS:
buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD |
SOUND_MASK_MIC | SOUND_MASK_LINE |
SOUND_MASK_SYNTH | SOUND_MASK_PCM |
SOUND_MASK_LINE2);
switch (aci_idcode[1]) {
case 'C': /* PCM20 radio */
buf |= (SOUND_MASK_RADIO |
SOUND_MASK_BASS | SOUND_MASK_TREBLE);
break;
default:
buf |= SOUND_MASK_LINE1;
}
__put_user(buf, p);
return 0;
case SOUND_MIXER_READ_RECMASK:
buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
SOUND_MASK_SYNTH| SOUND_MASK_LINE2| SOUND_MASK_PCM);
if (aci_idcode[1] == 'C') /* PCM20 radio */
buf |= SOUND_MASK_RADIO;
else
buf |= SOUND_MASK_LINE1;
__put_user(buf, p);
return 0;
case SOUND_MIXER_READ_RECSRC:
buf = (SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE |
SOUND_MASK_SYNTH | SOUND_MASK_LINE2);
/* do we need aci_solo or can I get it from the ACI? */
switch (aci_idcode[1]) {
case 'B': /* PCM12 */
case 'C': /* PCM20 radio */
if (aci_version >= 0xb0) {
if ((vol=aci_rw_cmd(ACI_STATUS,
ACI_S_GENERAL, -1))<0)
return vol;
if (vol & 0x20)
buf |= SOUND_MASK_PCM;
}
else
if (!aci_solo)
buf |= SOUND_MASK_PCM;
break;
default:
buf |= SOUND_MASK_PCM;
}
if (aci_idcode[1] == 'C') /* PCM20 radio */
buf |= SOUND_MASK_RADIO;
else
buf |= SOUND_MASK_LINE1;
__put_user(buf, p);
return 0;
case SOUND_MIXER_READ_CAPS:
__put_user(0, p);
return 0;
case SOUND_MIXER_READ_VOLUME:
return getvolume(p, 0x04, 0x03);
case SOUND_MIXER_READ_CD:
return getvolume(p, 0x0a, 0x09);
case SOUND_MIXER_READ_MIC:
return getvolume(p, 0x06, 0x05);
case SOUND_MIXER_READ_LINE:
return getvolume(p, 0x08, 0x07);
case SOUND_MIXER_READ_SYNTH:
return getvolume(p, 0x0c, 0x0b);
case SOUND_MIXER_READ_PCM:
return getvolume(p, 0x0e, 0x0d);
case MIXER_READ(SOUND_MIXER_RADIO): /* fall through */
case SOUND_MIXER_READ_LINE1: /* AUX1 */
return getvolume(p, 0x11, 0x10);
case SOUND_MIXER_READ_LINE2: /* AUX2 */
return getvolume(p, 0x13, 0x12);
case SOUND_MIXER_READ_BASS: /* get band one */
if (aci_idcode[1]=='C') {
return getequalizer(p, 0x23, 0x22);
}
break;
case SOUND_MIXER_READ_TREBLE: /* get band seven */
if (aci_idcode[1]=='C') {
return getequalizer(p, 0x2f, 0x2e);
}
break;
case SOUND_MIXER_READ_IGAIN: /* MIC pre-amp */
if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
/* aci_micpreamp or ACI? */
if (aci_version >= 0xb0) {
if ((buf=aci_indexed_cmd(ACI_STATUS,
ACI_S_READ_IGAIN))<0)
return buf;
}
else
buf=aci_micpreamp;
vol = SCALE(3, 100, buf <= 3 ? buf : 3);
vol |= vol << 8;
__put_user(vol, p);
return 0;
}
break;
case SOUND_MIXER_READ_OGAIN:
if (aci_amp)
buf = (100 || 100<<8);
else
buf = 0;
__put_user(buf, p);
return 0;
}
return -EINVAL;
}
static struct mixer_operations aci_mixer_operations =
{
.owner = THIS_MODULE,
.id = "ACI",
.ioctl = aci_mixer_ioctl
};
/*
* There is also an internal mixer in the codec (CS4231A or AD1845),
* that deserves no purpose in an ACI based system which uses an
* external ACI controlled stereo mixer. Make sure that this codec
* mixer has the AUX1 input selected as the recording source, that the
* input gain is set near maximum and that the other channels going
* from the inputs to the codec output are muted.
*/
static int __init attach_aci(void)
{
char *boardname;
int i, rc = -EBUSY;
mutex_init(&aci_mutex);
outb(0xE3, 0xf8f); /* Write MAD16 password */
aci_port = (inb(0xf90) & 0x10) ?
0x344: 0x354; /* Get aci_port from MC4_PORT */
if (!request_region(aci_port, 3, "sound mixer (ACI)")) {
printk(KERN_NOTICE
"aci: I/O area 0x%03x-0x%03x already used.\n",
aci_port, aci_port+2);
goto out;
}
/* force ACI into a known state */
rc = -EFAULT;
for (i=0; i<3; i++)
if (aci_rw_cmd(ACI_ERROR_OP, -1, -1)<0)
goto out_release_region;
/* official this is one aci read call: */
rc = -EFAULT;
if ((aci_idcode[0]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0 ||
(aci_idcode[1]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0) {
printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n",
aci_port);
goto out_release_region;
}
if ((aci_version=aci_rw_cmd(ACI_READ_VERSION, -1, -1))<0) {
printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n",
aci_port);
goto out_release_region;
}
if (aci_idcode[0] == 'm') {
/* It looks like a miro sound card. */
switch (aci_idcode[1]) {
case 'A':
boardname = "PCM1 pro / early PCM12";
break;
case 'B':
boardname = "PCM12";
break;
case 'C':
boardname = "PCM20 radio";
break;
default:
boardname = "unknown miro";
}
} else {
printk(KERN_WARNING "aci: Warning: unsupported card! - "
"no hardware, no specs...\n");
boardname = "unknown Cardinal Technologies";
}
printk(KERN_INFO "<ACI 0x%02x, id %02x/%02x \"%c/%c\", (%s)> at 0x%03x\n",
aci_version,
aci_idcode[0], aci_idcode[1],
aci_idcode[0], aci_idcode[1],
boardname, aci_port);
rc = -EBUSY;
if (reset) {
/* first write()s after reset fail with my PCM20 */
if (aci_rw_cmd(ACI_INIT, -1, -1)<0 ||
aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0 ||
aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0)
goto out_release_region;
}
/* the PCM20 is muted after reset (and reboot) */
if (aci_rw_cmd(ACI_SET_MUTE, 0x00, -1)<0)
goto out_release_region;
if (ide>=0)
if (aci_rw_cmd(ACI_SET_IDE, !ide, -1)<0)
goto out_release_region;
if (wss>=0 && aci_idcode[1]=='A')
if (aci_rw_cmd(ACI_SET_WSS, !!wss, -1)<0)
goto out_release_region;
mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, boardname,
&aci_mixer_operations,
sizeof(aci_mixer_operations), NULL);
rc = 0;
if (mixer_device < 0) {
printk(KERN_ERR "aci: Failed to install mixer.\n");
rc = mixer_device;
goto out_release_region;
} /* else Maybe initialize the CS4231A mixer here... */
out: return rc;
out_release_region:
release_region(aci_port, 3);
goto out;
}
static void __exit unload_aci(void)
{
sound_unload_mixerdev(mixer_device);
release_region(aci_port, 3);
}
module_init(attach_aci);
module_exit(unload_aci);
MODULE_LICENSE("GPL");

View file

@ -1,57 +0,0 @@
#ifndef _ACI_H_
#define _ACI_H_
extern int aci_port;
extern int aci_version; /* ACI firmware version */
extern int aci_rw_cmd(int write1, int write2, int write3);
#define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1)
#define aci_write_cmd(a, b) aci_rw_cmd(a, b, -1)
#define aci_read_cmd(a) aci_rw_cmd(a,-1, -1)
#define COMMAND_REGISTER (aci_port) /* write register */
#define STATUS_REGISTER (aci_port + 1) /* read register */
#define BUSY_REGISTER (aci_port + 2) /* also used for rds */
#define RDS_REGISTER BUSY_REGISTER
#define ACI_SET_MUTE 0x0d
#define ACI_SET_POWERAMP 0x0f
#define ACI_SET_TUNERMUTE 0xa3
#define ACI_SET_TUNERMONO 0xa4
#define ACI_SET_IDE 0xd0
#define ACI_SET_WSS 0xd1
#define ACI_SET_SOLOMODE 0xd2
#define ACI_WRITE_IGAIN 0x03
#define ACI_WRITE_TUNE 0xa7
#define ACI_READ_TUNERSTEREO 0xa8
#define ACI_READ_TUNERSTATION 0xa9
#define ACI_READ_VERSION 0xf1
#define ACI_READ_IDCODE 0xf2
#define ACI_INIT 0xff
#define ACI_STATUS 0xf0
#define ACI_S_GENERAL 0x00
#define ACI_S_READ_IGAIN 0x21
#define ACI_ERROR_OP 0xdf
/*
* The following macro SCALE can be used to scale one integer volume
* value into another one using only integer arithmetic. If the input
* value x is in the range 0 <= x <= xmax, then the result will be in
* the range 0 <= SCALE(xmax,ymax,x) <= ymax.
*
* This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
* following nice properties:
*
* - SCALE(xmax,ymax,xmax) = ymax
* - SCALE(xmax,ymax,0) = 0
* - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
*
* In addition, the rounding error is minimal and nicely distributed.
* The proofs are left as an exercise to the reader.
*/
#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
#endif /* _ACI_H_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,135 +0,0 @@
#ifndef _AD1889_H_
#define _AD1889_H_
#define AD_DS_WSMC 0x00 /* DMA input wave/syn mixer control */
#define AD_DS_RAMC 0x02 /* DMA output resamp/ADC mixer control */
#define AD_DS_WADA 0x04 /* DMA input wave attenuation */
#define AD_DS_SYDA 0x06 /* DMA input syn attentuation */
#define AD_DS_WAS 0x08 /* wave input sample rate */
#define AD_DS_RES 0x0a /* resampler output sample rate */
#define AD_DS_CCS 0x0c /* chip control/status */
#define AD_DMA_RESBA 0x40 /* RES base addr */
#define AD_DMA_RESCA 0x44 /* RES current addr */
#define AD_DMA_RESBC 0x48 /* RES base cnt */
#define AD_DMA_RESCC 0x4c /* RES current count */
#define AD_DMA_ADCBA 0x50 /* ADC */
#define AD_DMA_ADCCA 0x54
#define AD_DMA_ADCBC 0x58
#define AD_DMA_ADCCC 0x5c
#define AD_DMA_SYNBA 0x60 /* SYN */
#define AD_DMA_SYNCA 0x64
#define AD_DMA_SYNBC 0x68
#define AD_DMA_SYNCC 0x6c
#define AD_DMA_WAVBA 0x70 /* WAV */
#define AD_DMA_WAVCA 0x74
#define AD_DMA_WAVBC 0x78
#define AD_DMA_WAVCC 0x7c
#define AD_DMA_RESICC 0x80 /* RES interrupt current count */
#define AD_DMA_RESIBC 0x84 /* RES interrupt base count */
#define AD_DMA_ADCICC 0x88 /* ADC interrupt current count */
#define AD_DMA_ADCIBC 0x8c /* ADC interrupt base count */
#define AD_DMA_SYNICC 0x90 /* SYN interrupt current count */
#define AD_DMA_SYNIBC 0x94 /* SYN interrupt base count */
#define AD_DMA_WAVICC 0x98 /* WAV interrupt current count */
#define AD_DMA_WAVIBC 0x9c /* WAV interrupt base count */
#define AD_DMA_RESCTRL 0xa0 /* RES PCI control/status */
#define AD_DMA_ADCCTRL 0xa8 /* ADC PCI control/status */
#define AD_DMA_SYNCTRL 0xb0 /* SYN PCI control/status */
#define AD_DMA_WAVCTRL 0xb8 /* WAV PCI control/status */
#define AD_DMA_DISR 0xc0 /* PCI DMA intr status */
#define AD_DMA_CHSS 0xc4 /* PCI DMA channel stop status */
#define AD_GPIO_IPC 0xc8 /* IO port ctrl */
#define AD_GPIO_OP 0xca /* IO output status */
#define AD_GPIO_IP 0xcc /* IO input status */
/* AC97 registers, 0x100 - 0x17f; see ac97.h */
#define AD_AC97_BASE 0x100 /* ac97 base register */
#define AD_AC97_ACIC 0x180 /* AC Link interface ctrl */
/* OPL3; BAR1 */
#define AD_OPL_M0AS 0x00 /* Music0 address/status */
#define AD_OPL_M0DATA 0x01 /* Music0 data */
#define AD_OPL_M1A 0x02 /* Music1 address */
#define AD_OPL_M1DATA 0x03 /* Music1 data */
/* 0x04-0x0f reserved */
/* MIDI; BAR2 */
#define AD_MIDA 0x00 /* MIDI data */
#define AD_MISC 0x01 /* MIDI status/cmd */
/* 0x02-0xff reserved */
#define AD_DS_IOMEMSIZE 512
#define AD_OPL_MEMSIZE 16
#define AD_MIDI_MEMSIZE 16
#define AD_WAV_STATE 0
#define AD_ADC_STATE 1
#define AD_MAX_STATES 2
#define DMA_SIZE (128*1024)
#define DMA_FLAG_MAPPED 1
struct ad1889_dev;
typedef struct ad1889_state {
struct ad1889_dev *card;
mode_t open_mode;
struct dmabuf {
unsigned int rate;
unsigned char fmt, enable;
/* buf management */
size_t rawbuf_size;
void *rawbuf;
dma_addr_t dma_handle; /* mapped address */
unsigned long dma_len; /* number of bytes mapped */
/* indexes into rawbuf for setting up DMA engine */
volatile unsigned long rd_ptr, wr_ptr;
wait_queue_head_t wait; /* to wait for buf servicing */
/* OSS bits */
unsigned int mapped:1;
unsigned int ready:1;
unsigned int ossfragshift;
int ossmaxfrags;
unsigned int subdivision;
} dmabuf;
struct mutex mutex;
} ad1889_state_t;
typedef struct ad1889_dev {
void __iomem *regbase;
struct pci_dev *pci;
spinlock_t lock;
int dev_audio;
/* states; one per channel; right now only WAV and ADC */
struct ad1889_state state[AD_MAX_STATES];
/* AC97 codec */
struct ac97_codec *ac97_codec;
u16 ac97_features;
/* debugging stuff */
struct stats {
unsigned int wav_intrs, adc_intrs;
unsigned int blocks, underrun, error;
} stats;
} ad1889_dev_t;
typedef struct ad1889_reg {
const char *name;
int offset;
int width;
} ad1889_reg_t;
#endif

View file

@ -1,73 +0,0 @@
/*
* sound/oss/adlib_card.c
*
* Detection routine for the AdLib card.
*
* 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/module.h>
#include <linux/init.h>
#include "sound_config.h"
#include "opl3.h"
static void __init attach_adlib_card(struct address_info *hw_config)
{
hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp, THIS_MODULE);
}
static int __init probe_adlib(struct address_info *hw_config)
{
return opl3_detect(hw_config->io_base, hw_config->osp);
}
static struct address_info cfg;
static int __initdata io = -1;
module_param(io, int, 0);
static int __init init_adlib(void)
{
cfg.io_base = io;
if (cfg.io_base == -1) {
printk(KERN_ERR "adlib: must specify I/O address.\n");
return -EINVAL;
}
if (probe_adlib(&cfg) == 0)
return -ENODEV;
attach_adlib_card(&cfg);
return 0;
}
static void __exit cleanup_adlib(void)
{
sound_unload_synthdev(cfg.slots[0]);
}
module_init(init_adlib);
module_exit(cleanup_adlib);
#ifndef MODULE
static int __init setup_adlib(char *str)
{
/* io */
int ints[2];
str = get_options(str, ARRAY_SIZE(ints), ints);
io = ints[1];
return 1;
}
__setup("adlib=", setup_adlib);
#endif
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load diff

View file

@ -1,322 +0,0 @@
/****************************************************************************
* "CWCIMAGE.H"-- For CS46XX. Ver 1.04
* Copyright 1998-2001 (c) Cirrus Logic Corp.
* Version 1.04
****************************************************************************
*/
#ifndef __CS_IMAGE_H
#define __CS_IMAGE_H
#define CLEAR__COUNT 3
#define FILL__COUNT 4
#define BA1__DWORD_SIZE 13*1024+512
static struct
{
unsigned BA1__DestByteOffset;
unsigned BA1__SourceSize;
} ClrStat[CLEAR__COUNT] ={ {0x00000000, 0x00003000 },
{0x00010000, 0x00003800 },
{0x00020000, 0x00007000 } };
static u32 FillArray1[]={
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000163,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00200040,0x00008010,0x00000000,
0x00000000,0x80000001,0x00000001,0x00060000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00900080,0x00000173,0x00000000,
0x00000000,0x00000010,0x00800000,0x00900000,
0xf2c0000f,0x00000200,0x00000000,0x00010600,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000163,0x330300c2,
0x06000000,0x00000000,0x80008000,0x80008000,
0x3fc0000f,0x00000301,0x00010400,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00b00000,0x00d0806d,0x330480c3,
0x04800000,0x00000001,0x00800001,0x0000ffff,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x066a0600,0x06350070,0x0000929d,0x929d929d,
0x00000000,0x0000735a,0x00000600,0x00000000,
0x929d735a,0x00000000,0x00010000,0x735a735a,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x0000804f,0x000000c3,
0x05000000,0x00a00010,0x00000000,0x80008000,
0x00000000,0x00000000,0x00000700,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000080,0x00a00000,0x0000809a,0x000000c2,
0x07400000,0x00000000,0x80008000,0xffffffff,
0x00c80028,0x00005555,0x00000000,0x000107a0,
0x00c80028,0x000000c2,0x06800000,0x00000000,
0x06e00080,0x00300000,0x000080bb,0x000000c9,
0x07a00000,0x04000000,0x80008000,0xffffffff,
0x00c80028,0x00005555,0x00000000,0x00000780,
0x00c80028,0x000000c5,0xff800000,0x00000000,
0x00640080,0x00c00000,0x00008197,0x000000c9,
0x07800000,0x04000000,0x80008000,0xffffffff,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x0000805e,0x000000c1,
0x00000000,0x00800000,0x80008000,0x80008000,
0x00020000,0x0000ffff,0x00000000,0x00000000};
static u32 FillArray2[]={
0x929d0600,0x929d929d,0x929d929d,0x929d0000,
0x929d929d,0x929d929d,0x929d929d,0x929d929d,
0x929d929d,0x00100635,0x060b013f,0x00000004,
0x00000001,0x007a0002,0x00000000,0x066e0610,
0x0105929d,0x929d929d,0x929d929d,0x929d929d,
0x929d929d,0xa431ac75,0x0001735a,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051,
0x00000000,0x929d929d,0x929d929d,0x929d929d,
0x929d929d,0x929d929d,0x929d929d,0x929d929d,
0x929d929d,0x929d929d,0x00000000,0x06400136,
0x0000270f,0x00010000,0x007a0000,0x00000000,
0x068e0645,0x0105929d,0x929d929d,0x929d929d,
0x929d929d,0x929d929d,0xa431ac75,0x0001735a,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
0x735a0100,0x00000000,0x00000000,0x00000000};
static u32 FillArray3[]={
0x00000000,0x00000000,0x00000000,0x00010004};
static u32 FillArray4[]={
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00001705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00009705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00011705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00019705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00021705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00029705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00031705,0x00001400,0x000a411e,0x00001003,
0x00040730,0x00001002,0x000f619e,0x00001003,
0x00039705,0x00001400,0x000a411e,0x00001003,
0x000fe19e,0x00001003,0x0009c730,0x00001003,
0x0008e19c,0x00001003,0x000083c1,0x00093040,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00009705,0x00001400,0x000a211e,0x00001003,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00011705,0x00001400,0x000a211e,0x00001003,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00019705,0x00001400,0x000a211e,0x00001003,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00021705,0x00001400,0x000a211e,0x00001003,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00029705,0x00001400,0x000a211e,0x00001003,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00031705,0x00001400,0x000a211e,0x00001003,
0x00098730,0x00001002,0x000ee19e,0x00001003,
0x00039705,0x00001400,0x000a211e,0x00001003,
0x0000a730,0x00001008,0x000e2730,0x00001002,
0x0000a731,0x00001002,0x0000a731,0x00001002,
0x0000a731,0x00001002,0x0000a731,0x00001002,
0x0000a731,0x00001002,0x0000a731,0x00001002,
0x00000000,0x00000000,0x000f619c,0x00001003,
0x0007f801,0x000c0000,0x00000037,0x00001000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x000c0000,0x00000000,0x00000000,
0x0000373c,0x00001000,0x00000000,0x00000000,
0x000ee19c,0x00001003,0x0007f801,0x000c0000,
0x00000037,0x00001000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x0000273c,0x00001000,
0x00000033,0x00001000,0x000e679e,0x00001003,
0x00007705,0x00001400,0x000ac71e,0x00001003,
0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
0x00000037,0x00001000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x0000a730,0x00001003,
0x00000033,0x00001000,0x0007f801,0x000c0000,
0x00000037,0x00001000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x000c0000,
0x00000032,0x00001000,0x0000273d,0x00001000,
0x0004a730,0x00001003,0x00000f41,0x00097140,
0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
0x00000000,0x00000000,0x0001bf05,0x0003fc40,
0x00002725,0x000aa400,0x00013705,0x00093a00,
0x0000002e,0x0009d6c0,0x00038630,0x00001004,
0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000,
0x00000000,0x000c70e0,0x0007d182,0x0002c640,
0x00000630,0x00001004,0x000799b8,0x0002c6c0,
0x00031705,0x00092240,0x00039f05,0x000932c0,
0x0003520a,0x00000000,0x00040731,0x0000100b,
0x00010705,0x000b20c0,0x00000000,0x000eba44,
0x00032108,0x000c60c4,0x00065208,0x000c2917,
0x000406b0,0x00001007,0x00012f05,0x00036880,
0x0002818e,0x000c0000,0x0004410a,0x00000000,
0x00040630,0x00001007,0x00029705,0x000c0000,
0x00000000,0x00000000,0x00003fc1,0x0003fc40,
0x000037c1,0x00091b40,0x00003fc1,0x000911c0,
0x000037c1,0x000957c0,0x00003fc1,0x000951c0,
0x000037c1,0x00000000,0x00003fc1,0x000991c0,
0x000037c1,0x00000000,0x00003fc1,0x0009d1c0,
0x000037c1,0x00000000,0x0001ccc1,0x000915c0,
0x0001c441,0x0009d800,0x0009cdc1,0x00091240,
0x0001c541,0x00091d00,0x0009cfc1,0x00095240,
0x0001c741,0x00095c80,0x000e8ca9,0x00099240,
0x000e85ad,0x00095640,0x00069ca9,0x00099d80,
0x000e952d,0x00099640,0x000eaca9,0x0009d6c0,
0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80,
0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0,
0x000ec5ad,0x0009da40,0x000edca9,0x0009d300,
0x000a6e0a,0x00001000,0x000ed52d,0x00091e40,
0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40,
0x0006fca9,0x00002500,0x000fb208,0x000c59a0,
0x000ef52d,0x0009de40,0x00068ca9,0x000912c1,
0x000683ad,0x00095241,0x00020f05,0x000991c1,
0x00000000,0x00000000,0x00086f88,0x00001000,
0x0009cf81,0x000b5340,0x0009c701,0x000b92c0,
0x0009de81,0x000bd300,0x0009d601,0x000b1700,
0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0,
0x000a0f81,0x000bd740,0x00020701,0x000b5c80,
0x000a1681,0x000b97c0,0x00021601,0x00002500,
0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0,
0x00021681,0x00002d00,0x00020f81,0x000bd800,
0x000a0701,0x000b5bc0,0x00021601,0x00003500,
0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0,
0x00021681,0x00003d00,0x00020f81,0x000b1d00,
0x000a0701,0x000b1fc0,0x00021601,0x00020500,
0x00020f81,0x000b1341,0x000a0701,0x000b9fc0,
0x00021681,0x00020d00,0x00020f81,0x000bde80,
0x000a0701,0x000bdfc0,0x00021601,0x00021500,
0x00020f81,0x000b9341,0x00020701,0x000b53c1,
0x00021681,0x00021d00,0x000a0f81,0x000d0380,
0x0000b601,0x000b15c0,0x00007b01,0x00000000,
0x00007b81,0x000bd1c0,0x00007b01,0x00000000,
0x00007b81,0x000b91c0,0x00007b01,0x000b57c0,
0x00007b81,0x000b51c0,0x00007b01,0x000b1b40,
0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0,
0x0007e488,0x000d7e45,0x00000000,0x000d7a44,
0x0007e48a,0x00000000,0x00011f05,0x00084080,
0x00000000,0x00000000,0x00001705,0x000b3540,
0x00008a01,0x000bf040,0x00007081,0x000bb5c0,
0x00055488,0x00000000,0x0000d482,0x0003fc40,
0x0003fc88,0x00000000,0x0001e401,0x000b3a00,
0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784,
0x000c86b0,0x00001007,0x00008281,0x000bb240,
0x0000b801,0x000b7140,0x00007888,0x00000000,
0x0000073c,0x00001000,0x0007f188,0x000c0000,
0x00000000,0x00000000,0x00055288,0x000c555c,
0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
0x0000fa88,0x00000000,0x00000032,0x00001000,
0x0000073d,0x00001000,0x0007f188,0x000c0000,
0x00000000,0x00000000,0x0008c01c,0x00001003,
0x00002705,0x00001008,0x0008b201,0x000c1392,
0x0000ba01,0x00000000,0x00008731,0x00001400,
0x0004c108,0x000fe0c4,0x00057488,0x00000000,
0x000a6388,0x00001001,0x0008b334,0x000bc141,
0x0003020e,0x00000000,0x000886b0,0x00001008,
0x00003625,0x000c5dfa,0x000a638a,0x00001001,
0x0008020e,0x00001002,0x0008a6b0,0x00001008,
0x0007f301,0x00000000,0x00000000,0x00000000,
0x00002725,0x000a8c40,0x000000ae,0x00000000,
0x000d8630,0x00001008,0x00000000,0x000c74e0,
0x0007d182,0x0002d640,0x000a8630,0x00001008,
0x000799b8,0x0002d6c0,0x0000748a,0x000c3ec5,
0x0007420a,0x000c0000,0x00062208,0x000c4117,
0x00070630,0x00001009,0x00000000,0x000c0000,
0x0001022e,0x00000000,0x0003a630,0x00001009,
0x00000000,0x000c0000,0x00000036,0x00001000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x0002a730,0x00001008,0x0007f801,0x000c0000,
0x00000037,0x00001000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x0002a730,0x00001008,
0x00000033,0x00001000,0x0002a705,0x00001008,
0x00007a01,0x000c0000,0x000e6288,0x000d550a,
0x0006428a,0x00000000,0x00060730,0x0000100a,
0x00000000,0x000c0000,0x00000000,0x00000000,
0x0007aab0,0x00034880,0x00078fb0,0x0000100b,
0x00057488,0x00000000,0x00033b94,0x00081140,
0x000183ae,0x00000000,0x000786b0,0x0000100b,
0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
0x00042731,0x00001003,0x0007aab0,0x00034880,
0x00048fb0,0x0000100a,0x00057488,0x00000000,
0x00033b94,0x00081140,0x000183ae,0x00000000,
0x000806b0,0x0000100b,0x00022f05,0x00000000,
0x00007401,0x00091140,0x00048f05,0x000951c0,
0x00042731,0x00001003,0x0000473d,0x00001000,
0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
0x000fe19e,0x00001003,0x00000000,0x00000000,
0x0008e19c,0x00001003,0x000083c1,0x00093040,
0x00000f41,0x00097140,0x0000a841,0x0009b240,
0x0000a0c1,0x0009f040,0x0001c641,0x00093540,
0x0001cec1,0x0009b5c0,0x00000000,0x000fdc44,
0x00055208,0x00000000,0x00010705,0x000a2880,
0x0000a23a,0x00093a00,0x0003fc8a,0x000df6c5,
0x0004ef0a,0x000c0000,0x00012f05,0x00036880,
0x00065308,0x000c2997,0x000d86b0,0x0000100a,
0x0004410a,0x000d40c7,0x00000000,0x00000000,
0x00080730,0x00001004,0x00056f0a,0x000ea105,
0x00000000,0x00000000,0x0000473d,0x00001000,
0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
0x0000273d,0x00001000,0x00000000,0x000eba44,
0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
0x00000734,0x00001000,0x00010705,0x000a6880,
0x00006a88,0x000c75c4,0x00000000,0x000e5084,
0x00000000,0x000eba44,0x00087401,0x000e4782,
0x00000734,0x00001000,0x00010705,0x000a6880,
0x00006a88,0x000c75c4,0x0007c108,0x000c0000,
0x0007e721,0x000bed40,0x00005f25,0x000badc0,
0x0003ba97,0x000beb80,0x00065590,0x000b2e00,
0x00033217,0x00003ec0,0x00065590,0x000b8e40,
0x0003ed80,0x000491c0,0x00073fb0,0x00074c80,
0x000283a0,0x0000100c,0x000ee388,0x00042970,
0x00008301,0x00021ef2,0x000b8f14,0x0000000f,
0x000c4d8d,0x0000001b,0x000d6dc2,0x000e06c6,
0x000032ac,0x000c3916,0x0004edc2,0x00074c80,
0x00078898,0x00001000,0x00038894,0x00000032,
0x000c4d8d,0x00092e1b,0x000d6dc2,0x000e06c6,
0x0004edc2,0x000c1956,0x0000722c,0x00034a00,
0x00041705,0x0009ed40,0x00058730,0x00001400,
0x000d7488,0x000c3a00,0x00048f05,0x00000000};
static struct
{ u32 Offset;
u32 Size;
u32 *pFill;
} FillStat[FILL__COUNT] = {
{0x00000000, sizeof(FillArray1), FillArray1},
{0x00001800, sizeof(FillArray2), FillArray2},
{0x000137f0, sizeof(FillArray3), FillArray3},
{0x00020000, sizeof(FillArray4), FillArray4}
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,56 +0,0 @@
/*******************************************************************************
*
* "cs46xx_wrapper.c" -- Cirrus Logic-Crystal CS46XX linux audio driver.
*
* Copyright (C) 2000,2001 Cirrus Logic Corp.
* -- tom woller (twoller@crystal.cirrus.com) or
* (pcaudio@crystal.cirrus.com).
*
* 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.
*
* 01/11/2001 trw - new file from cs4281 wrapper code.
*
*******************************************************************************/
#ifndef __CS46XX_WRAPPER24_H
#define __CS46XX_WRAPPER24_H
#include <linux/spinlock.h>
#define CS_OWNER .owner =
#define CS_THIS_MODULE THIS_MODULE,
static inline void cs46xx_null(struct pci_dev *pcidev) { return; }
#define cs4x_mem_map_reserve(page) SetPageReserved(page)
#define cs4x_mem_map_unreserve(page) ClearPageReserved(page)
#define free_dmabuf(card, dmabuf) \
pci_free_consistent((card)->pci_dev, \
PAGE_SIZE << (dmabuf)->buforder, \
(dmabuf)->rawbuf, (dmabuf)->dmaaddr);
#define free_dmabuf2(card, dmabuf) \
pci_free_consistent((card)->pci_dev, \
PAGE_SIZE << (dmabuf)->buforder_tmpbuff, \
(dmabuf)->tmpbuff, (dmabuf)->dmaaddr_tmpbuff);
#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
#define PCI_GET_DRIVER_DATA pci_get_drvdata
#define PCI_SET_DRIVER_DATA pci_set_drvdata
#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask
#endif

View file

@ -1,70 +0,0 @@
/*******************************************************************************
*
* "cs46xxpm.h" -- Cirrus Logic-Crystal CS46XX linux audio driver.
*
* Copyright (C) 2000,2001 Cirrus Logic Corp.
* -- tom woller (twoller@crystal.cirrus.com) or
* (pcaudio@crystal.cirrus.com).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* 12/22/00 trw - new file.
*
*******************************************************************************/
#ifndef __CS46XXPM_H
#define __CS46XXPM_H
#define CS46XX_AC97_HIGHESTREGTORESTORE 0x26
#define CS46XX_AC97_NUMBER_RESTORE_REGS (CS46XX_AC97_HIGHESTREGTORESTORE/2-1)
/* PM state defintions */
#define CS46XX_PM_NOT_REGISTERED 0x1000
#define CS46XX_PM_IDLE 0x0001
#define CS46XX_PM_SUSPENDING 0x0002
#define CS46XX_PM_SUSPENDED 0x0004
#define CS46XX_PM_RESUMING 0x0008
#define CS46XX_PM_RESUMED 0x0010
#define CS_POWER_DAC 0x0001
#define CS_POWER_ADC 0x0002
#define CS_POWER_MIXVON 0x0004
#define CS_POWER_MIXVOFF 0x0008
#define CS_AC97_POWER_CONTROL_ON 0xf000 /* always on bits (inverted) */
#define CS_AC97_POWER_CONTROL_ADC 0x0100
#define CS_AC97_POWER_CONTROL_DAC 0x0200
#define CS_AC97_POWER_CONTROL_MIXVON 0x0400
#define CS_AC97_POWER_CONTROL_MIXVOFF 0x0800
#define CS_AC97_POWER_CONTROL_ADC_ON 0x0001
#define CS_AC97_POWER_CONTROL_DAC_ON 0x0002
#define CS_AC97_POWER_CONTROL_MIXVON_ON 0x0004
#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008
struct cs46xx_pm {
unsigned long flags;
u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
u32 u32SSPM_BITS;
u32 ac97[CS46XX_AC97_NUMBER_RESTORE_REGS];
u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
u32 u32hwptr_playback,u32hwptr_capture;
unsigned dmabuf_swptr_play;
int dmabuf_count_play;
unsigned dmabuf_swptr_capture;
int dmabuf_count_capture;
};
#endif

View file

@ -1,737 +0,0 @@
/*
**********************************************************************
* 8010.h
* Copyright 1999-2001 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS
* line endings
* December 8, 1999 Jon Taylor Added lots of new register info
* May 16, 2001 Daniel Bertrand Added unofficial DBG register info
* Oct-Nov 2001 D.B. Added unofficial Audigy registers
*
**********************************************************************
*
* 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 _8010_H
#define _8010_H
#include <linux/types.h>
// Driver version:
#define MAJOR_VER 0
#define MINOR_VER 20
#define DRIVER_VERSION "0.20a"
// Audigy specify registers are prefixed with 'A_'
/************************************************************************************************/
/* PCI function 0 registers, address = <val> + PCIBASE0 */
/************************************************************************************************/
#define PTR 0x00 /* Indexed register set pointer register */
/* NOTE: The CHANNELNUM and ADDRESS words can */
/* be modified independently of each other. */
#define PTR_CHANNELNUM_MASK 0x0000003f /* For each per-channel register, indicates the */
/* channel number of the register to be */
/* accessed. For non per-channel registers the */
/* value should be set to zero. */
#define PTR_ADDRESS_MASK 0x07ff0000 /* Register index */
#define DATA 0x04 /* Indexed register set data register */
#define IPR 0x08 /* Global interrupt pending register */
/* Clear pending interrupts by writing a 1 to */
/* the relevant bits and zero to the other bits */
/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */
#define A_IPR_MIDITRANSBUFEMPTY2 0x10000000 /* MIDI UART transmit buffer empty */
#define A_IPR_MIDIRECVBUFEMPTY2 0x08000000 /* MIDI UART receive buffer empty */
#define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */
#define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */
#define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */
#define IPR_PCIERROR 0x00200000 /* PCI bus error */
#define IPR_VOLINCR 0x00100000 /* Volume increment button pressed */
#define IPR_VOLDECR 0x00080000 /* Volume decrement button pressed */
#define IPR_MUTE 0x00040000 /* Mute button pressed */
#define IPR_MICBUFFULL 0x00020000 /* Microphone buffer full */
#define IPR_MICBUFHALFFULL 0x00010000 /* Microphone buffer half full */
#define IPR_ADCBUFFULL 0x00008000 /* ADC buffer full */
#define IPR_ADCBUFHALFFULL 0x00004000 /* ADC buffer half full */
#define IPR_EFXBUFFULL 0x00002000 /* Effects buffer full */
#define IPR_EFXBUFHALFFULL 0x00001000 /* Effects buffer half full */
#define IPR_GPSPDIFSTATUSCHANGE 0x00000800 /* GPSPDIF channel status change */
#define IPR_CDROMSTATUSCHANGE 0x00000400 /* CD-ROM channel status change */
#define IPR_INTERVALTIMER 0x00000200 /* Interval timer terminal count */
#define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */
#define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */
#define IPR_CHANNELLOOP 0x00000040 /* One or more channel loop interrupts pending */
#define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */
/* Highest set channel in CLIPL or CLIPH. When */
/* IP is written with CL set, the bit in CLIPL */
/* or CLIPH corresponding to the CIN value */
/* written will be cleared. */
#define A_IPR_MIDITRANSBUFEMPTY1 IPR_MIDITRANSBUFEMPTY /* MIDI UART transmit buffer empty */
#define A_IPR_MIDIRECVBUFEMPTY1 IPR_MIDIRECVBUFEMPTY /* MIDI UART receive buffer empty */
#define INTE 0x0c /* Interrupt enable register */
#define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */
#define INTE_VIRTUALSB_220 0x00000000 /* Capture at I/O base address 0x220-0x22f */
#define INTE_VIRTUALSB_240 0x40000000 /* Capture at I/O base address 0x240 */
#define INTE_VIRTUALSB_260 0x80000000 /* Capture at I/O base address 0x260 */
#define INTE_VIRTUALSB_280 0xc0000000 /* Capture at I/O base address 0x280 */
#define INTE_VIRTUALMPU_MASK 0x30000000 /* Virtual MPU I/O port capture */
#define INTE_VIRTUALMPU_300 0x00000000 /* Capture at I/O base address 0x300-0x301 */
#define INTE_VIRTUALMPU_310 0x10000000 /* Capture at I/O base address 0x310 */
#define INTE_VIRTUALMPU_320 0x20000000 /* Capture at I/O base address 0x320 */
#define INTE_VIRTUALMPU_330 0x30000000 /* Capture at I/O base address 0x330 */
#define INTE_MASTERDMAENABLE 0x08000000 /* Master DMA emulation at 0x000-0x00f */
#define INTE_SLAVEDMAENABLE 0x04000000 /* Slave DMA emulation at 0x0c0-0x0df */
#define INTE_MASTERPICENABLE 0x02000000 /* Master PIC emulation at 0x020-0x021 */
#define INTE_SLAVEPICENABLE 0x01000000 /* Slave PIC emulation at 0x0a0-0x0a1 */
#define INTE_VSBENABLE 0x00800000 /* Enable virtual Soundblaster */
#define INTE_ADLIBENABLE 0x00400000 /* Enable AdLib emulation at 0x388-0x38b */
#define INTE_MPUENABLE 0x00200000 /* Enable virtual MPU */
#define INTE_FORCEINT 0x00100000 /* Continuously assert INTAN */
#define INTE_MRHANDENABLE 0x00080000 /* Enable the "Mr. Hand" logic */
/* NOTE: There is no reason to use this under */
/* Linux, and it will cause odd hardware */
/* behavior and possibly random segfaults and */
/* lockups if enabled. */
/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */
#define A_INTE_MIDITXENABLE2 0x00020000 /* Enable MIDI transmit-buffer-empty interrupts */
#define A_INTE_MIDIRXENABLE2 0x00010000 /* Enable MIDI receive-buffer-empty interrupts */
#define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */
/* NOTE: This bit must always be enabled */
#define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */
#define INTE_PCIERRORENABLE 0x00000800 /* Enable PCI bus error interrupts */
#define INTE_VOLINCRENABLE 0x00000400 /* Enable volume increment button interrupts */
#define INTE_VOLDECRENABLE 0x00000200 /* Enable volume decrement button interrupts */
#define INTE_MUTEENABLE 0x00000100 /* Enable mute button interrupts */
#define INTE_MICBUFENABLE 0x00000080 /* Enable microphone buffer interrupts */
#define INTE_ADCBUFENABLE 0x00000040 /* Enable ADC buffer interrupts */
#define INTE_EFXBUFENABLE 0x00000020 /* Enable Effects buffer interrupts */
#define INTE_GPSPDIFENABLE 0x00000010 /* Enable GPSPDIF status interrupts */
#define INTE_CDSPDIFENABLE 0x00000008 /* Enable CDSPDIF status interrupts */
#define INTE_INTERVALTIMERENB 0x00000004 /* Enable interval timer interrupts */
#define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */
#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */
/* The next two interrupts are for the midi port on the Audigy (A_MPU2) */
#define A_INTE_MIDITXENABLE1 INTE_MIDITXENABLE
#define A_INTE_MIDIRXENABLE1 INTE_MIDIRXENABLE
#define WC 0x10 /* Wall Clock register */
#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */
#define WC_SAMPLECOUNTER 0x14060010
#define WC_CURRENTCHANNEL 0x0000003F /* Channel [0..63] currently being serviced */
/* NOTE: Each channel takes 1/64th of a sample */
/* period to be serviced. */
#define HCFG 0x14 /* Hardware config register */
/* NOTE: There is no reason to use the legacy */
/* SoundBlaster emulation stuff described below */
/* under Linux, and all kinds of weird hardware */
/* behavior can result if you try. Don't. */
#define HCFG_LEGACYFUNC_MASK 0xe0000000 /* Legacy function number */
#define HCFG_LEGACYFUNC_MPU 0x00000000 /* Legacy MPU */
#define HCFG_LEGACYFUNC_SB 0x40000000 /* Legacy SB */
#define HCFG_LEGACYFUNC_AD 0x60000000 /* Legacy AD */
#define HCFG_LEGACYFUNC_MPIC 0x80000000 /* Legacy MPIC */
#define HCFG_LEGACYFUNC_MDMA 0xa0000000 /* Legacy MDMA */
#define HCFG_LEGACYFUNC_SPCI 0xc0000000 /* Legacy SPCI */
#define HCFG_LEGACYFUNC_SDMA 0xe0000000 /* Legacy SDMA */
#define HCFG_IOCAPTUREADDR 0x1f000000 /* The 4 LSBs of the captured I/O address. */
#define HCFG_LEGACYWRITE 0x00800000 /* 1 = write, 0 = read */
#define HCFG_LEGACYWORD 0x00400000 /* 1 = word, 0 = byte */
#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */
/* NOTE: The rest of the bits in this register */
/* _are_ relevant under Linux. */
#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */
#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */
#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */
#define HCFG_GPINPUT0 0x00004000 /* External pin112 */
#define HCFG_GPINPUT1 0x00002000 /* External pin110 */
#define HCFG_GPOUTPUT_MASK 0x00001c00 /* External pins which may be controlled */
#define HCFG_GPOUT0 0x00001000 /* set to enable digital out on 5.1 cards */
#define HCFG_JOYENABLE 0x00000200 /* Internal joystick enable */
#define HCFG_PHASETRACKENABLE 0x00000100 /* Phase tracking enable */
/* 1 = Force all 3 async digital inputs to use */
/* the same async sample rate tracker (ZVIDEO) */
#define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */
#define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */
#define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */
#define HCFG_AC3ENABLE_GPSPDIF 0x00000020 /* Channels 0 and 1 replace GPSPDIF */
#define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */
/* will automatically mute their output when */
/* they are not rate-locked to the external */
/* async audio source */
#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
/* NOTE: This should generally never be used. */
#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */
/* NOTE: This should generally never be used. */
#define HCFG_LOCKTANKCACHE 0x01020014
#define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */
/* NOTE: This is a 'cheap' way to implement a */
/* master mute function on the mute button, and */
/* in general should not be used unless a more */
/* sophisticated master mute function has not */
/* been written. */
#define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */
/* Should be set to 1 when the EMU10K1 is */
/* completely initialized. */
//For Audigy, MPU port move to 0x70-0x74 ptr register
#define MUDATA 0x18 /* MPU401 data register (8 bits) */
#define MUCMD 0x19 /* MPU401 command register (8 bits) */
#define MUCMD_RESET 0xff /* RESET command */
#define MUCMD_ENTERUARTMODE 0x3f /* Enter_UART_mode command */
/* NOTE: All other commands are ignored */
#define MUSTAT MUCMD /* MPU401 status register (8 bits) */
#define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */
#define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */
#define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */
#define A_GPINPUT_MASK 0xff00
#define A_GPOUTPUT_MASK 0x00ff
#define TIMER 0x1a /* Timer terminal count register (16-bit) */
/* NOTE: After the rate is changed, a maximum */
/* of 1024 sample periods should be allowed */
/* before the new rate is guaranteed accurate. */
#define TIMER_RATE_MASK 0x03ff /* Timer interrupt rate in sample periods */
/* 0 == 1024 periods, [1..4] are not useful */
#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */
#define AC97ADDRESS_READY 0x80 /* Read-only bit, reflects CODEC READY signal */
#define AC97ADDRESS_ADDRESS 0x7f /* Address of indexed AC97 register */
/********************************************************************************************************/
/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers */
/********************************************************************************************************/
#define CPF 0x00 /* Current pitch and fraction register */
#define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */
#define CPF_CURRENTPITCH 0x10100000
#define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */
#define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */
#define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */
#define PTRX 0x01 /* Pitch target and send A/B amounts register */
#define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */
#define PTRX_PITCHTARGET 0x10100001
#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */
#define PTRX_FXSENDAMOUNT_A 0x08080001
#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */
#define PTRX_FXSENDAMOUNT_B 0x08000001
#define CVCF 0x02 /* Current volume and filter cutoff register */
#define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */
#define CVCF_CURRENTVOL 0x10100002
#define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */
#define CVCF_CURRENTFILTER 0x10000002
#define VTFT 0x03 /* Volume target and filter cutoff target register */
#define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */
#define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */
#define Z1 0x05 /* Filter delay memory 1 register */
#define Z2 0x04 /* Filter delay memory 2 register */
#define PSST 0x06 /* Send C amount and loop start address register */
#define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */
#define PSST_FXSENDAMOUNT_C 0x08180006
#define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */
#define PSST_LOOPSTARTADDR 0x18000006
#define DSL 0x07 /* Send D amount and loop start address register */
#define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */
#define DSL_FXSENDAMOUNT_D 0x08180007
#define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */
#define DSL_LOOPENDADDR 0x18000007
#define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */
#define CCCA_RESONANCE 0xf0000000 /* Lowpass filter resonance (Q) height */
#define CCCA_INTERPROMMASK 0x0e000000 /* Selects passband of interpolation ROM */
/* 1 == full band, 7 == lowpass */
/* ROM 0 is used when pitch shifting downward or less */
/* then 3 semitones upward. Increasingly higher ROM */
/* numbers are used, typically in steps of 3 semitones, */
/* as upward pitch shifting is performed. */
#define CCCA_INTERPROM_0 0x00000000 /* Select interpolation ROM 0 */
#define CCCA_INTERPROM_1 0x02000000 /* Select interpolation ROM 1 */
#define CCCA_INTERPROM_2 0x04000000 /* Select interpolation ROM 2 */
#define CCCA_INTERPROM_3 0x06000000 /* Select interpolation ROM 3 */
#define CCCA_INTERPROM_4 0x08000000 /* Select interpolation ROM 4 */
#define CCCA_INTERPROM_5 0x0a000000 /* Select interpolation ROM 5 */
#define CCCA_INTERPROM_6 0x0c000000 /* Select interpolation ROM 6 */
#define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */
#define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
#define CCCA_CURRADDR 0x18000008
#define CCR 0x09 /* Cache control register */
#define CCR_CACHEINVALIDSIZE 0x07190009
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
#define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */
#define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */
#define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */
#define CCR_READADDRESS 0x06100009
#define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */
#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */
/* NOTE: This is valid only if CACHELOOPFLAG is set */
#define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */
#define CCR_CACHELOOPADDRHI 0x000000ff /* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */
#define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
/* NOTE: This register is normally not used */
#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address (DSL_LOOPSTARTADDR [0..15]) */
#define FXRT 0x0b /* Effects send routing register */
/* NOTE: It is illegal to assign the same routing to */
/* two effects sends. */
#define FXRT_CHANNELA 0x000f0000 /* Effects send bus number for channel's effects send A */
#define FXRT_CHANNELB 0x00f00000 /* Effects send bus number for channel's effects send B */
#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */
#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */
#define MAPA 0x0c /* Cache map A */
#define MAPB 0x0d /* Cache map B */
#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
#define ENVVOL 0x10 /* Volume envelope register */
#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */
/* 0x8000-n == 666*n usec delay */
#define ATKHLDV 0x11 /* Volume envelope hold and attack register */
#define ATKHLDV_PHASE0 0x00008000 /* 0 = Begin attack phase */
#define ATKHLDV_HOLDTIME_MASK 0x00007f00 /* Envelope hold time (127-n == n*88.2msec) */
#define ATKHLDV_ATTACKTIME_MASK 0x0000007f /* Envelope attack time, log encoded */
/* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec */
#define DCYSUSV 0x12 /* Volume envelope sustain and decay register */
#define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */
#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */
#define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 1 = Inhibit envelope engine from writing values in */
/* this channel and from writing to pitch, filter and */
/* volume targets. */
#define DCYSUSV_DECAYTIME_MASK 0x0000007f /* Volume envelope decay time, log encoded */
/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */
#define LFOVAL1 0x13 /* Modulation LFO value */
#define LFOVAL_MASK 0x0000ffff /* Current value of modulation LFO state variable */
/* 0x8000-n == 666*n usec delay */
#define ENVVAL 0x14 /* Modulation envelope register */
#define ENVVAL_MASK 0x0000ffff /* Current value of modulation envelope state variable */
/* 0x8000-n == 666*n usec delay */
#define ATKHLDM 0x15 /* Modulation envelope hold and attack register */
#define ATKHLDM_PHASE0 0x00008000 /* 0 = Begin attack phase */
#define ATKHLDM_HOLDTIME 0x00007f00 /* Envelope hold time (127-n == n*42msec) */
#define ATKHLDM_ATTACKTIME 0x0000007f /* Envelope attack time, log encoded */
/* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec */
#define DCYSUSM 0x16 /* Modulation envelope decay and sustain register */
#define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */
#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */
#define DCYSUSM_DECAYTIME_MASK 0x0000007f /* Envelope decay time, log encoded */
/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */
#define LFOVAL2 0x17 /* Vibrato LFO register */
#define LFOVAL2_MASK 0x0000ffff /* Current value of vibrato LFO state variable */
/* 0x8000-n == 666*n usec delay */
#define IP 0x18 /* Initial pitch register */
#define IP_MASK 0x0000ffff /* Exponential initial pitch shift */
/* 4 bits of octave, 12 bits of fractional octave */
#define IP_UNITY 0x0000e000 /* Unity pitch shift */
#define IFATN 0x19 /* Initial filter cutoff and attenuation register */
#define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */
/* 6 most significant bits are semitones */
/* 2 least significant bits are fractions */
#define IFATN_FILTERCUTOFF 0x08080019
#define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */
#define IFATN_ATTENUATION 0x08000019
#define PEFE 0x1a /* Pitch envelope and filter envelope amount register */
#define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */
/* Signed 2's complement, +/- one octave peak extremes */
#define PEFE_PITCHAMOUNT 0x0808001a
#define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */
/* Signed 2's complement, +/- six octaves peak extremes */
#define PEFE_FILTERAMOUNT 0x0800001a
#define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */
#define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */
/* Signed 2's complement, +/- one octave extremes */
#define FMMOD_MOFILTER 0x000000ff /* Filter LFO modulation depth */
/* Signed 2's complement, +/- three octave extremes */
#define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */
#define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */
/* Signed 2's complement, with +/- 12dB extremes */
#define TREMFRQ_FREQUENCY 0x000000ff /* Tremolo LFO frequency */
/* ??Hz steps, maximum of ?? Hz. */
#define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */
#define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */
/* Signed 2's complement, +/- one octave extremes */
#define FM2FRQ2_FREQUENCY 0x000000ff /* Vibrato LFO frequency */
/* 0.039Hz steps, maximum of 9.85 Hz. */
#define TEMPENV 0x1e /* Tempory envelope register */
#define TEMPENV_MASK 0x0000ffff /* 16-bit value */
/* NOTE: All channels contain internal variables; do */
/* not write to these locations. */
#define CD0 0x20 /* Cache data 0 register */
#define CD1 0x21 /* Cache data 1 register */
#define CD2 0x22 /* Cache data 2 register */
#define CD3 0x23 /* Cache data 3 register */
#define CD4 0x24 /* Cache data 4 register */
#define CD5 0x25 /* Cache data 5 register */
#define CD6 0x26 /* Cache data 6 register */
#define CD7 0x27 /* Cache data 7 register */
#define CD8 0x28 /* Cache data 8 register */
#define CD9 0x29 /* Cache data 9 register */
#define CDA 0x2a /* Cache data A register */
#define CDB 0x2b /* Cache data B register */
#define CDC 0x2c /* Cache data C register */
#define CDD 0x2d /* Cache data D register */
#define CDE 0x2e /* Cache data E register */
#define CDF 0x2f /* Cache data F register */
#define PTB 0x40 /* Page table base register */
#define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */
#define TCB 0x41 /* Tank cache base register */
#define TCB_MASK 0xfffff000 /* Physical address of the bottom of host based TRAM */
#define ADCCR 0x42 /* ADC sample rate/stereo control register */
#define ADCCR_RCHANENABLE 0x00000010 /* Enables right channel for writing to the host */
#define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */
/* NOTE: To guarantee phase coherency, both channels */
/* must be disabled prior to enabling both channels. */
#define A_ADCCR_RCHANENABLE 0x00000020
#define A_ADCCR_LCHANENABLE 0x00000010
#define A_ADCCR_SAMPLERATE_MASK 0x0000000F /* Audigy sample rate convertor output rate */
#define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */
#define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */
#define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */
#define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */
#define ADCCR_SAMPLERATE_24 0x00000003 /* 24kHz sample rate */
#define ADCCR_SAMPLERATE_22 0x00000004 /* 22.05kHz sample rate */
#define ADCCR_SAMPLERATE_16 0x00000005 /* 16kHz sample rate */
#define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */
#define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */
#define A_ADCCR_SAMPLERATE_12 0x00000006 /* 12kHz sample rate */
#define A_ADCCR_SAMPLERATE_11 0x00000007 /* 11.025kHz sample rate */
#define A_ADCCR_SAMPLERATE_8 0x00000008 /* 8kHz sample rate */
#define FXWC 0x43 /* FX output write channels register */
/* When set, each bit enables the writing of the */
/* corresponding FX output channel (internal registers */
/* 0x20-0x3f) into host memory. This mode of recording */
/* is 16bit, 48KHz only. All 32 channels can be enabled */
/* simultaneously. */
#define TCBS 0x44 /* Tank cache buffer size register */
#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
#define TCBS_BUFFSIZE_16K 0x00000000
#define TCBS_BUFFSIZE_32K 0x00000001
#define TCBS_BUFFSIZE_64K 0x00000002
#define TCBS_BUFFSIZE_128K 0x00000003
#define TCBS_BUFFSIZE_256K 0x00000004
#define TCBS_BUFFSIZE_512K 0x00000005
#define TCBS_BUFFSIZE_1024K 0x00000006
#define TCBS_BUFFSIZE_2048K 0x00000007
#define MICBA 0x45 /* AC97 microphone buffer address register */
#define MICBA_MASK 0xfffff000 /* 20 bit base address */
#define ADCBA 0x46 /* ADC buffer address register */
#define ADCBA_MASK 0xfffff000 /* 20 bit base address */
#define FXBA 0x47 /* FX Buffer Address */
#define FXBA_MASK 0xfffff000 /* 20 bit base address */
#define MICBS 0x49 /* Microphone buffer size register */
#define ADCBS 0x4a /* ADC buffer size register */
#define FXBS 0x4b /* FX buffer size register */
/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */
#define ADCBS_BUFSIZE_NONE 0x00000000
#define ADCBS_BUFSIZE_384 0x00000001
#define ADCBS_BUFSIZE_448 0x00000002
#define ADCBS_BUFSIZE_512 0x00000003
#define ADCBS_BUFSIZE_640 0x00000004
#define ADCBS_BUFSIZE_768 0x00000005
#define ADCBS_BUFSIZE_896 0x00000006
#define ADCBS_BUFSIZE_1024 0x00000007
#define ADCBS_BUFSIZE_1280 0x00000008
#define ADCBS_BUFSIZE_1536 0x00000009
#define ADCBS_BUFSIZE_1792 0x0000000a
#define ADCBS_BUFSIZE_2048 0x0000000b
#define ADCBS_BUFSIZE_2560 0x0000000c
#define ADCBS_BUFSIZE_3072 0x0000000d
#define ADCBS_BUFSIZE_3584 0x0000000e
#define ADCBS_BUFSIZE_4096 0x0000000f
#define ADCBS_BUFSIZE_5120 0x00000010
#define ADCBS_BUFSIZE_6144 0x00000011
#define ADCBS_BUFSIZE_7168 0x00000012
#define ADCBS_BUFSIZE_8192 0x00000013
#define ADCBS_BUFSIZE_10240 0x00000014
#define ADCBS_BUFSIZE_12288 0x00000015
#define ADCBS_BUFSIZE_14366 0x00000016
#define ADCBS_BUFSIZE_16384 0x00000017
#define ADCBS_BUFSIZE_20480 0x00000018
#define ADCBS_BUFSIZE_24576 0x00000019
#define ADCBS_BUFSIZE_28672 0x0000001a
#define ADCBS_BUFSIZE_32768 0x0000001b
#define ADCBS_BUFSIZE_40960 0x0000001c
#define ADCBS_BUFSIZE_49152 0x0000001d
#define ADCBS_BUFSIZE_57344 0x0000001e
#define ADCBS_BUFSIZE_65536 0x0000001f
#define CDCS 0x50 /* CD-ROM digital channel status register */
#define GPSCS 0x51 /* General Purpose SPDIF channel status register*/
#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
/* definitions for debug register - taken from the alsa drivers */
#define DBG_ZC 0x80000000 /* zero tram counter */
#define DBG_SATURATION_OCCURED 0x02000000 /* saturation control */
#define DBG_SATURATION_ADDR 0x01ff0000 /* saturation address */
#define DBG_SINGLE_STEP 0x00008000 /* single step mode */
#define DBG_STEP 0x00004000 /* start single step */
#define DBG_CONDITION_CODE 0x00003e00 /* condition code */
#define DBG_SINGLE_STEP_ADDR 0x000001ff /* single step address */
#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
#define A_DBG 0x53
#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */
#define A_DBG_ZC 0x40000000 /* zero tram counter */
#define A_DBG_STEP_ADDR 0x000003ff
#define A_DBG_SATURATION_OCCURED 0x20000000
#define A_DBG_SATURATION_ADDR 0x0ffc0000
#define SPCS0 0x54 /* SPDIF output Channel Status 0 register */
#define SPCS1 0x55 /* SPDIF output Channel Status 1 register */
#define SPCS2 0x56 /* SPDIF output Channel Status 2 register */
#define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */
#define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */
#define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */
#define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */
#define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */
#define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */
#define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */
#define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */
#define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */
#define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */
#define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */
#define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */
#define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */
#define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */
#define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */
#define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */
#define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */
#define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */
#define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */
#define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */
#define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */
#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */
#define CLIEL 0x58 /* Channel loop interrupt enable low register */
#define CLIEH 0x59 /* Channel loop interrupt enable high register */
#define CLIPL 0x5a /* Channel loop interrupt pending low register */
#define CLIPH 0x5b /* Channel loop interrupt pending high register */
#define SOLEL 0x5c /* Stop on loop enable low register */
#define SOLEH 0x5d /* Stop on loop enable high register */
#define SPBYPASS 0x5e /* SPDIF BYPASS mode register */
#define SPBYPASS_ENABLE 0x00000001 /* Enable SPDIF bypass mode */
#define AC97SLOT 0x5f /* additional AC97 slots enable bits */
#define AC97SLOT_CNTR 0x10 /* Center enable */
#define AC97SLOT_LFE 0x20 /* LFE enable */
#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */
#define GPSRCS 0x61 /* General Purpose SPDIF sample rate cvt status */
#define ZVSRCS 0x62 /* ZVideo sample rate converter status */
/* NOTE: This one has no SPDIFLOCKED field */
/* Assumes sample lock */
/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */
#define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */
#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */
#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */
/* Note that these values can vary +/- by a small amount */
#define SRCS_SPDIFRATE_44 0x0003acd9
#define SRCS_SPDIFRATE_48 0x00040000
#define SRCS_SPDIFRATE_96 0x00080000
#define MICIDX 0x63 /* Microphone recording buffer index register */
#define MICIDX_MASK 0x0000ffff /* 16-bit value */
#define MICIDX_IDX 0x10000063
#define A_ADCIDX 0x63
#define A_ADCIDX_IDX 0x10000063
#define ADCIDX 0x64 /* ADC recording buffer index register */
#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */
#define ADCIDX_IDX 0x10000064
#define FXIDX 0x65 /* FX recording buffer index register */
#define FXIDX_MASK 0x0000ffff /* 16-bit value */
#define FXIDX_IDX 0x10000065
/* This is the MPU port on the card (via the game port) */
#define A_MUDATA1 0x70
#define A_MUCMD1 0x71
#define A_MUSTAT1 A_MUCMD1
/* This is the MPU port on the Audigy Drive */
#define A_MUDATA2 0x72
#define A_MUCMD2 0x73
#define A_MUSTAT2 A_MUCMD2
/* The next two are the Audigy equivalent of FXWC */
/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) */
/* Each bit selects a channel for recording */
#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */
#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
#define A_SPDIF_48000 0x00000080
#define A_SPDIF_44100 0x00000000
#define A_SPDIF_96000 0x00000040
#define A_FXRT2 0x7c
#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */
#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send G */
#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send H */
#define A_SENDAMOUNTS 0x7d
#define A_FXSENDAMOUNT_E_MASK 0xff000000
#define A_FXSENDAMOUNT_F_MASK 0x00ff0000
#define A_FXSENDAMOUNT_G_MASK 0x0000ff00
#define A_FXSENDAMOUNT_H_MASK 0x000000ff
/* The send amounts for this one are the same as used with the emu10k1 */
#define A_FXRT1 0x7e
#define A_FXRT_CHANNELA 0x0000003f
#define A_FXRT_CHANNELB 0x00003f00
#define A_FXRT_CHANNELC 0x003f0000
#define A_FXRT_CHANNELD 0x3f000000
/* Each FX general purpose register is 32 bits in length, all bits are used */
#define FXGPREGBASE 0x100 /* FX general purpose registers base */
#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */
/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */
/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */
/* locations are for external TRAM. */
#define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */
#define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */
/* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */
#define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */
#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */
#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */
#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */
#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */
#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */
#define MICROCODEBASE 0x400 /* Microcode data base address */
/* Each DSP microcode instruction is mapped into 2 doublewords */
/* NOTE: When writing, always write the LO doubleword first. Reads can be in either order. */
#define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */
#define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */
#define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */
#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */
#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */
/* Audigy Soundcard have a different instruction format */
#define AUDIGY_CODEBASE 0x600
#define A_LOWORD_OPY_MASK 0x000007ff
#define A_LOWORD_OPX_MASK 0x007ff000
#define A_HIWORD_OPCODE_MASK 0x0f000000
#define A_HIWORD_RESULT_MASK 0x007ff000
#define A_HIWORD_OPA_MASK 0x000007ff
#endif /* _8010_H */

View file

@ -1,17 +0,0 @@
# Makefile for Creative Labs EMU10K1
#
# 12 Apr 2000 Rui Sousa
obj-$(CONFIG_SOUND_EMU10K1) += emu10k1.o
emu10k1-objs := audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
efxmgr.o emuadxmg.o hwaccess.o irqmgr.o main.o midi.o \
mixer.o passthrough.o recmgr.o timer.o voicemgr.o
ifdef DEBUG
EXTRA_CFLAGS += -DEMU10K1_DEBUG
endif
ifdef CONFIG_MIDI_EMU10K1
EXTRA_CFLAGS += -DEMU10K1_SEQUENCER
endif

File diff suppressed because it is too large Load diff

View file

@ -1,44 +0,0 @@
/*
**********************************************************************
* audio.c -- /dev/dsp interface for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox cleaned up types/leaks
*
**********************************************************************
*
* 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 _AUDIO_H
#define _AUDIO_H
struct emu10k1_wavedevice
{
struct emu10k1_card *card;
struct wiinst *wiinst;
struct woinst *woinst;
u16 enablebits;
};
#endif /* _AUDIO_H */

View file

@ -1,832 +0,0 @@
/*
**********************************************************************
* sblive_mi.c - MIDI UART input HAL for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox clean up
*
**********************************************************************
*
* 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/slab.h>
#include <linux/jiffies.h>
#include "hwaccess.h"
#include "8010.h"
#include "cardmi.h"
#include "irqmgr.h"
static int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid);
static int sblive_miStateInit(struct emu10k1_mpuin *);
static int sblive_miStateEntry(struct emu10k1_mpuin *, u8);
static int sblive_miStateParse(struct emu10k1_mpuin *, u8);
static int sblive_miState3Byte(struct emu10k1_mpuin *, u8);
static int sblive_miState3ByteKey(struct emu10k1_mpuin *, u8);
static int sblive_miState3ByteVel(struct emu10k1_mpuin *, u8);
static int sblive_miState2Byte(struct emu10k1_mpuin *, u8);
static int sblive_miState2ByteKey(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysCommon2(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysCommon3(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysExNorm(struct emu10k1_mpuin *, u8);
static int sblive_miStateSysReal(struct emu10k1_mpuin *, u8);
static struct {
int (*Fn) (struct emu10k1_mpuin *, u8);
} midistatefn[] = {
{
sblive_miStateParse}, {
sblive_miState3Byte}, /* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */
{
sblive_miState3ByteKey}, /* Byte 1 */
{
sblive_miState3ByteVel}, /* Byte 2 */
{
sblive_miState2Byte}, /* 0xCn, 0xDn */
{
sblive_miState2ByteKey}, /* Byte 1 */
{
sblive_miStateSysCommon2}, /* 0xF1 , 0xF3 */
{
sblive_miStateSysCommon2Key}, /* 0xF1 , 0xF3, Byte 1 */
{
sblive_miStateSysCommon3}, /* 0xF2 */
{
sblive_miStateSysCommon3Key}, /* 0xF2 , Byte 1 */
{
sblive_miStateSysCommon3Vel}, /* 0xF2 , Byte 2 */
{
sblive_miStateSysExNorm}, /* 0xF0, 0xF7, Normal mode */
{
sblive_miStateSysReal} /* 0xF4 - 0xF6 ,0xF8 - 0xFF */
};
/* Installs the IRQ handler for the MPU in port */
/* and initialize parameters */
int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
{
struct emu10k1_mpuin *card_mpuin = card->mpuin;
DPF(2, "emu10k1_mpuin_open\n");
if (!(card_mpuin->status & FLAGS_AVAILABLE))
return -1;
/* Copy open info and mark channel as in use */
card_mpuin->openinfo = *openinfo;
card_mpuin->status &= ~FLAGS_AVAILABLE; /* clear */
card_mpuin->status |= FLAGS_READY; /* set */
card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
card_mpuin->firstmidiq = NULL;
card_mpuin->lastmidiq = NULL;
card_mpuin->qhead = 0;
card_mpuin->qtail = 0;
sblive_miStateInit(card_mpuin);
emu10k1_mpu_reset(card);
emu10k1_mpu_acquire(card);
return 0;
}
int emu10k1_mpuin_close(struct emu10k1_card *card)
{
struct emu10k1_mpuin *card_mpuin = card->mpuin;
DPF(2, "emu10k1_mpuin_close()\n");
/* Check if there are pending input SysEx buffers */
if (card_mpuin->firstmidiq != NULL) {
ERROR();
return -1;
}
/* Disable RX interrupt */
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
emu10k1_mpu_release(card);
card_mpuin->status |= FLAGS_AVAILABLE; /* set */
card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
return 0;
}
/* Adds MIDI buffer to local queue list */
int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *midihdr)
{
struct midi_queue *midiq;
unsigned long flags;
DPF(2, "emu10k1_mpuin_add_buffer()\n");
/* Update MIDI buffer flags */
midihdr->flags |= MIDIBUF_INQUEUE; /* set */
midihdr->flags &= ~MIDIBUF_DONE; /* clear */
if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
/* Message lost */
return -1;
}
midiq->next = NULL;
midiq->qtype = 1;
midiq->length = midihdr->bufferlength;
midiq->sizeLeft = midihdr->bufferlength;
midiq->midibyte = midihdr->data;
midiq->refdata = (unsigned long) midihdr;
spin_lock_irqsave(&card_mpuin->lock, flags);
if (card_mpuin->firstmidiq == NULL) {
card_mpuin->firstmidiq = midiq;
card_mpuin->lastmidiq = midiq;
} else {
(card_mpuin->lastmidiq)->next = midiq;
card_mpuin->lastmidiq = midiq;
}
spin_unlock_irqrestore(&card_mpuin->lock, flags);
return 0;
}
/* First set the Time Stamp if MIDI IN has not started. */
/* Then enable RX Irq. */
int emu10k1_mpuin_start(struct emu10k1_card *card)
{
struct emu10k1_mpuin *card_mpuin = card->mpuin;
u8 dummy;
DPF(2, "emu10k1_mpuin_start()\n");
/* Set timestamp if not set */
if (card_mpuin->status & FLAGS_MIDM_STARTED) {
DPF(2, "Time Stamp not changed\n");
} else {
while (!emu10k1_mpu_read_data(card, &dummy));
card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */
/* Set new time stamp */
card_mpuin->timestart = (jiffies * 1000) / HZ;
DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart);
card_mpuin->qhead = 0;
card_mpuin->qtail = 0;
emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
}
return 0;
}
/* Disable the RX Irq. If a partial recorded buffer */
/* exist, send it up to IMIDI level. */
int emu10k1_mpuin_stop(struct emu10k1_card *card)
{
struct emu10k1_mpuin *card_mpuin = card->mpuin;
struct midi_queue *midiq;
unsigned long flags;
DPF(2, "emu10k1_mpuin_stop()\n");
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
if (card_mpuin->firstmidiq) {
spin_lock_irqsave(&card_mpuin->lock, flags);
midiq = card_mpuin->firstmidiq;
if (midiq != NULL) {
if (midiq->sizeLeft == midiq->length)
midiq = NULL;
else {
card_mpuin->firstmidiq = midiq->next;
if (card_mpuin->firstmidiq == NULL)
card_mpuin->lastmidiq = NULL;
}
}
spin_unlock_irqrestore(&card_mpuin->lock, flags);
if (midiq) {
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
kfree(midiq);
}
}
return 0;
}
/* Disable the RX Irq. If any buffer */
/* exist, send it up to IMIDI level. */
int emu10k1_mpuin_reset(struct emu10k1_card *card)
{
struct emu10k1_mpuin *card_mpuin = card->mpuin;
struct midi_queue *midiq;
DPF(2, "emu10k1_mpuin_reset()\n");
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
while (card_mpuin->firstmidiq) {
midiq = card_mpuin->firstmidiq;
card_mpuin->firstmidiq = midiq->next;
if (midiq->sizeLeft == midiq->length)
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
else
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
kfree(midiq);
}
card_mpuin->lastmidiq = NULL;
card_mpuin->status &= ~FLAGS_MIDM_STARTED;
return 0;
}
/* Passes the message with the data back to the client */
/* via IRQ & DPC callbacks to Ring 3 */
static int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid)
{
unsigned long timein;
struct midi_queue *midiq;
unsigned long callback_msg[3];
struct midi_hdr *midihdr;
/* Called during ISR. The data & code touched are:
* 1. card_mpuin
* 2. The function to be called
*/
timein = card_mpuin->timein;
if (card_mpuin->timestart <= timein)
callback_msg[0] = timein - card_mpuin->timestart;
else
callback_msg[0] = (~0x0L - card_mpuin->timestart) + timein;
if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR) {
callback_msg[1] = data;
callback_msg[2] = bytesvalid;
DPD(2, "emu10k1_mpuin_callback: midimsg = %#lx\n", data);
} else {
midiq = (struct midi_queue *) data;
midihdr = (struct midi_hdr *) midiq->refdata;
callback_msg[1] = midiq->length - midiq->sizeLeft;
callback_msg[2] = midiq->refdata;
midihdr->flags &= ~MIDIBUF_INQUEUE;
midihdr->flags |= MIDIBUF_DONE;
midihdr->bytesrecorded = midiq->length - midiq->sizeLeft;
}
/* Notify client that Sysex buffer has been sent */
emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg);
return 0;
}
void emu10k1_mpuin_bh(unsigned long refdata)
{
u8 data;
unsigned idx;
struct emu10k1_mpuin *card_mpuin = (struct emu10k1_mpuin *) refdata;
unsigned long flags;
while (card_mpuin->qhead != card_mpuin->qtail) {
spin_lock_irqsave(&card_mpuin->lock, flags);
idx = card_mpuin->qhead;
data = card_mpuin->midiq[idx].data;
card_mpuin->timein = card_mpuin->midiq[idx].timein;
idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
card_mpuin->qhead = idx;
spin_unlock_irqrestore(&card_mpuin->lock, flags);
sblive_miStateEntry(card_mpuin, data);
}
return;
}
/* IRQ callback handler routine for the MPU in port */
int emu10k1_mpuin_irqhandler(struct emu10k1_card *card)
{
unsigned idx;
unsigned count;
u8 MPUIvalue;
struct emu10k1_mpuin *card_mpuin = card->mpuin;
/* IRQ service routine. The data and code touched are:
* 1. card_mpuin
*/
count = 0;
idx = card_mpuin->qtail;
while (1) {
if (emu10k1_mpu_read_data(card, &MPUIvalue) < 0) {
break;
} else {
++count;
card_mpuin->midiq[idx].data = MPUIvalue;
card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ;
idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
}
}
if (count) {
card_mpuin->qtail = idx;
tasklet_hi_schedule(&card_mpuin->tasklet);
}
return 0;
}
/*****************************************************************************/
/* Supporting functions for Midi-In Interpretation State Machine */
/*****************************************************************************/
/* FIXME: This should be a macro */
static int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin)
{
card_mpuin->status = 0; /* For MIDI running status */
card_mpuin->fstatus = 0; /* For 0xFn status only */
card_mpuin->curstate = STIN_PARSE;
card_mpuin->laststate = STIN_PARSE;
card_mpuin->data = 0;
card_mpuin->timestart = 0;
card_mpuin->timein = 0;
return 0;
}
/* FIXME: This should be a macro */
static int sblive_miStateEntry(struct emu10k1_mpuin *card_mpuin, u8 data)
{
return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
}
static int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data)
{
switch (data & 0xf0) {
case 0x80:
case 0x90:
case 0xA0:
case 0xB0:
case 0xE0:
card_mpuin->curstate = STIN_3BYTE;
break;
case 0xC0:
case 0xD0:
card_mpuin->curstate = STIN_2BYTE;
break;
case 0xF0:
/* System messages do not affect the previous running status! */
switch (data & 0x0f) {
case 0x0:
card_mpuin->laststate = card_mpuin->curstate;
card_mpuin->curstate = STIN_SYS_EX_NORM;
if (card_mpuin->firstmidiq) {
struct midi_queue *midiq;
midiq = card_mpuin->firstmidiq;
*midiq->midibyte = data;
--midiq->sizeLeft;
++midiq->midibyte;
}
return CTSTATUS_NEXT_BYTE;
case 0x7:
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0);
return -1;
case 0x2:
card_mpuin->laststate = card_mpuin->curstate;
card_mpuin->curstate = STIN_SYS_COMMON_3;
break;
case 0x1:
case 0x3:
card_mpuin->laststate = card_mpuin->curstate;
card_mpuin->curstate = STIN_SYS_COMMON_2;
break;
default:
/* includes 0xF4 - 0xF6, 0xF8 - 0xFF */
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
}
break;
default:
DPF(2, "BUG: default case hit\n");
return -1;
}
return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
}
static int sblive_miState3Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
{
u8 temp = data & 0xf0;
if (temp < 0x80) {
return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data);
} else if (temp <= 0xe0 && temp != 0xc0 && temp != 0xd0) {
card_mpuin->status = data;
card_mpuin->curstate = STIN_3BYTE_KEY;
return CTSTATUS_NEXT_BYTE;
}
return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
}
static int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
/* byte 1 */
{
unsigned long tmp;
if (data > 0x7f) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = STIN_PARSE;
tmp = ((unsigned long) data) << 8;
tmp |= (unsigned long) card_mpuin->status;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
return -1;
}
card_mpuin->data = data;
card_mpuin->curstate = STIN_3BYTE_VEL;
return CTSTATUS_NEXT_BYTE;
}
static int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data)
/* byte 2 */
{
unsigned long tmp;
if (data > 0x7f) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = STIN_PARSE;
tmp = ((unsigned long) data) << 8;
tmp |= card_mpuin->data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->status;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
return -1;
}
card_mpuin->curstate = STIN_3BYTE;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->status;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
return 0;
}
static int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
{
u8 temp = data & 0xf0;
if ((temp == 0xc0) || (temp == 0xd0)) {
card_mpuin->status = data;
card_mpuin->curstate = STIN_2BYTE_KEY;
return CTSTATUS_NEXT_BYTE;
}
if (temp < 0x80)
return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data);
return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
}
static int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
/* byte 1 */
{
unsigned long tmp;
if (data > 0x7f) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = STIN_PARSE;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->status;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
return -1;
}
card_mpuin->curstate = STIN_2BYTE;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->status;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
return 0;
}
static int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data)
{
card_mpuin->fstatus = data;
card_mpuin->curstate = STIN_SYS_COMMON_2_KEY;
return CTSTATUS_NEXT_BYTE;
}
static int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data)
/* byte 1 */
{
unsigned long tmp;
if (data > 0x7f) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = card_mpuin->laststate;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->fstatus;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
return -1;
}
card_mpuin->curstate = card_mpuin->laststate;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->fstatus;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
return 0;
}
static int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data)
{
card_mpuin->fstatus = data;
card_mpuin->curstate = STIN_SYS_COMMON_3_KEY;
return CTSTATUS_NEXT_BYTE;
}
static int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data)
/* byte 1 */
{
unsigned long tmp;
if (data > 0x7f) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = card_mpuin->laststate;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->fstatus;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
return -1;
}
card_mpuin->data = data;
card_mpuin->curstate = STIN_SYS_COMMON_3_VEL;
return CTSTATUS_NEXT_BYTE;
}
static int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data)
/* byte 2 */
{
unsigned long tmp;
if (data > 0x7f) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = card_mpuin->laststate;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->fstatus;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
return -1;
}
card_mpuin->curstate = card_mpuin->laststate;
tmp = (unsigned long) data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->data;
tmp = tmp << 8;
tmp |= (unsigned long) card_mpuin->fstatus;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
return 0;
}
static int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data)
{
unsigned long flags;
if ((data > 0x7f) && (data != 0xf7)) {
/* Real-time messages check */
if (data > 0xf7)
return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
/* Invalid Data! */
DPF(2, "Invalid data!\n");
card_mpuin->curstate = card_mpuin->laststate;
if (card_mpuin->firstmidiq) {
struct midi_queue *midiq;
midiq = card_mpuin->firstmidiq;
*midiq->midibyte = data;
--midiq->sizeLeft;
++midiq->midibyte;
spin_lock_irqsave(&card_mpuin->lock, flags);
card_mpuin->firstmidiq = midiq->next;
if (card_mpuin->firstmidiq == NULL)
card_mpuin->lastmidiq = NULL;
spin_unlock_irqrestore(&card_mpuin->lock, flags);
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
kfree(midiq);
}
return -1;
}
if (card_mpuin->firstmidiq) {
struct midi_queue *midiq;
midiq = card_mpuin->firstmidiq;
*midiq->midibyte = data;
--midiq->sizeLeft;
++midiq->midibyte;
}
if (data == 0xf7) {
/* End of Sysex buffer */
/* Send down the buffer */
card_mpuin->curstate = card_mpuin->laststate;
if (card_mpuin->firstmidiq) {
struct midi_queue *midiq;
midiq = card_mpuin->firstmidiq;
spin_lock_irqsave(&card_mpuin->lock, flags);
card_mpuin->firstmidiq = midiq->next;
if (card_mpuin->firstmidiq == NULL)
card_mpuin->lastmidiq = NULL;
spin_unlock_irqrestore(&card_mpuin->lock, flags);
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
kfree(midiq);
}
return 0;
}
if (card_mpuin->firstmidiq) {
struct midi_queue *midiq;
midiq = card_mpuin->firstmidiq;
if (midiq->sizeLeft == 0) {
/* Special case */
spin_lock_irqsave(&card_mpuin->lock, flags);
card_mpuin->firstmidiq = midiq->next;
if (card_mpuin->firstmidiq == NULL)
card_mpuin->lastmidiq = NULL;
spin_unlock_irqrestore(&card_mpuin->lock, flags);
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
kfree(midiq);
return CTSTATUS_NEXT_BYTE;
}
}
return CTSTATUS_NEXT_BYTE;
}
static int sblive_miStateSysReal(struct emu10k1_mpuin *card_mpuin, u8 data)
{
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, data, 1);
return CTSTATUS_NEXT_BYTE;
}

View file

@ -1,97 +0,0 @@
/*
**********************************************************************
* sblive_mi.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox cleaned up
*
**********************************************************************
*
* 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 _CARDMI_H
#define _CARDMI_H
#include "icardmid.h"
#include <linux/interrupt.h>
typedef enum
{
STIN_PARSE = 0,
STIN_3BYTE, /* 0x80, 0x90, 0xA0, 0xB0, 0xE0 */
STIN_3BYTE_KEY, /* Byte 1 */
STIN_3BYTE_VEL, /* Byte 1 */
STIN_2BYTE, /* 0xC0, 0xD0 */
STIN_2BYTE_KEY, /* Byte 1 */
STIN_SYS_COMMON_2, /* 0xF1, 0xF3 */
STIN_SYS_COMMON_2_KEY,
STIN_SYS_COMMON_3, /* 0xF2 */
STIN_SYS_COMMON_3_KEY,
STIN_SYS_COMMON_3_VEL,
STIN_SYS_EX_NORM, /* 0xF0, Normal mode */
STIN_SYS_REAL
} midi_in_state;
/* flags for card MIDI in object */
#define FLAGS_MIDM_STARTED 0x00001000 // Data has started to come in after Midm Start
#define MIDIIN_MAX_BUFFER_SIZE 200 // Definition for struct emu10k1_mpuin
struct midi_data
{
u8 data;
u32 timein;
};
struct emu10k1_mpuin
{
spinlock_t lock;
struct midi_queue *firstmidiq;
struct midi_queue *lastmidiq;
unsigned qhead, qtail;
struct midi_data midiq[MIDIIN_MAX_BUFFER_SIZE];
struct tasklet_struct tasklet;
struct midi_openinfo openinfo;
/* For MIDI state machine */
u8 status; /* For MIDI running status */
u8 fstatus; /* For 0xFn status only */
midi_in_state curstate;
midi_in_state laststate;
u32 timestart;
u32 timein;
u8 data;
};
int emu10k1_mpuin_open(struct emu10k1_card *, struct midi_openinfo *);
int emu10k1_mpuin_close(struct emu10k1_card *);
int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *, struct midi_hdr *);
int emu10k1_mpuin_start(struct emu10k1_card *);
int emu10k1_mpuin_stop(struct emu10k1_card *);
int emu10k1_mpuin_reset(struct emu10k1_card *);
int emu10k1_mpuin_irqhandler(struct emu10k1_card *);
void emu10k1_mpuin_bh(unsigned long);
#endif /* _CARDMI_H */

View file

@ -1,229 +0,0 @@
/*
**********************************************************************
* cardmo.c - MIDI UART output HAL for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox cleaned up
*
**********************************************************************
*
* 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/slab.h>
#include "hwaccess.h"
#include "8010.h"
#include "cardmo.h"
#include "irqmgr.h"
/* Installs the IRQ handler for the MPU out port *
* and initialize parameters */
int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
{
struct emu10k1_mpuout *card_mpuout = card->mpuout;
DPF(2, "emu10k1_mpuout_open()\n");
if (!(card_mpuout->status & FLAGS_AVAILABLE))
return -1;
/* Copy open info and mark channel as in use */
card_mpuout->intr = 0;
card_mpuout->openinfo = *openinfo;
card_mpuout->status &= ~FLAGS_AVAILABLE;
card_mpuout->laststatus = 0x80;
card_mpuout->firstmidiq = NULL;
card_mpuout->lastmidiq = NULL;
emu10k1_mpu_reset(card);
emu10k1_mpu_acquire(card);
return 0;
}
int emu10k1_mpuout_close(struct emu10k1_card *card)
{
struct emu10k1_mpuout *card_mpuout = card->mpuout;
struct midi_queue *midiq;
struct midi_hdr *midihdr;
unsigned long flags;
DPF(2, "emu10k1_mpuout_close()\n");
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
spin_lock_irqsave(&card_mpuout->lock, flags);
while (card_mpuout->firstmidiq != NULL) {
midiq = card_mpuout->firstmidiq;
midihdr = (struct midi_hdr *) midiq->refdata;
card_mpuout->firstmidiq = midiq->next;
kfree(midihdr->data);
kfree(midihdr);
kfree(midiq);
}
card_mpuout->lastmidiq = NULL;
emu10k1_mpu_release(card);
card_mpuout->status |= FLAGS_AVAILABLE;
spin_unlock_irqrestore(&card_mpuout->lock, flags);
return 0;
}
/* If there isn't enough buffer space, reject Midi Buffer. *
* Otherwise, disable TX, create object to hold Midi *
* uffer, update buffer flags and other parameters *
* before enabling TX again. */
int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr)
{
struct emu10k1_mpuout *card_mpuout = card->mpuout;
struct midi_queue *midiq;
unsigned long flags;
DPF(2, "emu10k1_mpuout_add_buffer()\n");
if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
return 0;
midihdr->flags |= MIDIBUF_INQUEUE;
midihdr->flags &= ~MIDIBUF_DONE;
if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
/* Message lost */
return -1;
}
midiq->next = NULL;
midiq->qtype = 1;
midiq->length = midihdr->bufferlength;
midiq->sizeLeft = midihdr->bufferlength;
midiq->midibyte = midihdr->data;
midiq->refdata = (unsigned long) midihdr;
spin_lock_irqsave(&card_mpuout->lock, flags);
if (card_mpuout->firstmidiq == NULL) {
card_mpuout->firstmidiq = midiq;
card_mpuout->lastmidiq = midiq;
} else {
(card_mpuout->lastmidiq)->next = midiq;
card_mpuout->lastmidiq = midiq;
}
card_mpuout->intr = 0;
emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
spin_unlock_irqrestore(&card_mpuout->lock, flags);
return 0;
}
void emu10k1_mpuout_bh(unsigned long refdata)
{
struct emu10k1_card *card = (struct emu10k1_card *) refdata;
struct emu10k1_mpuout *card_mpuout = card->mpuout;
int cByteSent = 0;
struct midi_queue *midiq;
struct midi_queue *doneq = NULL;
unsigned long flags;
spin_lock_irqsave(&card_mpuout->lock, flags);
while (card_mpuout->firstmidiq != NULL) {
midiq = card_mpuout->firstmidiq;
while (cByteSent < 4 && midiq->sizeLeft) {
if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) {
DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
} else {
++cByteSent;
--midiq->sizeLeft;
++midiq->midibyte;
}
}
if (midiq->sizeLeft == 0) {
if (doneq == NULL)
doneq = midiq;
card_mpuout->firstmidiq = midiq->next;
} else
break;
}
if (card_mpuout->firstmidiq == NULL)
card_mpuout->lastmidiq = NULL;
if (doneq != NULL) {
while (doneq != card_mpuout->firstmidiq) {
unsigned long callback_msg[3];
midiq = doneq;
doneq = midiq->next;
if (midiq->qtype) {
callback_msg[0] = 0;
callback_msg[1] = midiq->length;
callback_msg[2] = midiq->refdata;
emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg);
} else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F)
card_mpuout->laststatus = (u8) midiq->refdata;
kfree(midiq);
}
}
if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
card_mpuout->intr = 0;
emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
}
spin_unlock_irqrestore(&card_mpuout->lock, flags);
return;
}
int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
{
struct emu10k1_mpuout *card_mpuout = card->mpuout;
DPF(4, "emu10k1_mpuout_irqhandler\n");
card_mpuout->intr = 1;
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
tasklet_hi_schedule(&card_mpuout->tasklet);
return 0;
}

View file

@ -1,62 +0,0 @@
/*
**********************************************************************
* cardmo.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox cleaned up
*
**********************************************************************
*
* 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 _CARDMO_H
#define _CARDMO_H
#include "icardmid.h"
#include <linux/interrupt.h>
#define CARDMIDIOUT_STATE_DEFAULT 0x00000000
#define CARDMIDIOUT_STATE_SUSPEND 0x00000001
struct emu10k1_mpuout
{
u32 status;
u32 state;
volatile int intr;
struct midi_queue *firstmidiq;
struct midi_queue *lastmidiq;
u8 laststatus;
struct tasklet_struct tasklet;
spinlock_t lock;
struct midi_openinfo openinfo;
};
int emu10k1_mpuout_open(struct emu10k1_card *, struct midi_openinfo *);
int emu10k1_mpuout_close(struct emu10k1_card *);
int emu10k1_mpuout_add_buffer(struct emu10k1_card *, struct midi_hdr *);
int emu10k1_mpuout_irqhandler(struct emu10k1_card *);
void emu10k1_mpuout_bh(unsigned long);
#endif /* _CARDMO_H */

View file

@ -1,384 +0,0 @@
/*
**********************************************************************
* cardwi.c - PCM input HAL for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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/poll.h>
#include "hwaccess.h"
#include "timer.h"
#include "recmgr.h"
#include "audio.h"
#include "cardwi.h"
/**
* query_format - returns a valid sound format
*
* This function will return a valid sound format as close
* to the requested one as possible.
*/
static void query_format(int recsrc, struct wave_format *wave_fmt)
{
switch (recsrc) {
case WAVERECORD_AC97:
if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
wave_fmt->channels = 2;
if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2)
wave_fmt->samplingrate = 0xBB80;
else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2)
wave_fmt->samplingrate = 0xAC44;
else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2)
wave_fmt->samplingrate = 0x7D00;
else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2)
wave_fmt->samplingrate = 0x5DC0;
else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2)
wave_fmt->samplingrate = 0x5622;
else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2)
wave_fmt->samplingrate = 0x3E80;
else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2)
wave_fmt->samplingrate = 0x2B11;
else
wave_fmt->samplingrate = 0x1F40;
switch (wave_fmt->id) {
case AFMT_S16_LE:
wave_fmt->bitsperchannel = 16;
break;
case AFMT_U8:
wave_fmt->bitsperchannel = 8;
break;
default:
wave_fmt->id = AFMT_S16_LE;
wave_fmt->bitsperchannel = 16;
break;
}
break;
/* these can't be changed from the original values */
case WAVERECORD_MIC:
case WAVERECORD_FX:
break;
default:
BUG();
break;
}
wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
wave_fmt->bytespervoicesample = wave_fmt->bytespersample;
}
static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov,
&buffer->dma_handle);
if (buffer->addr == NULL)
return -1;
return 0;
}
static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
if (buffer->addr != NULL)
pci_free_consistent(card->pci_dev, buffer->size * buffer->cov,
buffer->addr, buffer->dma_handle);
}
int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
struct wiinst **wiinst_tmp = NULL;
u16 delay;
unsigned long flags;
DPF(2, "emu10k1_wavein_open()\n");
switch (wiinst->recsrc) {
case WAVERECORD_AC97:
wiinst_tmp = &card->wavein.ac97;
break;
case WAVERECORD_MIC:
wiinst_tmp = &card->wavein.mic;
break;
case WAVERECORD_FX:
wiinst_tmp = &card->wavein.fx;
break;
default:
BUG();
break;
}
spin_lock_irqsave(&card->lock, flags);
if (*wiinst_tmp != NULL) {
spin_unlock_irqrestore(&card->lock, flags);
return -1;
}
*wiinst_tmp = wiinst;
spin_unlock_irqrestore(&card->lock, flags);
/* handle 8 bit recording */
if (wiinst->format.bytesperchannel == 1) {
if (wiinst->buffer.size > 0x8000) {
wiinst->buffer.size = 0x8000;
wiinst->buffer.sizeregval = 0x1f;
} else
wiinst->buffer.sizeregval += 4;
wiinst->buffer.cov = 2;
} else
wiinst->buffer.cov = 1;
if (alloc_buffer(card, &wiinst->buffer) < 0) {
ERROR();
return -1;
}
emu10k1_set_record_src(card, wiinst);
emu10k1_reset_record(card, &wiinst->buffer);
wiinst->buffer.hw_pos = 0;
wiinst->buffer.pos = 0;
wiinst->buffer.bytestocopy = 0;
delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
emu10k1_timer_install(card, &wiinst->timer, delay / 2);
wiinst->state = WAVE_STATE_OPEN;
return 0;
}
void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
unsigned long flags;
DPF(2, "emu10k1_wavein_close()\n");
emu10k1_wavein_stop(wave_dev);
emu10k1_timer_uninstall(card, &wiinst->timer);
free_buffer(card, &wiinst->buffer);
spin_lock_irqsave(&card->lock, flags);
switch (wave_dev->wiinst->recsrc) {
case WAVERECORD_AC97:
card->wavein.ac97 = NULL;
break;
case WAVERECORD_MIC:
card->wavein.mic = NULL;
break;
case WAVERECORD_FX:
card->wavein.fx = NULL;
break;
default:
BUG();
break;
}
spin_unlock_irqrestore(&card->lock, flags);
wiinst->state = WAVE_STATE_CLOSED;
}
void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
DPF(2, "emu10k1_wavein_start()\n");
emu10k1_start_record(card, &wiinst->buffer);
emu10k1_timer_enable(wave_dev->card, &wiinst->timer);
wiinst->state |= WAVE_STATE_STARTED;
}
void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
DPF(2, "emu10k1_wavein_stop()\n");
if (!(wiinst->state & WAVE_STATE_STARTED))
return;
emu10k1_timer_disable(card, &wiinst->timer);
emu10k1_stop_record(card, &wiinst->buffer);
wiinst->state &= ~WAVE_STATE_STARTED;
}
int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
u16 delay;
DPF(2, "emu10k1_wavein_setformat()\n");
if (wiinst->state & WAVE_STATE_STARTED)
return -1;
query_format(wiinst->recsrc, format);
if ((wiinst->format.samplingrate != format->samplingrate)
|| (wiinst->format.bitsperchannel != format->bitsperchannel)
|| (wiinst->format.channels != format->channels)) {
wiinst->format = *format;
if (wiinst->state == WAVE_STATE_CLOSED)
return 0;
wiinst->buffer.size *= wiinst->buffer.cov;
if (wiinst->format.bytesperchannel == 1) {
wiinst->buffer.cov = 2;
wiinst->buffer.size /= wiinst->buffer.cov;
} else
wiinst->buffer.cov = 1;
emu10k1_timer_uninstall(card, &wiinst->timer);
delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
emu10k1_timer_install(card, &wiinst->timer, delay / 2);
}
return 0;
}
void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size)
{
struct wavein_buffer *buffer = &wiinst->buffer;
*size = buffer->bytestocopy;
if (wiinst->mmapped)
return;
if (*size > buffer->size) {
*size = buffer->size;
buffer->pos = buffer->hw_pos;
buffer->bytestocopy = buffer->size;
DPF(1, "buffer overrun\n");
}
}
static int copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov)
{
if (cov == 1) {
if (__copy_to_user(dst, src + str, len))
return -EFAULT;
} else {
u8 byte;
u32 i;
src += 1 + 2 * str;
for (i = 0; i < len; i++) {
byte = src[2 * i] ^ 0x80;
if (__copy_to_user(dst + i, &byte, 1))
return -EFAULT;
}
}
return 0;
}
int emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size)
{
struct wavein_buffer *buffer = &wiinst->buffer;
u32 sizetocopy, sizetocopy_now, start;
unsigned long flags;
int ret;
sizetocopy = min_t(u32, buffer->size, *size);
*size = sizetocopy;
if (!sizetocopy)
return 0;
spin_lock_irqsave(&wiinst->lock, flags);
start = buffer->pos;
buffer->pos += sizetocopy;
buffer->pos %= buffer->size;
buffer->bytestocopy -= sizetocopy;
sizetocopy_now = buffer->size - start;
spin_unlock_irqrestore(&wiinst->lock, flags);
if (sizetocopy > sizetocopy_now) {
sizetocopy -= sizetocopy_now;
ret = copy_block(data, buffer->addr, start, sizetocopy_now,
buffer->cov);
if (ret == 0)
ret = copy_block(data + sizetocopy_now, buffer->addr, 0,
sizetocopy, buffer->cov);
} else {
ret = copy_block(data, buffer->addr, start, sizetocopy,
buffer->cov);
}
return ret;
}
void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst)
{
u32 hw_pos;
u32 diff;
/* There is no actual start yet */
if (!(wiinst->state & WAVE_STATE_STARTED)) {
hw_pos = wiinst->buffer.hw_pos;
} else {
/* hw_pos in byte units */
hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov;
}
diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size;
wiinst->total_recorded += diff;
wiinst->buffer.bytestocopy += diff;
wiinst->buffer.hw_pos = hw_pos;
}

View file

@ -1,91 +0,0 @@
/*
**********************************************************************
* cardwi.h -- header file for card wave input functions
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _CARDWI_H
#define _CARDWI_H
#include "icardwav.h"
#include "audio.h"
#include "timer.h"
struct wavein_buffer {
u16 ossfragshift;
u32 fragment_size;
u32 numfrags;
u32 hw_pos; /* hardware cursor position */
u32 pos; /* software cursor position */
u32 bytestocopy; /* bytes of recorded data available */
u32 size;
u32 pages;
u32 sizereg;
u32 sizeregval;
u32 addrreg;
u32 idxreg;
u32 adcctl;
void *addr;
u8 cov;
dma_addr_t dma_handle;
};
struct wiinst
{
u8 state;
struct emu_timer timer;
struct wave_format format;
struct wavein_buffer buffer;
wait_queue_head_t wait_queue;
u8 mmapped;
u32 total_recorded; /* total bytes read() from device */
u32 blocks;
spinlock_t lock;
u8 recsrc;
u16 fxwc;
};
#define WAVEIN_MAXBUFSIZE 65536
#define WAVEIN_MINBUFSIZE 368
#define WAVEIN_DEFAULTFRAGLEN 100
#define WAVEIN_DEFAULTBUFLEN 1000
#define WAVEIN_MINFRAGSHIFT 8
#define WAVEIN_MINFRAGS 2
int emu10k1_wavein_open(struct emu10k1_wavedevice *);
void emu10k1_wavein_close(struct emu10k1_wavedevice *);
void emu10k1_wavein_start(struct emu10k1_wavedevice *);
void emu10k1_wavein_stop(struct emu10k1_wavedevice *);
void emu10k1_wavein_getxfersize(struct wiinst *, u32 *);
int emu10k1_wavein_xferdata(struct wiinst *, u8 __user *, u32 *);
int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *);
void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *);
#endif /* _CARDWI_H */

View file

@ -1,643 +0,0 @@
/*
**********************************************************************
* cardwo.c - PCM output HAL for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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/poll.h>
#include "hwaccess.h"
#include "8010.h"
#include "voicemgr.h"
#include "cardwo.h"
#include "audio.h"
static u32 samplerate_to_linearpitch(u32 samplingrate)
{
samplingrate = (samplingrate << 8) / 375;
return (samplingrate >> 1) + (samplingrate & 1);
}
static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format *wave_fmt)
{
int i, j, do_passthrough = 0, is_ac3 = 0;
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
if ((wave_fmt->channels > 2) && (wave_fmt->id != AFMT_S16_LE) && (wave_fmt->id != AFMT_U8))
wave_fmt->channels = 2;
if ((wave_fmt->channels < 1) || (wave_fmt->channels > WAVEOUT_MAXVOICES))
wave_fmt->channels = 2;
if (wave_fmt->channels == 2)
woinst->num_voices = 1;
else
woinst->num_voices = wave_fmt->channels;
if (wave_fmt->samplingrate >= 0x2ee00)
wave_fmt->samplingrate = 0x2ee00;
wave_fmt->passthrough = 0;
do_passthrough = is_ac3 = 0;
if (card->pt.selected)
do_passthrough = 1;
switch (wave_fmt->id) {
case AFMT_S16_LE:
wave_fmt->bitsperchannel = 16;
break;
case AFMT_U8:
wave_fmt->bitsperchannel = 8;
break;
case AFMT_AC3:
do_passthrough = 1;
is_ac3 = 1;
break;
default:
wave_fmt->id = AFMT_S16_LE;
wave_fmt->bitsperchannel = 16;
break;
}
if (do_passthrough) {
/* currently only one waveout instance may use pass-through */
if (woinst->state != WAVE_STATE_CLOSED ||
card->pt.state != PT_STATE_INACTIVE ||
(wave_fmt->samplingrate != 48000 && !is_ac3)) {
DPF(2, "unable to set pass-through mode\n");
} else if (USE_PT_METHOD1) {
i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
if (i < 0 || j < 0)
DPF(2, "unable to set pass-through mode\n");
else {
wave_fmt->samplingrate = 48000;
wave_fmt->channels = 2;
card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
card->pt.pos_gpr_name);
wave_fmt->passthrough = 1;
card->pt.intr_gpr = i;
card->pt.enable_gpr = j;
card->pt.state = PT_STATE_INACTIVE;
DPD(2, "is_ac3 is %d\n", is_ac3);
card->pt.ac3data = is_ac3;
wave_fmt->bitsperchannel = 16;
}
}else{
DPF(2, "Using Passthrough Method 2\n");
card->pt.enable_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
card->pt.enable_gpr_name);
wave_fmt->passthrough = 2;
wave_fmt->bitsperchannel = 16;
}
}
wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
if (wave_fmt->channels == 2)
wave_fmt->bytespervoicesample = wave_fmt->channels * wave_fmt->bytesperchannel;
else
wave_fmt->bytespervoicesample = wave_fmt->bytesperchannel;
}
static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned int voicenum)
{
struct emu_voice *voice = &woinst->voice[voicenum];
/* Allocate voices here, if no voices available, return error. */
voice->usage = VOICE_USAGE_PLAYBACK;
voice->flags = 0;
if (woinst->format.channels == 2)
voice->flags |= VOICE_FLAGS_STEREO;
if (woinst->format.bitsperchannel == 16)
voice->flags |= VOICE_FLAGS_16BIT;
if (emu10k1_voice_alloc(card, voice) < 0) {
voice->usage = VOICE_USAGE_FREE;
return -1;
}
/* Calculate pitch */
voice->initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8);
voice->pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate);
DPD(2, "Initial pitch --> %#x\n", voice->initial_pitch);
voice->startloop = (voice->mem.emupageindex << 12) /
woinst->format.bytespervoicesample;
voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample;
voice->start = voice->startloop;
voice->params[0].volume_target = 0xffff;
voice->params[0].initial_fc = 0xff;
voice->params[0].initial_attn = 0x00;
voice->params[0].byampl_env_sustain = 0x7f;
voice->params[0].byampl_env_decay = 0x7f;
if (voice->flags & VOICE_FLAGS_STEREO) {
if (woinst->format.passthrough == 2) {
voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PT];
voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PT];
voice->params[0].send_dcba = 0xff;
voice->params[1].send_dcba = 0xff00;
voice->params[0].send_hgfe = voice->params[1].send_hgfe=0;
} else {
voice->params[0].send_dcba = card->waveout.send_dcba[SEND_LEFT];
voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_LEFT];
voice->params[1].send_dcba = card->waveout.send_dcba[SEND_RIGHT];
voice->params[1].send_hgfe = card->waveout.send_hgfe[SEND_RIGHT];
if (woinst->device) {
// /dev/dps1
voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM1];
voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
} else {
voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM];
voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
}
}
voice->params[1].volume_target = 0xffff;
voice->params[1].initial_fc = 0xff;
voice->params[1].initial_attn = 0x00;
voice->params[1].byampl_env_sustain = 0x7f;
voice->params[1].byampl_env_decay = 0x7f;
} else {
if (woinst->num_voices > 1) {
// Multichannel pcm
voice->params[0].send_dcba=0xff;
voice->params[0].send_hgfe=0;
if (card->is_audigy) {
voice->params[0].send_routing = 0x3f3f3f00 + card->mchannel_fx + voicenum;
voice->params[0].send_routing2 = 0x3f3f3f3f;
} else {
voice->params[0].send_routing = 0xfff0 + card->mchannel_fx + voicenum;
}
} else {
voice->params[0].send_dcba = card->waveout.send_dcba[SEND_MONO];
voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_MONO];
if (woinst->device) {
voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM1];
voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
} else {
voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM];
voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
}
}
}
DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop);
emu10k1_voice_playback_setup(voice);
return 0;
}
int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
struct waveout_buffer *buffer = &woinst->buffer;
unsigned int voicenum;
u16 delay;
DPF(2, "emu10k1_waveout_open()\n");
for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
if (emu10k1_voice_alloc_buffer(card, &woinst->voice[voicenum].mem, woinst->buffer.pages) < 0) {
ERROR();
emu10k1_waveout_close(wave_dev);
return -1;
}
if (get_voice(card, woinst, voicenum) < 0) {
ERROR();
emu10k1_waveout_close(wave_dev);
return -1;
}
}
buffer->fill_silence = 0;
buffer->silence_bytes = 0;
buffer->silence_pos = 0;
buffer->hw_pos = 0;
buffer->free_bytes = woinst->buffer.size;
delay = (48000 * woinst->buffer.fragment_size) /
(woinst->format.samplingrate * woinst->format.bytespervoicesample);
emu10k1_timer_install(card, &woinst->timer, delay);
woinst->state = WAVE_STATE_OPEN;
return 0;
}
void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
unsigned int voicenum;
DPF(2, "emu10k1_waveout_close()\n");
emu10k1_waveout_stop(wave_dev);
emu10k1_timer_uninstall(card, &woinst->timer);
for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
emu10k1_voice_free(&woinst->voice[voicenum]);
emu10k1_voice_free_buffer(card, &woinst->voice[voicenum].mem);
}
woinst->state = WAVE_STATE_CLOSED;
}
void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
struct pt_data *pt = &card->pt;
DPF(2, "emu10k1_waveout_start()\n");
if (woinst->format.passthrough == 2) {
emu10k1_pt_setup(wave_dev);
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 1);
pt->state = PT_STATE_PLAYING;
}
/* Actual start */
emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played);
emu10k1_timer_enable(card, &woinst->timer);
woinst->state |= WAVE_STATE_STARTED;
}
int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
unsigned int voicenum;
u16 delay;
DPF(2, "emu10k1_waveout_setformat()\n");
if (woinst->state & WAVE_STATE_STARTED)
return -1;
query_format(wave_dev, format);
if (woinst->format.samplingrate != format->samplingrate ||
woinst->format.channels != format->channels ||
woinst->format.bitsperchannel != format->bitsperchannel) {
woinst->format = *format;
if (woinst->state == WAVE_STATE_CLOSED)
return 0;
emu10k1_timer_uninstall(card, &woinst->timer);
for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
emu10k1_voice_free(&woinst->voice[voicenum]);
if (get_voice(card, woinst, voicenum) < 0) {
ERROR();
emu10k1_waveout_close(wave_dev);
return -1;
}
}
delay = (48000 * woinst->buffer.fragment_size) /
(woinst->format.samplingrate * woinst->format.bytespervoicesample);
emu10k1_timer_install(card, &woinst->timer, delay);
}
return 0;
}
void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
DPF(2, "emu10k1_waveout_stop()\n");
if (!(woinst->state & WAVE_STATE_STARTED))
return;
emu10k1_timer_disable(card, &woinst->timer);
/* Stop actual voices */
emu10k1_voices_stop(woinst->voice, woinst->num_voices);
emu10k1_waveout_update(woinst);
woinst->state &= ~WAVE_STATE_STARTED;
}
/**
* emu10k1_waveout_getxfersize -
*
* gives the total free bytes on the voice buffer, including silence bytes
* (basically: total_free_bytes = free_bytes + silence_bytes).
*
*/
void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 *total_free_bytes)
{
struct waveout_buffer *buffer = &woinst->buffer;
int pending_bytes;
if (woinst->mmapped) {
*total_free_bytes = buffer->free_bytes;
return;
}
pending_bytes = buffer->size - buffer->free_bytes;
buffer->fill_silence = (pending_bytes < (signed) buffer->fragment_size * 2) ? 1 : 0;
if (pending_bytes > (signed) buffer->silence_bytes) {
*total_free_bytes = (buffer->free_bytes + buffer->silence_bytes);
} else {
*total_free_bytes = buffer->size;
buffer->silence_bytes = pending_bytes;
if (pending_bytes < 0) {
buffer->silence_pos = buffer->hw_pos;
buffer->silence_bytes = 0;
buffer->free_bytes = buffer->size;
DPF(1, "buffer underrun\n");
}
}
}
/**
* copy_block -
*
* copies a block of pcm data to a voice buffer.
* Notice that the voice buffer is actually a set of disjointed memory pages.
*
*/
static void copy_block(void **dst, u32 str, u8 __user *src, u32 len)
{
unsigned int pg;
unsigned int pgoff;
unsigned int k;
pg = str / PAGE_SIZE;
pgoff = str % PAGE_SIZE;
if (len > PAGE_SIZE - pgoff) {
k = PAGE_SIZE - pgoff;
if (__copy_from_user((u8 *)dst[pg] + pgoff, src, k))
return;
len -= k;
while (len > PAGE_SIZE) {
if (__copy_from_user(dst[++pg], src + k, PAGE_SIZE))
return;
k += PAGE_SIZE;
len -= PAGE_SIZE;
}
if (__copy_from_user(dst[++pg], src + k, len))
return;
} else
__copy_from_user((u8 *)dst[pg] + pgoff, src, len);
}
/**
* copy_ilv_block -
*
* copies a block of pcm data containing n interleaved channels to n mono voice buffers.
* Notice that the voice buffer is actually a set of disjointed memory pages.
*
*/
static void copy_ilv_block(struct woinst *woinst, u32 str, u8 __user *src, u32 len)
{
unsigned int pg;
unsigned int pgoff;
unsigned int voice_num;
struct emu_voice *voice = woinst->voice;
pg = str / PAGE_SIZE;
pgoff = str % PAGE_SIZE;
while (len) {
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) {
if (__copy_from_user((u8 *)(voice[voice_num].mem.addr[pg]) + pgoff, src, woinst->format.bytespervoicesample))
return;
src += woinst->format.bytespervoicesample;
}
len -= woinst->format.bytespervoicesample;
pgoff += woinst->format.bytespervoicesample;
if (pgoff >= PAGE_SIZE) {
pgoff = 0;
pg++;
}
}
}
/**
* fill_block -
*
* fills a set voice buffers with a block of a given sample.
*
*/
static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len)
{
unsigned int pg;
unsigned int pgoff;
unsigned int voice_num;
struct emu_voice *voice = woinst->voice;
unsigned int k;
pg = str / PAGE_SIZE;
pgoff = str % PAGE_SIZE;
if (len > PAGE_SIZE - pgoff) {
k = PAGE_SIZE - pgoff;
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset((u8 *)voice[voice_num].mem.addr[pg] + pgoff, data, k);
len -= k;
while (len > PAGE_SIZE) {
pg++;
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset(voice[voice_num].mem.addr[pg], data, PAGE_SIZE);
len -= PAGE_SIZE;
}
pg++;
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset(voice[voice_num].mem.addr[pg], data, len);
} else {
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset((u8 *)voice[voice_num].mem.addr[pg] + pgoff, data, len);
}
}
/**
* emu10k1_waveout_xferdata -
*
* copies pcm data to the voice buffer. Silence samples
* previously added to the buffer are overwritten.
*
*/
void emu10k1_waveout_xferdata(struct woinst *woinst, u8 __user *data, u32 *size)
{
struct waveout_buffer *buffer = &woinst->buffer;
struct voice_mem *mem = &woinst->voice[0].mem;
u32 sizetocopy, sizetocopy_now, start;
unsigned long flags;
sizetocopy = min_t(u32, buffer->size, *size);
*size = sizetocopy;
if (!sizetocopy)
return;
spin_lock_irqsave(&woinst->lock, flags);
start = (buffer->size + buffer->silence_pos - buffer->silence_bytes) % buffer->size;
if (sizetocopy > buffer->silence_bytes) {
buffer->silence_pos += sizetocopy - buffer->silence_bytes;
buffer->free_bytes -= sizetocopy - buffer->silence_bytes;
buffer->silence_bytes = 0;
} else
buffer->silence_bytes -= sizetocopy;
spin_unlock_irqrestore(&woinst->lock, flags);
sizetocopy_now = buffer->size - start;
if (sizetocopy > sizetocopy_now) {
sizetocopy -= sizetocopy_now;
if (woinst->num_voices > 1) {
copy_ilv_block(woinst, start, data, sizetocopy_now);
copy_ilv_block(woinst, 0, data + sizetocopy_now * woinst->num_voices, sizetocopy);
} else {
copy_block(mem->addr, start, data, sizetocopy_now);
copy_block(mem->addr, 0, data + sizetocopy_now, sizetocopy);
}
} else {
if (woinst->num_voices > 1)
copy_ilv_block(woinst, start, data, sizetocopy);
else
copy_block(mem->addr, start, data, sizetocopy);
}
}
/**
* emu10k1_waveout_fillsilence -
*
* adds samples of silence to the voice buffer so that we
* don't loop over stale pcm data.
*
*/
void emu10k1_waveout_fillsilence(struct woinst *woinst)
{
struct waveout_buffer *buffer = &woinst->buffer;
u32 sizetocopy, sizetocopy_now, start;
u8 filldata;
unsigned long flags;
sizetocopy = buffer->fragment_size;
if (woinst->format.bitsperchannel == 16)
filldata = 0x00;
else
filldata = 0x80;
spin_lock_irqsave(&woinst->lock, flags);
buffer->silence_bytes += sizetocopy;
buffer->free_bytes -= sizetocopy;
buffer->silence_pos %= buffer->size;
start = buffer->silence_pos;
buffer->silence_pos += sizetocopy;
spin_unlock_irqrestore(&woinst->lock, flags);
sizetocopy_now = buffer->size - start;
if (sizetocopy > sizetocopy_now) {
sizetocopy -= sizetocopy_now;
fill_block(woinst, start, filldata, sizetocopy_now);
fill_block(woinst, 0, filldata, sizetocopy);
} else {
fill_block(woinst, start, filldata, sizetocopy);
}
}
/**
* emu10k1_waveout_update -
*
* updates the position of the voice buffer hardware pointer (hw_pos)
* and the number of free bytes on the buffer (free_bytes).
* The free bytes _don't_ include silence bytes that may have been
* added to the buffer.
*
*/
void emu10k1_waveout_update(struct woinst *woinst)
{
u32 hw_pos;
u32 diff;
/* There is no actual start yet */
if (!(woinst->state & WAVE_STATE_STARTED)) {
hw_pos = woinst->buffer.hw_pos;
} else {
/* hw_pos in sample units */
hw_pos = sblive_readptr(woinst->voice[0].card, CCCA_CURRADDR, woinst->voice[0].num);
if(hw_pos < woinst->voice[0].start)
hw_pos += woinst->buffer.size / woinst->format.bytespervoicesample - woinst->voice[0].start;
else
hw_pos -= woinst->voice[0].start;
hw_pos *= woinst->format.bytespervoicesample;
}
diff = (woinst->buffer.size + hw_pos - woinst->buffer.hw_pos) % woinst->buffer.size;
woinst->total_played += diff;
woinst->buffer.free_bytes += diff;
woinst->buffer.hw_pos = hw_pos;
}

View file

@ -1,90 +0,0 @@
/*
**********************************************************************
* cardwo.h -- header file for card wave out functions
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _CARDWO_H
#define _CARDWO_H
#include "icardwav.h"
#include "audio.h"
#include "voicemgr.h"
#include "timer.h"
/* setting this to other than a power of two may break some applications */
#define WAVEOUT_MAXBUFSIZE MAXBUFSIZE
#define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */
#define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */
#define WAVEOUT_MINFRAGSHIFT 6 /* Minimum fragment size in bytes is 2^6 */
#define WAVEOUT_MINFRAGS 3 /* _don't_ go bellow 3, it would break silence filling */
#define WAVEOUT_MAXVOICES 6
struct waveout_buffer {
u16 ossfragshift;
u32 numfrags;
u32 fragment_size; /* in bytes units */
u32 size; /* in bytes units */
u32 pages; /* buffer size in page units*/
u32 silence_pos; /* software cursor position (including silence bytes) */
u32 hw_pos; /* hardware cursor position */
u32 free_bytes; /* free bytes available on the buffer (not including silence bytes) */
u8 fill_silence;
u32 silence_bytes; /* silence bytes on the buffer */
};
struct woinst
{
u8 state;
u8 num_voices;
struct emu_voice voice[WAVEOUT_MAXVOICES];
struct emu_timer timer;
struct wave_format format;
struct waveout_buffer buffer;
wait_queue_head_t wait_queue;
u8 mmapped;
u32 total_copied; /* total number of bytes written() to the buffer (excluding silence) */
u32 total_played; /* total number of bytes played including silence */
u32 blocks;
u8 device;
spinlock_t lock;
};
int emu10k1_waveout_open(struct emu10k1_wavedevice *);
void emu10k1_waveout_close(struct emu10k1_wavedevice *);
void emu10k1_waveout_start(struct emu10k1_wavedevice *);
void emu10k1_waveout_stop(struct emu10k1_wavedevice *);
void emu10k1_waveout_getxfersize(struct woinst*, u32 *);
void emu10k1_waveout_xferdata(struct woinst*, u8 __user *, u32 *);
void emu10k1_waveout_fillsilence(struct woinst*);
int emu10k1_waveout_setformat(struct emu10k1_wavedevice*, struct wave_format*);
void emu10k1_waveout_update(struct woinst*);
#endif /* _CARDWO_H */

View file

@ -1,157 +0,0 @@
/*
**********************************************************************
* ecard.c - E-card initialization code
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 "ecard.h"
#include "hwaccess.h"
/* Private routines */
static void ecard_setadcgain(struct emu10k1_card *, struct ecard_state *, u16);
static void ecard_write(struct emu10k1_card *, u32);
/**************************************************************************
* @func Set the gain of the ECARD's CS3310 Trim/gain controller. The
* trim value consists of a 16bit value which is composed of two
* 8 bit gain/trim values, one for the left channel and one for the
* right channel. The following table maps from the Gain/Attenuation
* value in decibels into the corresponding bit pattern for a single
* channel.
*/
static void ecard_setadcgain(struct emu10k1_card *card, struct ecard_state *ecard, u16 gain)
{
u32 currbit;
ecard->adc_gain = gain;
/* Enable writing to the TRIM registers */
ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
/* Do it again to insure that we meet hold time requirements */
ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
for (currbit = (1L << 15); currbit; currbit >>= 1) {
u32 value = ecard->control_bits & ~(EC_TRIM_CSN|EC_TRIM_SDATA);
if (gain & currbit)
value |= EC_TRIM_SDATA;
/* Clock the bit */
ecard_write(card, value);
ecard_write(card, value | EC_TRIM_SCLK);
ecard_write(card, value);
}
ecard_write(card, ecard->control_bits);
}
/**************************************************************************
* @func Clock bits into the Ecard's control latch. The Ecard uses a
* control latch will is loaded bit-serially by toggling the Modem control
* lines from function 2 on the E8010. This function hides these details
* and presents the illusion that we are actually writing to a distinct
* register.
*/
static void ecard_write(struct emu10k1_card *card, u32 value)
{
u16 count;
u32 data, hcvalue;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
hcvalue = inl(card->iobase + HCFG) & ~(HOOKN_BIT|HANDN_BIT|PULSEN_BIT);
outl(card->iobase + HCFG, hcvalue);
for (count = 0 ; count < EC_NUM_CONTROL_BITS; count++) {
/* Set up the value */
data = ((value & 0x1) ? PULSEN_BIT : 0);
value >>= 1;
outl(card->iobase + HCFG, hcvalue | data);
/* Clock the shift register */
outl(card->iobase + HCFG, hcvalue | data | HANDN_BIT);
outl(card->iobase + HCFG, hcvalue | data);
}
/* Latch the bits */
outl(card->iobase + HCFG, hcvalue | HOOKN_BIT);
outl(card->iobase + HCFG, hcvalue);
spin_unlock_irqrestore(&card->lock, flags);
}
void __devinit emu10k1_ecard_init(struct emu10k1_card *card)
{
u32 hcvalue;
struct ecard_state ecard;
/* Set up the initial settings */
ecard.mux0_setting = EC_DEFAULT_SPDIF0_SEL;
ecard.mux1_setting = EC_DEFAULT_SPDIF1_SEL;
ecard.mux2_setting = 0;
ecard.adc_gain = EC_DEFAULT_ADC_GAIN;
ecard.control_bits = EC_RAW_RUN_MODE |
EC_SPDIF0_SELECT(ecard.mux0_setting) |
EC_SPDIF1_SELECT(ecard.mux1_setting);
/* Step 0: Set the codec type in the hardware control register
* and enable audio output */
hcvalue = emu10k1_readfn0(card, HCFG);
emu10k1_writefn0(card, HCFG, hcvalue | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S);
/* Step 1: Turn off the led and deassert TRIM_CS */
ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
/* Step 2: Calibrate the ADC and DAC */
ecard_write(card, EC_DACCAL | EC_LEDN | EC_TRIM_CSN);
/* Step 3: Wait for awhile; FIXME: Is this correct? */
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ);
/* Step 4: Switch off the DAC and ADC calibration. Note
* That ADC_CAL is actually an inverted signal, so we assert
* it here to stop calibration. */
ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
/* Step 4: Switch into run mode */
ecard_write(card, ecard.control_bits);
/* Step 5: Set the analog input gain */
ecard_setadcgain(card, &ecard, ecard.adc_gain);
}

View file

@ -1,113 +0,0 @@
/*
**********************************************************************
* ecard.h
* Copyright 1999, 2000 Creative Labs, 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 _ECARD_H
#define _ECARD_H
#include "8010.h"
#include "hwaccess.h"
#include <linux/init.h>
/* In A1 Silicon, these bits are in the HC register */
#define HOOKN_BIT (1L << 12)
#define HANDN_BIT (1L << 11)
#define PULSEN_BIT (1L << 10)
#define EC_GDI1 (1 << 13)
#define EC_GDI0 (1 << 14)
#define EC_NUM_CONTROL_BITS 20
#define EC_AC3_DATA_SELN 0x0001L
#define EC_EE_DATA_SEL 0x0002L
#define EC_EE_CNTRL_SELN 0x0004L
#define EC_EECLK 0x0008L
#define EC_EECS 0x0010L
#define EC_EESDO 0x0020L
#define EC_TRIM_CSN 0x0040L
#define EC_TRIM_SCLK 0x0080L
#define EC_TRIM_SDATA 0x0100L
#define EC_TRIM_MUTEN 0x0200L
#define EC_ADCCAL 0x0400L
#define EC_ADCRSTN 0x0800L
#define EC_DACCAL 0x1000L
#define EC_DACMUTEN 0x2000L
#define EC_LEDN 0x4000L
#define EC_SPDIF0_SEL_SHIFT 15
#define EC_SPDIF1_SEL_SHIFT 17
#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT)
#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT)
#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK)
#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK)
#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should
* be incremented any time the EEPROM's
* format is changed. */
#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */
/* Addresses for special values stored in to EEPROM */
#define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */
#define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */
#define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */
#define EC_LAST_PROMFILE_ADDR 0x2f
#define EC_SERIALNUM_ADD 0x30 /* First word of serial number. The number
* can be up to 30 characters in length
* and is stored as a NULL-terminated
* ASCII string. Any unused bytes must be
* filled with zeros */
#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */
/* Most of this stuff is pretty self-evident. According to the hardware
* dudes, we need to leave the ADCCAL bit low in order to avoid a DC
* offset problem. Weird.
*/
#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | EC_TRIM_CSN)
#define EC_DEFAULT_ADC_GAIN 0xC4C4
#define EC_DEFAULT_SPDIF0_SEL 0x0
#define EC_DEFAULT_SPDIF1_SEL 0x4
#define HC_EA 0x01L
/* ECARD state structure. This structure maintains the state
* for various portions of the ECARD's onboard hardware.
*/
struct ecard_state {
u32 control_bits;
u16 adc_gain;
u16 mux0_setting;
u16 mux1_setting;
u16 mux2_setting;
};
void emu10k1_ecard_init(struct emu10k1_card *) __devinit;
#endif /* _ECARD_H */

View file

@ -1,220 +0,0 @@
/*
**********************************************************************
* efxmgr.c
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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/bitops.h>
#include "hwaccess.h"
#include "efxmgr.h"
int emu10k1_find_control_gpr(struct patch_manager *mgr, const char *patch_name, const char *gpr_name)
{
struct dsp_patch *patch;
struct dsp_rpatch *rpatch;
char s[PATCH_NAME_SIZE + 4];
unsigned long *gpr_used;
int i;
DPD(2, "emu10k1_find_control_gpr(): %s %s\n", patch_name, gpr_name);
rpatch = &mgr->rpatch;
if (!strcmp(rpatch->name, patch_name)) {
gpr_used = rpatch->gpr_used;
goto match;
}
for (i = 0; i < mgr->current_pages * PATCHES_PER_PAGE; i++) {
patch = PATCH(mgr, i);
sprintf(s,"%s", patch->name);
if (!strcmp(s, patch_name)) {
gpr_used = patch->gpr_used;
goto match;
}
}
return -1;
match:
for (i = 0; i < NUM_GPRS; i++)
if (mgr->gpr[i].type == GPR_TYPE_CONTROL &&
test_bit(i, gpr_used) &&
!strcmp(mgr->gpr[i].name, gpr_name))
return i;
return -1;
}
void emu10k1_set_control_gpr(struct emu10k1_card *card, int addr, s32 val, int flag)
{
struct patch_manager *mgr = &card->mgr;
DPD(2, "emu10k1_set_control_gpr(): %d %x\n", addr, val);
if (addr < 0 || addr >= NUM_GPRS)
return;
//fixme: once patch manager is up, remember to fix this for the audigy
if (card->is_audigy) {
sblive_writeptr(card, A_GPR_BASE + addr, 0, val);
} else {
if (flag)
val += sblive_readptr(card, GPR_BASE + addr, 0);
if (val > mgr->gpr[addr].max)
val = mgr->gpr[addr].max;
else if (val < mgr->gpr[addr].min)
val = mgr->gpr[addr].min;
sblive_writeptr(card, GPR_BASE + addr, 0, val);
}
}
//TODO: make this configurable:
#define VOLCTRL_CHANNEL SOUND_MIXER_VOLUME
#define VOLCTRL_STEP_SIZE 5
//An internal function for setting OSS mixer controls.
static void emu10k1_set_oss_vol(struct emu10k1_card *card, int oss_mixer,
unsigned int left, unsigned int right)
{
extern char volume_params[SOUND_MIXER_NRDEVICES];
card->ac97->mixer_state[oss_mixer] = (right << 8) | left;
if (!card->is_aps)
card->ac97->write_mixer(card->ac97, oss_mixer, left, right);
emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left,
volume_params[oss_mixer]);
emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][1], right,
volume_params[oss_mixer]);
}
//FIXME: mute should unmute when pressed a second time
void emu10k1_mute_irqhandler(struct emu10k1_card *card)
{
int oss_channel = VOLCTRL_CHANNEL;
int left, right;
static int val;
if (val) {
left = val & 0xff;
right = (val >> 8) & 0xff;
val = 0;
} else {
val = card->ac97->mixer_state[oss_channel];
left = 0;
right = 0;
}
emu10k1_set_oss_vol(card, oss_channel, left, right);
}
void emu10k1_volincr_irqhandler(struct emu10k1_card *card)
{
int oss_channel = VOLCTRL_CHANNEL;
int left, right;
left = card->ac97->mixer_state[oss_channel] & 0xff;
right = (card->ac97->mixer_state[oss_channel] >> 8) & 0xff;
if ((left += VOLCTRL_STEP_SIZE) > 100)
left = 100;
if ((right += VOLCTRL_STEP_SIZE) > 100)
right = 100;
emu10k1_set_oss_vol(card, oss_channel, left, right);
}
void emu10k1_voldecr_irqhandler(struct emu10k1_card *card)
{
int oss_channel = VOLCTRL_CHANNEL;
int left, right;
left = card->ac97->mixer_state[oss_channel] & 0xff;
right = (card->ac97->mixer_state[oss_channel] >> 8) & 0xff;
if ((left -= VOLCTRL_STEP_SIZE) < 0)
left = 0;
if ((right -= VOLCTRL_STEP_SIZE) < 0)
right = 0;
emu10k1_set_oss_vol(card, oss_channel, left, right);
}
void emu10k1_set_volume_gpr(struct emu10k1_card *card, int addr, s32 vol, int scale)
{
struct patch_manager *mgr = &card->mgr;
unsigned long flags;
static const s32 log2lin[4] ={ // attenuation (dB)
0x7fffffff, // 0.0
0x7fffffff * 0.840896415253715 , // 1.5
0x7fffffff * 0.707106781186548, // 3.0
0x7fffffff * 0.594603557501361 , // 4.5
};
if (addr < 0)
return;
vol = (100 - vol ) * scale / 100;
// Thanks to the comp.dsp newsgroup for this neat trick:
vol = (vol >= scale) ? 0 : (log2lin[vol & 3] >> (vol >> 2));
spin_lock_irqsave(&mgr->lock, flags);
emu10k1_set_control_gpr(card, addr, vol, 0);
spin_unlock_irqrestore(&mgr->lock, flags);
}
void emu10k1_dsp_irqhandler(struct emu10k1_card *card)
{
unsigned long flags;
if (card->pt.state != PT_STATE_INACTIVE) {
u32 bc;
bc = sblive_readptr(card, GPR_BASE + card->pt.intr_gpr, 0);
if (bc != 0) {
DPD(3, "pt interrupt, bc = %d\n", bc);
spin_lock_irqsave(&card->pt.lock, flags);
card->pt.blocks_played = bc;
if (card->pt.blocks_played >= card->pt.blocks_copied) {
DPF(1, "buffer underrun in passthrough playback\n");
emu10k1_pt_stop(card);
}
wake_up_interruptible(&card->pt.wait);
spin_unlock_irqrestore(&card->pt.lock, flags);
}
}
}

View file

@ -1,270 +0,0 @@
/*
**********************************************************************
* sblive_fx.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _EFXMGR_H
#define _EFXMGR_H
struct emu_efx_info_t{
int opcode_shift;
int high_operand_shift;
int instruction_start;
int gpr_base;
int output_base;
};
#define WRITE_EFX(a, b, c) sblive_writeptr((a), emu_efx_info[card->is_audigy].instruction_start + (b), 0, (c))
#define OP(op, z, w, x, y) \
do { WRITE_EFX(card, (pc) * 2, ((x) << emu_efx_info[card->is_audigy].high_operand_shift) | (y)); \
WRITE_EFX(card, (pc) * 2 + 1, ((op) << emu_efx_info[card->is_audigy].opcode_shift ) | ((z) << emu_efx_info[card->is_audigy].high_operand_shift) | (w)); \
++pc; } while (0)
#define NUM_INPUTS 0x20
#define NUM_OUTPUTS 0x20
#define NUM_GPRS 0x100
#define A_NUM_INPUTS 0x60
#define A_NUM_OUTPUTS 0x60 //fixme: this may or may not be true
#define A_NUM_GPRS 0x200
#define GPR_NAME_SIZE 32
#define PATCH_NAME_SIZE 32
struct dsp_rpatch {
char name[PATCH_NAME_SIZE];
u16 code_start;
u16 code_size;
unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
unsigned long route[NUM_OUTPUTS];
unsigned long route_v[NUM_OUTPUTS];
};
struct dsp_patch {
char name[PATCH_NAME_SIZE];
u8 id;
unsigned long input; /* bitmap of the lines used as inputs */
unsigned long output; /* bitmap of the lines used as outputs */
u16 code_start;
u16 code_size;
unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1]; /* bitmap of used gprs */
unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
u8 traml_istart; /* starting address of the internal tram lines used */
u8 traml_isize; /* number of internal tram lines used */
u8 traml_estart;
u8 traml_esize;
u16 tramb_istart; /* starting address of the internal tram memory used */
u16 tramb_isize; /* amount of internal memory used */
u32 tramb_estart;
u32 tramb_esize;
};
struct dsp_gpr {
u8 type; /* gpr type, STATIC, DYNAMIC, INPUT, OUTPUT, CONTROL */
char name[GPR_NAME_SIZE]; /* gpr value, only valid for control gprs */
s32 min, max; /* value range for this gpr, only valid for control gprs */
u8 line; /* which input/output line is the gpr attached, only valid for input/output gprs */
u8 usage;
};
enum {
GPR_TYPE_NULL = 0,
GPR_TYPE_IO,
GPR_TYPE_STATIC,
GPR_TYPE_DYNAMIC,
GPR_TYPE_CONTROL,
GPR_TYPE_CONSTANT
};
#define GPR_BASE 0x100
#define OUTPUT_BASE 0x20
#define A_GPR_BASE 0x400
#define A_OUTPUT_BASE 0x60
#define MAX_PATCHES_PAGES 32
struct patch_manager {
void *patch[MAX_PATCHES_PAGES];
int current_pages;
struct dsp_rpatch rpatch;
struct dsp_gpr gpr[NUM_GPRS]; /* gpr usage table */
spinlock_t lock;
s16 ctrl_gpr[SOUND_MIXER_NRDEVICES][2];
};
#define PATCHES_PER_PAGE (PAGE_SIZE / sizeof(struct dsp_patch))
#define PATCH(mgr, i) ((struct dsp_patch *) (mgr)->patch[(i) / PATCHES_PER_PAGE] + (i) % PATCHES_PER_PAGE)
/* PCM volume control */
#define TMP_PCM_L 0x100 //temp PCM L (after the vol control)
#define TMP_PCM_R 0x101
#define VOL_PCM_L 0x102 //vol PCM
#define VOL_PCM_R 0x103
/* Routing patch */
#define TMP_AC_L 0x104 //tmp ac97 out
#define TMP_AC_R 0x105
#define TMP_REAR_L 0x106 //output - Temp Rear
#define TMP_REAR_R 0x107
#define TMP_DIGI_L 0x108 //output - Temp digital
#define TMP_DIGI_R 0x109
#define DSP_VOL_L 0x10a // main dsp volume
#define DSP_VOL_R 0x10b
/* hw inputs */
#define PCM_IN_L 0x00
#define PCM_IN_R 0x01
#define PCM1_IN_L 0x04
#define PCM1_IN_R 0x05
//mutilchannel playback stream appear here:
#define MULTI_FRONT_L 0x08
#define MULTI_FRONT_R 0x09
#define MULTI_REAR_L 0x0a
#define MULTI_REAR_R 0x0b
#define MULTI_CENTER 0x0c
#define MULTI_LFE 0x0d
#define AC97_IN_L 0x10
#define AC97_IN_R 0x11
#define SPDIF_CD_L 0x12
#define SPDIF_CD_R 0x13
/* hw outputs */
#define AC97_FRONT_L 0x20
#define AC97_FRONT_R 0x21
#define DIGITAL_OUT_L 0x22
#define DIGITAL_OUT_R 0x23
#define DIGITAL_CENTER 0x24
#define DIGITAL_LFE 0x25
#define ANALOG_REAR_L 0x28
#define ANALOG_REAR_R 0x29
#define ADC_REC_L 0x2a
#define ADC_REC_R 0x2b
#define ANALOG_CENTER 0x31
#define ANALOG_LFE 0x32
#define INPUT_PATCH_START(patch, nm, ln, i) \
do { \
patch = PATCH(mgr, patch_n); \
strcpy(patch->name, nm); \
patch->code_start = pc * 2; \
patch->input = (1<<(0x1f&ln)); \
patch->output= (1<<(0x1f&ln)); \
patch->id = i; \
} while(0)
#define INPUT_PATCH_END(patch) \
do { \
patch->code_size = pc * 2 - patch->code_start; \
patch_n++; \
} while(0)
#define ROUTING_PATCH_START(patch, nm) \
do { \
patch = &mgr->rpatch; \
strcpy(patch->name, nm); \
patch->code_start = pc * 2; \
} while(0)
#define ROUTING_PATCH_END(patch) \
do { \
patch->code_size = pc * 2 - patch->code_start; \
} while(0)
#define CONNECT(input, output) set_bit(input, &rpatch->route[(output) - OUTPUT_BASE]);
#define CONNECT_V(input, output) set_bit(input, &rpatch->route_v[(output) - OUTPUT_BASE]);
#define OUTPUT_PATCH_START(patch, nm, ln, i) \
do { \
patch = PATCH(mgr, patch_n); \
strcpy(patch->name, nm); \
patch->code_start = pc * 2; \
patch->input = (1<<(0x1f&ln)); \
patch->output= (1<<(0x1f&ln)); \
patch->id = i; \
} while(0)
#define OUTPUT_PATCH_END(patch) \
do { \
patch->code_size = pc * 2 - patch->code_start; \
patch_n++; \
} while(0)
#define GET_OUTPUT_GPR(patch, g, ln) \
do { \
mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_IO; \
mgr->gpr[(g) - GPR_BASE].usage++; \
mgr->gpr[(g) - GPR_BASE].line = ln; \
set_bit((g) - GPR_BASE, patch->gpr_used); \
} while(0)
#define GET_INPUT_GPR(patch, g, ln) \
do { \
mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_IO; \
mgr->gpr[(g) - GPR_BASE].usage++; \
mgr->gpr[(g) - GPR_BASE].line = ln; \
set_bit((g) - GPR_BASE, patch->gpr_used); \
set_bit((g) - GPR_BASE, patch->gpr_input); \
} while(0)
#define GET_DYNAMIC_GPR(patch, g) \
do { \
mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_DYNAMIC; \
mgr->gpr[(g) - GPR_BASE].usage++; \
set_bit((g) - GPR_BASE, patch->gpr_used); \
} while(0)
#define GET_CONTROL_GPR(patch, g, nm, a, b) \
do { \
strcpy(mgr->gpr[(g) - GPR_BASE].name, nm); \
mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_CONTROL; \
mgr->gpr[(g) - GPR_BASE].usage++; \
mgr->gpr[(g) - GPR_BASE].min = a; \
mgr->gpr[(g) - GPR_BASE].max = b; \
sblive_writeptr(card, g, 0, b); \
set_bit((g) - GPR_BASE, patch->gpr_used); \
} while(0)
#endif /* _EFXMGR_H */

View file

@ -1,104 +0,0 @@
/*
**********************************************************************
* emuadxmg.c - Address space manager for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 "hwaccess.h"
/* Allocates emu address space */
int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card)
{
u16 *pagetable = card->emupagetable;
u16 index = 0;
u16 numpages;
unsigned long flags;
/* Convert bytes to pages */
numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0);
spin_lock_irqsave(&card->lock, flags);
while (index < (MAXPAGES - 1)) {
if (pagetable[index] & 0x8000) {
/* This block of pages is in use, jump to the start of the next block. */
index += (pagetable[index] & 0x7fff);
} else {
/* Found free block */
if (pagetable[index] >= numpages) {
/* Block is large enough */
/* If free block is larger than the block requested
* then adjust the size of the block remaining */
if (pagetable[index] > numpages)
pagetable[index + numpages] = pagetable[index] - numpages;
pagetable[index] = (numpages | 0x8000); /* Mark block as used */
spin_unlock_irqrestore(&card->lock, flags);
return index;
} else {
/* Block too small, jump to the start of the next block */
index += pagetable[index];
}
}
}
spin_unlock_irqrestore(&card->lock, flags);
return -1;
}
/* Frees a previously allocated emu address space. */
void emu10k1_addxmgr_free(struct emu10k1_card *card, int index)
{
u16 *pagetable = card->emupagetable;
u16 origsize = 0;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
if (pagetable[index] & 0x8000) {
/* Block is allocated - mark block as free */
origsize = pagetable[index] & 0x7fff;
pagetable[index] = origsize;
/* If next block is free, we concat both blocks */
if (!(pagetable[index + origsize] & 0x8000))
pagetable[index] += pagetable[index + origsize] & 0x7fff;
}
spin_unlock_irqrestore(&card->lock, flags);
return;
}

View file

@ -1,507 +0,0 @@
/*
**********************************************************************
* hwaccess.c -- Hardware access layer
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* December 9, 1999 Jon Taylor rewrote the I/O subsystem
*
**********************************************************************
*
* 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 <asm/io.h>
#include "hwaccess.h"
#include "8010.h"
#include "icardmid.h"
/*************************************************************************
* Function : srToPitch *
* Input : sampleRate - sampling rate *
* Return : pitch value *
* About : convert sampling rate to pitch *
* Note : for 8010, sampling rate is at 48kHz, this function should *
* be changed. *
*************************************************************************/
u32 srToPitch(u32 sampleRate)
{
int i;
/* FIXME: These tables should be defined in a headerfile */
static u32 logMagTable[128] = {
0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
};
static char logSlopeTable[128] = {
0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
};
if (sampleRate == 0)
return 0; /* Bail out if no leading "1" */
sampleRate *= 11185; /* Scale 48000 to 0x20002380 */
for (i = 31; i > 0; i--) {
if (sampleRate & 0x80000000) { /* Detect leading "1" */
return (u32) (((s32) (i - 15) << 20) +
logMagTable[0x7f & (sampleRate >> 24)] +
(0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]);
}
sampleRate = sampleRate << 1;
}
DPF(2, "srToPitch: BUG!\n");
return 0; /* Should never reach this point */
}
/*******************************************
* write/read PCI function 0 registers *
********************************************/
void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
{
unsigned long flags;
if (reg & 0xff000000) {
u32 mask;
u8 size, offset;
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
data = (data << offset) & mask;
reg &= 0x7f;
spin_lock_irqsave(&card->lock, flags);
data |= inl(card->iobase + reg) & ~mask;
outl(data, card->iobase + reg);
spin_unlock_irqrestore(&card->lock, flags);
} else {
spin_lock_irqsave(&card->lock, flags);
outl(data, card->iobase + reg);
spin_unlock_irqrestore(&card->lock, flags);
}
return;
}
#ifdef DBGEMU
void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size)
{
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
if (size == 32)
outl(data, card->iobase + (reg & 0x1F));
else if (size == 16)
outw(data, card->iobase + (reg & 0x1F));
else
outb(data, card->iobase + (reg & 0x1F));
spin_unlock_irqrestore(&card->lock, flags);
return;
}
#endif /* DBGEMU */
u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
{
u32 val;
unsigned long flags;
if (reg & 0xff000000) {
u32 mask;
u8 size, offset;
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
reg &= 0x7f;
spin_lock_irqsave(&card->lock, flags);
val = inl(card->iobase + reg);
spin_unlock_irqrestore(&card->lock, flags);
return (val & mask) >> offset;
} else {
spin_lock_irqsave(&card->lock, flags);
val = inl(card->iobase + reg);
spin_unlock_irqrestore(&card->lock, flags);
return val;
}
}
void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
{
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
outw(data & TIMER_RATE_MASK, card->iobase + TIMER);
spin_unlock_irqrestore(&card->lock, flags);
}
/************************************************************************
* write/read Emu10k1 pointer-offset register set, accessed through *
* the PTR and DATA registers *
*************************************************************************/
#define A_PTR_ADDRESS_MASK 0x0fff0000
void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
{
u32 regptr;
unsigned long flags;
regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
if (reg & 0xff000000) {
u32 mask;
u8 size, offset;
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
data = (data << offset) & mask;
spin_lock_irqsave(&card->lock, flags);
outl(regptr, card->iobase + PTR);
data |= inl(card->iobase + DATA) & ~mask;
outl(data, card->iobase + DATA);
spin_unlock_irqrestore(&card->lock, flags);
} else {
spin_lock_irqsave(&card->lock, flags);
outl(regptr, card->iobase + PTR);
outl(data, card->iobase + DATA);
spin_unlock_irqrestore(&card->lock, flags);
}
}
/* ... : data, reg, ... , TAGLIST_END */
void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
{
va_list args;
unsigned long flags;
u32 reg;
va_start(args, channel);
spin_lock_irqsave(&card->lock, flags);
while ((reg = va_arg(args, u32)) != TAGLIST_END) {
u32 data = va_arg(args, u32);
u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK)
| (channel & PTR_CHANNELNUM_MASK));
outl(regptr, card->iobase + PTR);
if (reg & 0xff000000) {
int size = (reg >> 24) & 0x3f;
int offset = (reg >> 16) & 0x1f;
u32 mask = ((1 << size) - 1) << offset;
data = (data << offset) & mask;
data |= inl(card->iobase + DATA) & ~mask;
}
outl(data, card->iobase + DATA);
}
spin_unlock_irqrestore(&card->lock, flags);
va_end(args);
return;
}
u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
{
u32 regptr, val;
unsigned long flags;
regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
if (reg & 0xff000000) {
u32 mask;
u8 size, offset;
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
spin_lock_irqsave(&card->lock, flags);
outl(regptr, card->iobase + PTR);
val = inl(card->iobase + DATA);
spin_unlock_irqrestore(&card->lock, flags);
return (val & mask) >> offset;
} else {
spin_lock_irqsave(&card->lock, flags);
outl(regptr, card->iobase + PTR);
val = inl(card->iobase + DATA);
spin_unlock_irqrestore(&card->lock, flags);
return val;
}
}
void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask)
{
u32 val;
unsigned long flags;
DPF(2,"emu10k1_irq_enable()\n");
spin_lock_irqsave(&card->lock, flags);
val = inl(card->iobase + INTE) | irq_mask;
outl(val, card->iobase + INTE);
spin_unlock_irqrestore(&card->lock, flags);
return;
}
void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask)
{
u32 val;
unsigned long flags;
DPF(2,"emu10k1_irq_disable()\n");
spin_lock_irqsave(&card->lock, flags);
val = inl(card->iobase + INTE) & ~irq_mask;
outl(val, card->iobase + INTE);
spin_unlock_irqrestore(&card->lock, flags);
return;
}
void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
{
/* Voice interrupt */
if (voicenum >= 32)
sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
else
sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
return;
}
static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
{
volatile unsigned uCount;
u32 newtime = 0, curtime;
curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
while (wait--) {
uCount = 0;
while (uCount++ < TIMEOUT) {
newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
if (newtime != curtime)
break;
}
if (uCount >= TIMEOUT)
break;
curtime = newtime;
}
}
u16 emu10k1_ac97_read(struct ac97_codec *codec, u8 reg)
{
struct emu10k1_card *card = codec->private_data;
u16 data;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
outb(reg, card->iobase + AC97ADDRESS);
data = inw(card->iobase + AC97DATA);
spin_unlock_irqrestore(&card->lock, flags);
return data;
}
void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
{
struct emu10k1_card *card = codec->private_data;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
outb(reg, card->iobase + AC97ADDRESS);
outw(value, card->iobase + AC97DATA);
outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
spin_unlock_irqrestore(&card->lock, flags);
}
/*********************************************************
* MPU access functions *
**********************************************************/
int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
{
unsigned long flags;
int ret;
if (card->is_audigy) {
if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) {
sblive_writeptr(card, A_MUDATA, 0, data);
ret = 0;
} else
ret = -1;
} else {
spin_lock_irqsave(&card->lock, flags);
if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
outb(data, card->iobase + MUDATA);
ret = 0;
} else
ret = -1;
spin_unlock_irqrestore(&card->lock, flags);
}
return ret;
}
int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
{
unsigned long flags;
int ret;
if (card->is_audigy) {
if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) {
*data = sblive_readptr(card, A_MUDATA,0);
ret = 0;
} else
ret = -1;
} else {
spin_lock_irqsave(&card->lock, flags);
if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
*data = inb(card->iobase + MUDATA);
ret = 0;
} else
ret = -1;
spin_unlock_irqrestore(&card->lock, flags);
}
return ret;
}
int emu10k1_mpu_reset(struct emu10k1_card *card)
{
u8 status;
unsigned long flags;
DPF(2, "emu10k1_mpu_reset()\n");
if (card->is_audigy) {
if (card->mpuacqcount == 0) {
sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
sblive_wcwait(card, 8);
sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
sblive_wcwait(card, 8);
sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE);
sblive_wcwait(card, 8);
status = sblive_readptr(card, A_MUDATA, 0);
if (status == 0xfe)
return 0;
else
return -1;
}
return 0;
} else {
if (card->mpuacqcount == 0) {
spin_lock_irqsave(&card->lock, flags);
outb(MUCMD_RESET, card->iobase + MUCMD);
spin_unlock_irqrestore(&card->lock, flags);
sblive_wcwait(card, 8);
spin_lock_irqsave(&card->lock, flags);
outb(MUCMD_RESET, card->iobase + MUCMD);
spin_unlock_irqrestore(&card->lock, flags);
sblive_wcwait(card, 8);
spin_lock_irqsave(&card->lock, flags);
outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
spin_unlock_irqrestore(&card->lock, flags);
sblive_wcwait(card, 8);
spin_lock_irqsave(&card->lock, flags);
status = inb(card->iobase + MUDATA);
spin_unlock_irqrestore(&card->lock, flags);
if (status == 0xfe)
return 0;
else
return -1;
}
return 0;
}
}
int emu10k1_mpu_acquire(struct emu10k1_card *card)
{
/* FIXME: This should be a macro */
++card->mpuacqcount;
return 0;
}
int emu10k1_mpu_release(struct emu10k1_card *card)
{
/* FIXME: this should be a macro */
--card->mpuacqcount;
return 0;
}

View file

@ -1,247 +0,0 @@
/*
**********************************************************************
* hwaccess.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _HWACCESS_H
#define _HWACCESS_H
#include <linux/fs.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <asm/io.h>
#include "efxmgr.h"
#include "passthrough.h"
#include "midi.h"
#define EMUPAGESIZE 4096 /* don't change */
#define NUM_G 64 /* use all channels */
#define NUM_FXSENDS 4 /* don't change */
/* setting this to other than a power of two may break some applications */
#define MAXBUFSIZE 65536
#define MAXPAGES 8192
#define BUFMAXPAGES (MAXBUFSIZE / PAGE_SIZE)
#define FLAGS_AVAILABLE 0x0001
#define FLAGS_READY 0x0002
struct memhandle
{
dma_addr_t dma_handle;
void *addr;
u32 size;
};
#define DEBUG_LEVEL 2
#ifdef EMU10K1_DEBUG
# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0)
# define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0)
#else
# define DPD(level,x,y...) do { } while (0) /* not debugging: nothing */
# define DPF(level,x) do { } while (0)
#endif /* EMU10K1_DEBUG */
#define ERROR() DPF(1,"error\n")
/* DATA STRUCTURES */
struct emu10k1_waveout
{
u32 send_routing[3];
// audigy only:
u32 send_routing2[3];
u32 send_dcba[3];
// audigy only:
u32 send_hgfe[3];
};
#define ROUTE_PCM 0
#define ROUTE_PT 1
#define ROUTE_PCM1 2
#define SEND_MONO 0
#define SEND_LEFT 1
#define SEND_RIGHT 2
struct emu10k1_wavein
{
struct wiinst *ac97;
struct wiinst *mic;
struct wiinst *fx;
u8 recsrc;
u32 fxwc;
};
#define CMD_READ 1
#define CMD_WRITE 2
struct mixer_private_ioctl {
u32 cmd;
u32 val[90];
};
/* bogus ioctls numbers to escape from OSS mixer limitations */
#define CMD_WRITEFN0 _IOW('D', 0, struct mixer_private_ioctl)
#define CMD_READFN0 _IOR('D', 1, struct mixer_private_ioctl)
#define CMD_WRITEPTR _IOW('D', 2, struct mixer_private_ioctl)
#define CMD_READPTR _IOR('D', 3, struct mixer_private_ioctl)
#define CMD_SETRECSRC _IOW('D', 4, struct mixer_private_ioctl)
#define CMD_GETRECSRC _IOR('D', 5, struct mixer_private_ioctl)
#define CMD_GETVOICEPARAM _IOR('D', 6, struct mixer_private_ioctl)
#define CMD_SETVOICEPARAM _IOW('D', 7, struct mixer_private_ioctl)
#define CMD_GETPATCH _IOR('D', 8, struct mixer_private_ioctl)
#define CMD_GETGPR _IOR('D', 9, struct mixer_private_ioctl)
#define CMD_GETCTLGPR _IOR('D', 10, struct mixer_private_ioctl)
#define CMD_SETPATCH _IOW('D', 11, struct mixer_private_ioctl)
#define CMD_SETGPR _IOW('D', 12, struct mixer_private_ioctl)
#define CMD_SETCTLGPR _IOW('D', 13, struct mixer_private_ioctl)
#define CMD_SETGPOUT _IOW('D', 14, struct mixer_private_ioctl)
#define CMD_GETGPR2OSS _IOR('D', 15, struct mixer_private_ioctl)
#define CMD_SETGPR2OSS _IOW('D', 16, struct mixer_private_ioctl)
#define CMD_SETMCH_FX _IOW('D', 17, struct mixer_private_ioctl)
#define CMD_SETPASSTHROUGH _IOW('D', 18, struct mixer_private_ioctl)
#define CMD_PRIVATE3_VERSION _IOW('D', 19, struct mixer_private_ioctl)
#define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl)
//up this number when breaking compatibility
#define PRIVATE3_VERSION 2
struct emu10k1_card
{
struct list_head list;
struct memhandle virtualpagetable;
struct memhandle tankmem;
struct memhandle silentpage;
spinlock_t lock;
u8 voicetable[NUM_G];
u16 emupagetable[MAXPAGES];
struct list_head timers;
u16 timer_delay;
spinlock_t timer_lock;
struct pci_dev *pci_dev;
unsigned long iobase;
unsigned long length;
unsigned short model;
unsigned int irq;
int audio_dev;
int audio_dev1;
int midi_dev;
#ifdef EMU10K1_SEQUENCER
int seq_dev;
struct emu10k1_mididevice *seq_mididev;
#endif
struct ac97_codec *ac97;
int ac97_supported_mixers;
int ac97_stereo_mixers;
/* Number of first fx voice for multichannel output */
u8 mchannel_fx;
struct emu10k1_waveout waveout;
struct emu10k1_wavein wavein;
struct emu10k1_mpuout *mpuout;
struct emu10k1_mpuin *mpuin;
struct mutex open_sem;
mode_t open_mode;
wait_queue_head_t open_wait;
u32 mpuacqcount; // Mpu acquire count
u32 has_toslink; // TOSLink detection
u8 chiprev; /* Chip revision */
u8 is_audigy;
u8 is_aps;
struct patch_manager mgr;
struct pt_data pt;
};
int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
void emu10k1_addxmgr_free(struct emu10k1_card *, int);
int emu10k1_find_control_gpr(struct patch_manager *, const char *, const char *);
void emu10k1_set_control_gpr(struct emu10k1_card *, int , s32, int );
void emu10k1_set_volume_gpr(struct emu10k1_card *, int, s32, int);
#define VOL_6BIT 0x40
#define VOL_5BIT 0x20
#define VOL_4BIT 0x10
#define TIMEOUT 16384
u32 srToPitch(u32);
extern struct list_head emu10k1_devs;
/* Hardware Abstraction Layer access functions */
void emu10k1_writefn0(struct emu10k1_card *, u32, u32);
void emu10k1_writefn0_2(struct emu10k1_card *, u32, u32, int);
u32 emu10k1_readfn0(struct emu10k1_card *, u32);
void emu10k1_timer_set(struct emu10k1_card *, u16);
void sblive_writeptr(struct emu10k1_card *, u32, u32, u32);
void sblive_writeptr_tag(struct emu10k1_card *, u32, ...);
#define TAGLIST_END 0
u32 sblive_readptr(struct emu10k1_card *, u32 , u32 );
void emu10k1_irq_enable(struct emu10k1_card *, u32);
void emu10k1_irq_disable(struct emu10k1_card *, u32);
void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32);
/* AC97 Codec register access function */
u16 emu10k1_ac97_read(struct ac97_codec *, u8);
void emu10k1_ac97_write(struct ac97_codec *, u8, u16);
/* MPU access function*/
int emu10k1_mpu_write_data(struct emu10k1_card *, u8);
int emu10k1_mpu_read_data(struct emu10k1_card *, u8 *);
int emu10k1_mpu_reset(struct emu10k1_card *);
int emu10k1_mpu_acquire(struct emu10k1_card *);
int emu10k1_mpu_release(struct emu10k1_card *);
#endif /* _HWACCESS_H */

View file

@ -1,163 +0,0 @@
/*
**********************************************************************
* isblive_mid.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _ICARDMIDI_H
#define _ICARDMIDI_H
/* MIDI defines */
#define MIDI_DATA_FIRST 0x00
#define MIDI_DATA_LAST 0x7F
#define MIDI_STATUS_FIRST 0x80
#define MIDI_STATUS_LAST 0xFF
/* Channel status bytes */
#define MIDI_STATUS_CHANNEL_FIRST 0x80
#define MIDI_STATUS_CHANNEL_LAST 0xE0
#define MIDI_STATUS_CHANNEL_MASK 0xF0
/* Channel voice messages */
#define MIDI_VOICE_NOTE_OFF 0x80
#define MIDI_VOICE_NOTE_ON 0x90
#define MIDI_VOICE_POLY_PRESSURE 0xA0
#define MIDI_VOICE_CONTROL_CHANGE 0xB0
#define MIDI_VOICE_PROGRAM_CHANGE 0xC0
#define MIDI_VOICE_CHANNEL_PRESSURE 0xD0
#define MIDI_VOICE_PITCH_BEND 0xE0
/* Channel mode messages */
#define MIDI_MODE_CHANNEL MIDI_VOICE_CONTROL_CHANGE
/* System status bytes */
#define MIDI_STATUS_SYSTEM_FIRST 0xF0
#define MIDI_STATUS_SYSTEM_LAST 0xFF
/* System exclusive messages */
#define MIDI_SYSEX_BEGIN 0xF0
#define MIDI_SYSEX_EOX 0xF7
/* System common messages */
#define MIDI_COMMON_TCQF 0xF1 /* Time code quarter frame */
#define MIDI_COMMON_SONG_POSITION 0xF2
#define MIDI_COMMON_SONG_SELECT 0xF3
#define MIDI_COMMON_UNDEFINED_F4 0xF4
#define MIDI_COMMON_UNDEFINED_F5 0xF5
#define MIDI_COMMON_TUNE_REQUEST 0xF6
/* System real-time messages */
#define MIDI_RTIME_TIMING_CLOCK 0xF8
#define MIDI_RTIME_UNDEFINED_F9 0xF9
#define MIDI_RTIME_START 0xFA
#define MIDI_RTIME_CONTINUE 0xFB
#define MIDI_RTIME_STOP 0xFC
#define MIDI_RTIME_UNDEFINED_FD 0xFD
#define MIDI_RTIME_ACTIVE_SENSING 0xFE
#define MIDI_RTIME_SYSTEM_RESET 0xFF
/* Flags for flags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */
#define MIDI_CACHE_ALL 1
#define MIDI_CACHE_BESTFIT 2
#define MIDI_CACHE_QUERY 3
#define MIDI_UNCACHE 4
/* Event declarations for MPU IRQ Callbacks */
#define ICARDMIDI_INLONGDATA 0x00000001 /* MIM_LONGDATA */
#define ICARDMIDI_INLONGERROR 0x00000002 /* MIM_LONGERROR */
#define ICARDMIDI_OUTLONGDATA 0x00000004 /* MOM_DONE for MPU OUT buffer */
#define ICARDMIDI_INDATA 0x00000010 /* MIM_DATA */
#define ICARDMIDI_INDATAERROR 0x00000020 /* MIM_ERROR */
/* Declaration for flags in CARDMIDIBUFFERHDR */
/* Make it the same as MHDR_DONE, MHDR_INQUEUE in mmsystem.h */
#define MIDIBUF_DONE 0x00000001
#define MIDIBUF_INQUEUE 0x00000004
/* Declaration for msg parameter in midiCallbackFn */
#define ICARDMIDI_OUTBUFFEROK 0x00000001
#define ICARDMIDI_INMIDIOK 0x00000002
/* Declaration for technology in struct midi_caps */
#define MT_MIDIPORT 0x00000001 /* In original MIDIOUTCAPS structure */
#define MT_FMSYNTH 0x00000004 /* In original MIDIOUTCAPS structure */
#define MT_AWESYNTH 0x00001000
#define MT_PCISYNTH 0x00002000
#define MT_PCISYNTH64 0x00004000
#define CARDMIDI_AWEMASK 0x0000F000
enum LocalErrorCode
{
CTSTATUS_NOTENABLED = 0x7000,
CTSTATUS_READY,
CTSTATUS_BUSY,
CTSTATUS_DATAAVAIL,
CTSTATUS_NODATA,
CTSTATUS_NEXT_BYTE
};
/* MIDI data block header */
struct midi_hdr
{
u8 *reserved; /* Pointer to original locked data block */
u32 bufferlength; /* Length of data in data block */
u32 bytesrecorded; /* Used for input only */
u32 user; /* For client's use */
u32 flags; /* Assorted flags (see defines) */
struct list_head list; /* Reserved for driver */
u8 *data; /* Second copy of first pointer */
};
/* Enumeration for SetControl */
enum
{
MIDIOBJVOLUME = 0x1,
MIDIQUERYACTIVEINST
};
struct midi_queue
{
struct midi_queue *next;
u32 qtype; /* 0 = short message, 1 = long data */
u32 length;
u32 sizeLeft;
u8 *midibyte;
unsigned long refdata;
};
struct midi_openinfo
{
u32 cbsize;
u32 flags;
unsigned long refdata;
u32 streamid;
};
int emu10k1_midi_callback(unsigned long , unsigned long, unsigned long *);
#endif /* _ICARDMIDI_H */

View file

@ -1,53 +0,0 @@
/*
**********************************************************************
* icardwav.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _ICARDWAV_H
#define _ICARDWAV_H
struct wave_format
{
int id;
int samplingrate;
u8 bitsperchannel;
u8 channels; /* 1 = Mono, 2 = Stereo, 3, ... = Multichannel */
u8 bytesperchannel;
u8 bytespervoicesample;
u8 bytespersample;
int bytespersec;
u8 passthrough;
};
/* emu10k1_wave states */
#define WAVE_STATE_OPEN 0x01
#define WAVE_STATE_STARTED 0x02
#define WAVE_STATE_CLOSED 0x04
#endif /* _ICARDWAV_H */

View file

@ -1,113 +0,0 @@
/*
**********************************************************************
* irqmgr.c - IRQ manager for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 "hwaccess.h"
#include "8010.h"
#include "cardmi.h"
#include "cardmo.h"
#include "irqmgr.h"
/* Interrupt handler */
irqreturn_t emu10k1_interrupt(int irq, void *dev_id)
{
struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
u32 irqstatus, irqstatus_tmp;
int handled = 0;
DPD(4, "emu10k1_interrupt called, irq = %u\n", irq);
/*
** NOTE :
** We do a 'while loop' here cos on certain machines, with both
** playback and recording going on at the same time, IRQs will
** stop coming in after a while. Checking IPND indeed shows that
** there are interrupts pending but the PIC says no IRQs pending.
** I suspect that some boards need edge-triggered IRQs but are not
** getting that condition if we don't completely clear the IPND
** (make sure no more interrupts are pending).
** - Eric
*/
while ((irqstatus = inl(card->iobase + IPR))) {
DPD(4, "irq status %#x\n", irqstatus);
irqstatus_tmp = irqstatus;
if (irqstatus & IRQTYPE_TIMER) {
emu10k1_timer_irqhandler(card);
irqstatus &= ~IRQTYPE_TIMER;
}
if (irqstatus & IRQTYPE_DSP) {
emu10k1_dsp_irqhandler(card);
irqstatus &= ~IRQTYPE_DSP;
}
if (irqstatus & IRQTYPE_MPUIN) {
emu10k1_mpuin_irqhandler(card);
irqstatus &= ~IRQTYPE_MPUIN;
}
if (irqstatus & IRQTYPE_MPUOUT) {
emu10k1_mpuout_irqhandler(card);
irqstatus &= ~IRQTYPE_MPUOUT;
}
if (irqstatus & IPR_MUTE) {
emu10k1_mute_irqhandler(card);
irqstatus &=~IPR_MUTE;
}
if (irqstatus & IPR_VOLINCR) {
emu10k1_volincr_irqhandler(card);
irqstatus &=~IPR_VOLINCR;
}
if (irqstatus & IPR_VOLDECR) {
emu10k1_voldecr_irqhandler(card);
irqstatus &=~IPR_VOLDECR;
}
if (irqstatus){
printk(KERN_ERR "emu10k1: Warning, unhandled interrupt: %#08x\n", irqstatus);
//make sure any interrupts we don't handle are disabled:
emu10k1_irq_disable(card, ~(INTE_MIDIRXENABLE | INTE_MIDITXENABLE | INTE_INTERVALTIMERENB |
INTE_VOLDECRENABLE | INTE_VOLINCRENABLE | INTE_MUTEENABLE |
INTE_FXDSPENABLE));
}
/* acknowledge interrupt */
outl(irqstatus_tmp, card->iobase + IPR);
handled = 1;
}
return IRQ_RETVAL(handled);
}

View file

@ -1,52 +0,0 @@
/*
**********************************************************************
* irq.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _IRQ_H
#define _IRQ_H
/* EMU Irq Types */
#define IRQTYPE_PCIBUSERROR IPR_PCIERROR
#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
#define IRQTYPE_MPUOUT (IPR_MIDITRANSBUFEMPTY | A_IPR_MIDITRANSBUFEMPTY2)
#define IRQTYPE_MPUIN (IPR_MIDIRECVBUFEMPTY | A_IPR_MIDIRECVBUFEMPTY2)
#define IRQTYPE_TIMER IPR_INTERVALTIMER
#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
#define IRQTYPE_DSP IPR_FXDSP
void emu10k1_timer_irqhandler(struct emu10k1_card *);
void emu10k1_dsp_irqhandler(struct emu10k1_card *);
void emu10k1_mute_irqhandler(struct emu10k1_card *);
void emu10k1_volincr_irqhandler(struct emu10k1_card *);
void emu10k1_voldecr_irqhandler(struct emu10k1_card *);
#endif /* _IRQ_H */

File diff suppressed because it is too large Load diff

View file

@ -1,614 +0,0 @@
/*
**********************************************************************
* midi.c - /dev/midi interface for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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/poll.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include "hwaccess.h"
#include "cardmo.h"
#include "cardmi.h"
#include "midi.h"
#ifdef EMU10K1_SEQUENCER
#include "../sound_config.h"
#endif
static DEFINE_SPINLOCK(midi_spinlock);
static void init_midi_hdr(struct midi_hdr *midihdr)
{
midihdr->bufferlength = MIDIIN_BUFLEN;
midihdr->bytesrecorded = 0;
midihdr->flags = 0;
}
static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr)
{
struct midi_hdr *midihdr;
if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
ERROR();
return -EINVAL;
}
init_midi_hdr(midihdr);
midihdr->data = kmalloc(MIDIIN_BUFLEN, GFP_KERNEL);
if (!midihdr->data) {
ERROR();
kfree(midihdr);
return -1;
}
if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) {
ERROR();
kfree(midihdr->data);
kfree(midihdr);
return -1;
}
*midihdrptr = midihdr;
list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
return 0;
}
static int emu10k1_midi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct emu10k1_card *card = NULL;
struct emu10k1_mididevice *midi_dev;
struct list_head *entry;
DPF(2, "emu10k1_midi_open()\n");
/* Check for correct device to open */
list_for_each(entry, &emu10k1_devs) {
card = list_entry(entry, struct emu10k1_card, list);
if (card->midi_dev == minor)
goto match;
}
return -ENODEV;
match:
#ifdef EMU10K1_SEQUENCER
if (card->seq_mididev) /* card is opened by sequencer */
return -EBUSY;
#endif
/* Wait for device to become free */
mutex_lock(&card->open_sem);
while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
if (file->f_flags & O_NONBLOCK) {
mutex_unlock(&card->open_sem);
return -EBUSY;
}
mutex_unlock(&card->open_sem);
interruptible_sleep_on(&card->open_wait);
if (signal_pending(current)) {
return -ERESTARTSYS;
}
mutex_lock(&card->open_sem);
}
if ((midi_dev = kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
return -EINVAL;
midi_dev->card = card;
midi_dev->mistate = MIDIIN_STATE_STOPPED;
init_waitqueue_head(&midi_dev->oWait);
init_waitqueue_head(&midi_dev->iWait);
midi_dev->ird = 0;
midi_dev->iwr = 0;
midi_dev->icnt = 0;
INIT_LIST_HEAD(&midi_dev->mid_hdrs);
if (file->f_mode & FMODE_READ) {
struct midi_openinfo dsCardMidiOpenInfo;
struct midi_hdr *midihdr1;
struct midi_hdr *midihdr2;
dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) {
ERROR();
kfree(midi_dev);
return -ENODEV;
}
/* Add two buffers to receive sysex buffer */
if (midiin_add_buffer(midi_dev, &midihdr1) < 0) {
kfree(midi_dev);
return -ENODEV;
}
if (midiin_add_buffer(midi_dev, &midihdr2) < 0) {
list_del(&midihdr1->list);
kfree(midihdr1->data);
kfree(midihdr1);
kfree(midi_dev);
return -ENODEV;
}
}
if (file->f_mode & FMODE_WRITE) {
struct midi_openinfo dsCardMidiOpenInfo;
dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
ERROR();
kfree(midi_dev);
return -ENODEV;
}
}
file->private_data = (void *) midi_dev;
card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
mutex_unlock(&card->open_sem);
return nonseekable_open(inode, file);
}
static int emu10k1_midi_release(struct inode *inode, struct file *file)
{
struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
struct emu10k1_card *card;
lock_kernel();
card = midi_dev->card;
DPF(2, "emu10k1_midi_release()\n");
if (file->f_mode & FMODE_WRITE) {
if (!(file->f_flags & O_NONBLOCK)) {
while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) {
DPF(4, "Cannot close - buffers not empty\n");
interruptible_sleep_on(&midi_dev->oWait);
}
}
emu10k1_mpuout_close(card);
}
if (file->f_mode & FMODE_READ) {
struct midi_hdr *midihdr;
if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
emu10k1_mpuin_stop(card);
midi_dev->mistate = MIDIIN_STATE_STOPPED;
}
emu10k1_mpuin_reset(card);
emu10k1_mpuin_close(card);
while (!list_empty(&midi_dev->mid_hdrs)) {
midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list);
list_del(midi_dev->mid_hdrs.next);
kfree(midihdr->data);
kfree(midihdr);
}
}
kfree(midi_dev);
mutex_lock(&card->open_sem);
card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
mutex_unlock(&card->open_sem);
wake_up_interruptible(&card->open_wait);
unlock_kernel();
return 0;
}
static ssize_t emu10k1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t * pos)
{
struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
ssize_t ret = 0;
u16 cnt;
unsigned long flags;
DPD(4, "emu10k1_midi_read(), count %#x\n", (u32) count);
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
if (emu10k1_mpuin_start(midi_dev->card) < 0) {
ERROR();
return -EINVAL;
}
midi_dev->mistate = MIDIIN_STATE_STARTED;
}
while (count > 0) {
cnt = MIDIIN_BUFLEN - midi_dev->ird;
spin_lock_irqsave(&midi_spinlock, flags);
if (midi_dev->icnt < cnt)
cnt = midi_dev->icnt;
spin_unlock_irqrestore(&midi_spinlock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
DPF(2, " Go to sleep...\n");
interruptible_sleep_on(&midi_dev->iWait);
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
}
if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
ERROR();
return ret ? ret : -EFAULT;
}
midi_dev->ird += cnt;
midi_dev->ird %= MIDIIN_BUFLEN;
spin_lock_irqsave(&midi_spinlock, flags);
midi_dev->icnt -= cnt;
spin_unlock_irqrestore(&midi_spinlock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
if (midi_dev->icnt == 0)
break;
}
return ret;
}
static ssize_t emu10k1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t * pos)
{
struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
struct midi_hdr *midihdr;
unsigned long flags;
DPD(4, "emu10k1_midi_write(), count=%#x\n", (u32) count);
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
return -EINVAL;
midihdr->bufferlength = count;
midihdr->bytesrecorded = 0;
midihdr->flags = 0;
midihdr->data = kmalloc(count, GFP_KERNEL);
if (!midihdr->data) {
ERROR();
kfree(midihdr);
return -EINVAL;
}
if (copy_from_user(midihdr->data, buffer, count)) {
kfree(midihdr->data);
kfree(midihdr);
return -EFAULT;
}
spin_lock_irqsave(&midi_spinlock, flags);
if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) {
ERROR();
kfree(midihdr->data);
kfree(midihdr);
spin_unlock_irqrestore(&midi_spinlock, flags);
return -EINVAL;
}
spin_unlock_irqrestore(&midi_spinlock, flags);
return count;
}
static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
{
struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
unsigned long flags;
unsigned int mask = 0;
DPF(4, "emu10k1_midi_poll() called\n");
if (file->f_mode & FMODE_WRITE)
poll_wait(file, &midi_dev->oWait, wait);
if (file->f_mode & FMODE_READ)
poll_wait(file, &midi_dev->iWait, wait);
spin_lock_irqsave(&midi_spinlock, flags);
if (file->f_mode & FMODE_WRITE)
mask |= POLLOUT | POLLWRNORM;
if (file->f_mode & FMODE_READ) {
if (midi_dev->mistate == MIDIIN_STATE_STARTED)
if (midi_dev->icnt > 0)
mask |= POLLIN | POLLRDNORM;
}
spin_unlock_irqrestore(&midi_spinlock, flags);
return mask;
}
int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
{
struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata;
struct midi_hdr *midihdr = NULL;
unsigned long flags;
int i;
DPF(4, "emu10k1_midi_callback()\n");
spin_lock_irqsave(&midi_spinlock, flags);
switch (msg) {
case ICARDMIDI_OUTLONGDATA:
midihdr = (struct midi_hdr *) pmsg[2];
kfree(midihdr->data);
kfree(midihdr);
wake_up_interruptible(&midi_dev->oWait);
break;
case ICARDMIDI_INLONGDATA:
midihdr = (struct midi_hdr *) pmsg[2];
for (i = 0; i < midihdr->bytesrecorded; i++) {
midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i];
midi_dev->iwr %= MIDIIN_BUFLEN;
}
midi_dev->icnt += midihdr->bytesrecorded;
if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
init_midi_hdr(midihdr);
emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr);
wake_up_interruptible(&midi_dev->iWait);
}
break;
case ICARDMIDI_INDATA:
{
u8 *pBuf = (u8 *) & pmsg[1];
u16 bytesvalid = pmsg[2];
for (i = 0; i < bytesvalid; i++) {
midi_dev->iBuf[midi_dev->iwr++] = pBuf[i];
midi_dev->iwr %= MIDIIN_BUFLEN;
}
midi_dev->icnt += bytesvalid;
}
wake_up_interruptible(&midi_dev->iWait);
break;
default: /* Unknown message */
spin_unlock_irqrestore(&midi_spinlock, flags);
return -1;
}
spin_unlock_irqrestore(&midi_spinlock, flags);
return 0;
}
/* MIDI file operations */
const struct file_operations emu10k1_midi_fops = {
.owner = THIS_MODULE,
.read = emu10k1_midi_read,
.write = emu10k1_midi_write,
.poll = emu10k1_midi_poll,
.open = emu10k1_midi_open,
.release = emu10k1_midi_release,
};
#ifdef EMU10K1_SEQUENCER
/* functions used for sequencer access */
int emu10k1_seq_midi_open(int dev, int mode,
void (*input) (int dev, unsigned char data),
void (*output) (int dev))
{
struct emu10k1_card *card;
struct midi_openinfo dsCardMidiOpenInfo;
struct emu10k1_mididevice *midi_dev;
if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
return -EINVAL;
card = midi_devs[dev]->devc;
if (card->open_mode) /* card is opened native */
return -EBUSY;
DPF(2, "emu10k1_seq_midi_open()\n");
if ((midi_dev = kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
return -EINVAL;
midi_dev->card = card;
midi_dev->mistate = MIDIIN_STATE_STOPPED;
init_waitqueue_head(&midi_dev->oWait);
init_waitqueue_head(&midi_dev->iWait);
midi_dev->ird = 0;
midi_dev->iwr = 0;
midi_dev->icnt = 0;
INIT_LIST_HEAD(&midi_dev->mid_hdrs);
dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
ERROR();
return -ENODEV;
}
card->seq_mididev = midi_dev;
return 0;
}
void emu10k1_seq_midi_close(int dev)
{
struct emu10k1_card *card;
DPF(2, "emu10k1_seq_midi_close()\n");
if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
return;
card = midi_devs[dev]->devc;
emu10k1_mpuout_close(card);
kfree(card->seq_mididev);
card->seq_mididev = NULL;
}
int emu10k1_seq_midi_out(int dev, unsigned char midi_byte)
{
struct emu10k1_card *card;
struct midi_hdr *midihdr;
unsigned long flags;
if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
return -EINVAL;
card = midi_devs[dev]->devc;
if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
return -EINVAL;
midihdr->bufferlength = 1;
midihdr->bytesrecorded = 0;
midihdr->flags = 0;
midihdr->data = kmalloc(1, GFP_KERNEL);
if (!midihdr->data) {
ERROR();
kfree(midihdr);
return -EINVAL;
}
*(midihdr->data) = midi_byte;
spin_lock_irqsave(&midi_spinlock, flags);
if (emu10k1_mpuout_add_buffer(card, midihdr) < 0) {
ERROR();
kfree(midihdr->data);
kfree(midihdr);
spin_unlock_irqrestore(&midi_spinlock, flags);
return -EINVAL;
}
spin_unlock_irqrestore(&midi_spinlock, flags);
return 1;
}
int emu10k1_seq_midi_start_read(int dev)
{
return 0;
}
int emu10k1_seq_midi_end_read(int dev)
{
return 0;
}
void emu10k1_seq_midi_kick(int dev)
{
}
int emu10k1_seq_midi_buffer_status(int dev)
{
int count;
struct midi_queue *queue;
struct emu10k1_card *card;
if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
return -EINVAL;
count = 0;
card = midi_devs[dev]->devc;
queue = card->mpuout->firstmidiq;
while (queue != NULL) {
count++;
if (queue == card->mpuout->lastmidiq)
break;
queue = queue->next;
}
return count;
}
#endif

View file

@ -1,78 +0,0 @@
/*
**********************************************************************
* midi.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _MIDI_H
#define _MIDI_H
#define FMODE_MIDI_SHIFT 3
#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
#define MIDIIN_STATE_STARTED 0x00000001
#define MIDIIN_STATE_STOPPED 0x00000002
#define MIDIIN_BUFLEN 1024
struct emu10k1_mididevice
{
struct emu10k1_card *card;
u32 mistate;
wait_queue_head_t oWait;
wait_queue_head_t iWait;
s8 iBuf[MIDIIN_BUFLEN];
u16 ird, iwr, icnt;
struct list_head mid_hdrs;
};
/* uncomment next line to use midi port on Audigy drive */
//#define USE_AUDIGY_DRIVE_MIDI
#ifdef USE_AUDIGY_DRIVE_MIDI
#define A_MUDATA A_MUDATA2
#define A_MUCMD A_MUCMD2
#define A_MUSTAT A_MUCMD2
#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY2
#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY2
#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE2
#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE2
#else
#define A_MUDATA A_MUDATA1
#define A_MUCMD A_MUCMD1
#define A_MUSTAT A_MUCMD1
#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY1
#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY1
#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE1
#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE1
#endif
#endif /* _MIDI_H */

View file

@ -1,690 +0,0 @@
/*
**********************************************************************
* mixer.c - /dev/mixer interface for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
* November 2, 1999 Alan Cox cleaned up stuff
*
**********************************************************************
*
* 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 <asm/uaccess.h>
#include <linux/fs.h>
#include "hwaccess.h"
#include "8010.h"
#include "recmgr.h"
static const u32 bass_table[41][5] = {
{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
{ 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
{ 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
{ 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
{ 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
{ 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
{ 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
{ 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
{ 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
{ 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
{ 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
{ 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
{ 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
{ 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
{ 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
{ 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
{ 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
{ 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
{ 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
{ 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
{ 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
{ 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
{ 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
{ 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
{ 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
{ 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
{ 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
{ 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
{ 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
{ 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
{ 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
{ 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
{ 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
{ 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
{ 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
{ 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
{ 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
{ 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
{ 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
{ 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
};
static const u32 treble_table[41][5] = {
{ 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
{ 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
{ 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
{ 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
{ 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
{ 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
{ 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
{ 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
{ 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
{ 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
{ 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
{ 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
{ 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
{ 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
{ 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
{ 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
{ 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
{ 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
{ 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
{ 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
{ 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
{ 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
{ 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
{ 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
{ 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
{ 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
{ 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
{ 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
{ 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
{ 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
{ 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
{ 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
{ 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
{ 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
{ 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
{ 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
{ 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
{ 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
{ 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
{ 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
{ 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
};
static void set_bass(struct emu10k1_card *card, int l, int r)
{
int i;
l = (l * 40 + 50) / 100;
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++)
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
}
static void set_treble(struct emu10k1_card *card, int l, int r)
{
int i;
l = (l * 40 + 50) / 100;
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++)
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
}
const char volume_params[SOUND_MIXER_NRDEVICES]= {
/* Used by the ac97 driver */
[SOUND_MIXER_VOLUME] = VOL_6BIT,
[SOUND_MIXER_BASS] = VOL_4BIT,
[SOUND_MIXER_TREBLE] = VOL_4BIT,
[SOUND_MIXER_PCM] = VOL_5BIT,
[SOUND_MIXER_SPEAKER] = VOL_4BIT,
[SOUND_MIXER_LINE] = VOL_5BIT,
[SOUND_MIXER_MIC] = VOL_5BIT,
[SOUND_MIXER_CD] = VOL_5BIT,
[SOUND_MIXER_ALTPCM] = VOL_6BIT,
[SOUND_MIXER_IGAIN] = VOL_4BIT,
[SOUND_MIXER_LINE1] = VOL_5BIT,
[SOUND_MIXER_PHONEIN] = VOL_5BIT,
[SOUND_MIXER_PHONEOUT] = VOL_6BIT,
[SOUND_MIXER_VIDEO] = VOL_5BIT,
/* Not used by the ac97 driver */
[SOUND_MIXER_SYNTH] = VOL_5BIT,
[SOUND_MIXER_IMIX] = VOL_5BIT,
[SOUND_MIXER_RECLEV] = VOL_5BIT,
[SOUND_MIXER_OGAIN] = VOL_5BIT,
[SOUND_MIXER_LINE2] = VOL_5BIT,
[SOUND_MIXER_LINE3] = VOL_5BIT,
[SOUND_MIXER_DIGITAL1] = VOL_5BIT,
[SOUND_MIXER_DIGITAL2] = VOL_5BIT,
[SOUND_MIXER_DIGITAL3] = VOL_5BIT,
[SOUND_MIXER_RADIO] = VOL_5BIT,
[SOUND_MIXER_MONITOR] = VOL_5BIT
};
/* Mixer file operations */
static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, unsigned long arg)
{
struct mixer_private_ioctl *ctl;
struct dsp_patch *patch;
u32 size, page;
int addr, size_reg, i, ret;
unsigned int id, ch;
void __user *argp = (void __user *)arg;
switch (cmd) {
case SOUND_MIXER_PRIVATE3:
ctl = kmalloc(sizeof(struct mixer_private_ioctl), GFP_KERNEL);
if (ctl == NULL)
return -ENOMEM;
if (copy_from_user(ctl, argp, sizeof(struct mixer_private_ioctl))) {
kfree(ctl);
return -EFAULT;
}
ret = 0;
switch (ctl->cmd) {
#ifdef DBGEMU
case CMD_WRITEFN0:
emu10k1_writefn0_2(card, ctl->val[0], ctl->val[1], ctl->val[2]);
break;
#endif
case CMD_WRITEPTR:
#ifdef DBGEMU
if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000) {
#else
if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000 || ((ctl->val[0] < 0x100 ) &&
//Any register allowed raw access goes here:
(ctl->val[0] != A_SPDIF_SAMPLERATE) && (ctl->val[0] != A_DBG)
)
) {
#endif
ret = -EINVAL;
break;
}
sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]);
break;
case CMD_READFN0:
ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]);
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_READPTR:
if (ctl->val[1] >= 0x40 || (ctl->val[0] & 0x7ff) > 0xff) {
ret = -EINVAL;
break;
}
if ((ctl->val[0] & 0x7ff) > 0x3f)
ctl->val[1] = 0x00;
ctl->val[2] = sblive_readptr(card, ctl->val[0], ctl->val[1]);
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_SETRECSRC:
switch (ctl->val[0]) {
case WAVERECORD_AC97:
if (card->is_aps) {
ret = -EINVAL;
break;
}
card->wavein.recsrc = WAVERECORD_AC97;
break;
case WAVERECORD_MIC:
card->wavein.recsrc = WAVERECORD_MIC;
break;
case WAVERECORD_FX:
card->wavein.recsrc = WAVERECORD_FX;
card->wavein.fxwc = ctl->val[1] & 0xffff;
if (!card->wavein.fxwc)
ret = -EINVAL;
break;
default:
ret = -EINVAL;
break;
}
break;
case CMD_GETRECSRC:
ctl->val[0] = card->wavein.recsrc;
ctl->val[1] = card->wavein.fxwc;
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_GETVOICEPARAM:
ctl->val[0] = card->waveout.send_routing[0];
ctl->val[1] = card->waveout.send_dcba[0];
ctl->val[2] = card->waveout.send_routing[1];
ctl->val[3] = card->waveout.send_dcba[1];
ctl->val[4] = card->waveout.send_routing[2];
ctl->val[5] = card->waveout.send_dcba[2];
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_SETVOICEPARAM:
card->waveout.send_routing[0] = ctl->val[0];
card->waveout.send_dcba[0] = ctl->val[1];
card->waveout.send_routing[1] = ctl->val[2];
card->waveout.send_dcba[1] = ctl->val[3];
card->waveout.send_routing[2] = ctl->val[4];
card->waveout.send_dcba[2] = ctl->val[5];
break;
case CMD_SETMCH_FX:
card->mchannel_fx = ctl->val[0] & 0x000f;
break;
case CMD_GETPATCH:
if (ctl->val[0] == 0) {
if (copy_to_user(argp, &card->mgr.rpatch, sizeof(struct dsp_rpatch)))
ret = -EFAULT;
} else {
if ((ctl->val[0] - 1) / PATCHES_PER_PAGE >= card->mgr.current_pages) {
ret = -EINVAL;
break;
}
if (copy_to_user(argp, PATCH(&card->mgr, ctl->val[0] - 1), sizeof(struct dsp_patch)))
ret = -EFAULT;
}
break;
case CMD_GETGPR:
id = ctl->val[0];
if (id > NUM_GPRS) {
ret = -EINVAL;
break;
}
if (copy_to_user(argp, &card->mgr.gpr[id], sizeof(struct dsp_gpr)))
ret = -EFAULT;
break;
case CMD_GETCTLGPR:
addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, &((char *) ctl->val)[PATCH_NAME_SIZE]);
ctl->val[0] = sblive_readptr(card, addr, 0);
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_SETPATCH:
if (ctl->val[0] == 0)
memcpy(&card->mgr.rpatch, &ctl->val[1], sizeof(struct dsp_rpatch));
else {
page = (ctl->val[0] - 1) / PATCHES_PER_PAGE;
if (page > MAX_PATCHES_PAGES) {
ret = -EINVAL;
break;
}
if (page >= card->mgr.current_pages) {
for (i = card->mgr.current_pages; i < page + 1; i++) {
card->mgr.patch[i] = (void *)__get_free_page(GFP_KERNEL);
if(card->mgr.patch[i] == NULL) {
card->mgr.current_pages = i;
ret = -ENOMEM;
break;
}
memset(card->mgr.patch[i], 0, PAGE_SIZE);
}
card->mgr.current_pages = page + 1;
}
patch = PATCH(&card->mgr, ctl->val[0] - 1);
memcpy(patch, &ctl->val[1], sizeof(struct dsp_patch));
if (patch->code_size == 0) {
for(i = page + 1; i < card->mgr.current_pages; i++)
free_page((unsigned long) card->mgr.patch[i]);
card->mgr.current_pages = page + 1;
}
}
break;
case CMD_SETGPR:
if (ctl->val[0] > NUM_GPRS) {
ret = -EINVAL;
break;
}
memcpy(&card->mgr.gpr[ctl->val[0]], &ctl->val[1], sizeof(struct dsp_gpr));
break;
case CMD_SETCTLGPR:
addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, (char *) ctl->val + PATCH_NAME_SIZE);
emu10k1_set_control_gpr(card, addr, *((s32 *)((char *) ctl->val + 2 * PATCH_NAME_SIZE)), 0);
break;
case CMD_SETGPOUT:
if ( ((ctl->val[0] > 2) && (!card->is_audigy))
|| (ctl->val[0] > 15) || ctl->val[1] > 1) {
ret= -EINVAL;
break;
}
if (card->is_audigy)
emu10k1_writefn0(card, (1 << 24) | ((ctl->val[0]) << 16) | A_IOCFG, ctl->val[1]);
else
emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]);
break;
case CMD_GETGPR2OSS:
id = ctl->val[0];
ch = ctl->val[1];
if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) {
ret = -EINVAL;
break;
}
ctl->val[2] = card->mgr.ctrl_gpr[id][ch];
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_SETGPR2OSS:
id = ctl->val[0];
/* 0 == left, 1 == right */
ch = ctl->val[1];
addr = ctl->val[2];
if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) {
ret = -EINVAL;
break;
}
card->mgr.ctrl_gpr[id][ch] = addr;
if (card->is_aps)
break;
if (addr >= 0) {
unsigned int state = card->ac97->mixer_state[id];
if (ch == 1) {
state >>= 8;
card->ac97->stereo_mixers |= (1 << id);
}
card->ac97->supported_mixers |= (1 << id);
if (id == SOUND_MIXER_TREBLE) {
set_treble(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff);
} else if (id == SOUND_MIXER_BASS) {
set_bass(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff);
} else
emu10k1_set_volume_gpr(card, addr, state & 0xff,
volume_params[id]);
} else {
card->ac97->stereo_mixers &= ~(1 << id);
card->ac97->stereo_mixers |= card->ac97_stereo_mixers;
if (ch == 0) {
card->ac97->supported_mixers &= ~(1 << id);
card->ac97->supported_mixers |= card->ac97_supported_mixers;
}
}
break;
case CMD_SETPASSTHROUGH:
card->pt.selected = ctl->val[0] ? 1 : 0;
if (card->pt.state != PT_STATE_INACTIVE)
break;
card->pt.spcs_to_use = ctl->val[0] & 0x07;
break;
case CMD_PRIVATE3_VERSION:
ctl->val[0] = PRIVATE3_VERSION; //private3 version
ctl->val[1] = MAJOR_VER; //major driver version
ctl->val[2] = MINOR_VER; //minor driver version
ctl->val[3] = card->is_audigy; //1=card is audigy
if (card->is_audigy)
ctl->val[4]=emu10k1_readfn0(card, 0x18);
if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_AC97_BOOST:
if (ctl->val[0])
emu10k1_ac97_write(card->ac97, 0x18, 0x0);
else
emu10k1_ac97_write(card->ac97, 0x18, 0x0808);
break;
default:
ret = -EINVAL;
break;
}
kfree(ctl);
return ret;
break;
case SOUND_MIXER_PRIVATE4:
if (copy_from_user(&size, argp, sizeof(size)))
return -EFAULT;
DPD(2, "External tram size %#x\n", size);
if (size > 0x1fffff)
return -EINVAL;
size_reg = 0;
if (size != 0) {
size = (size - 1) >> 14;
while (size) {
size >>= 1;
size_reg++;
}
size = 0x4000 << size_reg;
}
DPD(2, "External tram size %#x %#x\n", size, size_reg);
if (size != card->tankmem.size) {
if (card->tankmem.size > 0) {
emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1);
sblive_writeptr_tag(card, 0, TCB, 0, TCBS, 0, TAGLIST_END);
pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle);
card->tankmem.size = 0;
}
if (size != 0) {
card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size, &card->tankmem.dma_handle);
if (card->tankmem.addr == NULL)
return -ENOMEM;
card->tankmem.size = size;
sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS,(u32) size_reg, TAGLIST_END);
emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
}
}
return 0;
break;
default:
break;
}
return -EINVAL;
}
static int emu10k1_dsp_mixer(struct emu10k1_card *card, unsigned int oss_mixer, unsigned long arg)
{
unsigned int left, right;
int val;
int scale;
card->ac97->modcnt++;
if (get_user(val, (int __user *)arg))
return -EFAULT;
/* cleanse input a little */
right = ((val >> 8) & 0xff);
left = (val & 0xff);
if (right > 100) right = 100;
if (left > 100) left = 100;
card->ac97->mixer_state[oss_mixer] = (right << 8) | left;
if (oss_mixer == SOUND_MIXER_TREBLE) {
set_treble(card, left, right);
return 0;
} if (oss_mixer == SOUND_MIXER_BASS) {
set_bass(card, left, right);
return 0;
}
if (oss_mixer == SOUND_MIXER_VOLUME)
scale = 1 << card->ac97->bit_resolution;
else
scale = volume_params[oss_mixer];
emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left, scale);
emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][1], right, scale);
if (card->ac97_supported_mixers & (1 << oss_mixer))
card->ac97->write_mixer(card->ac97, oss_mixer, left, right);
return 0;
}
static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
struct emu10k1_card *card = file->private_data;
unsigned int oss_mixer = _IOC_NR(cmd);
ret = -EINVAL;
if (!card->is_aps) {
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
strlcpy(info.id, card->ac97->name, sizeof(info.id));
if (card->is_audigy)
strlcpy(info.name, "Audigy - Emu10k1", sizeof(info.name));
else
strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
info.modify_counter = card->ac97->modcnt;
if (copy_to_user((void __user *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
if ((_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) && oss_mixer <= SOUND_MIXER_NRDEVICES)
ret = emu10k1_dsp_mixer(card, oss_mixer, arg);
else
ret = card->ac97->mixer_ioctl(card->ac97, cmd, arg);
}
if (ret < 0)
ret = emu10k1_private_mixer(card, cmd, arg);
return ret;
}
static int emu10k1_mixer_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct emu10k1_card *card = NULL;
struct list_head *entry;
DPF(4, "emu10k1_mixer_open()\n");
list_for_each(entry, &emu10k1_devs) {
card = list_entry(entry, struct emu10k1_card, list);
if (card->ac97->dev_mixer == minor)
goto match;
}
return -ENODEV;
match:
file->private_data = card;
return 0;
}
static int emu10k1_mixer_release(struct inode *inode, struct file *file)
{
DPF(4, "emu10k1_mixer_release()\n");
return 0;
}
const struct file_operations emu10k1_mixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = emu10k1_mixer_ioctl,
.open = emu10k1_mixer_open,
.release = emu10k1_mixer_release,
};

View file

@ -1,240 +0,0 @@
/*
**********************************************************************
* passthrough.c -- Emu10k1 digital passthrough
* Copyright (C) 2001 Juha Yrjölä <jyrjola@cc.hut.fi>
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* May 15, 2001 Juha Yrjölä base code release
*
**********************************************************************
*
* 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/poll.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include "hwaccess.h"
#include "cardwo.h"
#include "cardwi.h"
#include "recmgr.h"
#include "irqmgr.h"
#include "audio.h"
#include "8010.h"
static void pt_putsamples(struct pt_data *pt, u16 *ptr, u16 left, u16 right)
{
unsigned int idx;
ptr[pt->copyptr] = left;
idx = pt->copyptr + PT_SAMPLES/2;
idx %= PT_SAMPLES;
ptr[idx] = right;
}
static inline int pt_can_write(struct pt_data *pt)
{
return pt->blocks_copied < pt->blocks_played + 8;
}
static int pt_wait_for_write(struct emu10k1_wavedevice *wavedev, int nonblock)
{
struct emu10k1_card *card = wavedev->card;
struct pt_data *pt = &card->pt;
if (nonblock && !pt_can_write(pt))
return -EAGAIN;
while (!pt_can_write(pt) && pt->state != PT_STATE_INACTIVE) {
interruptible_sleep_on(&pt->wait);
if (signal_pending(current))
return -ERESTARTSYS;
}
if (pt->state == PT_STATE_INACTIVE)
return -EAGAIN;
return 0;
}
static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonblock)
{
struct woinst *woinst = wave_dev->woinst;
struct emu10k1_card *card = wave_dev->card;
struct pt_data *pt = &card->pt;
u16 *ptr = (u16 *) card->tankmem.addr;
int i = 0, r;
unsigned long flags;
r = pt_wait_for_write(wave_dev, nonblock);
if (r < 0)
return r;
spin_lock_irqsave(&card->pt.lock, flags);
while (i < PT_BLOCKSAMPLES) {
pt_putsamples(pt, ptr, block[2*i], block[2*i+1]);
if (pt->copyptr == 0)
pt->copyptr = PT_SAMPLES;
pt->copyptr--;
i++;
}
woinst->total_copied += PT_BLOCKSIZE;
pt->blocks_copied++;
if (pt->blocks_copied >= 4 && pt->state != PT_STATE_PLAYING) {
DPF(2, "activating digital pass-through playback\n");
sblive_writeptr(card, GPR_BASE + pt->enable_gpr, 0, 1);
pt->state = PT_STATE_PLAYING;
}
spin_unlock_irqrestore(&card->pt.lock, flags);
return 0;
}
int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev)
{
u32 bits;
struct emu10k1_card *card = wave_dev->card;
struct pt_data *pt = &card->pt;
int i;
for (i = 0; i < 3; i++) {
pt->old_spcs[i] = sblive_readptr(card, SPCS0 + i, 0);
if (pt->spcs_to_use & (1 << i)) {
DPD(2, "using S/PDIF port %d\n", i);
bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |
0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
if (pt->ac3data)
bits |= SPCS_NOTAUDIODATA;
sblive_writeptr(card, SPCS0 + i, 0, bits);
}
}
return 0;
}
ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t count)
{
struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
struct emu10k1_card *card = wave_dev->card;
struct pt_data *pt = &card->pt;
int nonblock, i, r, blocks, blocks_copied, bytes_copied = 0;
DPD(3, "emu10k1_pt_write(): %d bytes\n", count);
nonblock = file->f_flags & O_NONBLOCK;
if (card->tankmem.size < PT_SAMPLES*2)
return -EFAULT;
if (pt->state == PT_STATE_INACTIVE) {
DPF(2, "bufptr init\n");
pt->playptr = PT_SAMPLES-1;
pt->copyptr = PT_INITPTR;
pt->blocks_played = pt->blocks_copied = 0;
memset(card->tankmem.addr, 0, card->tankmem.size);
pt->state = PT_STATE_ACTIVATED;
pt->buf = kmalloc(PT_BLOCKSIZE, GFP_KERNEL);
pt->prepend_size = 0;
if (pt->buf == NULL)
return -ENOMEM;
emu10k1_pt_setup(wave_dev);
}
if (pt->prepend_size) {
int needed = PT_BLOCKSIZE - pt->prepend_size;
DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed);
if (count < needed) {
if (copy_from_user(pt->buf + pt->prepend_size,
buffer, count))
return -EFAULT;
pt->prepend_size += count;
DPD(3, "prepend size now %d\n", pt->prepend_size);
return count;
}
if (copy_from_user(pt->buf + pt->prepend_size, buffer, needed))
return -EFAULT;
r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock);
if (r)
return r;
bytes_copied += needed;
pt->prepend_size = 0;
}
blocks = (count-bytes_copied)/PT_BLOCKSIZE;
blocks_copied = 0;
while (blocks > 0) {
u16 __user *bufptr = (u16 __user *) buffer + (bytes_copied/2);
if (copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE))
return -EFAULT;
r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock);
if (r) {
if (bytes_copied)
return bytes_copied;
else
return r;
}
bytes_copied += PT_BLOCKSIZE;
blocks--;
blocks_copied++;
}
i = count - bytes_copied;
if (i) {
pt->prepend_size = i;
if (copy_from_user(pt->buf, buffer + bytes_copied, i))
return -EFAULT;
bytes_copied += i;
DPD(3, "filling prepend buffer with %d bytes", i);
}
return bytes_copied;
}
void emu10k1_pt_stop(struct emu10k1_card *card)
{
struct pt_data *pt = &card->pt;
int i;
if (pt->state != PT_STATE_INACTIVE) {
DPF(2, "digital pass-through stopped\n");
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 0);
for (i = 0; i < 3; i++) {
if (pt->spcs_to_use & (1 << i))
sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
}
pt->state = PT_STATE_INACTIVE;
kfree(pt->buf);
}
}
void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev)
{
struct woinst *woinst = wave_dev->woinst;
struct pt_data *pt = &wave_dev->card->pt;
u32 pos;
if (pt->state == PT_STATE_PLAYING && pt->pos_gpr >= 0) {
pos = sblive_readptr(wave_dev->card, GPR_BASE + pt->pos_gpr, 0);
if (pos > PT_BLOCKSAMPLES)
pos = PT_BLOCKSAMPLES;
pos = 4 * (PT_BLOCKSAMPLES - pos);
} else
pos = 0;
woinst->total_played = pt->blocks_played * woinst->buffer.fragment_size + pos;
woinst->buffer.hw_pos = pos;
}

View file

@ -1,99 +0,0 @@
/*
**********************************************************************
* passthrough.h -- Emu10k1 digital passthrough header file
* Copyright (C) 2001 Juha Yrjölä <jyrjola@cc.hut.fi>
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* May 15, 2001 Juha Yrjölä base code release
*
**********************************************************************
*
* 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 _PASSTHROUGH_H
#define _PASSTHROUGH_H
#include "audio.h"
/* number of 16-bit stereo samples in XTRAM buffer */
#define PT_SAMPLES 0x8000
#define PT_BLOCKSAMPLES 0x400
#define PT_BLOCKSIZE (PT_BLOCKSAMPLES*4)
#define PT_BLOCKSIZE_LOG2 12
#define PT_BLOCKCOUNT (PT_SAMPLES/PT_BLOCKSAMPLES)
#define PT_INITPTR (PT_SAMPLES/2-1)
#define PT_STATE_INACTIVE 0
#define PT_STATE_ACTIVATED 1
#define PT_STATE_PLAYING 2
/* passthrough struct */
struct pt_data
{
u8 selected, state, spcs_to_use;
int intr_gpr, enable_gpr, pos_gpr;
u32 blocks_played, blocks_copied, old_spcs[3];
u32 playptr, copyptr;
u32 prepend_size;
u8 *buf;
u8 ac3data;
char *patch_name, *intr_gpr_name, *enable_gpr_name, *pos_gpr_name;
wait_queue_head_t wait;
spinlock_t lock;
};
/*
Passthrough can be done in two methods:
Method 1 : tram
In original emu10k1, we couldn't bypass the sample rate converters. Even at 48kHz
(the internal sample rate of the emu10k1) the samples would get messed up.
To over come this, samples are copied into the tram and a special dsp patch copies
the samples out and generates interrupts when a block has finnished playing.
Method 2 : Interpolator bypass
Creative fixed the sample rate convert problem in emu10k1 rev 7 and higher
(including the emu10k2 (audigy)). This allows us to use the regular, and much simpler
playback method.
In both methods, dsp code is used to mux audio and passthrough. This ensures that the spdif
doesn't receive audio and pasthrough data at the same time. The spdif flag SPCS_NOTAUDIODATA
is set to tell
*/
// emu10k1 revs greater than or equal to 7 can use method2
#define USE_PT_METHOD2 (card->is_audigy)
#define USE_PT_METHOD1 !USE_PT_METHOD2
ssize_t emu10k1_pt_write(struct file *file, const char __user *buf, size_t count);
int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev);
void emu10k1_pt_stop(struct emu10k1_card *card);
void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev);
#endif /* _PASSTHROUGH_H */

View file

@ -1,147 +0,0 @@
/*
**********************************************************************
* recmgr.c -- Recording manager for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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/delay.h>
#include "8010.h"
#include "recmgr.h"
void emu10k1_reset_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
DPF(2, "emu10k1_reset_record()\n");
sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE);
sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval);
while (sblive_readptr(card, buffer->idxreg, 0))
udelay(5);
}
void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
DPF(2, "emu10k1_start_record()\n");
if (buffer->adcctl)
sblive_writeptr(card, ADCCR, 0, buffer->adcctl);
}
void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
DPF(2, "emu10k1_stop_record()\n");
/* Disable record transfer */
if (buffer->adcctl)
sblive_writeptr(card, ADCCR, 0, 0);
}
void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
{
struct wavein_buffer *buffer = &wiinst->buffer;
DPF(2, "emu10k1_set_record_src()\n");
switch (wiinst->recsrc) {
case WAVERECORD_AC97:
DPF(2, "recording source: AC97\n");
buffer->sizereg = ADCBS;
buffer->addrreg = ADCBA;
buffer->idxreg = card->is_audigy ? A_ADCIDX_IDX : ADCIDX_IDX;
switch (wiinst->format.samplingrate) {
case 0xBB80:
buffer->adcctl = ADCCR_SAMPLERATE_48;
break;
case 0xAC44:
buffer->adcctl = ADCCR_SAMPLERATE_44;
break;
case 0x7D00:
buffer->adcctl = ADCCR_SAMPLERATE_32;
break;
case 0x5DC0:
buffer->adcctl = ADCCR_SAMPLERATE_24;
break;
case 0x5622:
buffer->adcctl = ADCCR_SAMPLERATE_22;
break;
case 0x3E80:
buffer->adcctl = ADCCR_SAMPLERATE_16;
break;
// FIXME: audigy supports 12kHz recording
/*
case ????:
buffer->adcctl = A_ADCCR_SAMPLERATE_12;
break;
*/
case 0x2B11:
buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_11 : ADCCR_SAMPLERATE_11;
break;
case 0x1F40:
buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_8 : ADCCR_SAMPLERATE_8;
break;
default:
BUG();
break;
}
buffer->adcctl |= card->is_audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
if (wiinst->format.channels == 2)
buffer->adcctl |= card->is_audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
break;
case WAVERECORD_MIC:
DPF(2, "recording source: MIC\n");
buffer->sizereg = MICBS;
buffer->addrreg = MICBA;
buffer->idxreg = MICIDX_IDX;
buffer->adcctl = 0;
break;
case WAVERECORD_FX:
DPF(2, "recording source: FX\n");
buffer->sizereg = FXBS;
buffer->addrreg = FXBA;
buffer->idxreg = FXIDX_IDX;
buffer->adcctl = 0;
sblive_writeptr(card, FXWC, 0, wiinst->fxwc);
break;
default:
BUG();
break;
}
DPD(2, "bus addx: %#lx\n", (unsigned long) buffer->dma_handle);
sblive_writeptr(card, buffer->addrreg, 0, (u32)buffer->dma_handle);
}

View file

@ -1,48 +0,0 @@
/*
**********************************************************************
* recmgr.h
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _RECORDMGR_H
#define _RECORDMGR_H
#include "hwaccess.h"
#include "cardwi.h"
/* Recording resources */
#define WAVERECORD_AC97 0x01
#define WAVERECORD_MIC 0x02
#define WAVERECORD_FX 0x03
void emu10k1_reset_record(struct emu10k1_card *card, struct wavein_buffer *buffer);
void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *);
void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *);
void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst);
#endif /* _RECORDMGR_H */

View file

@ -1,176 +0,0 @@
/*
**********************************************************************
* timer.c
* Copyright (C) 1999, 2000 Creative Labs, 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.
*
**********************************************************************
*/
/* 3/6/2000 Improved support for different timer delays Rui Sousa */
/* 4/3/2000 Implemented timer list using list.h Rui Sousa */
#include "hwaccess.h"
#include "8010.h"
#include "irqmgr.h"
#include "timer.h"
/* Try to schedule only once per fragment */
void emu10k1_timer_irqhandler(struct emu10k1_card *card)
{
struct emu_timer *t;
struct list_head *entry;
spin_lock(&card->timer_lock);
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
if (t->state & TIMER_STATE_ACTIVE) {
t->count++;
if (t->count == t->count_max) {
t->count = 0;
tasklet_hi_schedule(&t->tasklet);
}
}
}
spin_unlock(&card->timer_lock);
return;
}
void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u16 delay)
{
struct emu_timer *t;
struct list_head *entry;
unsigned long flags;
if (delay < 5)
delay = 5;
timer->delay = delay;
timer->state = TIMER_STATE_INSTALLED;
spin_lock_irqsave(&card->timer_lock, flags);
timer->count_max = timer->delay / (card->timer_delay < 1024 ? card->timer_delay : 1024);
timer->count = timer->count_max - 1;
list_add(&timer->list, &card->timers);
if (card->timer_delay > delay) {
if (card->timer_delay == TIMER_STOPPED)
emu10k1_irq_enable(card, INTE_INTERVALTIMERENB);
card->timer_delay = delay;
delay = (delay < 1024 ? delay : 1024);
emu10k1_timer_set(card, delay);
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
t->count_max = t->delay / delay;
/* don't want to think much, just force scheduling
on the next interrupt */
t->count = t->count_max - 1;
}
DPD(2, "timer rate --> %u\n", delay);
}
spin_unlock_irqrestore(&card->timer_lock, flags);
return;
}
void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
{
struct emu_timer *t;
struct list_head *entry;
u16 delay = TIMER_STOPPED;
unsigned long flags;
if (timer->state == TIMER_STATE_UNINSTALLED)
return;
spin_lock_irqsave(&card->timer_lock, flags);
list_del(&timer->list);
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
if (t->delay < delay)
delay = t->delay;
}
if (card->timer_delay != delay) {
card->timer_delay = delay;
if (delay == TIMER_STOPPED)
emu10k1_irq_disable(card, INTE_INTERVALTIMERENB);
else {
delay = (delay < 1024 ? delay : 1024);
emu10k1_timer_set(card, delay);
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
t->count_max = t->delay / delay;
t->count = t->count_max - 1;
}
}
DPD(2, "timer rate --> %u\n", delay);
}
spin_unlock_irqrestore(&card->timer_lock, flags);
timer->state = TIMER_STATE_UNINSTALLED;
return;
}
void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer)
{
unsigned long flags;
spin_lock_irqsave(&card->timer_lock, flags);
timer->state |= TIMER_STATE_ACTIVE;
spin_unlock_irqrestore(&card->timer_lock, flags);
return;
}
void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer)
{
unsigned long flags;
spin_lock_irqsave(&card->timer_lock, flags);
timer->state &= ~TIMER_STATE_ACTIVE;
spin_unlock_irqrestore(&card->timer_lock, flags);
return;
}

View file

@ -1,54 +0,0 @@
/*
**********************************************************************
* timer.h
* Copyright (C) 1999, 2000 Creative Labs, 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 _TIMER_H
#define _TIMER_H
#include <linux/sched.h>
#include <linux/interrupt.h>
#include "hwaccess.h"
struct emu_timer
{
struct list_head list;
struct tasklet_struct tasklet;
u8 state;
u16 count; /* current number of interrupts */
u16 count_max; /* number of interrupts needed to schedule the bh */
u16 delay; /* timer delay */
};
void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u16);
void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *);
void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *);
void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *);
#define TIMER_STOPPED 0xffff
#define TIMER_STATE_INSTALLED 0x01
#define TIMER_STATE_ACTIVE 0x02
#define TIMER_STATE_UNINSTALLED 0x04
#endif /* _TIMER_H */

View file

@ -1,398 +0,0 @@
/*
**********************************************************************
* voicemgr.c - Voice manager for emu10k1 driver
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 "voicemgr.h"
#include "8010.h"
#define PITCH_48000 0x00004000
#define PITCH_96000 0x00008000
#define PITCH_85000 0x00007155
#define PITCH_80726 0x00006ba2
#define PITCH_67882 0x00005a82
#define PITCH_57081 0x00004c1c
static u32 emu10k1_select_interprom(struct emu10k1_card *card,
struct emu_voice *voice)
{
if(voice->pitch_target==PITCH_48000)
return CCCA_INTERPROM_0;
else if(voice->pitch_target<PITCH_48000)
return CCCA_INTERPROM_1;
else if(voice->pitch_target>=PITCH_96000)
return CCCA_INTERPROM_0;
else if(voice->pitch_target>=PITCH_85000)
return CCCA_INTERPROM_6;
else if(voice->pitch_target>=PITCH_80726)
return CCCA_INTERPROM_5;
else if(voice->pitch_target>=PITCH_67882)
return CCCA_INTERPROM_4;
else if(voice->pitch_target>=PITCH_57081)
return CCCA_INTERPROM_3;
else
return CCCA_INTERPROM_2;
}
/**
* emu10k1_voice_alloc_buffer -
*
* allocates the memory buffer for a voice. Two page tables are kept for each buffer.
* One (dma_handle) keeps track of the host memory pages used and the other (virtualpagetable)
* is passed to the device so that it can do DMA to host memory.
*
*/
int emu10k1_voice_alloc_buffer(struct emu10k1_card *card, struct voice_mem *mem, u32 pages)
{
u32 pageindex, pagecount;
u32 busaddx;
int i;
DPD(2, "requested pages is: %d\n", pages);
if ((mem->emupageindex = emu10k1_addxmgr_alloc(pages * PAGE_SIZE, card)) < 0)
{
DPF(1, "couldn't allocate emu10k1 address space\n");
return -1;
}
/* Fill in virtual memory table */
for (pagecount = 0; pagecount < pages; pagecount++) {
if ((mem->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &mem->dma_handle[pagecount]))
== NULL) {
mem->pages = pagecount;
DPF(1, "couldn't allocate dma memory\n");
return -1;
}
DPD(2, "Virtual Addx: %p\n", mem->addr[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
busaddx = (u32) mem->dma_handle[pagecount] + i * EMUPAGESIZE;
DPD(3, "Bus Addx: %#x\n", busaddx);
pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
((u32 *) card->virtualpagetable.addr)[pageindex] = cpu_to_le32((busaddx * 2) | pageindex);
}
}
mem->pages = pagecount;
return 0;
}
/**
* emu10k1_voice_free_buffer -
*
* frees the memory buffer for a voice.
*/
void emu10k1_voice_free_buffer(struct emu10k1_card *card, struct voice_mem *mem)
{
u32 pagecount, pageindex;
int i;
if (mem->emupageindex < 0)
return;
for (pagecount = 0; pagecount < mem->pages; pagecount++) {
pci_free_consistent(card->pci_dev, PAGE_SIZE,
mem->addr[pagecount],
mem->dma_handle[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
((u32 *) card->virtualpagetable.addr)[pageindex] =
cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pageindex);
}
}
emu10k1_addxmgr_free(card, mem->emupageindex);
mem->emupageindex = -1;
}
int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
{
u8 *voicetable = card->voicetable;
int i;
unsigned long flags;
DPF(2, "emu10k1_voice_alloc()\n");
spin_lock_irqsave(&card->lock, flags);
if (voice->flags & VOICE_FLAGS_STEREO) {
for (i = 0; i < NUM_G; i += 2)
if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) {
voicetable[i] = voice->usage;
voicetable[i + 1] = voice->usage;
break;
}
} else {
for (i = 0; i < NUM_G; i++)
if (voicetable[i] == VOICE_USAGE_FREE) {
voicetable[i] = voice->usage;
break;
}
}
spin_unlock_irqrestore(&card->lock, flags);
if (i >= NUM_G)
return -1;
voice->card = card;
voice->num = i;
for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
DPD(2, " voice allocated -> %d\n", voice->num + i);
sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff,
DCYSUSV, 0,
VTFT, 0x0000ffff,
PTRX, 0,
TAGLIST_END);
}
return 0;
}
void emu10k1_voice_free(struct emu_voice *voice)
{
struct emu10k1_card *card = voice->card;
int i;
unsigned long flags;
DPF(2, "emu10k1_voice_free()\n");
if (voice->usage == VOICE_USAGE_FREE)
return;
for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
DPD(2, " voice released -> %d\n", voice->num + i);
sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0,
VTFT, 0x0000ffff,
PTRX_PITCHTARGET, 0,
CVCF, 0x0000ffff,
//CPF, 0,
TAGLIST_END);
sblive_writeptr(card, CPF, voice->num + i, 0);
}
voice->usage = VOICE_USAGE_FREE;
spin_lock_irqsave(&card->lock, flags);
card->voicetable[voice->num] = VOICE_USAGE_FREE;
if (voice->flags & VOICE_FLAGS_STEREO)
card->voicetable[voice->num + 1] = VOICE_USAGE_FREE;
spin_unlock_irqrestore(&card->lock, flags);
}
void emu10k1_voice_playback_setup(struct emu_voice *voice)
{
struct emu10k1_card *card = voice->card;
u32 start;
int i;
DPF(2, "emu10k1_voice_playback_setup()\n");
if (voice->flags & VOICE_FLAGS_STEREO) {
/* Set stereo bit */
start = 28;
sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
} else {
start = 30;
sblive_writeptr(card, CPF, voice->num, 0);
}
if(!(voice->flags & VOICE_FLAGS_16BIT))
start *= 2;
voice->start += start;
for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
if (card->is_audigy) {
sblive_writeptr(card, A_FXRT1, voice->num + i, voice->params[i].send_routing);
sblive_writeptr(card, A_FXRT2, voice->num + i, voice->params[i].send_routing2);
sblive_writeptr(card, A_SENDAMOUNTS, voice->num + i, voice->params[i].send_hgfe);
} else {
sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
}
/* Stop CA */
/* Assumption that PT is already 0 so no harm overwriting */
sblive_writeptr(card, PTRX, voice->num + i, ((voice->params[i].send_dcba & 0xff) << 8)
| ((voice->params[i].send_dcba & 0xff00) >> 8));
sblive_writeptr_tag(card, voice->num + i,
/* CSL, ST, CA */
DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000),
PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8),
CCCA, (voice->start) | emu10k1_select_interprom(card,voice) |
((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
/* Clear filter delay memory */
Z1, 0,
Z2, 0,
/* Invalidate maps */
MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
/* modulation envelope */
CVCF, 0x0000ffff,
VTFT, 0x0000ffff,
ATKHLDM, 0,
DCYSUSM, 0x007f,
LFOVAL1, 0x8000,
LFOVAL2, 0x8000,
FMMOD, 0,
TREMFRQ, 0,
FM2FRQ2, 0,
ENVVAL, 0x8000,
/* volume envelope */
ATKHLDV, 0x7f7f,
ENVVOL, 0x8000,
/* filter envelope */
PEFE_FILTERAMOUNT, 0x7f,
/* pitch envelope */
PEFE_PITCHAMOUNT, 0, TAGLIST_END);
voice->params[i].fc_target = 0xffff;
}
}
void emu10k1_voices_start(struct emu_voice *first_voice, unsigned int num_voices, int set)
{
struct emu10k1_card *card = first_voice->card;
struct emu_voice *voice;
unsigned int voicenum;
int j;
DPF(2, "emu10k1_voices_start()\n");
for (voicenum = 0; voicenum < num_voices; voicenum++)
{
voice = first_voice + voicenum;
if (!set) {
u32 cra, ccis, cs, sample;
if (voice->flags & VOICE_FLAGS_STEREO) {
cra = 64;
ccis = 28;
cs = 4;
} else {
cra = 64;
ccis = 30;
cs = 2;
}
if(voice->flags & VOICE_FLAGS_16BIT) {
sample = 0x00000000;
} else {
sample = 0x80808080;
ccis *= 2;
}
for(j = 0; j < cs; j++)
sblive_writeptr(card, CD0 + j, voice->num, sample);
/* Reset cache */
sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0);
if (voice->flags & VOICE_FLAGS_STEREO)
sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0);
sblive_writeptr(card, CCR_READADDRESS, voice->num, cra);
if (voice->flags & VOICE_FLAGS_STEREO)
sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra);
/* Fill cache */
sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis);
}
for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
sblive_writeptr_tag(card, voice->num + j,
IFATN, (voice->params[j].initial_fc << 8) | voice->params[j].initial_attn,
VTFT, (voice->params[j].volume_target << 16) | voice->params[j].fc_target,
CVCF, (voice->params[j].volume_target << 16) | voice->params[j].fc_target,
DCYSUSV, (voice->params[j].byampl_env_sustain << 8) | voice->params[j].byampl_env_decay,
TAGLIST_END);
emu10k1_clear_stop_on_loop(card, voice->num + j);
}
}
for (voicenum = 0; voicenum < num_voices; voicenum++)
{
voice = first_voice + voicenum;
for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + j, voice->pitch_target);
if (j == 0)
sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target);
sblive_writeptr(card, IP, voice->num + j, voice->initial_pitch);
}
}
}
void emu10k1_voices_stop(struct emu_voice *first_voice, int num_voices)
{
struct emu10k1_card *card = first_voice->card;
struct emu_voice *voice;
unsigned int voice_num;
int j;
DPF(2, "emu10k1_voice_stop()\n");
for (voice_num = 0; voice_num < num_voices; voice_num++)
{
voice = first_voice + voice_num;
for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
sblive_writeptr_tag(card, voice->num + j,
PTRX_PITCHTARGET, 0,
CPF_CURRENTPITCH, 0,
IFATN, 0xffff,
VTFT, 0x0000ffff,
CVCF, 0x0000ffff,
IP, 0,
TAGLIST_END);
}
}
}

View file

@ -1,103 +0,0 @@
/*
**********************************************************************
* sblive_voice.h -- EMU Voice Resource Manager header file
* Copyright 1999, 2000 Creative Labs, Inc.
*
**********************************************************************
*
* Date Author Summary of changes
* ---- ------ ------------------
* October 20, 1999 Bertrand Lee base code release
*
**********************************************************************
*
* 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 _VOICEMGR_H
#define _VOICEMGR_H
#include "hwaccess.h"
/* struct emu_voice.usage flags */
#define VOICE_USAGE_FREE 0x01
#define VOICE_USAGE_MIDI 0x02
#define VOICE_USAGE_PLAYBACK 0x04
/* struct emu_voice.flags flags */
#define VOICE_FLAGS_STEREO 0x02
#define VOICE_FLAGS_16BIT 0x04
struct voice_param
{
/* FX bus amount send */
u32 send_routing;
// audigy only:
u32 send_routing2;
u32 send_dcba;
// audigy only:
u32 send_hgfe;
u32 initial_fc;
u32 fc_target;
u32 initial_attn;
u32 volume_target;
u32 byampl_env_sustain;
u32 byampl_env_decay;
};
struct voice_mem {
int emupageindex;
void *addr[BUFMAXPAGES];
dma_addr_t dma_handle[BUFMAXPAGES];
u32 pages;
};
struct emu_voice
{
struct emu10k1_card *card;
u8 usage; /* Free, MIDI, playback */
u8 num; /* Voice ID */
u8 flags; /* Stereo/mono, 8/16 bit */
u32 startloop;
u32 endloop;
u32 start;
u32 initial_pitch;
u32 pitch_target;
struct voice_param params[2];
struct voice_mem mem;
};
int emu10k1_voice_alloc_buffer(struct emu10k1_card *, struct voice_mem *, u32);
void emu10k1_voice_free_buffer(struct emu10k1_card *, struct voice_mem *);
int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *);
void emu10k1_voice_free(struct emu_voice *);
void emu10k1_voice_playback_setup(struct emu_voice *);
void emu10k1_voices_start(struct emu_voice *, unsigned int, int);
void emu10k1_voices_stop(struct emu_voice *, int);
#endif /* _VOICEMGR_H */

View file

@ -1,292 +0,0 @@
#ifndef _NM256_H_
#define _NM256_H_
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include "ac97.h"
/* The revisions that we currently handle. */
enum nm256rev {
REV_NM256AV, REV_NM256ZX
};
/* Per-card structure. */
struct nm256_info
{
/* Magic number used to verify that this struct is valid. */
#define NM_MAGIC_SIG 0x55aa00ff
int magsig;
/* Revision number */
enum nm256rev rev;
struct ac97_hwint mdev;
/* Our audio device numbers. */
int dev[2];
/* The # of times each device has been opened. (Should only be
0 or 1). */
int opencnt[2];
/* We use two devices, because we can do simultaneous play and record.
This keeps track of which device is being used for what purpose;
these are the actual device numbers. */
int dev_for_play;
int dev_for_record;
spinlock_t lock;
/* The mixer device. */
int mixer_oss_dev;
/*
* Can only be opened once for each operation. These aren't set
* until an actual I/O operation is performed; this allows one
* device to be open for read/write without inhibiting I/O to
* the other device.
*/
int is_open_play;
int is_open_record;
/* Non-zero if we're currently playing a sample. */
int playing;
/* Ditto for recording a sample. */
int recording;
/* The two memory ports. */
struct nm256_ports {
/* Physical address of the port. */
u32 physaddr;
/* Our mapped-in pointer. */
char __iomem *ptr;
/* PTR's offset within the physical port. */
u32 start_offset;
/* And the offset of the end of the buffer. */
u32 end_offset;
} port[2];
/* The following are offsets within memory port 1. */
u32 coeffBuf;
u32 allCoeffBuf;
/* Record and playback buffers. */
u32 abuf1, abuf2;
/* Offset of the AC97 mixer in memory port 2. */
u32 mixer;
/* Offset of the mixer status register in memory port 2. */
u32 mixer_status_offset;
/* Non-zero if we have written initial values to the mixer. */
u8 mixer_values_init;
/*
* Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means
* it's ready.
*/
u16 mixer_status_mask;
/* The sizes of the playback and record ring buffers. */
u32 playbackBufferSize;
u32 recordBufferSize;
/* Are the coefficient values in the memory cache current? */
u8 coeffsCurrent;
/* For writes, the amount we last wrote. */
u32 requested_amt;
/* The start of the block currently playing. */
u32 curPlayPos;
/* The amount of data we were requested to record. */
u32 requestedRecAmt;
/* The offset of the currently-recording block. */
u32 curRecPos;
/* The destination buffer. */
char *recBuf;
/* Our IRQ number. */
int irq;
/* A flag indicating how many times we've grabbed the IRQ. */
int has_irq;
/* The card interrupt service routine. */
irq_handler_t introutine;
/* Current audio config, cached. */
struct sinfo {
u32 samplerate;
u8 bits;
u8 stereo;
} sinfo[2]; /* goes with each device */
/* The cards are stored in a chain; this is the next card. */
struct nm256_info *next_card;
};
/* The BIOS signature. */
#define NM_SIGNATURE 0x4e4d0000
/* Signature mask. */
#define NM_SIG_MASK 0xffff0000
/* Size of the second memory area. */
#define NM_PORT2_SIZE 4096
/* The base offset of the mixer in the second memory area. */
#define NM_MIXER_OFFSET 0x600
/* The maximum size of a coefficient entry. */
#define NM_MAX_COEFFICIENT 0x5000
/* The interrupt register. */
#define NM_INT_REG 0xa04
/* And its bits. */
#define NM_PLAYBACK_INT 0x40
#define NM_RECORD_INT 0x100
#define NM_MISC_INT_1 0x4000
#define NM_MISC_INT_2 0x1
#define NM_ACK_INT(CARD, X) nm256_writePort16((CARD), 2, NM_INT_REG, (X) << 1)
/* The AV's "mixer ready" status bit and location. */
#define NM_MIXER_STATUS_OFFSET 0xa04
#define NM_MIXER_READY_MASK 0x0800
#define NM_MIXER_PRESENCE 0xa06
#define NM_PRESENCE_MASK 0x0050
#define NM_PRESENCE_VALUE 0x0040
/*
* For the ZX. It uses the same interrupt register, but it holds 32
* bits instead of 16.
*/
#define NM2_PLAYBACK_INT 0x10000
#define NM2_RECORD_INT 0x80000
#define NM2_MISC_INT_1 0x8
#define NM2_MISC_INT_2 0x2
#define NM2_ACK_INT(CARD, X) nm256_writePort32((CARD), 2, NM_INT_REG, (X))
/* The ZX's "mixer ready" status bit and location. */
#define NM2_MIXER_STATUS_OFFSET 0xa06
#define NM2_MIXER_READY_MASK 0x0800
/* The playback registers start from here. */
#define NM_PLAYBACK_REG_OFFSET 0x0
/* The record registers start from here. */
#define NM_RECORD_REG_OFFSET 0x200
/* The rate register is located 2 bytes from the start of the register area. */
#define NM_RATE_REG_OFFSET 2
/* Mono/stereo flag, number of bits on playback, and rate mask. */
#define NM_RATE_STEREO 1
#define NM_RATE_BITS_16 2
#define NM_RATE_MASK 0xf0
/* Playback enable register. */
#define NM_PLAYBACK_ENABLE_REG (NM_PLAYBACK_REG_OFFSET + 0x1)
#define NM_PLAYBACK_ENABLE_FLAG 1
#define NM_PLAYBACK_ONESHOT 2
#define NM_PLAYBACK_FREERUN 4
/* Mutes the audio output. */
#define NM_AUDIO_MUTE_REG (NM_PLAYBACK_REG_OFFSET + 0x18)
#define NM_AUDIO_MUTE_LEFT 0x8000
#define NM_AUDIO_MUTE_RIGHT 0x0080
/* Recording enable register. */
#define NM_RECORD_ENABLE_REG (NM_RECORD_REG_OFFSET + 0)
#define NM_RECORD_ENABLE_FLAG 1
#define NM_RECORD_FREERUN 2
#define NM_RBUFFER_START (NM_RECORD_REG_OFFSET + 0x4)
#define NM_RBUFFER_END (NM_RECORD_REG_OFFSET + 0x10)
#define NM_RBUFFER_WMARK (NM_RECORD_REG_OFFSET + 0xc)
#define NM_RBUFFER_CURRP (NM_RECORD_REG_OFFSET + 0x8)
#define NM_PBUFFER_START (NM_PLAYBACK_REG_OFFSET + 0x4)
#define NM_PBUFFER_END (NM_PLAYBACK_REG_OFFSET + 0x14)
#define NM_PBUFFER_WMARK (NM_PLAYBACK_REG_OFFSET + 0xc)
#define NM_PBUFFER_CURRP (NM_PLAYBACK_REG_OFFSET + 0x8)
/* A few trivial routines to make it easier to work with the registers
on the chip. */
/* This is a common code portion used to fix up the port offsets. */
#define NM_FIX_PORT \
if (port < 1 || port > 2 || card == NULL) \
return -1; \
\
if (offset < card->port[port - 1].start_offset \
|| offset >= card->port[port - 1].end_offset) { \
printk (KERN_ERR "Bad access: port %d, offset 0x%x\n", port, offset); \
return -1; \
} \
offset -= card->port[port - 1].start_offset;
#define DEFwritePortX(X, func) \
static inline int nm256_writePort##X (struct nm256_info *card,\
int port, int offset, int value)\
{\
u##X __iomem *addr;\
\
if (nm256_debug > 1)\
printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\
\
NM_FIX_PORT;\
\
addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
func (value, addr);\
return 0;\
}
DEFwritePortX (8, writeb)
DEFwritePortX (16, writew)
DEFwritePortX (32, writel)
#define DEFreadPortX(X, func) \
static inline u##X nm256_readPort##X (struct nm256_info *card,\
int port, int offset)\
{\
u##X __iomem *addr;\
\
NM_FIX_PORT\
\
addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
return func(addr);\
}
DEFreadPortX (8, readb)
DEFreadPortX (16, readw)
DEFreadPortX (32, readl)
static inline int
nm256_writeBuffer8 (struct nm256_info *card, u8 *src, int port, int offset,
int amt)
{
NM_FIX_PORT;
memcpy_toio (card->port[port - 1].ptr + offset, src, amt);
return 0;
}
static inline int
nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset,
int amt)
{
NM_FIX_PORT;
memcpy_fromio (dst, card->port[port - 1].ptr + offset, amt);
return 0;
}
/* Returns a non-zero value if we should use the coefficient cache. */
static int nm256_cachedCoefficients (struct nm256_info *card);
#endif
/*
* Local variables:
* c-basic-offset: 4
* End:
*/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,6 @@
#include "sound_config.h"
#include "opl3.h"
#include "opl3_hw.h"
#define MAX_VOICE 18
@ -73,7 +72,6 @@ typedef struct opl_devinfo
unsigned char cmask;
int is_opl4;
int *osp;
} opl_devinfo;
static struct opl_devinfo *devc = NULL;
@ -144,7 +142,7 @@ static int opl3_ioctl(int dev, unsigned int cmd, void __user * arg)
}
}
int opl3_detect(int ioaddr, int *osp)
static int opl3_detect(int ioaddr)
{
/*
* This function returns 1 if the FM chip is present at the given I/O port
@ -182,7 +180,6 @@ int opl3_detect(int ioaddr, int *osp)
goto cleanup_devc;
}
devc->osp = osp;
devc->base = ioaddr;
/* Reset timers 1 and 2 */
@ -1105,7 +1102,7 @@ static struct synth_operations opl3_operations =
.setup_voice = opl3_setup_voice
};
int opl3_init(int ioaddr, int *osp, struct module *owner)
static int opl3_init(int ioaddr, struct module *owner)
{
int i;
int me;
@ -1194,9 +1191,6 @@ int opl3_init(int ioaddr, int *osp, struct module *owner)
return me;
}
EXPORT_SYMBOL(opl3_init);
EXPORT_SYMBOL(opl3_detect);
static int me;
static int io = -1;
@ -1209,12 +1203,12 @@ static int __init init_opl3 (void)
if (io != -1) /* User loading pure OPL3 module */
{
if (!opl3_detect(io, NULL))
if (!opl3_detect(io))
{
return -ENODEV;
}
me = opl3_init(io, NULL, THIS_MODULE);
me = opl3_init(io, THIS_MODULE);
}
return 0;

View file

@ -1,5 +0,0 @@
int opl3_detect (int ioaddr, int *osp);
int opl3_init(int ioaddr, int *osp, struct module *owner);
void enable_opl3_mode(int left, int right, int both);

File diff suppressed because it is too large Load diff