Bid a fond farewell to these files, they live on various forms in
dev/pcm/* and dev/pcm/isa/*
This commit is contained in:
parent
894071bb70
commit
a534126855
@ -1,359 +0,0 @@
|
||||
In this file I will try to build a database of cards supported by
|
||||
this driver. I also include the command to use for manual configuration
|
||||
of the card in case your BIOS is not PnP-aware. Of course it is
|
||||
your responsibility to pick up free port ranges and irq and drq
|
||||
channels.
|
||||
|
||||
For PnP cards, I also include the vendor_id and serial numbers of
|
||||
cards I have encountered. Underscores in the PnP id mean that
|
||||
(I believe) there is a large variety of values in those positions,
|
||||
and the code in the audio driver generally masks those bits.
|
||||
|
||||
Finally, where available, I have put the URL where you can find the
|
||||
data sheets of the chip.
|
||||
|
||||
To my knowledge, there are the following families of audio cards:
|
||||
|
||||
* WSS (also called MSS) and clones:
|
||||
these are true full duplex cards, have a very nice architecture and
|
||||
are well documented. Chipsets implementing these functionalities
|
||||
are made from Crystal, Analog Devices, Yamaha, OPTI.
|
||||
|
||||
* SB16 and clones:
|
||||
these cards have a higly asymmetric architecture, and are not very
|
||||
well suited to full duplex operation. Made by Creative, Realtek.
|
||||
There is no documentation on the newer codecs (Vibra16X and ALS100+),
|
||||
so they are not fully working.
|
||||
|
||||
* ESS
|
||||
ESS builds cards that implement a superset of SB16. They are
|
||||
often capable of full duplex, but my driver does not support them
|
||||
other than in full duplex emulation. My fault, since documentation
|
||||
on these cards _is_ available.
|
||||
|
||||
* PCI cards.
|
||||
There are a quite few PCI audio cards around based on a number of
|
||||
different chipsets. Some of them are documented (e.g. S3 Sonic
|
||||
Vibes, Ensoniq ES1370), some are not (e.g. Yamaha YMF724),
|
||||
work is in progress to support such cards. See the notes below.
|
||||
Note that CreativeLabs has recently (fall'97) acquired Ensoniq
|
||||
and the audio division of OPTI, both of which had a PCI audio
|
||||
chipset. I don't know if there are other manufacturers of PCI
|
||||
audio cards.
|
||||
|
||||
Finally, some people wrote patches for the following chips:
|
||||
|
||||
AD1816
|
||||
MAD16
|
||||
ESS
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
CS4235: PnP id 0x25__630e
|
||||
CS4236: PnP id 0x36__630e 0x35__630e
|
||||
CS4237: PnP id 0x37__630e
|
||||
|
||||
MANUFACTURER:
|
||||
A/Open (or AcerOpen) AW32, AW35, AW37
|
||||
Also, integrated on the motherboard on some machines.
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.crystal.com/ 4237full.pdf
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x534 port2 0x220 irq0 5 drq0 1 drq1 3
|
||||
|
||||
COMMENTS:
|
||||
Work like a charm. All modes, including full duplex, supported in
|
||||
MSS mode.
|
||||
|
||||
Cards based on the 4237, and possibly the 4236 as well, connect
|
||||
the CD to AUX2. When used in MODE1/2 (as this driver does)
|
||||
there is no route in the input mixer from AUX2 to the ADC. So,
|
||||
to record directly from the CD, the only way is to set the
|
||||
input to SOUND_MASK_IMIX.
|
||||
|
||||
Some machines with the cs4235 in non-pnp mode map the codec at 0x530
|
||||
instead of 0x534. For those machines you need an unusual config line
|
||||
|
||||
device pcm0 at isa ? port 0x52C ...
|
||||
|
||||
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
CS4232: PnP id 0x3242630e
|
||||
|
||||
MANUFACTURER:
|
||||
???
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.crystal.com/
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x534 port2 0x220 irq0 5 drq0 1 drq1 3
|
||||
|
||||
COMMENTS:
|
||||
This chip is reported as broken in the OSS documentation. As a
|
||||
matter of fact, on my Intel Zappa motherboard, I have problems in
|
||||
make it use the secondary DMA channel. I have it working in
|
||||
half duplex (both capture and playback) in SB3.2 emulation,
|
||||
and working in playback mode in MSS emulation.
|
||||
Also have reports from some user that it works ok.
|
||||
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
AD1815/1816
|
||||
|
||||
MANUFACTURER:
|
||||
Analog Devices
|
||||
|
||||
DOCUMENTATION:
|
||||
http://www.analog.com
|
||||
|
||||
COMMENTS:
|
||||
This is a chip for ISA-PnP cards, and so should be configured
|
||||
using the PnP interface. For full function configure port2,
|
||||
irq0, drq0 and drq1 of ldn0.
|
||||
The driver is contributed by German Tischler
|
||||
|
||||
FORMATS:
|
||||
ALAW/ULAW/8bit/16bit(le)/16bit(be),8kHz-55.2kHz,full duplex
|
||||
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
OPTi931: PnP id 0x3109143e
|
||||
OPTi933: PnP id 0x3109143e (yes, it's the same)
|
||||
|
||||
MANUFACTURER:
|
||||
ExpertColor MED931 (europe)
|
||||
Shuttle HOT-247 (uses the 933, $15 retail in the US)
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.opti.com/ opti931_21.pdf
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 1 os enable port0 0x534 port2 0x220 port3 0xe0d irq0 10 drq0 1 drq1 6
|
||||
|
||||
COMMENTS:
|
||||
The data sheets of this chip are very cryptic and do not match
|
||||
what the cards I have seem to do. I have it working
|
||||
in WSS emulation, in full duplex and all modes.
|
||||
In SB emulation mode the driver does not work yet (maybe I do
|
||||
not initialize it the right way). It is not a major concern
|
||||
anyways.
|
||||
I am strongly convinced of a couple of bugs in the chip. I have
|
||||
sent email to OPTI but got no reply so far. The bugs are:
|
||||
- you cannot set both playback and capture format to use
|
||||
a companded mode (ULAW, ALAW). If you do, the card will screw
|
||||
up on the capture section.
|
||||
The driver has a partial fix in software: when using ULAW, it
|
||||
programs ULAW on the playback section, U8 on the capture, and
|
||||
does a conversion in software (much like the SBPro). Of course
|
||||
you lose 4-5 bits of dynamic range in the process.
|
||||
- in full duplex (and single DMA mode), the card occasionally
|
||||
misses interrupts, or generates spurious ones, or generates
|
||||
interrupts before setting the status bits in the registers.
|
||||
Spurious ints are not problematic since they can be easily
|
||||
ignored, but missing interrupts are a nightmare to handle...
|
||||
The only way to have this card work semi-reliably is to use
|
||||
auto-dma mode (which is the default mode of operation in the
|
||||
driver).
|
||||
In any case, these cards are very cheap and widely available and
|
||||
are a reasonable solution if you cannot find some other decent WSS
|
||||
device.
|
||||
|
||||
-------------------------------
|
||||
CHIPSET:
|
||||
SB16: PnP id 0x__008c0e
|
||||
Vibra16X: PnP id 0xf0008c0e
|
||||
|
||||
MANUFACTURER:
|
||||
CreativeLabs
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.creative.com sbhwpg.pdf or SBHWPG.EXE
|
||||
ftp://www.creaf.com/pub/creative/devinfo/ctsbhwpg.exe
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x220 irq0 5 drq0 1 drq1 5
|
||||
|
||||
COMMENTS:
|
||||
SB16 really refers to a large number of different cards, starting
|
||||
from the original, non-PnP SB16, to more modern cards (SB16PnP,
|
||||
Vibra16C) and other including Wavetable Synthesis (AWE32, AWE64,
|
||||
etc.). All these cards have different PnP ID. They have
|
||||
different synthesis devices, which we do not support, so we
|
||||
are not affected by these differences. Don't worry if the driver
|
||||
identifies the card as a different SB16 than the one you have.
|
||||
|
||||
BEWARE -- all recent (1998 ?) SB16 use a new codec, Vibra16X,
|
||||
which is sufficiently different from the old one to not work with
|
||||
this driver in capture mode or in full duplex. Documentation is
|
||||
not available from Creative. I suggest to stay away from these
|
||||
cards (and from SB16 in general).
|
||||
|
||||
Full duplex support of this card is tricky since one channel can
|
||||
work in 16-bit and the other in 8-bit mode. You will need to use
|
||||
the new set of ioctl to use separate data formats on the two
|
||||
channels (the vat driver does this). Of course, quality in 8-bit
|
||||
is much lower than in 16-bit.
|
||||
|
||||
Full duplex operation is unsupported by Creative. It seems to
|
||||
work, although on my Vibra16C the command to stop DMA transfer
|
||||
seems to erroneously affect both channels instead of the one
|
||||
they are issued for. The driver has a workaround, but I cannot
|
||||
guarantee that it works for everybody. I have had several
|
||||
positive reports.
|
||||
|
||||
Some docs on how to use this card with the voxware driver
|
||||
are at http://multiverse.com/~rhh/awedrv
|
||||
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
ALS100, ALS110, ALS120, ...
|
||||
Avance Asound 100: PnP id 0x01009305
|
||||
Avance Asound 100+: PnP id 0x10019305
|
||||
Avance Logic ALS120: PnP id 0x20019305
|
||||
|
||||
MANUFACTURER:
|
||||
Realtek (also Avance Asound and possibly other names)
|
||||
Asound Gold (AS007) has an ALS120
|
||||
|
||||
|
||||
DOCUMENTATION:
|
||||
|
||||
http://www.realtek.com.tw/cp/cp.html
|
||||
but not very useful or detailed.
|
||||
|
||||
COMMENTS:
|
||||
These card should be recognised as SB16 clones. Some of them
|
||||
emulate the Vibra16X, so the comments above apply.
|
||||
|
||||
|
||||
------------------------------
|
||||
CHIPSET:
|
||||
Yamaha SA2/SA3 . Both PnP and non-PnP versions.
|
||||
OPL3-SA2 Sound Chip: PnP id 0x2000a865
|
||||
OPL/SA3 : PnP id 0x3000a865
|
||||
|
||||
MANUFACTURER:
|
||||
no-name cards, and also used in various laptops, e.g. Toshiba
|
||||
Libretto and others. I
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.yamaha.com ? YM711.pdf
|
||||
ftp://ftp.yamahayst.com/pub/Fax_Back_Doc/Sound
|
||||
http://www.imail.net.tw/qtronix/qumax_product_yamaha.htm
|
||||
|
||||
This is a huge file containing a few pages scanned and converted
|
||||
to pdf. Not very detailed. Luckily, this chipset appears to do a
|
||||
good (i.e. bug-free) emulation of the WSS, so it is fully
|
||||
supported by the driver.
|
||||
|
||||
pnp 1 0 os enable port0 0x220 port1 0x530 port2 0x388 port3 0x370 irq0 5 drq0 1 drq1 0
|
||||
|
||||
this card emulates a WSS or SB. Have reports that it works, although
|
||||
it has incomplete mixer support (Yamaha defines an additional set
|
||||
of registers to control some mixer functions, such as the master
|
||||
output volume -- this is at 0x370 or 0x310). Currently we set
|
||||
the master volume to 100% for the PnP card. Will put in code to do the
|
||||
same for the non PnP card as soon as I find out how to tell
|
||||
the Yamaha from other cards.
|
||||
Driver reported to work also on
|
||||
Toshiba DynaBook Portege 300CT with OPL3SA-3(non-PNP), and on the
|
||||
Libretto50CT (has the non-PnP device).
|
||||
|
||||
------------------------
|
||||
CHIPSET:
|
||||
ENSONIQ SoundscapeVIVO ENS4081: PnP id 0x8140d315
|
||||
MANUFACTURER:
|
||||
Ensoniq Soundscape VIVO
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x220 port1 0x530 irq0 5 drq0 1 drq1 5
|
||||
|
||||
COMMENTS:
|
||||
this card emulates a WSS or SB. Have reports that it works.
|
||||
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
AMD...
|
||||
|
||||
MANUFACTURER:
|
||||
GusPnP: PnP id 0x0100561e
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x220 port1 0x320 port2 0x32c irq0 5 drq0 7 drq1 5
|
||||
|
||||
COMMENTS:
|
||||
It works in U8 and S16 mode, ulaw support still not working.
|
||||
The Gus has been discontinued, so support for this card is only
|
||||
there for historical reasons (the Gus used to be the only card
|
||||
well supported in full duplex mode).
|
||||
|
||||
|
||||
---- THE FOLLOWING CARDS ARE NOT FULLY SUPPORTED: ----
|
||||
|
||||
CHIPSET:
|
||||
OPTI925: PnP id 0x2509143e
|
||||
|
||||
COMMENTS:
|
||||
there is code to recognize it as a SB clone. I have reports that
|
||||
it probes ok, but not sure if it works.
|
||||
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
OPTI924: PnP
|
||||
|
||||
COMMENT:
|
||||
I have this card but it is still unsupported.
|
||||
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
OPTI930:
|
||||
|
||||
should work as an MSS clone, but support for it is not implemented
|
||||
yet.
|
||||
|
||||
CHIPSET:
|
||||
ESS1868
|
||||
ESS688
|
||||
|
||||
http://www.esstech.com
|
||||
|
||||
pnp 1 1 os enable irq0 7 drq0 1 port0 0x220
|
||||
|
||||
There used to be documentation for the 1868 on the ESS site
|
||||
(files ds1868b1.pdf and ds1868b2.pdf) but I am unable to find
|
||||
it now (980122). I have asked ESS but no reply so far.
|
||||
|
||||
partly supported in SB emulation.
|
||||
|
||||
(the ESS688 is used on many notebooks. It is probably able to do 8
|
||||
and 16-bit, half duplex).
|
||||
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
es1370 (ensoniq)
|
||||
es1371 (ensoniq)
|
||||
used on SB64 PCI, Shuttle HOT-255, and maybe others
|
||||
|
||||
A driver for this is in the works.
|
||||
see http://www.ensoniq.com/multimedia/semi_html/index.htm
|
||||
for documentation. See also http://alsa.jcu.cz/alsa/ for a Linux
|
||||
driver.
|
||||
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
YMF724
|
||||
used on various Yamaha (WaveForce) and other cards.
|
||||
|
||||
NOT SUPPORTED.
|
||||
|
||||
There is no public docs on this card, the closest thing being
|
||||
http://www.imail.net.tw/qtronix/driver/qumax/yamaha/ds1e1110.pdf
|
||||
http://www.imail.net.tw/qtronix/qumax_product_yamaha.htm
|
||||
which however does not document how the card works in non-legacy
|
||||
mode and how to make it talk to the AC97 codec.
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
@ -1,224 +0,0 @@
|
||||
--- A new FreeBSD audio driver ---
|
||||
by Luigi Rizzo (luigi@iet.unipi.it)
|
||||
|
||||
This is a new, completely rewritten, audio driver for FreeBSD.
|
||||
Only "soundcard.h" has remained largely similar to the original
|
||||
OSS/Voxware header file, mostly for compatibility with existing
|
||||
applications.
|
||||
|
||||
This driver tries to cover those areas where the Voxware 3.0 driver
|
||||
is mostly lacking: full-duplex, audio applications, modern (mostly
|
||||
PnP) cards. For backward compatibility, the driver implements most
|
||||
of the Voxware ioctl() audio calls, so that many applications --
|
||||
even commercial ones -- will run unmodified with this driver. On
|
||||
the other hand, at the moment this driver does not support /dev/midi
|
||||
and /dev/synth, or some ioctl() used in xquake. Do not expect
|
||||
/dev/synth to be supported anytime soon.
|
||||
|
||||
I also have implemented a new software interface with an independent
|
||||
set of ioctl(), to support some functions which were not easy to
|
||||
express with the existing software interface (e.g. full duplex on
|
||||
old SB16 cards). To make an effective use of the new functionalities
|
||||
you need to recompile applications by replacing the audio module(s).
|
||||
Such modified driver modules are present in the misc/ directory
|
||||
for several applications.
|
||||
|
||||
This file gives quick information on how to install the driver.
|
||||
Updated versions of this code will be available at the following URL:
|
||||
|
||||
http://www.iet.unipi.it/~luigi/FreeBSD.html
|
||||
|
||||
Please READ CAREFULLY this file (and possibly the LaTeX documentation)
|
||||
to build a working kernel. The configuration is DIFFERENT (and
|
||||
hopefully much simpler) from the original Voxware driver. The
|
||||
relevant steps are indicated at "---INSTALLATION---".
|
||||
|
||||
CARDS:
|
||||
|
||||
The driver supports most clones of WSS, SB16 and SBPro cards.
|
||||
This includes those based on the Crystal CS423x, OPTI931, GUSPnP,
|
||||
Yamaha, SB16/32 (both plain ISA, PnP, and the various AWExx).
|
||||
Many PnP cards are directly recognized, for others you might need
|
||||
manual configuration. See the file "CARDS" for more details.
|
||||
|
||||
APPLICATIONS:
|
||||
|
||||
In general, most applications which use /dev/audio or /dev/dsp
|
||||
work unmodified or with a specially-supplied module.
|
||||
|
||||
UNMODIFIED:
|
||||
- raplayer (Real Audio Player), rvplayer (linux version)
|
||||
- xboing
|
||||
- xanim
|
||||
- various mpeg players (mpg123, amp, ...);
|
||||
|
||||
WITH SPECIAL DRIVER MODULE (supplied)
|
||||
- speak_freely, full duplex (requires removing the definition of
|
||||
HALF_DUPLEX in the Makefile);
|
||||
- the realaudio player (3.0, dynamically linked);
|
||||
- vat, full duplex (the version in ports is already modified);
|
||||
- timidity, a software midi-to-pcm converter;
|
||||
|
||||
NOT WORKING
|
||||
- xquake (we do not support mmapped buffers yet);
|
||||
|
||||
|
||||
---INSTALLATION---
|
||||
|
||||
* add the following lines to your kernel configuration file:
|
||||
|
||||
controller pnp0 # this is required for PnP support
|
||||
|
||||
device pcm0 at isa ? port? tty irq N drq D flags F
|
||||
|
||||
where
|
||||
|
||||
N is the IRQ address used by the sound card,
|
||||
D is the primary DMA channel used by the sound card,
|
||||
F is used to specify a number of options, in particular:
|
||||
bit 2..0 secondary DMA channel;
|
||||
bit 4 set if the board uses two dma channels;
|
||||
bit 15..8 board type, overrides autodetection; leave it
|
||||
zero if don't know what to put in (and you don't,
|
||||
since this is unsupported at the moment...).
|
||||
|
||||
The code will probe for common port addresses (0x220, 0x240
|
||||
for SB and clones, 0x530 for WSS and clones), so you don't need
|
||||
to specify them if your system uses one of them. In case you
|
||||
do, note that for WSS cards the code assumes that the board
|
||||
occupies 8 IO addresses, the first four used to configure
|
||||
IRQ/DRQ, and the other four to access codec registers. Many
|
||||
boards (including all the ones I have) do not have registers
|
||||
to program IRQ and DRQ, so they really start at 0x534... yet
|
||||
I decided to use the old convention for historical reasons.
|
||||
|
||||
You can use multiple sound cards, in which case you need more
|
||||
lines like
|
||||
|
||||
device pcm1 at isa ? port? tty irq N drq D flags F
|
||||
device pcm2 at isa ? port? tty irq N drq D flags F
|
||||
...
|
||||
|
||||
EXAMPLES: a typical "device" line for the SB16 (full duplex) is
|
||||
|
||||
device pcm0 at isa ? port? tty irq 5 drq 1 flags 0x15
|
||||
|
||||
The driver will check at the default addresses (or the one you
|
||||
specify) which type of SoundBlaster you have (1.5, 2.0, 3.X
|
||||
aka SBPro, 4.X aka SB16) and use the correct commands. You
|
||||
_do_not_ need to specify different drivers (sb,sbpro,sbxvi) as
|
||||
it was the case (and a big source of confusion) in the previous
|
||||
sound driver.
|
||||
|
||||
For a WSS-compatible codec (non PnP) working in full duplex using
|
||||
dma channels 1 and 3, you can specify:
|
||||
|
||||
device pcm0 at isa ? port 0x530 tty irq 7 drq 1 flags 0x13
|
||||
|
||||
(0x530 is a default if no port address is specified). The
|
||||
"flags 0x13" specifies that you have a dual dma board with
|
||||
channel 3 as secondary DMA channel.
|
||||
|
||||
* build the kernel using the standard steps
|
||||
|
||||
config MYKERNEL
|
||||
cd /sys/compile/MYKERNEL
|
||||
make depend
|
||||
make
|
||||
|
||||
* note for PnP cards:
|
||||
|
||||
For PnP cards, only the line for "pcm0" is needed (the code
|
||||
will allocate entries for more cards if found), but IT MUST
|
||||
INCLUDE ALL FIELDS. You can use the following line:
|
||||
|
||||
device pcm0 at isa ? port? tty irq 7 drq 1
|
||||
|
||||
NOTE that:
|
||||
- the parameters for the PnP device(s) will be read from the
|
||||
configuration of the card(s); they are usually assigned by
|
||||
the bios, and there is no way (at the moment) to override
|
||||
them, so if you have a broken (or no) PnP bios your only
|
||||
chance is to patch the pnp attach code in the driver for your
|
||||
card (ad1848.c, sb_dsp.c, clones.c) and write there the
|
||||
parameters you want;
|
||||
- The driver will assign unit numbers to the PnP cards starting
|
||||
from the next free one (e.g. 1, 2, ...) same as it is done
|
||||
with PCI devices which are clones of ISA devices.
|
||||
|
||||
The driver assumes a working PnP bios, which will assign correct
|
||||
addresses and IO and DMA channels to the devices. If you do not
|
||||
have a PnP-aware BIOS, you must boot with the -c option and assign
|
||||
addresses manually the first time. The general commands are described in
|
||||
the pnp README file. For the card-specific commands check in the
|
||||
file CARDS.
|
||||
|
||||
WHAT IF THIS DRIVER DOES NOT WORK:
|
||||
|
||||
If the driver does not work with your hardware, I might to help
|
||||
but I need the following information:
|
||||
|
||||
- relevant lines in your config file;
|
||||
- dmesg output
|
||||
- possibly, pnpinfo output
|
||||
|
||||
Please send all the above in plain text, not as a mime attachment.
|
||||
|
||||
Common mistakes:
|
||||
|
||||
* you are trying to use /dev/audio0 instead of /dev/audio1
|
||||
For technical reasons, a PnP device is attached as unit 1 instead
|
||||
of unit 0 -- most applications are programmed to access the audio
|
||||
hardware through /dev/audio, /dev/dsp, /dev/mixer which are in turn
|
||||
symlinks to the correct device entries. Check them and possibly fix
|
||||
these symlinks in /dev
|
||||
|
||||
* you have used a wrong config line
|
||||
|
||||
The configuration of this driver is different from the Voxware one.
|
||||
Please read the information in this file carefully.
|
||||
|
||||
* your BIOS is leaving the card disabled.
|
||||
|
||||
Some BIOSes do not initialize the card, or leave it disabled. At the
|
||||
moment, the fix is to use the pnp code booting with "-c" and set the
|
||||
correct port, irq, drq etc for the card. See the PnP documentation.
|
||||
|
||||
* your card is not recognized.
|
||||
|
||||
This driver supports a large, but still limited, number of cards,
|
||||
mostly SB and WSS clones. Other cards may or may not work depending
|
||||
on how closely they emulate these devices. In case, send me an email
|
||||
with the info indicated above.
|
||||
|
||||
* the mixer does not work well
|
||||
|
||||
Different cards have different connections to the mixer, so it might
|
||||
well be that to control the volume of your CD you have to use the FM
|
||||
port, etc. Also, on some cards the volume might be lower than you
|
||||
expect. The mixer code still does not try to exploit the features of
|
||||
each card, and it just provides basic functionalities.
|
||||
|
||||
--- ACKNOWLEDGMENTS ---
|
||||
|
||||
Several people helped, directly or indirectly, in the development of
|
||||
this driver. In particular I would like to thank:
|
||||
|
||||
* Hannu Savolainen (the Voxware author) for making his code
|
||||
available. It was a very good source of technical info;
|
||||
* Amancio Hasty for continuous support and his work on guspnp code;
|
||||
* Jim Lowe for his suggestion on the block-mode select;
|
||||
* Allison Mankin and Brad Karp at ISI-East for supplying a GUS PnP
|
||||
which allowed me to support this card;
|
||||
* Eric J. Schwertfeger for donating an ES1868 card for writing the
|
||||
driver (which i haven't done yet...).
|
||||
* and many people who had the patience to try the driver
|
||||
on their cards and report success/failure and useful
|
||||
information.
|
||||
|
||||
It was certainly helpful to have the data sheets for some of the
|
||||
devices I support available on the net, especially in the (unfortunately
|
||||
rare) cases where the data sheets matched the actual behavior of
|
||||
the product. Too bad that no one of the chip/card manufacturers I
|
||||
have contacted by email regarding missing or inconsistent documentation
|
||||
on their products did even care to reply to my messages.
|
File diff suppressed because it is too large
Load Diff
@ -1,262 +0,0 @@
|
||||
/*
|
||||
* sound/clones.c
|
||||
*
|
||||
* init code for enabling clone cards to work in sb/mss emulation.
|
||||
*
|
||||
* Note -- this code is currently unused!
|
||||
*
|
||||
* Copyright by Luigi Rizzo - 1997
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met: 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer. 2. Redistributions in binary form must reproduce the
|
||||
* above copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file has been written using information from various sources
|
||||
* in the Voxware 3.5 distribution.
|
||||
*/
|
||||
|
||||
#include <i386/isa/snd/sound.h>
|
||||
#if NPCM > 0
|
||||
|
||||
/*
|
||||
* Known clones card include:
|
||||
*
|
||||
* Trix (emulating MSS)
|
||||
* MAD16 (emulating MSS)
|
||||
* OPTi930 -- same as the OPTi931, but no PnP ?
|
||||
*/
|
||||
|
||||
|
||||
#ifdef JAZZ16
|
||||
|
||||
/*
|
||||
* Initialization of a Media Vision ProSonic 16 Soundcard. The function
|
||||
* initializes a ProSonic 16 like PROS.EXE does for DOS. It sets the base
|
||||
* address, the DMA-channels, interrupts and enables the joystickport.
|
||||
*
|
||||
* Also used by Jazz 16 (same card, different name)
|
||||
*
|
||||
* written 1994 by Rainer Vranken E-Mail:
|
||||
* rvranken@polaris.informatik.uni-essen.de
|
||||
*/
|
||||
|
||||
#ifdef SM_WAVE
|
||||
/*
|
||||
* Logitech Soundman Wave detection and initialization by Hannu Savolainen.
|
||||
*
|
||||
* There is a microcontroller (8031) in the SM Wave card for MIDI emulation.
|
||||
* it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific
|
||||
* control register for MC reset, SCSI, OPL4 and DSP (future expansion)
|
||||
* address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16 based
|
||||
* soundcard.
|
||||
*/
|
||||
|
||||
static void
|
||||
smw_putmem(int base, int addr, u_char val)
|
||||
{
|
||||
u_long s;
|
||||
|
||||
s = spltty();
|
||||
|
||||
outb(base + 1, addr & 0xff); /* Low address bits */
|
||||
outb(base + 2, addr >> 8); /* High address bits */
|
||||
outb(base, val); /* Data */
|
||||
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static u_char
|
||||
smw_getmem(int base, int addr)
|
||||
{
|
||||
u_long s;
|
||||
u_char val;
|
||||
|
||||
s = spltty();
|
||||
|
||||
outb(base + 1, addr & 0xff); /* Low address bits */
|
||||
outb(base + 2, addr >> 8); /* High address bits */
|
||||
val = inb(base); /* Data */
|
||||
|
||||
splx(s);
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef SMW_MIDI0001_INCLUDED
|
||||
#include </sys/i386/isa/snd/smw-midi0001.h>
|
||||
#else
|
||||
u_char *smw_ucode = NULL;
|
||||
int smw_ucodeLen = 0;
|
||||
#endif /* SWM_MIDI0001_INCLUDED */
|
||||
|
||||
static int
|
||||
initialize_smw(int mpu_base)
|
||||
{
|
||||
|
||||
int i, mp_base = mpu_base + 4; /* Microcontroller base */
|
||||
u_char control;
|
||||
|
||||
/*
|
||||
* Reset the microcontroller so that the RAM can be accessed
|
||||
*/
|
||||
|
||||
control = inb(mpu_base + 7);
|
||||
outb(mpu_base + 7, control | 3); /* Set last two bits to 1 (?) */
|
||||
outb(mpu_base + 7, (control & 0xfe) | 2); /* xxxxxxx0 resets the mc */
|
||||
DELAY(3000); /* Wait at least 1ms */
|
||||
|
||||
outb(mpu_base + 7, control & 0xfc); /* xxxxxx00 enables RAM */
|
||||
|
||||
/*
|
||||
* Detect microcontroller by probing the 8k RAM area
|
||||
*/
|
||||
smw_putmem(mp_base, 0, 0x00);
|
||||
smw_putmem(mp_base, 1, 0xff);
|
||||
DELAY(10);
|
||||
|
||||
if (smw_getmem(mp_base, 0) != 0x00 || smw_getmem(mp_base, 1) != 0xff) {
|
||||
printf("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n",
|
||||
smw_getmem(mp_base, 0), smw_getmem(mp_base, 1));
|
||||
return 0; /* No RAM */
|
||||
}
|
||||
/*
|
||||
* There is RAM so assume it's really a SM Wave
|
||||
*/
|
||||
|
||||
if (smw_ucodeLen > 0) {
|
||||
if (smw_ucodeLen != 8192) {
|
||||
printf("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n");
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Download microcode
|
||||
*/
|
||||
|
||||
for (i = 0; i < 8192; i++)
|
||||
smw_putmem(mp_base, i, smw_ucode[i]);
|
||||
|
||||
/*
|
||||
* Verify microcode
|
||||
*/
|
||||
|
||||
for (i = 0; i < 8192; i++)
|
||||
if (smw_getmem(mp_base, i) != smw_ucode[i]) {
|
||||
printf("SM Wave: Microcode verification failed\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
control = 0;
|
||||
#ifdef SMW_SCSI_IRQ
|
||||
/*
|
||||
* Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
|
||||
* is disabled by default.
|
||||
*
|
||||
* Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10.
|
||||
*/
|
||||
{
|
||||
static u_char scsi_irq_bits[] =
|
||||
{0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0};
|
||||
|
||||
control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SMW_OPL4_ENABLE
|
||||
/*
|
||||
* Make the OPL4 chip visible on the PC bus at 0x380.
|
||||
*
|
||||
* There is no need to enable this feature since VoxWare doesn't support
|
||||
* OPL4 yet. Also there is no RAM in SM Wave so enabling OPL4 is
|
||||
* pretty useless.
|
||||
*/
|
||||
control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */
|
||||
/* control |= 0x20; Uncomment this if you want to use IRQ7 */
|
||||
#endif
|
||||
|
||||
outb(mpu_base + 7, control | 0x03); /* xxxxxx11 restarts */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* this is only called during the probe. Variables are found in
|
||||
* sb_probed.
|
||||
*/
|
||||
static sbdev_info sb_probed ;
|
||||
static int
|
||||
initialize_ProSonic16(snddev_info *d)
|
||||
{
|
||||
int x;
|
||||
static u_char int_translat[16] =
|
||||
{0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6},
|
||||
dma_translat[8] =
|
||||
{0, 1, 0, 2, 0, 3, 0, 4};
|
||||
|
||||
struct address_info *mpu_config = NULL;
|
||||
|
||||
int mpu_base, mpu_irq;
|
||||
|
||||
if (mpu_config != NULL) { /* XXX dead code? */
|
||||
mpu_base = mpu_config->io_base;
|
||||
mpu_irq = mpu_config->irq;
|
||||
} else {
|
||||
mpu_base = mpu_irq = 0;
|
||||
}
|
||||
|
||||
outb(0x201, 0xAF); /* ProSonic/Jazz16 wakeup */
|
||||
DELAY(15000); /* wait at least 10 milliseconds */
|
||||
outb(0x201, 0x50);
|
||||
outb(0x201, (sb_probed.io_base & 0x70) | ((mpu_base & 0x30) >> 4));
|
||||
|
||||
if (sb_reset_dsp(sb_probed.io_base)) { /* OK. We have at least a SB */
|
||||
|
||||
/* Check the version number of ProSonic (I guess) */
|
||||
|
||||
if (!sb_cmd(sb_probed.io_base, 0xFA))
|
||||
return 1;
|
||||
if (sb_get_byte(sb_probed.io_base) != 0x12)
|
||||
return 1;
|
||||
|
||||
if (sb_cmd(sb_probed.io_base, 0xFB) && /* set DMA and irq */
|
||||
sb_cmd(sb_probed.io_base,
|
||||
(dma_translat[JAZZ_DMA16]<<4)|dma_translat[sb_probed.dbuf_out.chan]) &&
|
||||
sb_cmd(sb_probed.io_base,
|
||||
(int_translat[mpu_irq]<<4)|int_translat[sb_probed.irq])) {
|
||||
d->bf_flags |= BD_F_JAZZ16 ;
|
||||
if (mpu_base == 0)
|
||||
printf("Jazz16: No MPU401 devices configured "
|
||||
"- MIDI port not initialized\n");
|
||||
|
||||
#ifdef SM_WAVE
|
||||
if (mpu_base != 0)
|
||||
if (initialize_smw(mpu_base))
|
||||
d->bf_flags |= BD_F_JAZZ16_2 ;
|
||||
#endif
|
||||
/* sb_dsp_disable_midi(); */
|
||||
}
|
||||
return 1; /* There was at least a SB */
|
||||
}
|
||||
return 0; /* No SB or ProSonic16 detected */
|
||||
}
|
||||
|
||||
#endif /* ifdef JAZZ16 */
|
||||
|
||||
#endif /* NPCM */
|
@ -1,810 +0,0 @@
|
||||
/*
|
||||
* snd/dmabuf.c
|
||||
*
|
||||
* This file implements the new DMA routines for the sound driver.
|
||||
* AUTO DMA MODE (ISA DMA SIDE).
|
||||
*
|
||||
* Copyright by Luigi Rizzo - 1997-99
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <i386/isa/snd/sound.h>
|
||||
#include <i386/isa/snd/ulaw.h>
|
||||
|
||||
#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
|
||||
#define DMA_ALIGN_THRESHOLD 4
|
||||
#define DMA_ALIGN_MASK (~ (DMA_ALIGN_THRESHOLD - 1))
|
||||
|
||||
static void dsp_wr_dmadone(snddev_info *d);
|
||||
static void dsp_rd_dmadone(snddev_info *d);
|
||||
|
||||
/*
|
||||
* SOUND OUTPUT
|
||||
|
||||
We use a circular buffer to store samples directed to the DAC.
|
||||
The buffer is split into two variable-size regions, each identified
|
||||
by an offset in the buffer (rp,fp) and a length (rl,fl):
|
||||
|
||||
0 rp,rl fp,fl bufsize
|
||||
|__________>____________>________|
|
||||
FREE d READY w FREE
|
||||
|
||||
READY: data written from the process and ready to be sent to the DAC;
|
||||
FREE: free part of the buffer.
|
||||
|
||||
Both regions can wrap around the end of the buffer. At initialization,
|
||||
READY is empty, FREE takes all the available space, and dma is
|
||||
idle. dl contains the length of the current DMA transfer, dl=0
|
||||
means that the dma is idle.
|
||||
|
||||
The two boundaries (rp,fp) in the buffers are advanced by DMA [d]
|
||||
and write() [w] operations. The first portion of the READY region
|
||||
is used for DMA transfers. The transfer is started at rp and with
|
||||
chunks of length dl. During DMA operations, dsp_wr_dmaupdate()
|
||||
updates rp, rl and fl tracking the ISA DMA engine as the transfer
|
||||
makes progress.
|
||||
When a new block is written, fp advances and rl,fl are updated
|
||||
accordingly.
|
||||
|
||||
The code works as follows: the user write routine dsp_write_body()
|
||||
fills up the READY region with new data (reclaiming space from the
|
||||
FREE region) and starts the write DMA engine if inactive. When a
|
||||
DMA transfer is complete, an interrupt causes dsp_wrintr() to be
|
||||
called which extends the FREE region and possibly starts the next
|
||||
transfer.
|
||||
|
||||
In some cases, the code tries to track the current status of DMA
|
||||
operations by calling dsp_wr_dmaupdate() which changes rp, rl and fl.
|
||||
|
||||
The sistem tries to make all DMA transfers use the same size,
|
||||
play_blocksize or rec_blocksize. The size is either selected by
|
||||
the user, or computed by the system to correspond to about .25s of
|
||||
audio. The blocksize must be within a range which is currently:
|
||||
|
||||
min(5ms, 40 bytes) ... 1/2 buffer size.
|
||||
|
||||
When there aren't enough data (write) or space (read), a transfer
|
||||
is started with a reduced size.
|
||||
|
||||
To reduce problems in case of overruns, the routine which fills up
|
||||
the buffer should initialize (e.g. by repeating the last value) a
|
||||
reasonably long area after the last block so that no noise is
|
||||
produced on overruns.
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* dsp_wr_dmadone() updates pointers and wakes up any process sleeping
|
||||
* or waiting on a select().
|
||||
* Must be called at spltty().
|
||||
*/
|
||||
static void
|
||||
dsp_wr_dmadone(snddev_info *d)
|
||||
{
|
||||
snd_dbuf *b = & (d->dbuf_out) ;
|
||||
|
||||
if (d->special_dma)
|
||||
d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ;
|
||||
else
|
||||
dsp_wr_dmaupdate(b);
|
||||
/*
|
||||
* XXX here it would be more efficient to record if there
|
||||
* actually is a sleeping process, but this should still work.
|
||||
*/
|
||||
wakeup(b); /* wakeup possible sleepers */
|
||||
if (b->sel.si_pid &&
|
||||
( !(d->flags & SND_F_HAS_SIZE) || b->fl >= d->play_blocksize ) )
|
||||
selwakeup( & b->sel );
|
||||
}
|
||||
|
||||
/*
|
||||
* dsp_wr_dmaupdate() tracks the status of a (write) dma transfer,
|
||||
* updating pointers. It must be called at spltty() and the ISA DMA must
|
||||
* have been started.
|
||||
*
|
||||
* NOTE: when we are using auto dma in the device, rl might become
|
||||
* negative.
|
||||
*/
|
||||
void
|
||||
dsp_wr_dmaupdate(snd_dbuf *b)
|
||||
{
|
||||
int tmp, delta;
|
||||
|
||||
tmp = b->bufsize - isa_dmastatus1(b->chan) ;
|
||||
tmp &= DMA_ALIGN_MASK; /* align... */
|
||||
delta = tmp - b->rp;
|
||||
if (delta < 0) /* wrapped */
|
||||
delta += b->bufsize ;
|
||||
b->rp = tmp;
|
||||
b->rl -= delta ;
|
||||
b->fl += delta ;
|
||||
b->total += delta ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write interrupt routine. Can be called from other places (e.g.
|
||||
* to start a paused transfer), but with interrupts disabled.
|
||||
*/
|
||||
void
|
||||
dsp_wrintr(snddev_info *d)
|
||||
{
|
||||
snd_dbuf *b = & (d->dbuf_out) ;
|
||||
|
||||
if (b->dl) { /* dma was active */
|
||||
b->int_count++;
|
||||
dsp_wr_dmadone(d);
|
||||
}
|
||||
|
||||
DEB(if (b->rl < 0)
|
||||
printf("dsp_wrintr: dl %d, rp:rl %d:%d, fp:fl %d:%d\n",
|
||||
b->dl, b->rp, b->rl, b->fp, b->fl));
|
||||
/*
|
||||
* start another dma operation only if have ready data in the buffer,
|
||||
* there is no pending abort, have a full-duplex device, or have a
|
||||
* half duplex device and there is no pending op on the other side.
|
||||
*
|
||||
* Force transfers to be aligned to a boundary of 4, which is
|
||||
* needed when doing stereo and 16-bit. We could make this
|
||||
* adaptive, but why bother for now...
|
||||
*/
|
||||
if ( b->rl >= DMA_ALIGN_THRESHOLD &&
|
||||
! (d->flags & SND_F_ABORTING) &&
|
||||
( FULL_DUPLEX(d) || ! (d->flags & SND_F_READING) ) ) {
|
||||
int l = min(b->rl, d->play_blocksize ); /* avoid too large transfer */
|
||||
l &= DMA_ALIGN_MASK ; /* realign things */
|
||||
|
||||
/*
|
||||
* check if we need to reprogram the DMA on the sound card.
|
||||
* This happens if the size has changed _and_ the new size
|
||||
* is smaller, or it matches the blocksize.
|
||||
*/
|
||||
if (l != b->dl && (b->dl == 0 || l<b->dl || l == d->play_blocksize) ) {
|
||||
/* for any reason, size has changed. Stop and restart */
|
||||
DEB(printf("wrintr: bsz change from %d to %d, rp %d rl %d\n",
|
||||
b->dl, l, b->rp, b->rl));
|
||||
DEB(printf("wrintr: dl %d -> %d\n", b->dl, l);)
|
||||
if (b->dl != 0)
|
||||
d->callback(d, SND_CB_WR | SND_CB_STOP );
|
||||
/*
|
||||
* at high speed, it might well be that the count
|
||||
* changes in the meantime. So we try to update b->rl
|
||||
*/
|
||||
if (d->special_dma)
|
||||
d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ;
|
||||
else
|
||||
dsp_wr_dmaupdate(b) ;
|
||||
l = min(b->rl, d->play_blocksize );
|
||||
l &= DMA_ALIGN_MASK ; /* realign things */
|
||||
b->dl = l; /* record previous transfer size */
|
||||
d->callback(d, SND_CB_WR | SND_CB_START );
|
||||
}
|
||||
} else {
|
||||
/* cannot start a new dma transfer */
|
||||
DEB(printf("cannot start wr-dma flags 0x%08x rp %d rl %d\n",
|
||||
d->flags, b->rp, b->rl));
|
||||
if (b->dl > 0) { /* was active */
|
||||
b->dl = 0;
|
||||
d->callback(d, SND_CB_WR | SND_CB_STOP ); /* stop dma */
|
||||
if (d->flags & SND_F_WRITING)
|
||||
DEB(printf("Race! got wrint while reloading...\n"));
|
||||
else if (b->rl <= 0) /* XXX added 980110 lr */
|
||||
reset_dbuf(b, SND_CHAN_WR);
|
||||
}
|
||||
/*
|
||||
* if switching to read, should start the read dma...
|
||||
*/
|
||||
if ( !FULL_DUPLEX(d) && (d->flags & SND_F_READING) )
|
||||
dsp_rdintr(d);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* user write routine
|
||||
*
|
||||
* advance the boundary between READY and FREE, fill the space with
|
||||
* uiomove(), and possibly start DMA. Do the above until the transfer
|
||||
* is complete.
|
||||
*
|
||||
* To minimize latency in case a pending DMA transfer is about to end,
|
||||
* we do the transfer in pieces of increasing sizes, extending the
|
||||
* READY area at every checkpoint. In the (necessary) assumption that
|
||||
* memory bandwidth is larger than the rate at which the dma consumes
|
||||
* data, we reduce the latency to something proportional to the length
|
||||
* of the first piece, while keeping the overhead low and being able
|
||||
* to feed the DMA with large blocks.
|
||||
*
|
||||
* assume d->flags |= SND_F_WRITING ; has been done before
|
||||
*/
|
||||
|
||||
int
|
||||
dsp_write_body(snddev_info *d, struct uio *buf)
|
||||
{
|
||||
int n, l, bsz, ret = 0 ;
|
||||
long s;
|
||||
snd_dbuf *b = & (d->dbuf_out) ;
|
||||
|
||||
/*
|
||||
* bsz is the max size for the next transfer. If the dma was idle
|
||||
* (dl == 0), we want it as large as possible. Otherwise, start with
|
||||
* a small block to avoid underruns if we are close to the end of
|
||||
* the previous operation.
|
||||
*/
|
||||
bsz = b->dl ? MIN_CHUNK_SIZE : b->bufsize ;
|
||||
while ( (n = buf->uio_resid) ) {
|
||||
l = min (n, bsz); /* at most n bytes ... */
|
||||
s = spltty(); /* no interrupts here ... */
|
||||
if (d->special_dma)
|
||||
d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ;
|
||||
else
|
||||
dsp_wr_dmaupdate(b);
|
||||
l = min( l, b->fl ); /* no more than avail. space */
|
||||
DEB(printf("dsp_write_body: prepare %d bytes out of %d\n", l,n));
|
||||
/*
|
||||
* at this point, we assume that if l==0 the dma engine
|
||||
* must be running.
|
||||
*/
|
||||
if (l == 0) { /* no space, must sleep */
|
||||
int timeout;
|
||||
if (d->flags & SND_F_NBIO) {
|
||||
/* unless of course we are doing non-blocking i/o */
|
||||
splx(s);
|
||||
break;
|
||||
}
|
||||
DEB(printf("dsp_write_body: l=0, (fl %d) sleeping\n", b->fl));
|
||||
if ( b->fl < n )
|
||||
timeout = hz;
|
||||
else
|
||||
timeout = 1 ;
|
||||
ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dspwr", timeout);
|
||||
if (ret == EINTR)
|
||||
d->flags |= SND_F_ABORTING ;
|
||||
splx(s);
|
||||
if (ret == EINTR || ret == ERESTART)
|
||||
break ;
|
||||
continue;
|
||||
}
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* copy data to the buffer, and possibly do format
|
||||
* conversions (here, from ULAW to U8).
|
||||
* NOTE: I can use fp here since it is not modified by the
|
||||
* interrupt routines.
|
||||
*/
|
||||
if (b->fp + l > b->bufsize) {
|
||||
int l1 = b->bufsize - b->fp ;
|
||||
uiomove(b->buf + b->fp, l1, buf) ;
|
||||
uiomove(b->buf, l - l1, buf) ;
|
||||
if (d->flags & SND_F_XLAT8) {
|
||||
translate_bytes(ulaw_dsp, b->buf + b->fp, l1);
|
||||
translate_bytes(ulaw_dsp, b->buf , l - l1);
|
||||
}
|
||||
} else {
|
||||
uiomove(b->buf + b->fp, l, buf) ;
|
||||
if (d->flags & SND_F_XLAT8)
|
||||
translate_bytes(ulaw_dsp, b->buf + b->fp, l);
|
||||
}
|
||||
|
||||
s = spltty(); /* no interrupts here ... */
|
||||
b->rl += l ; /* this more ready bytes */
|
||||
b->fl -= l ; /* this less free bytes */
|
||||
b->fp += l ;
|
||||
if (b->fp >= b->bufsize) /* handle wraps */
|
||||
b->fp -= b->bufsize ;
|
||||
if ( b->dl == 0 ) /* dma was idle, restart it */
|
||||
dsp_wrintr(d) ;
|
||||
splx(s) ;
|
||||
if (buf->uio_resid == 0 && (b->fp & (b->sample_size - 1)) == 0) {
|
||||
/*
|
||||
* If data is correctly aligned, pad the region with
|
||||
* replicas of the last sample. l0 goes from current to
|
||||
* the buffer end, l1 is the portion which wraps around.
|
||||
*/
|
||||
int l0, l1, i;
|
||||
|
||||
l1 = min(/* b->dl */ d->play_blocksize, b->fl);
|
||||
l0 = min (l1, b->bufsize - b->fp);
|
||||
l1 = l1 - l0 ;
|
||||
|
||||
i = b->fp - b->sample_size;
|
||||
if (i < 0 ) i += b->bufsize ;
|
||||
if (b->sample_size == 1) {
|
||||
u_char *p= (u_char *)(b->buf + i), sample = *p;
|
||||
|
||||
for ( ; l0 ; l0--)
|
||||
*p++ = sample ;
|
||||
for (p= (u_char *)(b->buf) ; l1 ; l1--)
|
||||
*p++ = sample ;
|
||||
} else if (b->sample_size == 2) {
|
||||
u_short *p= (u_short *)(b->buf + i), sample = *p;
|
||||
|
||||
l1 /= 2 ;
|
||||
l0 /= 2 ;
|
||||
for ( ; l0 ; l0--)
|
||||
*p++ = sample ;
|
||||
for (p= (u_short *)(b->buf) ; l1 ; l1--)
|
||||
*p++ = sample ;
|
||||
} else { /* must be 4 ... */
|
||||
u_long *p= (u_long *)(b->buf + i), sample = *p;
|
||||
|
||||
l1 /= 4 ;
|
||||
l0 /= 4 ;
|
||||
for ( ; l0 ; l0--)
|
||||
*p++ = sample ;
|
||||
for (p= (u_long *)(b->buf) ; l1 ; l1--)
|
||||
*p++ = sample ;
|
||||
}
|
||||
|
||||
}
|
||||
bsz = min(b->bufsize, bsz*2);
|
||||
}
|
||||
s = spltty(); /* no interrupts here ... */
|
||||
d->flags &= ~SND_F_WRITING ;
|
||||
if (d->flags & SND_F_ABORTING) {
|
||||
d->flags &= ~SND_F_ABORTING;
|
||||
splx(s);
|
||||
dsp_wrabort(d, 1 /* restart */);
|
||||
/* XXX return EINTR ? */
|
||||
}
|
||||
splx(s) ;
|
||||
return ret ;
|
||||
}
|
||||
|
||||
/*
|
||||
* SOUND INPUT
|
||||
*
|
||||
|
||||
The input part is similar to the output one, with a circular buffer
|
||||
split in two regions, and boundaries advancing because of read() calls
|
||||
[r] or dma operation [d]. At initialization, as for the write
|
||||
routine, READY is empty, and FREE takes all the space.
|
||||
|
||||
0 rp,rl fp,fl bufsize
|
||||
|__________>____________>________|
|
||||
FREE r READY d FREE
|
||||
|
||||
Operation is as follows: upon user read (dsp_read_body()) a DMA read
|
||||
is started if not already active (marked by b->dl > 0),
|
||||
then as soon as data are available in the READY region they are
|
||||
transferred to the user buffer, thus advancing the boundary between FREE
|
||||
and READY. Upon interrupts, caused by a completion of a DMA transfer,
|
||||
the READY region is extended and possibly a new transfer is started.
|
||||
|
||||
When necessary, dsp_rd_dmaupdate() is called to advance fp (and update
|
||||
rl,fl accordingly). Upon user reads, rp is advanced and rl,fl are
|
||||
updated accordingly.
|
||||
|
||||
The rules to choose the size of the new DMA area are similar to
|
||||
the other case, with a preferred constant transfer size equal to
|
||||
rec_blocksize, and fallback to smaller sizes if no space is available.
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* dsp_rd_dmadone moves bytes in the input buffer from DMA region to
|
||||
* READY region. We assume it is called at spltty() and with dl>0
|
||||
*/
|
||||
static void
|
||||
dsp_rd_dmadone(snddev_info *d)
|
||||
{
|
||||
snd_dbuf *b = & (d->dbuf_in) ;
|
||||
|
||||
if (d->special_dma)
|
||||
d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ;
|
||||
else
|
||||
dsp_rd_dmaupdate(b);
|
||||
wakeup(b) ; /* wakeup possibly sleeping processes */
|
||||
if (b->sel.si_pid &&
|
||||
( !(d->flags & SND_F_HAS_SIZE) || b->rl >= d->rec_blocksize ) )
|
||||
selwakeup( & b->sel );
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function tracks the status of a (read) dma transfer,
|
||||
* and moves the boundary between the READY and the DMA regions.
|
||||
* It works under the following assumptions:
|
||||
* - the DMA engine is running;
|
||||
* - the function is called with interrupts blocked.
|
||||
*/
|
||||
void
|
||||
dsp_rd_dmaupdate(snd_dbuf *b)
|
||||
{
|
||||
int delta, tmp ;
|
||||
|
||||
tmp = b->bufsize - isa_dmastatus1(b->chan) ;
|
||||
tmp &= DMA_ALIGN_MASK; /* align... */
|
||||
delta = tmp - b->fp;
|
||||
if (delta < 0) /* wrapped */
|
||||
delta += b->bufsize ;
|
||||
b->fp = tmp;
|
||||
b->fl -= delta ;
|
||||
b->rl += delta ;
|
||||
b->total += delta ;
|
||||
}
|
||||
|
||||
/*
|
||||
* read interrupt routine. Must be called with interrupts blocked.
|
||||
*/
|
||||
void
|
||||
dsp_rdintr(snddev_info *d)
|
||||
{
|
||||
snd_dbuf *b = & (d->dbuf_in) ;
|
||||
|
||||
if (b->dl) { /* dma was active */
|
||||
b->int_count++;
|
||||
dsp_rd_dmadone(d);
|
||||
}
|
||||
|
||||
DEB(printf("dsp_rdintr: start dl %d, rp:rl %d:%d, fp:fl %d:%d\n",
|
||||
b->dl, b->rp, b->rl, b->fp, b->fl));
|
||||
/*
|
||||
* Restart if have enough free space to absorb overruns;
|
||||
*/
|
||||
if ( b->fl > 0x200 &&
|
||||
(d->flags & (SND_F_ABORTING|SND_F_CLOSING)) == 0 &&
|
||||
( FULL_DUPLEX(d) || (d->flags & SND_F_WRITING) == 0 ) ) {
|
||||
int l = min(b->fl - 0x100, d->rec_blocksize);
|
||||
l &= DMA_ALIGN_MASK ; /* realign sizes */
|
||||
DEB(printf("rdintr: dl %d -> %d\n", b->dl, l);)
|
||||
if (l != b->dl) {
|
||||
/* for any reason, size has changed. Stop and restart */
|
||||
if (b->dl > 0 )
|
||||
d->callback(d, SND_CB_RD | SND_CB_STOP );
|
||||
b->dl = l ;
|
||||
d->callback(d, SND_CB_RD | SND_CB_START );
|
||||
}
|
||||
} else {
|
||||
if (b->dl > 0) { /* was active */
|
||||
b->dl = 0;
|
||||
d->callback(d, SND_CB_RD | SND_CB_STOP);
|
||||
}
|
||||
/*
|
||||
* if switching to write, start write dma engine
|
||||
*/
|
||||
if ( ! FULL_DUPLEX(d) && (d->flags & SND_F_WRITING) )
|
||||
dsp_wrintr(d) ;
|
||||
DEB(printf("cannot start rd-dma rl %d fl %d\n",
|
||||
b->rl, b->fl));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* body of user-read routine
|
||||
*
|
||||
* Start DMA if not active; wait for READY not empty.
|
||||
* Transfer data from READY region using uiomove(), advance boundary
|
||||
* between FREE and READY. Repeat until transfer is complete.
|
||||
*
|
||||
* To avoid excessive latency in freeing up space for the DMA
|
||||
* engine, transfers are done in blocks of increasing size, so that
|
||||
* the latency is proportional to the size of the smallest block, but
|
||||
* we have a low overhead and are able to feed the dma engine with
|
||||
* large blocks.
|
||||
*
|
||||
* When we enter this routine, we assume that d->flags |= SND_F_READING
|
||||
* was done before.
|
||||
*
|
||||
* NOTE: in the current version, read will not return more than
|
||||
* blocksize bytes at once (unless more are already available), to
|
||||
* avoid that requests using very large buffers block for too long.
|
||||
*/
|
||||
|
||||
int
|
||||
dsp_read_body(snddev_info *d, struct uio *buf)
|
||||
{
|
||||
int limit, l, n, bsz, ret = 0 ;
|
||||
long s;
|
||||
snd_dbuf *b = & (d->dbuf_in) ;
|
||||
|
||||
/*
|
||||
* "limit" serves to return after at most one blocksize of data
|
||||
* (unless more are already available). Otherwise, things like
|
||||
* cat /dev/audio would use a 64K buffer and would start returning
|
||||
* data after a _very_ long time...
|
||||
* Note -- some applications depend on reads not returning short
|
||||
* blocks. But I believe these apps are broken, since interrupted
|
||||
* system calls might return short reads anyways, and the
|
||||
* application should better check that.
|
||||
*/
|
||||
|
||||
if (buf->uio_resid > d->rec_blocksize)
|
||||
limit = buf->uio_resid - d->rec_blocksize;
|
||||
else
|
||||
limit = 0;
|
||||
bsz = MIN_CHUNK_SIZE ; /* the current transfer (doubles at each step) */
|
||||
while ( (n = buf->uio_resid) > limit ) {
|
||||
DEB(printf("dsp_read_body: start waiting for %d bytes\n", n));
|
||||
l = min (n, bsz);
|
||||
s = spltty(); /* no interrupts here ! */
|
||||
if (d->special_dma)
|
||||
d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ;
|
||||
else
|
||||
dsp_rd_dmaupdate(b);
|
||||
l = min( l, b->rl ); /* no more than avail. data */
|
||||
if (l == 0) {
|
||||
int timeout;
|
||||
/*
|
||||
* If there is no data ready, then we must sleep (unless
|
||||
* of course we have doing non-blocking i/o). But also
|
||||
* consider restarting the DMA engine.
|
||||
*/
|
||||
if ( b->dl == 0 ) { /* dma was idle, start it */
|
||||
if ( d->flags & SND_F_INIT && d->dbuf_out.dl == 0 ) {
|
||||
/* want to init and there is no pending DMA activity */
|
||||
splx(s);
|
||||
d->callback(d, SND_CB_INIT); /* this is slow! */
|
||||
s = spltty();
|
||||
}
|
||||
dsp_rdintr(d);
|
||||
}
|
||||
if (d->flags & SND_F_NBIO) {
|
||||
splx(s);
|
||||
break;
|
||||
}
|
||||
if (n-limit > b->dl)
|
||||
timeout = hz; /* we need to wait for an int. */
|
||||
else
|
||||
timeout = 1; /* maybe data will be ready earlier */
|
||||
ret = tsleep( (caddr_t)b, PRIBIO | PCATCH , "dsprd", timeout ) ;
|
||||
if (ret == EINTR)
|
||||
d->flags |= SND_F_ABORTING ;
|
||||
splx(s);
|
||||
if (ret == EINTR || ret == ERESTART)
|
||||
break ;
|
||||
continue;
|
||||
}
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Do any necessary format conversion, and copy to user space.
|
||||
* NOTE: I _can_ use rp here because it is not modified by the
|
||||
* interrupt routines.
|
||||
*/
|
||||
if (b->rp + l > b->bufsize) { /* handle wraparounds */
|
||||
int l1 = b->bufsize - b->rp ;
|
||||
if (d->flags & SND_F_XLAT8) {
|
||||
translate_bytes(dsp_ulaw, b->buf + b->rp, l1);
|
||||
translate_bytes(dsp_ulaw, b->buf , l - l1);
|
||||
}
|
||||
uiomove(b->buf + b->rp, l1, buf) ;
|
||||
uiomove(b->buf, l - l1, buf) ;
|
||||
} else {
|
||||
if (d->flags & SND_F_XLAT8)
|
||||
translate_bytes(dsp_ulaw, b->buf + b->rp, l);
|
||||
uiomove(b->buf + b->rp, l, buf) ;
|
||||
}
|
||||
|
||||
s = spltty(); /* no interrupts here ... */
|
||||
b->fl += l ; /* this more free bytes */
|
||||
b->rl -= l ; /* this less ready bytes */
|
||||
b->rp += l ; /* advance ready pointer */
|
||||
if (b->rp >= b->bufsize) /* handle wraps */
|
||||
b->rp -= b->bufsize ;
|
||||
splx(s) ;
|
||||
bsz = min(b->bufsize, bsz*2);
|
||||
}
|
||||
s = spltty(); /* no interrupts here ... */
|
||||
d->flags &= ~SND_F_READING ;
|
||||
if (d->flags & SND_F_ABORTING) {
|
||||
d->flags &= ~SND_F_ABORTING; /* XXX */
|
||||
splx(s);
|
||||
dsp_rdabort(d, 1 /* restart */);
|
||||
/* XXX return EINTR ? */
|
||||
}
|
||||
splx(s) ;
|
||||
return ret ;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* short routine to initialize a dma buffer descriptor (usually
|
||||
* located in the XXX_desc structure). The first parameter is
|
||||
* the buffer size, the second one specifies that a 16-bit dma channel
|
||||
* is used (hence the buffer must be properly aligned).
|
||||
*/
|
||||
void
|
||||
alloc_dbuf(snd_dbuf *b, int size)
|
||||
{
|
||||
if (size > 0x10000)
|
||||
panic("max supported size is 64k");
|
||||
b->buf = contigmalloc(size, M_DEVBUF, M_NOWAIT,
|
||||
0ul, 0xfffffful, 1ul, 0x10000ul);
|
||||
/* should check that malloc does not fail... */
|
||||
b->rp = b->fp = 0 ;
|
||||
b->dl = b->rl = 0 ;
|
||||
b->bufsize = b->fl = size ;
|
||||
}
|
||||
|
||||
/*
|
||||
* this resets a buffer and starts the isa dma on that channel.
|
||||
* Must be called when the dma on the card is disabled (e.g. after init).
|
||||
*/
|
||||
void
|
||||
reset_dbuf(snd_dbuf *b, int chan)
|
||||
{
|
||||
DEB(printf("reset dbuf for chan %d\n", b->chan));
|
||||
b->rp = b->fp = 0 ;
|
||||
b->dl = b->rl = 0 ;
|
||||
b->fl = b->bufsize ;
|
||||
if (chan == SND_CHAN_NONE)
|
||||
return ;
|
||||
if (chan == SND_CHAN_WR)
|
||||
chan = B_WRITE | B_RAW ;
|
||||
else
|
||||
chan = B_READ | B_RAW ;
|
||||
if (b->chan != 4 && b->chan < 8) /* XXX hack for pci... */
|
||||
isa_dmastart( chan , b->buf, b->bufsize, b->chan);
|
||||
}
|
||||
|
||||
/*
|
||||
* snd_sync waits until the space in the given channel goes above
|
||||
* a threshold. chan = 1 : play, 2: capture. The threshold is
|
||||
* checked against fl or rl respectively.
|
||||
* Assume that the condition can become true, do not check here...
|
||||
*/
|
||||
int
|
||||
snd_sync(snddev_info *d, int chan, int threshold)
|
||||
{
|
||||
u_long s;
|
||||
int ret;
|
||||
snd_dbuf *b;
|
||||
|
||||
b = (chan == 1) ? &(d->dbuf_out ) : &(d->dbuf_in ) ;
|
||||
|
||||
for (;;) {
|
||||
s=spltty();
|
||||
if (d->special_dma)
|
||||
d->callback(d, (chan==1? SND_CB_WR:SND_CB_RD) | SND_CB_DMAUPDATE);
|
||||
else {
|
||||
if ( chan==1 )
|
||||
dsp_wr_dmaupdate(b);
|
||||
else
|
||||
dsp_rd_dmaupdate(b);
|
||||
}
|
||||
if ( (chan == 1 && b->fl <= threshold) ||
|
||||
(chan == 2 && b->rl <= threshold) ) {
|
||||
ret = tsleep((caddr_t)b, PRIBIO|PCATCH, "sndsyn", 1);
|
||||
splx(s);
|
||||
if (ret == ERESTART || ret == EINTR) {
|
||||
printf("tsleep returns %d\n", ret);
|
||||
return -1 ;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
splx(s);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
/*
|
||||
* dsp_wrabort(d) and dsp_rdabort(d) are non-blocking functions
|
||||
* which abort a pending DMA transfer and flush the buffers.
|
||||
* They return the number of bytes that has not been transferred.
|
||||
* The second parameter is used to restart the engine if needed.
|
||||
*/
|
||||
int
|
||||
dsp_wrabort(snddev_info *d, int restart)
|
||||
{
|
||||
long s;
|
||||
int missing = 0;
|
||||
snd_dbuf *b = & (d->dbuf_out) ;
|
||||
|
||||
s = spltty();
|
||||
if ( b->dl ) {
|
||||
b->dl = 0 ;
|
||||
d->flags &= ~ SND_F_WRITING ;
|
||||
if (d->callback)
|
||||
d->callback(d, SND_CB_WR | SND_CB_ABORT);
|
||||
if (!d->special_dma)
|
||||
isa_dmastop(b->chan) ;
|
||||
dsp_wr_dmadone(d);
|
||||
|
||||
DEB(printf("dsp_wrabort: stopped, %d bytes left\n", b->rl));
|
||||
}
|
||||
missing = b->rl;
|
||||
if (!d->special_dma)
|
||||
isa_dmadone(B_WRITE, b->buf, b->bufsize, b->chan); /*free chan */
|
||||
reset_dbuf(b, restart ? SND_CHAN_WR : SND_CHAN_NONE);
|
||||
splx(s);
|
||||
return missing;
|
||||
}
|
||||
|
||||
int
|
||||
dsp_rdabort(snddev_info *d, int restart)
|
||||
{
|
||||
long s;
|
||||
int missing = 0;
|
||||
snd_dbuf *b = & (d->dbuf_in) ;
|
||||
|
||||
s = spltty();
|
||||
if ( b->dl ) {
|
||||
b->dl = 0 ;
|
||||
d->flags &= ~ SND_F_READING ;
|
||||
if (d->callback)
|
||||
d->callback(d, SND_CB_RD | SND_CB_ABORT);
|
||||
if (!d->special_dma)
|
||||
isa_dmastop(b->chan) ;
|
||||
dsp_rd_dmadone(d);
|
||||
}
|
||||
missing = b->rl ;
|
||||
if (!d->special_dma)
|
||||
isa_dmadone(B_READ, b->buf, b->bufsize, b->chan);
|
||||
reset_dbuf(b, restart ? SND_CHAN_RD : SND_CHAN_NONE);
|
||||
splx(s);
|
||||
return missing;
|
||||
}
|
||||
|
||||
/*
|
||||
* this routine tries to flush the dma transfer. It is called
|
||||
* on a close. The caller must set SND_F_CLOSING, and insure that
|
||||
* interrupts are enabled. We immediately abort any read DMA
|
||||
* operation, and then wait for the play buffer to drain.
|
||||
*/
|
||||
|
||||
int
|
||||
snd_flush(snddev_info *d)
|
||||
{
|
||||
int ret, count=10;
|
||||
u_long s;
|
||||
snd_dbuf *b = &(d->dbuf_out) ;
|
||||
|
||||
DEB(printf("snd_flush d->flags 0x%08x\n", d->flags));
|
||||
dsp_rdabort(d, 0 /* no restart */);
|
||||
/* close write */
|
||||
while ( b->dl ) {
|
||||
/*
|
||||
* still pending output data.
|
||||
*/
|
||||
ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dmafl1", hz);
|
||||
if (d->special_dma)
|
||||
d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE);
|
||||
else
|
||||
dsp_wr_dmaupdate(b);
|
||||
DEB( printf("snd_sync: now rl : fl %d : %d\n", b->rl, b->fl ) );
|
||||
if (ret == EINTR) {
|
||||
printf("tsleep returns %d\n", ret);
|
||||
return -1 ;
|
||||
}
|
||||
if ( ret && --count == 0) {
|
||||
printf("timeout flushing dbuf_out, chan %d cnt 0x%x flags 0x%08lx\n",
|
||||
b->chan,
|
||||
b->rl, d->flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
s = spltty(); /* should not be necessary... */
|
||||
d->flags &= ~SND_F_CLOSING ;
|
||||
dsp_wrabort(d, 0 /* no restart */);
|
||||
splx(s);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
/*
|
||||
* end of new code for dma buffer handling
|
||||
*/
|
@ -1,304 +0,0 @@
|
||||
/*
|
||||
* file: mss.h
|
||||
*
|
||||
* (C) 1997 Luigi Rizzo (luigi@iet.unipi.it)
|
||||
*
|
||||
* This file contains information and macro definitions for
|
||||
* AD1848-compatible devices, used in the MSS/WSS compatible boards.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
|
||||
The codec part of the board is seen as a set of 4 registers mapped
|
||||
at the base address for the board (default 0x534). Note that some
|
||||
(early) boards implemented 4 additional registers 4 location before
|
||||
(usually 0x530) to store configuration information. This is a source
|
||||
of confusion in that one never knows what address to specify. The
|
||||
(current) convention is to use the old address (0x530) in the kernel
|
||||
configuration file and consider MSS registers start four location
|
||||
ahead.
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The four visible registers of the MSS :
|
||||
*
|
||||
*/
|
||||
|
||||
#define io_Index_Addr(d) ((d)->io_base + 4)
|
||||
#define IA_BUSY 0x80 /* readonly, set when busy */
|
||||
#define IA_MCE 0x40 /* the MCE bit. */
|
||||
/*
|
||||
* the MCE bit must be set whenever the current mode of the
|
||||
* codec is changed; this in particular is true for the
|
||||
* Data Format (I8, I28) and Interface Config(I9) registers.
|
||||
* Only exception are CEN and PEN which can be changed on the fly.
|
||||
* The DAC output is muted when MCE is set.
|
||||
*/
|
||||
#define IA_TRD 0x20 /* Transfer request disable */
|
||||
/*
|
||||
* When TRD is set, DMA transfers cease when the INT bit in
|
||||
* the MSS status reg is set. Must be cleared for automode
|
||||
* DMA, set otherwise.
|
||||
*/
|
||||
#define IA_AMASK 0x1f /* mask for indirect address */
|
||||
|
||||
#define io_Indexed_Data(d) ((d)->io_base+1+4)
|
||||
/*
|
||||
* data to be transferred to the indirect register addressed
|
||||
* by index addr. During init and sw. powerdown, cannot be
|
||||
* written to, and is always read as 0x80 (consistent with the
|
||||
* busy flag).
|
||||
*/
|
||||
|
||||
#define io_Status(d) ((d)->io_base+2+4)
|
||||
|
||||
#define IS_CUL 0x80 /* capture upper/lower */
|
||||
#define IS_CLR 0x40 /* capture left/right */
|
||||
#define IS_CRDY 0x20 /* capture ready for programmed i/o */
|
||||
#define IS_SER 0x10 /* sample error (overrun/underrun) */
|
||||
#define IS_PUL 0x08 /* playback upper/lower */
|
||||
#define IS_PLR 0x04 /* playback left/right */
|
||||
#define IS_PRDY 0x02 /* playback ready for programmed i/o */
|
||||
#define IS_INT 0x01 /* int status (1 = active) */
|
||||
/*
|
||||
* IS_INT is clreared by any write to the status register.
|
||||
*/
|
||||
|
||||
#define io_Polled_IO(d) ((d)->io_base+3+4)
|
||||
/*
|
||||
* this register is used in case of polled i/o
|
||||
*/
|
||||
|
||||
/*
|
||||
* The MSS has a set of 16 (or 32 depending on the model) indirect
|
||||
* registers accessible through the data port by specifying the
|
||||
* appropriate address in the address register.
|
||||
*
|
||||
* The 16 low registers are uniformly handled in AD1848/CS4248 compatible
|
||||
* mode (often called MODE1). For the upper 16 registers there are
|
||||
* some differences among different products, mainly Crystal uses them
|
||||
* differently from OPTi.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* volume registers
|
||||
*/
|
||||
|
||||
#define I6_MUTE 0x80
|
||||
|
||||
/*
|
||||
* register I9 -- interface configuration.
|
||||
*/
|
||||
|
||||
#define I9_PEN 0x01 /* playback enable */
|
||||
#define I9_CEN 0x02 /* capture enable */
|
||||
|
||||
/*
|
||||
* values used in bd_flags
|
||||
*/
|
||||
#define BD_F_MCE_BIT 0x0001
|
||||
#define BD_F_IRQ_OK 0x0002
|
||||
#define BD_F_TMR_RUN 0x0004
|
||||
|
||||
/* AD1816 register macros */
|
||||
|
||||
#define ad1816_ale(d) ((d)->io_base+0) /* indirect reg access */
|
||||
#define ad1816_int(d) ((d)->io_base+1) /* interupt status */
|
||||
#define ad1816_low(d) ((d)->io_base+2) /* indirect low byte */
|
||||
#define ad1816_high(d) ((d)->io_base+3) /* indirect high byte */
|
||||
/* unused */
|
||||
#define ad1816_pioD(d) ((d)->io_base+4) /* PIO debug */
|
||||
#define ad1816_pios(d) ((d)->io_base+5) /* PIO status */
|
||||
#define ad1816_piod(d) ((d)->io_base+6) /* PIO data */
|
||||
/* end of unused */
|
||||
/* values for playback/capture config:
|
||||
bits: 0 enable/disable
|
||||
1 pio/dma
|
||||
2 stereo/mono
|
||||
3 companded/linearPCM
|
||||
4-5 format : 00 8bit linear (uncomp)
|
||||
00 8bit mulaw (comp)
|
||||
01 16bit le (uncomp)
|
||||
01 8bit alaw (comp)
|
||||
11 16bit be (uncomp)
|
||||
*/
|
||||
#define ad1816_play(d) ((d)->io_base+8) /* playback config */
|
||||
#define ad1816_capt(d) ((d)->io_base+9) /* capture config */
|
||||
|
||||
#define AD1816_BUSY 0x80 /* chip is busy */
|
||||
#define AD1816_ALEMASK 0x3F /* mask for indirect adr. */
|
||||
/* unusud */
|
||||
#define AD1816_INTRSI 0x01 /* sb intr */
|
||||
#define AD1816_INTRGI 0x02 /* game intr */
|
||||
#define AD1816_INTRRI 0x04 /* ring intr */
|
||||
#define AD1816_INTRDI 0x08 /* dsp intr */
|
||||
#define AD1816_INTRVI 0x10 /* vol intr */
|
||||
#define AD1816_INTRTI 0x20 /* timer intr */
|
||||
/* used again */
|
||||
#define AD1816_INTRCI 0x40 /* capture intr */
|
||||
#define AD1816_INTRPI 0x80 /* playback intr */
|
||||
/* PIO stuff is not supplied here */
|
||||
/* playback / capture config */
|
||||
#define AD1816_ENABLE 0x01 /* enable pl/cp */
|
||||
#define AD1816_PIO 0x02 /* use pio */
|
||||
#define AD1816_STEREO 0x04
|
||||
#define AD1816_COMP 0x08 /* data is companded */
|
||||
#define AD1816_U8 0x00 /* 8 bit linear pcm */
|
||||
#define AD1816_MULAW 0x08 /* 8 bit mulaw */
|
||||
#define AD1816_ALAW 0x18 /* 8 bit alaw */
|
||||
#define AD1816_S16LE 0x10 /* 16 bit linear little endian */
|
||||
#define AD1816_S16BE 0x30 /* 16 bit linear big endian */
|
||||
#define AD1816_FORMASK 0x38 /* format mask */
|
||||
|
||||
/*
|
||||
* sound/ad1848_mixer.h
|
||||
*
|
||||
* Definitions for the mixer of AD1848 and compatible codecs.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1994
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* The AD1848 codec has generic input lines called Line, Aux1 and Aux2.
|
||||
* Soundcard manufacturers have connected actual inputs (CD, synth, line,
|
||||
* etc) to these inputs in different order. Therefore it's difficult
|
||||
* to assign mixer channels to to these inputs correctly. The following
|
||||
* contains two alternative mappings. The first one is for GUS MAX and
|
||||
* the second is just a generic one (line1, line2 and line3).
|
||||
* (Actually this is not a mapping but rather some kind of interleaving
|
||||
* solution).
|
||||
*/
|
||||
|
||||
#define MSS_REC_DEVICES \
|
||||
(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD|SOUND_MASK_IMIX)
|
||||
|
||||
|
||||
/*
|
||||
* Table of mixer registers. There is a default table for the
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more MSS
|
||||
* clones come out, there ought to be more tables.
|
||||
*
|
||||
* Fields in the table are : polarity, register, offset, bits
|
||||
*
|
||||
* The channel numbering used by individual soundcards is not fixed.
|
||||
* Some cards have assigned different meanings for the AUX1, AUX2
|
||||
* and LINE inputs. Some have different features...
|
||||
*
|
||||
* Following there is a macro ...MIXER_DEVICES which is a bitmap
|
||||
* of all non-zero fields in the table.
|
||||
* MODE1_MIXER_DEVICES is the basic mixer of the 1848 in mode 1
|
||||
* registers I0..I15)
|
||||
*
|
||||
*/
|
||||
|
||||
mixer_ent mix_devices[32][2] = {
|
||||
MIX_NONE(SOUND_MIXER_VOLUME),
|
||||
MIX_NONE(SOUND_MIXER_BASS),
|
||||
MIX_NONE(SOUND_MIXER_TREBLE),
|
||||
MIX_ENT(SOUND_MIXER_SYNTH, 2, 1, 0, 5, 3, 1, 0, 5),
|
||||
MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6),
|
||||
MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5),
|
||||
MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1),
|
||||
MIX_ENT(SOUND_MIXER_CD, 4, 1, 0, 5, 5, 1, 0, 5),
|
||||
MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0),
|
||||
MIX_NONE(SOUND_MIXER_ALTPCM),
|
||||
MIX_NONE(SOUND_MIXER_RECLEV),
|
||||
MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4),
|
||||
MIX_NONE(SOUND_MIXER_OGAIN),
|
||||
MIX_NONE(SOUND_MIXER_LINE1),
|
||||
MIX_NONE(SOUND_MIXER_LINE2),
|
||||
MIX_NONE(SOUND_MIXER_LINE3),
|
||||
};
|
||||
|
||||
#define MODE2_MIXER_DEVICES \
|
||||
(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | \
|
||||
SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \
|
||||
SOUND_MASK_IMIX | SOUND_MASK_IGAIN )
|
||||
|
||||
#define MODE1_MIXER_DEVICES \
|
||||
(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_IMIX | SOUND_MASK_IGAIN )
|
||||
|
||||
|
||||
/*
|
||||
* entries for the opti931...
|
||||
*/
|
||||
|
||||
mixer_ent opti931_devices[32][2] = { /* for the opti931 */
|
||||
MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 1, 5, 23, 1, 1, 5),
|
||||
MIX_NONE(SOUND_MIXER_BASS),
|
||||
MIX_NONE(SOUND_MIXER_TREBLE),
|
||||
MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 5, 1, 1, 4),
|
||||
MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 5, 7, 1, 0, 5),
|
||||
MIX_NONE(SOUND_MIXER_SPEAKER),
|
||||
MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4),
|
||||
MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1),
|
||||
MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4),
|
||||
MIX_NONE(SOUND_MIXER_IMIX),
|
||||
MIX_NONE(SOUND_MIXER_ALTPCM),
|
||||
MIX_NONE(SOUND_MIXER_RECLEV),
|
||||
MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4),
|
||||
MIX_NONE(SOUND_MIXER_OGAIN),
|
||||
MIX_ENT(SOUND_MIXER_LINE1, 16, 1, 1, 4, 17, 1, 1, 4),
|
||||
MIX_NONE(SOUND_MIXER_LINE2),
|
||||
MIX_NONE(SOUND_MIXER_LINE3),
|
||||
};
|
||||
|
||||
#define OPTI931_MIXER_DEVICES \
|
||||
(SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | SOUND_MASK_PCM | \
|
||||
SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \
|
||||
SOUND_MASK_IGAIN | SOUND_MASK_LINE1 )
|
||||
|
||||
#define AD1816_REC_DEVICES \
|
||||
(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
|
||||
|
||||
#define AD1816_MIXER_DEVICES \
|
||||
(SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH | \
|
||||
SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_IGAIN)
|
||||
|
||||
static u_short default_mixer_levels[SOUND_MIXER_NRDEVICES] = {
|
||||
0x5a5a, /* Master Volume */
|
||||
0x3232, /* Bass */
|
||||
0x3232, /* Treble */
|
||||
0x4b4b, /* FM */
|
||||
0x4040, /* PCM */
|
||||
0x4b4b, /* PC Speaker */
|
||||
0x2020, /* Ext Line */
|
||||
0x4040, /* Mic */
|
||||
0x4b4b, /* CD */
|
||||
0x0000, /* Recording monitor */
|
||||
0x4b4b, /* SB PCM */
|
||||
0x4b4b, /* Recording level */
|
||||
0x2525, /* Input gain */
|
||||
0x0000, /* Output gain */
|
||||
/* 0x4040, Line1 */
|
||||
0x0000, /* Line1 */
|
||||
0x0000, /* Line2 */
|
||||
0x1515 /* Line3 (usually line in)*/
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,405 +0,0 @@
|
||||
/*
|
||||
* file: sbcard.h
|
||||
*/
|
||||
|
||||
typedef struct _sbdev_info {
|
||||
|
||||
} sbdev_info ;
|
||||
|
||||
extern int sbc_major, sbc_minor ;
|
||||
/*
|
||||
* sound blaster registers
|
||||
*/
|
||||
|
||||
#define SBDSP_RST 0x6
|
||||
#define DSP_READ (io_base + 0xA)
|
||||
#define DSP_WRITE (io_base + 0xC)
|
||||
#define SBDSP_CMD 0xC
|
||||
#define SBDSP_STATUS 0xC
|
||||
#define DSP_DATA_AVAIL (io_base + 0xE)
|
||||
#define DSP_DATA_AVL16 (io_base + 0xF)
|
||||
|
||||
#define SB_MIX_ADDR 0x4
|
||||
#define SB_MIX_DATA 0x5
|
||||
#if 0
|
||||
#define OPL3_LEFT (io_base + 0x0)
|
||||
#define OPL3_RIGHT (io_base + 0x2)
|
||||
#define OPL3_BOTH (io_base + 0x8)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DSP Commands. There are many, and in many cases they are used explicitly
|
||||
*/
|
||||
|
||||
/* these are not used except for programmed I/O (not in this driver) */
|
||||
#define DSP_DAC8 0x10 /* direct DAC output */
|
||||
#define DSP_ADC8 0x20 /* direct ADC input */
|
||||
|
||||
/* these should be used in the SB 1.0 */
|
||||
#define DSP_CMD_DAC8 0x14 /* single cycle 8-bit dma out */
|
||||
#define DSP_CMD_ADC8 0x24 /* single cycle 8-bit dma in */
|
||||
|
||||
/* these should be used in the SB 2.0 and 2.01 */
|
||||
#define DSP_CMD_DAC8_AUTO 0x1c /* auto 8-bit dma out */
|
||||
#define DSP_CMD_ADC8_AUTO 0x2c /* auto 8-bit dma out */
|
||||
|
||||
#define DSP_CMD_HSSIZE 0x48 /* high speed dma count */
|
||||
#define DSP_CMD_HSDAC_AUTO 0x90 /* high speed dac, auto */
|
||||
#define DSP_CMD_HSADC_AUTO 0x98 /* high speed adc, auto */
|
||||
|
||||
/* SBPro commands. Some cards (JAZZ, SMW) also support 16 bits */
|
||||
|
||||
/* prepare for dma input */
|
||||
#define DSP_CMD_DMAMODE(stereo, bit16) (0xA0 | (stereo ? 8:0) | (bit16 ? 4:0))
|
||||
|
||||
#define DSP_CMD_DAC2 0x16 /* 2-bit adpcm dma out (cont) */
|
||||
#define DSP_CMD_DAC2S 0x17 /* 2-bit adpcm dma out (start) */
|
||||
|
||||
#define DSP_CMD_DAC2S_AUTO 0x1f /* auto 2-bit adpcm dma out (start) */
|
||||
|
||||
|
||||
/* SB16 commands */
|
||||
#define DSP_CMD_O16 0xb0
|
||||
#define DSP_CMD_I16 0xb8
|
||||
#define DSP_CMD_O8 0xc0
|
||||
#define DSP_CMD_I8 0xc8
|
||||
|
||||
#define DSP_MODE_U8MONO 0x00
|
||||
#define DSP_MODE_U8STEREO 0x20
|
||||
#define DSP_MODE_S16MONO 0x10
|
||||
#define DSP_MODE_S16STEREO 0x30
|
||||
|
||||
#define DSP_CMD_SPKON 0xD1
|
||||
#define DSP_CMD_SPKOFF 0xD3
|
||||
#define DSP_CMD_SPKR(on) (0xD1 | (on ? 0:2))
|
||||
|
||||
#define DSP_CMD_DMAPAUSE_8 0xD0
|
||||
#define DSP_CMD_DMAPAUSE_16 0xD5
|
||||
#define DSP_CMD_DMAEXIT_8 0xDA
|
||||
#define DSP_CMD_DMAEXIT_16 0xD9
|
||||
#define DSP_CMD_TCONST 0x40 /* set time constant */
|
||||
#define DSP_CMD_HSDAC 0x91 /* high speed dac */
|
||||
#define DSP_CMD_HSADC 0x99 /* high speed adc */
|
||||
|
||||
#define DSP_CMD_GETVER 0xE1
|
||||
#define DSP_CMD_GETID 0xE7 /* return id bytes */
|
||||
|
||||
|
||||
#define DSP_CMD_OUT16 0x41 /* send parms for dma out on sb16 */
|
||||
#define DSP_CMD_IN16 0x42 /* send parms for dma in on sb16 */
|
||||
#if 0 /*** unknown ***/
|
||||
#define DSP_CMD_FA 0xFA /* get version from prosonic*/
|
||||
#define DSP_CMD_FB 0xFB /* set irq/dma for prosonic*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* in fact, for the SB16, dma commands are as follows:
|
||||
*
|
||||
* cmd, mode, len_low, len_high.
|
||||
*
|
||||
* cmd is a combination of DSP_DMA16 or DSP_DMA8 and
|
||||
*/
|
||||
|
||||
#define DSP_DMA16 0xb0
|
||||
#define DSP_DMA8 0xc0
|
||||
# define DSP_F16_DAC 0x00
|
||||
# define DSP_F16_ADC 0x08
|
||||
# define DSP_F16_AUTO 0x04
|
||||
# define DSP_F16_FIFO_ON 0x02
|
||||
|
||||
/*
|
||||
* mode is a combination of the following:
|
||||
*/
|
||||
#define DSP_F16_STEREO 0x20
|
||||
#define DSP_F16_SIGNED 0x10
|
||||
|
||||
#define IMODE_NONE 0
|
||||
#define IMODE_OUTPUT PCM_ENABLE_OUTPUT
|
||||
#define IMODE_INPUT PCM_ENABLE_INPUT
|
||||
#define IMODE_INIT 3
|
||||
#define IMODE_MIDI 4
|
||||
|
||||
#define NORMAL_MIDI 0
|
||||
#define UART_MIDI 1
|
||||
|
||||
/*
|
||||
* values used for bd_flags in SoundBlaster driver
|
||||
*/
|
||||
#define BD_F_HISPEED 0x0001 /* doing high speed ... */
|
||||
|
||||
#define BD_F_JAZZ16 0x0002 /* jazz16 detected */
|
||||
#define BD_F_JAZZ16_2 0x0004 /* jazz16 type 2 */
|
||||
|
||||
#define BD_F_DUP_MIDI 0x0008 /* duplex midi */
|
||||
|
||||
#define BD_F_MIX_MASK 0x0070 /* up to 8 mixers (I know of 3) */
|
||||
#define BD_F_MIX_CT1335 0x0010 /* CT1335 */
|
||||
#define BD_F_MIX_CT1345 0x0020 /* CT1345 */
|
||||
#define BD_F_MIX_CT1745 0x0030 /* CT1745 */
|
||||
|
||||
#define BD_F_SB16 0x0100 /* this is a SB16 */
|
||||
#define BD_F_SB16X 0x0200 /* this is a vibra16X or clone */
|
||||
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
|
||||
#define BD_F_ESS 0x0800 /* this is an ESS chip */
|
||||
/*
|
||||
* on some SB16 cards, at times I swap DMA channels. Remember this
|
||||
* so that they can be restored later.
|
||||
*/
|
||||
#define BD_F_SWAPPED 0x1000 /* have swapped DMA channels */
|
||||
|
||||
|
||||
/*
|
||||
* sound/sb_mixer.h
|
||||
*
|
||||
* Definitions for the SB Pro and SB16 mixers
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Modified: Hunyue Yau Jan 6 1994 Added defines for the Sound Galaxy NX Pro
|
||||
* mixer.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SBPRO_RECORDING_DEVICES \
|
||||
(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
|
||||
|
||||
/* Same as SB Pro, unless I find otherwise */
|
||||
#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
|
||||
|
||||
#define SBPRO_MIXER_DEVICES \
|
||||
(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_VOLUME)
|
||||
|
||||
/*
|
||||
* SG NX Pro has treble and bass settings on the mixer. The 'speaker' channel
|
||||
* is the COVOX/DisneySoundSource emulation volume control on the mixer. It
|
||||
* does NOT control speaker volume. Should have own mask eventually?
|
||||
*/
|
||||
#define SGNXPRO_MIXER_DEVICES \
|
||||
(SBPRO_MIXER_DEVICES | SOUND_MASK_BASS | \
|
||||
SOUND_MASK_TREBLE | SOUND_MASK_SPEAKER )
|
||||
|
||||
#define SB16_RECORDING_DEVICES \
|
||||
(SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
|
||||
|
||||
#define SB16_MIXER_DEVICES \
|
||||
(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | \
|
||||
SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \
|
||||
SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
|
||||
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
|
||||
|
||||
/*
|
||||
* Mixer registers
|
||||
*
|
||||
* NOTE! RECORD_SRC == IN_FILTER
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mixer registers of SB Pro
|
||||
*/
|
||||
#define VOC_VOL 0x04
|
||||
#define MIC_VOL 0x0A
|
||||
#define MIC_MIX 0x0A
|
||||
#define RECORD_SRC 0x0C
|
||||
#define IN_FILTER 0x0C
|
||||
#define OUT_FILTER 0x0E
|
||||
#define MASTER_VOL 0x22
|
||||
#define FM_VOL 0x26
|
||||
#define CD_VOL 0x28
|
||||
#define LINE_VOL 0x2E
|
||||
#define IRQ_NR 0x80
|
||||
#define DMA_NR 0x81
|
||||
#define IRQ_STAT 0x82
|
||||
|
||||
/*
|
||||
* Additional registers on the SG NX Pro
|
||||
*/
|
||||
#define COVOX_VOL 0x42
|
||||
#define TREBLE_LVL 0x44
|
||||
#define BASS_LVL 0x46
|
||||
|
||||
#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
|
||||
#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
|
||||
#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
|
||||
#define FILT_OFF (1 << 5)
|
||||
|
||||
#define MONO_DAC 0x00
|
||||
#define STEREO_DAC 0x02
|
||||
|
||||
/*
|
||||
* Mixer registers of SB16
|
||||
*/
|
||||
#define SB16_IMASK_L 0x3d
|
||||
#define SB16_IMASK_R 0x3e
|
||||
#define SB16_OMASK 0x3c
|
||||
|
||||
|
||||
#ifndef __SB_MIXER_C__
|
||||
mixer_tab sbpro_mix;
|
||||
mixer_tab sb16_mix;
|
||||
#ifdef __SGNXPRO__
|
||||
mixer_tab sgnxpro_mix;
|
||||
#endif
|
||||
static u_char sb16_recmasks_L[SOUND_MIXER_NRDEVICES];
|
||||
static u_char sb16_recmasks_R[SOUND_MIXER_NRDEVICES];
|
||||
#else /* __SB_MIXER_C__ defined */
|
||||
mixer_tab sbpro_mix = {
|
||||
PMIX_ENT(SOUND_MIXER_VOLUME, 0x22, 4, 4, 0x22, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_SYNTH, 0x26, 4, 4, 0x26, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_PCM, 0x04, 4, 4, 0x04, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_LINE, 0x2e, 4, 4, 0x2e, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_MIC, 0x0a, 0, 3, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_CD, 0x28, 4, 4, 0x28, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
|
||||
};
|
||||
|
||||
#ifdef __SGNXPRO__
|
||||
mixer_tab sgnxpro_mix = {
|
||||
PMIX_ENT(SOUND_MIXER_VOLUME, 0x22, 4, 4, 0x22, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_BASS, 0x46, 0, 3, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_TREBLE, 0x44, 0, 3, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_SYNTH, 0x26, 4, 4, 0x26, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_PCM, 0x04, 4, 4, 0x04, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 0, 3, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_LINE, 0x2e, 4, 4, 0x2e, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_MIC, 0x0a, 0, 3, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_CD, 0x28, 4, 4, 0x28, 0, 4),
|
||||
PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0)
|
||||
};
|
||||
#endif
|
||||
|
||||
mixer_tab sb16_mix = {
|
||||
PMIX_ENT(SOUND_MIXER_VOLUME, 0x30, 3, 5, 0x31, 3, 5),
|
||||
PMIX_ENT(SOUND_MIXER_BASS, 0x46, 4, 4, 0x47, 4, 4),
|
||||
PMIX_ENT(SOUND_MIXER_TREBLE, 0x44, 4, 4, 0x45, 4, 4),
|
||||
PMIX_ENT(SOUND_MIXER_SYNTH, 0x34, 3, 5, 0x35, 3, 5),
|
||||
PMIX_ENT(SOUND_MIXER_PCM, 0x32, 3, 5, 0x33, 3, 5),
|
||||
PMIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 6, 2, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_LINE, 0x38, 3, 5, 0x39, 3, 5),
|
||||
PMIX_ENT(SOUND_MIXER_MIC, 0x3a, 3, 5, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_CD, 0x36, 3, 5, 0x37, 3, 5),
|
||||
PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
PMIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 6, 2, 0x40, 6, 2), /* Obsol,Use IGAIN*/
|
||||
PMIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 6, 2, 0x40, 6, 2),
|
||||
PMIX_ENT(SOUND_MIXER_OGAIN, 0x41, 6, 2, 0x42, 6, 2)
|
||||
};
|
||||
|
||||
#ifdef SM_GAMES /* Master volume is lower and PCM & FM
|
||||
* volumes higher than with SB Pro. This
|
||||
* improves the sound quality */
|
||||
|
||||
static u_short levels[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x2020, /* Master Volume */
|
||||
0x4b4b, /* Bass */
|
||||
0x4b4b, /* Treble */
|
||||
0x6464, /* FM */
|
||||
0x6464, /* PCM */
|
||||
0x4b4b, /* PC Speaker */
|
||||
0x4b4b, /* Ext Line */
|
||||
0x0000, /* Mic */
|
||||
0x4b4b, /* CD */
|
||||
0x4b4b, /* Recording monitor */
|
||||
0x4b4b, /* SB PCM */
|
||||
0x4b4b, /* Recording level */
|
||||
0x4b4b, /* Input gain */
|
||||
0x4b4b}; /* Output gain */
|
||||
|
||||
#else /* If the user selected just plain SB Pro */
|
||||
|
||||
static u_short levels[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x5a5a, /* Master Volume */
|
||||
0x4b4b, /* Bass */
|
||||
0x4b4b, /* Treble */
|
||||
0x4b4b, /* FM */
|
||||
0x4b4b, /* PCM */
|
||||
0x4b4b, /* PC Speaker */
|
||||
0x4b4b, /* Ext Line */
|
||||
0x1010, /* Mic */
|
||||
0x4b4b, /* CD */
|
||||
0x4b4b, /* Recording monitor */
|
||||
0x4b4b, /* SB PCM */
|
||||
0x4b4b, /* Recording level */
|
||||
0x4b4b, /* Input gain */
|
||||
0x4b4b}; /* Output gain */
|
||||
#endif /* SM_GAMES */
|
||||
|
||||
#if 0
|
||||
static u_char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x00, /* SOUND_MIXER_VOLUME */
|
||||
0x00, /* SOUND_MIXER_BASS */
|
||||
0x00, /* SOUND_MIXER_TREBLE */
|
||||
0x40, /* SOUND_MIXER_SYNTH */
|
||||
0x00, /* SOUND_MIXER_PCM */
|
||||
0x00, /* SOUND_MIXER_SPEAKER */
|
||||
0x10, /* SOUND_MIXER_LINE */
|
||||
0x01, /* SOUND_MIXER_MIC */
|
||||
0x04, /* SOUND_MIXER_CD */
|
||||
0x00, /* SOUND_MIXER_IMIX */
|
||||
0x00, /* SOUND_MIXER_ALTPCM */
|
||||
0x00, /* SOUND_MIXER_RECLEV */
|
||||
0x00, /* SOUND_MIXER_IGAIN */
|
||||
0x00 /* SOUND_MIXER_OGAIN */
|
||||
};
|
||||
|
||||
static u_char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x00, /* SOUND_MIXER_VOLUME */
|
||||
0x00, /* SOUND_MIXER_BASS */
|
||||
0x00, /* SOUND_MIXER_TREBLE */
|
||||
0x20, /* SOUND_MIXER_SYNTH */
|
||||
0x00, /* SOUND_MIXER_PCM */
|
||||
0x00, /* SOUND_MIXER_SPEAKER */
|
||||
0x08, /* SOUND_MIXER_LINE */
|
||||
0x01, /* SOUND_MIXER_MIC */
|
||||
0x02, /* SOUND_MIXER_CD */
|
||||
0x00, /* SOUND_MIXER_IMIX */
|
||||
0x00, /* SOUND_MIXER_ALTPCM */
|
||||
0x00, /* SOUND_MIXER_RECLEV */
|
||||
0x00, /* SOUND_MIXER_IGAIN */
|
||||
0x00 /* SOUND_MIXER_OGAIN */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Recording sources (SB Pro)
|
||||
*/
|
||||
#endif /* __SB_MIXER_C__ */
|
||||
|
||||
#define SRC_MIC 1 /* Select Microphone recording source */
|
||||
#define SRC_CD 3 /* Select CD recording source */
|
||||
#define SRC_LINE 7 /* Use Line-in for recording source */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,528 +0,0 @@
|
||||
/*
|
||||
* sound.h
|
||||
*
|
||||
* include file for kernel sources, sound driver.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1995
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
#include "pcm.h"
|
||||
#else
|
||||
#define NPCM 1
|
||||
#endif
|
||||
#if NPCM > 0
|
||||
|
||||
/*
|
||||
* first, include kernel header files.
|
||||
*/
|
||||
|
||||
#ifndef _OS_H_
|
||||
#define _OS_H_
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
#include <sys/filio.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <sys/kernel.h> /* for DATA_SET */
|
||||
|
||||
#include <sys/conf.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/buf.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <machine/clock.h> /* for DELAY */
|
||||
|
||||
/*
|
||||
* the following assumes that FreeBSD 3.X uses poll(2) instead of select(2).
|
||||
* This change dates to late 1997.
|
||||
*/
|
||||
#include <sys/poll.h>
|
||||
#define d_select_t d_poll_t
|
||||
|
||||
#else
|
||||
struct isa_device { int dummy ; } ;
|
||||
#define d_open_t void
|
||||
#define d_close_t void
|
||||
#define d_read_t void
|
||||
#define d_write_t void
|
||||
#define d_ioctl_t void
|
||||
#define d_select_t void
|
||||
#endif /* KERNEL */
|
||||
typedef void (irq_proc_t) (int irq);
|
||||
|
||||
#endif /* _OS_H_ */
|
||||
|
||||
/*
|
||||
* descriptor of a dma buffer. See dmabuf.c for documentation.
|
||||
* (rp,rl) and (fp,fl) identify the READY and FREE regions of the
|
||||
* buffer. dl contains the length used for dma transfer, dl>0 also
|
||||
* means that the channel is busy and there is a DMA transfer in progress.
|
||||
*/
|
||||
|
||||
typedef struct _snd_dbuf {
|
||||
char *buf;
|
||||
int bufsize ;
|
||||
volatile int rp, fp; /* pointers to the ready and free area */
|
||||
volatile int dl; /* transfer size */
|
||||
volatile int rl, fl; /* lenght of ready and free areas. */
|
||||
int int_count;
|
||||
int chan; /* dma channel */
|
||||
int sample_size ; /* 1, 2, 4 */
|
||||
struct selinfo sel;
|
||||
u_long total; /* total bytes processed */
|
||||
u_long prev_total; /* copy of the above when GETxPTR called */
|
||||
} snd_dbuf ;
|
||||
|
||||
/*
|
||||
* descriptor of audio operations ...
|
||||
*
|
||||
*/
|
||||
typedef struct _snddev_info snddev_info ;
|
||||
typedef int (snd_callback_t)(snddev_info *d, int reason);
|
||||
|
||||
struct _snddev_info {
|
||||
|
||||
/*
|
||||
* the first part of the descriptor is filled up from a
|
||||
* template.
|
||||
*/
|
||||
char name[64];
|
||||
|
||||
int type ;
|
||||
|
||||
int (*probe)(struct isa_device * dev);
|
||||
int (*attach)(struct isa_device * dev) ;
|
||||
d_open_t *open ;
|
||||
d_close_t *close ;
|
||||
d_read_t *read ;
|
||||
d_write_t *write ;
|
||||
d_ioctl_t *ioctl ;
|
||||
d_select_t *select ;
|
||||
irq_proc_t *isr ;
|
||||
snd_callback_t *callback;
|
||||
|
||||
int bufsize; /* space used for buffers */
|
||||
|
||||
u_long audio_fmt ; /* supported audio formats */
|
||||
|
||||
|
||||
/*
|
||||
* combinations of the following flags are used as second argument in
|
||||
* the callback from the dma module to the device-specific routines.
|
||||
*/
|
||||
|
||||
#define SND_CB_RD 0x100 /* read callback */
|
||||
#define SND_CB_WR 0x200 /* write callback */
|
||||
#define SND_CB_REASON_MASK 0xff
|
||||
#define SND_CB_START 0x01 /* start dma op */
|
||||
#define SND_CB_STOP 0x03 /* stop dma op */
|
||||
#define SND_CB_ABORT 0x04 /* abort dma op */
|
||||
#define SND_CB_INIT 0x05 /* init board parameters */
|
||||
|
||||
/*
|
||||
* callback extensions
|
||||
*/
|
||||
#define SND_CB_DMADONE 0x10
|
||||
#define SND_CB_DMAUPDATE 0x11
|
||||
#define SND_CB_DMASTOP 0x12
|
||||
|
||||
/* init can only be called with int enabled and
|
||||
* no pending DMA activity.
|
||||
*/
|
||||
|
||||
/*
|
||||
* whereas from here, parameters are set at runtime.
|
||||
* io_base == 0 means that the board is not configured.
|
||||
*/
|
||||
|
||||
int io_base ; /* primary I/O address for the board */
|
||||
int alt_base ; /* some codecs are accessible as SB+MSS... */
|
||||
int conf_base ; /* and the opti931 also has a config space */
|
||||
int mix_base ; /* base for the mixer... */
|
||||
int midi_base ; /* base for the midi */
|
||||
|
||||
int irq ;
|
||||
int bd_id ; /* used to hold board-id info, eg. sb version,
|
||||
* mss codec type, etc. etc.
|
||||
*/
|
||||
|
||||
snd_dbuf dbuf_out, dbuf_in;
|
||||
|
||||
int status_ptr; /* used to implement sndstat */
|
||||
|
||||
/*
|
||||
* these parameters describe the operation of the board.
|
||||
* Generic things like busy flag, speed, etc are here.
|
||||
*/
|
||||
|
||||
volatile u_long flags ; /* 32 bits, used for various purposes. */
|
||||
|
||||
/*
|
||||
* we have separate flags for read and write, although in some
|
||||
* cases this is probably not necessary (e.g. because we cannot
|
||||
* know how many processes are using the device, we cannot
|
||||
* distinguish if open, close, abort are for a write or for a
|
||||
* read).
|
||||
*/
|
||||
|
||||
/*
|
||||
* the following flag is used by open-close routines
|
||||
* to mark the status of the device.
|
||||
*/
|
||||
#define SND_F_BUSY 0x0001 /* has been opened */
|
||||
/*
|
||||
* Only the last close for a device will propagate to the driver.
|
||||
* Unfortunately, voxware uses 3 different minor numbers
|
||||
* (dsp, dsp16 and audio) to access the same unit. So, if
|
||||
* we want to support multiple opens and still keep track of
|
||||
* what is happening, we also need a separate flag for each minor
|
||||
* number. These are below...
|
||||
*/
|
||||
#define SND_F_BUSY_AUDIO 0x10000000
|
||||
#define SND_F_BUSY_DSP 0x20000000
|
||||
#define SND_F_BUSY_DSP16 0x40000000
|
||||
#define SND_F_BUSY_ANY 0x70000000
|
||||
#define SND_F_BUSY_SYNTH 0x80000000
|
||||
/*
|
||||
* the next two are used to allow only one pending operation of
|
||||
* each type.
|
||||
*/
|
||||
#define SND_F_READING 0x0004 /* have a pending read */
|
||||
#define SND_F_WRITING 0x0008 /* have a pending write */
|
||||
/*
|
||||
* these mark pending DMA operations. When you have pending dma ops,
|
||||
* you might get interrupts, so some manipulations of the
|
||||
* descriptors must be done with interrupts blocked.
|
||||
*/
|
||||
#if 0
|
||||
#define SND_F_RD_DMA 0x0010 /* read-dma active */
|
||||
#define SND_F_WR_DMA 0x0020 /* write-dma active */
|
||||
|
||||
#define SND_F_PENDING_IN (SND_F_READING | SND_F_RD_DMA)
|
||||
#define SND_F_PENDING_OUT (SND_F_WRITING | SND_F_WR_DMA)
|
||||
#endif
|
||||
#define SND_F_PENDING_IO (SND_F_READING | SND_F_WRITING)
|
||||
|
||||
/*
|
||||
* flag used to mark a pending close.
|
||||
*/
|
||||
#define SND_F_CLOSING 0x0040 /* a pending close */
|
||||
|
||||
/*
|
||||
* if user has not set block size, then make it adaptive
|
||||
* (0.25s, or the perhaps last read/write ?)
|
||||
*/
|
||||
#define SND_F_HAS_SIZE 0x0080 /* user set block size */
|
||||
/*
|
||||
* assorted flags related to operating mode.
|
||||
*/
|
||||
#define SND_F_STEREO 0x0100 /* doing stereo */
|
||||
#define SND_F_NBIO 0x0200 /* do non-blocking i/o */
|
||||
|
||||
/*
|
||||
* the user requested ulaw, but the board does not support it
|
||||
* natively, so a (software) format conversion is necessary.
|
||||
* The kernel is not really the place to do this, but since
|
||||
* many applications expect to use /dev/audio , we do it for
|
||||
* portability.
|
||||
*/
|
||||
#define SND_F_XLAT8 0x0400 /* u-law <--> 8-bit unsigned */
|
||||
#define SND_F_XLAT16 0x0800 /* u-law <--> 16-bit signed */
|
||||
|
||||
/*
|
||||
* these flags mark a pending abort on a r/w operation.
|
||||
*/
|
||||
#define SND_F_ABORTING 0x1000 /* a pending abort */
|
||||
|
||||
/*
|
||||
* this is used to mark that board initialization is needed, e.g.
|
||||
* because of a change in sampling rate, format, etc. -- It will
|
||||
* be done at the next convenient time.
|
||||
*/
|
||||
#define SND_F_INIT 0x4000 /* changed parameters. need init */
|
||||
|
||||
u_long bd_flags; /* board-specific flags */
|
||||
int play_speed, rec_speed;
|
||||
|
||||
int play_blocksize, rec_blocksize; /* blocksize for io and dma ops */
|
||||
u_long play_fmt, rec_fmt ; /* current audio format */
|
||||
|
||||
/*
|
||||
* mixer parameters
|
||||
*/
|
||||
u_long mix_devs; /* existing devices for mixer */
|
||||
u_long mix_rec_devs; /* possible recording sources */
|
||||
u_long mix_recsrc; /* current recording source(s) */
|
||||
u_short mix_levels[32];
|
||||
|
||||
#define wsel dbuf_out.sel
|
||||
#define rsel dbuf_in.sel
|
||||
u_long interrupts; /* counter of interrupts */
|
||||
u_long magic;
|
||||
#define MAGIC(unit) ( 0xa4d10de0 + unit )
|
||||
int synth_base ; /* base for the synth */
|
||||
int synth_type ; /* type of synth */
|
||||
void *device_data ; /* just in case it is needed...*/
|
||||
int special_dma ;
|
||||
/* when this is set, dsp_wr_dmaupdate etc.
|
||||
* are processed using callback extensions.
|
||||
*/
|
||||
} ;
|
||||
|
||||
/*
|
||||
* then ioctls and other stuff
|
||||
*/
|
||||
|
||||
#define NPCM_MAX 8 /* Number of supported devices */
|
||||
|
||||
/*
|
||||
* values used in bd_id for the mss boards
|
||||
*/
|
||||
#define MD_AD1848 0x91
|
||||
#define MD_AD1845 0x92
|
||||
#define MD_AD1816 0x93
|
||||
#define MD_CS4248 0xA1
|
||||
#define MD_CS4231 0xA2
|
||||
#define MD_CS4231A 0xA3
|
||||
#define MD_CS4232 0xA4
|
||||
#define MD_CS4232A 0xA5
|
||||
#define MD_CS4236 0xA6
|
||||
#define MD_CS4237 0xA7
|
||||
#define MD_OPTI931 0xB1
|
||||
#define MD_GUSPNP 0xB8
|
||||
#define MD_YM0020 0xC1
|
||||
#define MD_VIVO 0xD1
|
||||
|
||||
/*
|
||||
* TODO: add some card classes rather than specific types.
|
||||
*/
|
||||
#include <sys/soundcard.h>
|
||||
/*
|
||||
* many variables should be reduced to a range. Here define a macro
|
||||
*/
|
||||
|
||||
#define RANGE(var, low, high) (var) = \
|
||||
((var)<(low)?(low) : (var)>(high)?(high) : (var))
|
||||
|
||||
/*
|
||||
* finally, all default parameters
|
||||
*/
|
||||
#define DSP_BUFFSIZE (65536 - 256) /* XXX */
|
||||
/*
|
||||
* the last 256 bytes are room for buggy soundcard to overflow.
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
#include "pnp.h"
|
||||
#if NPNP > 0
|
||||
#include <i386/isa/pnp.h> /* XXX pnp support */
|
||||
#endif
|
||||
#endif /* KERNEL */
|
||||
|
||||
/*
|
||||
* Minor numbers for the sound driver.
|
||||
*
|
||||
* Unfortunately Creative called the codec chip of SB as a DSP. For this
|
||||
* reason the /dev/dsp is reserved for digitized audio use. There is a
|
||||
* device for true DSP processors but it will be called something else.
|
||||
* In v3.0 it's /dev/sndproc but this could be a temporary solution.
|
||||
*/
|
||||
|
||||
|
||||
#define SND_DEV_CTL 0 /* Control port /dev/mixer */
|
||||
#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
|
||||
synthesizer and MIDI output) */
|
||||
#define SND_DEV_MIDIN 2 /* Raw midi access */
|
||||
#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
|
||||
#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
|
||||
#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
|
||||
#define SND_DEV_STATUS 6 /* /dev/sndstat */
|
||||
/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
|
||||
#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
|
||||
#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
|
||||
#define SND_DEV_PSS SND_DEV_SNDPROC
|
||||
|
||||
#define DSP_DEFAULT_SPEED 8000
|
||||
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
|
||||
|
||||
#define SYNTH_MAX_VOICES 32
|
||||
|
||||
struct voice_alloc_info {
|
||||
int max_voice;
|
||||
int used_voices;
|
||||
int ptr; /* For device specific use */
|
||||
u_short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
|
||||
int timestamp;
|
||||
int alloc_times[SYNTH_MAX_VOICES];
|
||||
};
|
||||
|
||||
struct channel_info {
|
||||
int pgm_num;
|
||||
int bender_value;
|
||||
u_char controllers[128];
|
||||
};
|
||||
|
||||
/*
|
||||
* mixer description structure and macros
|
||||
*/
|
||||
|
||||
struct mixer_def {
|
||||
u_int regno:7;
|
||||
u_int polarity:1; /* 1 means reversed */
|
||||
u_int bitoffs:4;
|
||||
u_int nbits:4;
|
||||
};
|
||||
typedef struct mixer_def mixer_ent;
|
||||
typedef struct mixer_def mixer_tab[32][2];
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
#define FULL_DUPLEX(d) (d->dbuf_out.chan != d->dbuf_in.chan)
|
||||
#define MIX_ENT(name, reg_l, pol_l, pos_l, len_l, reg_r, pol_r, pos_r, len_r) \
|
||||
{{reg_l, pol_l, pos_l, len_l}, {reg_r, pol_r, pos_r, len_r}}
|
||||
#define PMIX_ENT(name, reg_l, pos_l, len_l, reg_r, pos_r, len_r) \
|
||||
{{reg_l, 0, pos_l, len_l}, {reg_r, 0, pos_r, len_r}}
|
||||
|
||||
#define MIX_NONE(name) MIX_ENT(name, 0,0,0,0, 0,0,0,0)
|
||||
|
||||
/*
|
||||
* some macros for debugging purposes
|
||||
* DDB/DEB to enable/disable debugging stuff
|
||||
* BVDDB to enable debugging when bootverbose
|
||||
*/
|
||||
#define DDB(x) x /* XXX */
|
||||
#define BVDDB(x) if (bootverbose) x
|
||||
|
||||
#ifndef DEB
|
||||
#define DEB(x)
|
||||
#endif
|
||||
|
||||
extern snddev_info pcm_info[NPCM_MAX] ;
|
||||
extern snddev_info midi_info[NPCM_MAX] ;
|
||||
extern snddev_info synth_info[NPCM_MAX] ;
|
||||
|
||||
extern u_long nsnd ;
|
||||
extern snddev_info *snddev_last_probed;
|
||||
|
||||
int pcmprobe(struct isa_device * dev);
|
||||
int midiprobe(struct isa_device * dev);
|
||||
int synthprobe(struct isa_device * dev);
|
||||
int pcmattach(struct isa_device * dev);
|
||||
int pcminit(snddev_info *d, int unit);
|
||||
int midiattach(struct isa_device * dev);
|
||||
int synthattach(struct isa_device * dev);
|
||||
|
||||
ointhand2_t pcmintr;
|
||||
|
||||
/*
|
||||
* DMA buffer calls
|
||||
*/
|
||||
|
||||
void dsp_wrintr(snddev_info *d);
|
||||
void dsp_rdintr(snddev_info *d);
|
||||
int dsp_write_body(snddev_info *d, struct uio *buf);
|
||||
int dsp_read_body(snddev_info *d, struct uio *buf);
|
||||
void alloc_dbuf(snd_dbuf *d, int size);
|
||||
|
||||
int snd_flush(snddev_info *d);
|
||||
|
||||
/* the following parameters are used in snd_sync and reset_dbuf
|
||||
* to decide whether or not to restart a channel
|
||||
*/
|
||||
#define SND_CHAN_NONE 0x0
|
||||
#define SND_CHAN_WR 0x1
|
||||
#define SND_CHAN_RD 0x2
|
||||
|
||||
void reset_dbuf(snd_dbuf *b, int chan);
|
||||
int snd_sync(snddev_info *d, int chan, int threshold);
|
||||
int dsp_wrabort(snddev_info *d, int restart);
|
||||
int dsp_rdabort(snddev_info *d, int restart);
|
||||
void dsp_wr_dmaupdate(snd_dbuf *b);
|
||||
void dsp_rd_dmaupdate(snd_dbuf *b);
|
||||
|
||||
d_select_t sndselect;
|
||||
|
||||
/*
|
||||
* library functions (in sound.c)
|
||||
*/
|
||||
|
||||
int ask_init(snddev_info *d);
|
||||
void translate_bytes(u_char *table, u_char *buff, int n);
|
||||
void change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval);
|
||||
int snd_conflict(int io_base);
|
||||
void snd_set_blocksize(snddev_info *d);
|
||||
int isa_dmastatus1(int channel);
|
||||
/*
|
||||
* routines in ad1848.c and sb_dsp.c which others might use
|
||||
*/
|
||||
int mss_detect (struct isa_device *dev);
|
||||
int sb_cmd (int io_base, u_char cmd);
|
||||
int sb_cmd2 (int io_base, u_char cmd, int val);
|
||||
int sb_cmd3 (int io_base, u_char cmd, int val);
|
||||
int sb_reset_dsp (int io_base);
|
||||
void sb_setmixer (int io_base, u_int port, u_int value);
|
||||
int sb_getmixer (int io_base, u_int port);
|
||||
|
||||
#endif /* KERNEL */
|
||||
|
||||
/*
|
||||
* usage of flags in device config entry (config file)
|
||||
*/
|
||||
|
||||
#define DV_F_DRQ_MASK 0x00000007 /* mask for secondary drq */
|
||||
#define DV_F_DUAL_DMA 0x00000010 /* set to use secondary dma channel */
|
||||
#define DV_F_DEV_MASK 0x0000ff00 /* force device type/class */
|
||||
#define DV_F_DEV_SHIFT 8 /* force device type/class */
|
||||
|
||||
/*
|
||||
* some flags are used in a device-specific manner, so that values can
|
||||
* be used multiple times.
|
||||
*/
|
||||
|
||||
#define DV_F_TRUE_MSS 0x00010000 /* mss _with_ base regs */
|
||||
/* almost all modern cards do not have this set of registers,
|
||||
* so it is better to make this the default behaviour
|
||||
*/
|
||||
|
||||
/*
|
||||
* the following flags are for PnP cards only and are undocumented
|
||||
*/
|
||||
#define DV_PNP_SBCODEC 0x1
|
||||
|
||||
#endif
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* on entry: ulaw, on exit: unsigned 8 bit.
|
||||
*/
|
||||
static unsigned char ulaw_dsp[] = {
|
||||
3, 7, 11, 15, 19, 23, 27, 31,
|
||||
35, 39, 43, 47, 51, 55, 59, 63,
|
||||
66, 68, 70, 72, 74, 76, 78, 80,
|
||||
82, 84, 86, 88, 90, 92, 94, 96,
|
||||
98, 99, 100, 101, 102, 103, 104, 105,
|
||||
106, 107, 108, 109, 110, 111, 112, 113,
|
||||
113, 114, 114, 115, 115, 116, 116, 117,
|
||||
117, 118, 118, 119, 119, 120, 120, 121,
|
||||
121, 121, 122, 122, 122, 122, 123, 123,
|
||||
123, 123, 124, 124, 124, 124, 125, 125,
|
||||
125, 125, 125, 125, 126, 126, 126, 126,
|
||||
126, 126, 126, 126, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 127,
|
||||
128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128,
|
||||
253, 249, 245, 241, 237, 233, 229, 225,
|
||||
221, 217, 213, 209, 205, 201, 197, 193,
|
||||
190, 188, 186, 184, 182, 180, 178, 176,
|
||||
174, 172, 170, 168, 166, 164, 162, 160,
|
||||
158, 157, 156, 155, 154, 153, 152, 151,
|
||||
150, 149, 148, 147, 146, 145, 144, 143,
|
||||
143, 142, 142, 141, 141, 140, 140, 139,
|
||||
139, 138, 138, 137, 137, 136, 136, 135,
|
||||
135, 135, 134, 134, 134, 134, 133, 133,
|
||||
133, 133, 132, 132, 132, 132, 131, 131,
|
||||
131, 131, 131, 131, 130, 130, 130, 130,
|
||||
130, 130, 130, 130, 129, 129, 129, 129,
|
||||
129, 129, 129, 129, 129, 129, 129, 129,
|
||||
128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128,
|
||||
128, 128, 128, 128, 128, 128, 128, 128,
|
||||
};
|
||||
|
||||
#ifndef DSP_ULAW_NOT_WANTED
|
||||
static unsigned char dsp_ulaw[] = {
|
||||
0, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 3, 3, 3,
|
||||
3, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7,
|
||||
7, 8, 8, 8, 8, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 11, 11, 11,
|
||||
11, 12, 12, 12, 12, 13, 13, 13,
|
||||
13, 14, 14, 14, 14, 15, 15, 15,
|
||||
15, 16, 16, 17, 17, 18, 18, 19,
|
||||
19, 20, 20, 21, 21, 22, 22, 23,
|
||||
23, 24, 24, 25, 25, 26, 26, 27,
|
||||
27, 28, 28, 29, 29, 30, 30, 31,
|
||||
31, 32, 33, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46,
|
||||
47, 49, 51, 53, 55, 57, 59, 61,
|
||||
63, 66, 70, 74, 78, 84, 92, 104,
|
||||
254, 231, 219, 211, 205, 201, 197, 193,
|
||||
190, 188, 186, 184, 182, 180, 178, 176,
|
||||
175, 174, 173, 172, 171, 170, 169, 168,
|
||||
167, 166, 165, 164, 163, 162, 161, 160,
|
||||
159, 159, 158, 158, 157, 157, 156, 156,
|
||||
155, 155, 154, 154, 153, 153, 152, 152,
|
||||
151, 151, 150, 150, 149, 149, 148, 148,
|
||||
147, 147, 146, 146, 145, 145, 144, 144,
|
||||
143, 143, 143, 143, 142, 142, 142, 142,
|
||||
141, 141, 141, 141, 140, 140, 140, 140,
|
||||
139, 139, 139, 139, 138, 138, 138, 138,
|
||||
137, 137, 137, 137, 136, 136, 136, 136,
|
||||
135, 135, 135, 135, 134, 134, 134, 134,
|
||||
133, 133, 133, 133, 132, 132, 132, 132,
|
||||
131, 131, 131, 131, 130, 130, 130, 130,
|
||||
129, 129, 129, 129, 128, 128, 128, 128,
|
||||
};
|
||||
#endif /* !DSP_ULAW_NOT_WANTED */
|
Loading…
Reference in New Issue
Block a user