mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 23:51:37 +00:00
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:
parent
786d7e1612
commit
b5d425c97f
@ -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
|
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
|
||||||
(temporary transition config option provided until then)
|
(temporary transition config option provided until then)
|
||||||
The transition config option will also be removed at the same time.
|
The transition config option will also be removed at the same time.
|
||||||
|
@ -238,16 +238,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||||||
Disable PIN 1 of APIC timer
|
Disable PIN 1 of APIC timer
|
||||||
Can be useful to work around chipset bugs.
|
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]
|
ad1848= [HW,OSS]
|
||||||
Format: <io>,<irq>,<dma>,<dma2>,<type>
|
Format: <io>,<irq>,<dma>,<dma2>,<type>
|
||||||
|
|
||||||
adlib= [HW,OSS]
|
|
||||||
Format: <io>
|
|
||||||
|
|
||||||
advansys= [HW,SCSI]
|
advansys= [HW,SCSI]
|
||||||
See header of drivers/scsi/advansys.c.
|
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]
|
opl3= [HW,OSS]
|
||||||
Format: <io>
|
Format: <io>
|
||||||
|
|
||||||
opl3sa2= [HW,OSS] Format:
|
|
||||||
<io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
|
|
||||||
|
|
||||||
oprofile.timer= [HW]
|
oprofile.timer= [HW]
|
||||||
Use timer interrupt instead of performance counters
|
Use timer interrupt instead of performance counters
|
||||||
|
|
||||||
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
||||||
|
|
35
MAINTAINERS
35
MAINTAINERS
@ -194,13 +194,6 @@ M: jes@trained-monkey.org
|
|||||||
L: linux-acenic@sunsite.dk
|
L: linux-acenic@sunsite.dk
|
||||||
S: Maintained
|
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
|
IPS SCSI RAID DRIVER
|
||||||
P: Adaptec OEM Raid Solutions
|
P: Adaptec OEM Raid Solutions
|
||||||
M: aacraid@adaptec.com
|
M: aacraid@adaptec.com
|
||||||
@ -272,21 +265,6 @@ L: linux-acpi@vger.kernel.org
|
|||||||
W: http://acpi.sourceforge.net/
|
W: http://acpi.sourceforge.net/
|
||||||
S: Supported
|
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
|
ADM1025 HARDWARE MONITOR DRIVER
|
||||||
P: Jean Delvare
|
P: Jean Delvare
|
||||||
M: khali@linux-fr.org
|
M: khali@linux-fr.org
|
||||||
@ -1404,13 +1382,6 @@ M: raisch@de.ibm.com
|
|||||||
L: general@lists.openfabrics.org
|
L: general@lists.openfabrics.org
|
||||||
S: Supported
|
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
|
EMULEX LPFC FC SCSI DRIVER
|
||||||
P: James Smart
|
P: James Smart
|
||||||
M: james.smart@emulex.com
|
M: james.smart@emulex.com
|
||||||
@ -2730,12 +2701,6 @@ L: osst-users@lists.sourceforge.net
|
|||||||
L: linux-scsi@vger.kernel.org
|
L: linux-scsi@vger.kernel.org
|
||||||
S: Maintained
|
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
|
OPROFILE
|
||||||
P: Philippe Elie
|
P: Philippe Elie
|
||||||
M: phil.el@wanadoo.fr
|
M: phil.el@wanadoo.fr
|
||||||
|
@ -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_SSCAPE) += sscape.o ad1848.o mpu401.o
|
||||||
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
|
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
|
||||||
obj-$(CONFIG_SOUND_MSS) += ad1848.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_PAS) += pas2.o sb.o sb_lib.o uart401.o
|
||||||
obj-$(CONFIG_SOUND_SB) += 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_KAHLUA) += kahlua.o
|
||||||
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
|
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
|
||||||
obj-$(CONFIG_SOUND_UART6850) += uart6850.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_YM3812) += opl3.o
|
||||||
obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
|
obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
|
||||||
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
|
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
|
||||||
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.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
|
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
|
||||||
ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
|
ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
|
||||||
@ -40,24 +35,16 @@ endif
|
|||||||
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
|
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
|
||||||
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
|
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
|
||||||
obj-$(CONFIG_SOUND_VWSND) += vwsnd.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_ICH) += i810_audio.o ac97_codec.o
|
||||||
obj-$(CONFIG_SOUND_ES1371) += es1371.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_VRC5477) += nec_vrc5477.o ac97_codec.o
|
||||||
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.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_TRIDENT) += trident.o ac97_codec.o
|
||||||
obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
|
|
||||||
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
|
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
|
||||||
obj-$(CONFIG_SOUND_BT878) += btaudio.o
|
obj-$(CONFIG_SOUND_BT878) += btaudio.o
|
||||||
|
|
||||||
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.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/
|
obj-$(CONFIG_DMASOUND) += dmasound/
|
||||||
|
|
||||||
# Declare multi-part drivers.
|
# Declare multi-part drivers.
|
||||||
|
432
sound/oss/ac97.c
432
sound/oss/ac97.c
@ -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:
|
|
||||||
*/
|
|
201
sound/oss/ac97.h
201
sound/oss/ac97.h
@ -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:
|
|
||||||
*/
|
|
712
sound/oss/aci.c
712
sound/oss/aci.c
@ -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");
|
|
@ -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_ */
|
|
1368
sound/oss/ad1816.c
1368
sound/oss/ad1816.c
File diff suppressed because it is too large
Load Diff
1101
sound/oss/ad1889.c
1101
sound/oss/ad1889.c
File diff suppressed because it is too large
Load Diff
@ -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
|
|
@ -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");
|
|
1691
sound/oss/cs461x.h
1691
sound/oss/cs461x.h
File diff suppressed because it is too large
Load Diff
@ -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
|
|
5444
sound/oss/cs46xx.c
5444
sound/oss/cs46xx.c
File diff suppressed because it is too large
Load Diff
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -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 */
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
|
||||||
}
|
|
@ -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
@ -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
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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);
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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 */
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 */
|
|
@ -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
@ -34,7 +34,6 @@
|
|||||||
|
|
||||||
#include "sound_config.h"
|
#include "sound_config.h"
|
||||||
|
|
||||||
#include "opl3.h"
|
|
||||||
#include "opl3_hw.h"
|
#include "opl3_hw.h"
|
||||||
|
|
||||||
#define MAX_VOICE 18
|
#define MAX_VOICE 18
|
||||||
@ -73,7 +72,6 @@ typedef struct opl_devinfo
|
|||||||
unsigned char cmask;
|
unsigned char cmask;
|
||||||
|
|
||||||
int is_opl4;
|
int is_opl4;
|
||||||
int *osp;
|
|
||||||
} opl_devinfo;
|
} opl_devinfo;
|
||||||
|
|
||||||
static struct opl_devinfo *devc = NULL;
|
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
|
* 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;
|
goto cleanup_devc;
|
||||||
}
|
}
|
||||||
|
|
||||||
devc->osp = osp;
|
|
||||||
devc->base = ioaddr;
|
devc->base = ioaddr;
|
||||||
|
|
||||||
/* Reset timers 1 and 2 */
|
/* Reset timers 1 and 2 */
|
||||||
@ -1105,7 +1102,7 @@ static struct synth_operations opl3_operations =
|
|||||||
.setup_voice = opl3_setup_voice
|
.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 i;
|
||||||
int me;
|
int me;
|
||||||
@ -1194,9 +1191,6 @@ int opl3_init(int ioaddr, int *osp, struct module *owner)
|
|||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(opl3_init);
|
|
||||||
EXPORT_SYMBOL(opl3_detect);
|
|
||||||
|
|
||||||
static int me;
|
static int me;
|
||||||
|
|
||||||
static int io = -1;
|
static int io = -1;
|
||||||
@ -1209,12 +1203,12 @@ static int __init init_opl3 (void)
|
|||||||
|
|
||||||
if (io != -1) /* User loading pure OPL3 module */
|
if (io != -1) /* User loading pure OPL3 module */
|
||||||
{
|
{
|
||||||
if (!opl3_detect(io, NULL))
|
if (!opl3_detect(io))
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
me = opl3_init(io, NULL, THIS_MODULE);
|
me = opl3_init(io, THIS_MODULE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -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);
|
|
1020
sound/oss/opl3sa2.c
1020
sound/oss/opl3sa2.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user