Commit bbf5aea1 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Linus Torvalds

[PATCH] ALSA patch for 2.5.6pre2

Hello,

	this recent ALSA patch includes:

- added initial version of Config.help files
- moved /proc/asound/sndstat to /proc/asound/oss/sndstat
- moved /proc/asound/oss-devices to /proc/asound/oss/devices
- snd-rtctimer updates (blocking of RTC driver change)
- added ioctl conversion code for 32-bit applications running on 64-bit kernels
- fixed dependencies in makefiles
- wavefront driver cleanups (removed LOOPS_PER_SEC)
- created Documentation/sound/alsa directory

						Jaroslav
parent adc4bc97
Brief Notes on C-Media 8738/8338 Driver
=======================================
Takashi Iwai <tiwai@suse.de>
Front/Rear Multi-channel Playback
---------------------------------
CM8x38 chip can use ADC as the second DAC so that two different stereo
channels can be used for front/rear playbacks. Since there are two
DACs, both streams are handled independently unlike the 4/6ch multi-
channel playbacks in the section below.
As default, ALSA driver assigns the first PCM device (i.e. hw:0,0 for
card#0) for front and 4/6ch playbacks, while the second PCM device
(hw:0,1) is assigned to the second DAC for rear playback.
There are slight difference between two DACs.
- The first DAC supports U8 and S16LE formats, while the second DAC
supports only S16LE.
- The second DAC supports only two channel stereo.
Please note that the CM8x38 DAC doesn't support continuous playback
rate but only fixed rates: 5512, 8000, 11025, 16000, 22050, 32000,
44100 and 48000 Hz.
The rear output can be heard only when "Four Channel Mode" switch is
disabled. Otherwise no signal will be routed to the rear speakers.
As default it's turned on.
*** WARNING ***
When "Four Channel Mode" switch is off, the output from rear speakers
will be FULL VOLUME regardless of Master and PCM volumes.
This might damage your audio equipment. Please disconnect speakers
before your turn off this switch.
*** WARNING ***
[ Well.. I once got the output with correct volume (i.e. same with the
front one) and was so excited. It was even with "Four Channel" bit
on and "double DAC" mode. Actually I could hear separate 4 channels
from front and rear speakers! But.. after reboot, all was gone.
It's a very pity that I didn't save the register dump at that
time.. Maybe there is an unknown register to achieve this... ]
If your card has an extra output jack for the rear output, the rear
playback should be routed there as default. If not, there is a
control switch in the driver "Line-In As Rear", which you can change
via alsamixer or somewhat else. When this switch is on, line-in jack
is used as rear output.
There are two more controls regarding to the rear output.
The "Exchange DAC" switch is used to exchange front and rear playback
routes, i.e. the 2nd DAC is output from front output.
4/6 Multi-Channel Playback
--------------------------
The recent CM8738 chips support for the 4/6 multi-channel playback
function. This is useful especially for AC3 decoding.
When the multi-channel is supported, the driver name has a suffix
"-MC" such like "CMI8738-MC6". You can check this name from
/proc/asound/cards.
When the 4/6-ch output is enabled, the front DAC accepts up to 6 (or
4) channels. This is different from the dual DACs described in the
previous section. While the dual DAC supports two different rates or
formats, the 4/6-ch playback supports only the same condition for all
channels.
For using 4/6 channel playback, you need to specify the PCM channels
as you like and set the format S16LE. For example, for playback with
4 channels,
snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
// or mmap if you like
snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(pcm, hw, 4);
and use the interleaved 4 channel data.
There is a control switch, "Line-In As Bass". As you can imagine from
its name, the line-in jack is used for the bass (5th and 6th channels)
output.
Digital I/O
-----------
The CM8x38 provides the excellent SPDIF capability with very chip
price (yes, that's the reason I bought the card :)
The SPDIF playback and capture are done via the third PCM device
(hw:0,2). Usually this is assigned to the PCM device "spdif".
The available rates are 44100 and 48000 Hz.
For playback with aplay, you can run like below:
% aplay -Dhw:0,2 foo.wav
or
% aplay -Dspdif foo.wav
So far, only S16LE format is supported. Still no 24bit. Sorry, not
enough info for this.
The playback and capture over SPDIF use normal DAC and ADC,
respectively, so you cannot playback both analog and digital streams
simultaneously.
To enable SPDIF output, you need to turn on "IEC958 Output Switch"
control via mixer or alsactl. Then you'll see the red light on from
the card so you know that's working obviously :)
The SPDIF input is always enabled, so you can hear SPDIF input data
from line-out with "IEC958 In Monitor" switch at any time (see
below).
You can play via SPDIF even with the first device (hw:0,0),
but SPDIF is enabled only when the proper format (S16LE), sample rate
(441100 or 48000) and channels (2) are used. Otherwise it's turned
off. (Also don't forget to turn on "IEC958 Output Switch", too.)
Additionally there are relevant control switches:
"IEC958 Mix Analog" - Mix analog PCM playback and FM-OPL/3 streams and
output through SPDIF. This switch appears only on old chip
models (CM8738 033 and 037).
Note: without this control you can output PCM to SPDIF.
This is "mixing" of streams, so e.g. it's not for AC3 output
(see the next section).
"IEC958 In Select" - Select SPDIF input, the internal CD-in (false)
and the external input (true). This switch appears only on
the chip models 039 or later.
"IEC958 Loop" - SPDIF input data is loop back into SPDIF
output (aka bypass)
"IEC958 Copyright" - Set the copyright bit.
"IEC958 5V" - Select 0.5V (coax) or 5V (optical) interface.
On some cards this doesn't work and you need to change the
configuration with hardware dip-switch.
"IEC958 In Monitor" - SPDIF input is routed to DAC.
"IEC958 In Phase Inverse" - Set SPDIF input format as inverse.
[FIXME: this doesn't work on all chips..]
"IEC958 In Valid" - Set input validity flag detection.
Note: When "PCM Playback Switch" is on, you'll hear the digital output
stream through analog line-out.
The AC3 (RAW DIGITAL) OUTPUT
----------------------------
The driver supports raw digital (typically AC3) i/o over SPDIF. This
can be toggled via IEC958 playback control, but usually you need to
access it via alsa-lib. See alsa-lib documents for more details.
On the raw digital mode, the "PCM Playback Switch" is automatically
turned off so that non-audio data is heard from the analog line-out.
Similarly the following switches are off: "IEC958 Mix Analog" and
"IEC958 Loop". The switches are resumed after closing the SPDIF PCM
device automatically to the previous state.
ANALOG MIXER INTERFACE
----------------------
The mixer interface on CM8x38 is similar to SB16.
There are Master, PCM, Synth, CD, Line, Mic and PC Speaker playback
volumes. Synth, CD, Line and Mic have playback and capture switches,
too, as well as SB16.
In addition to the standard SB mixer, CM8x38 provides more functions.
- PCM playback switch
- PCM capture switch (to capture the data sent to DAC)
- Mic Boost switch
- Mic capture volume
- Aux playback volume/switch and capture switch
- 3D control switch
MIDI CONTROLLER
---------------
The MPU401-UART interface is enabled as default only for the first
(CMIPCI) card. You need to set module option "snd_midi_port" properly
for the 2nd (CMIPCI) card.
There is _no_ hardware wavetable function on this chip (except for
OPL3 synth below).
What's said as MIDI synth on Windows is a software synthesizer
emulation. On Linux use TiMidity or other softsynth program for
playing MIDI music.
FM OPL/3 Synth
--------------
The FM OPL/3 is also enabled as default only for the first card.
Set "snd_fm_port" module option for more cards.
The output quality of FM OPL/3 is, however, very weird.
I don't know why..
Joystick and Modem
------------------
The joystick and modem should be available by enabling the control
switch "Joystick" and "Modem" respectively. But I myself have never
tested them yet.
Debugging Information
---------------------
The registers are shown in /proc/asound/cardX/cmipci. If you have any
problem (especially unexpected behavior of mixer), please attach the
output of this proc file together with the bug report.
Sound Blaster Live mixer / default DSP code
===========================================
The EMU10K1 chips have a DSP part which can be programmed to support
various ways of sample processing, which is described here.
(This acticle does not deal with the overall functionality of the
EMU10K1 chips. See the manuals section for further details.)
The ALSA driver programs this portion of chip by default code
(can be altered later) which offers the following functionality:
1) IEC958 (S/PDIF) raw PCM
--------------------------
This PCM device (it's the 4th PCM device (index 3!) and first subdevice
(index 0) for a given card) allows to forward 48kHz, stereo, 16-bit
little endian streams without any modifications to the digital output
(coaxial or optical). The universal interface allows the creation of up
to 8 raw PCM devices operating at 48kHz, 16-bit little endian. It would
be easy to add support for multichannel devices to the current code,
but the conversion routines exist only for stereo (2-channel streams)
at the time.
Look to tram_poke routines in lowlevel/emu10k1/emufx.c for more details.
2) Digital mixer controls
-------------------------
These controls are built using the DSP instructions. They offer extended
functionality. Only the default build-in code in the ALSA driver is described
here. Note that the controls work as attenuators: the maximum value is the
neutral position leaving the signal unchanged. Note that if the same destination
is mentioned in multiple controls, the signal is accumulated and can be wrapped
(set to maximal or minimal value without checking of overflow).
Explanation of used abbreviations:
DAC - digital to analog converter
ADC - analog to digital converter
I2S - one-way three wire serial bus for digital sound by Philips Semiconductors
(this standard is used for connecting standalone DAC and ADC converters)
LFE - low frequency effects (subwoofer signal)
AC97 - a chip containing an analog mixer, DAC and ADC converters
IEC958 - S/PDIF
FX-bus - the EMU10K1 chip has an effect bus containing 16 accumulators.
Each of the synthesizer voices can feed its output to these accumulators
and the DSP microcontroller can operate with the resulting sum.
name='Wave Playback Volume',index=0
This control is used to attenuate samples for left and right PCM FX-bus
accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
name='Wave Surround Playback Volume',index=0
This control is used to attenuate samples for left and right PCM FX-bus
accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
The result samples are forwarded to the rear I2S DACs. These DACs operates
separately (they are not inside the AC97 codec).
name='Wave Center Playback Volume',index=0
This control is used to attenuate samples for left and right PCM FX-bus
accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
The result is mixed to mono signal (single channel) and forwarded to
the ??rear?? right DAC PCM slot of the AC97 codec.
name='Wave LFE Playback Volume',index=0
This control is used to attenuate samples for left and right PCM FX-bus
accumulators. ALSA uses accumulators 0 and 1 for left and right PCM.
The result is mixed to mono signal (single channel) and forwarded to
the ??rear?? left DAC PCM slot of the AC97 codec.
name='Wave Capture Volume',index=0
name='Wave Capture Switch',index=0
These controls are used to attenuate samples for left and right PCM FX-bus
accumulator. ALSA uses accumulators 0 and 1 for left and right PCM.
The result is forwarded to the ADC capture FIFO (thus to the standard capture
PCM device).
name='Music Playback Volume',index=0
This control is used to attenuate samples for left and right MIDI FX-bus
accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples.
The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
name='Music Capture Volume',index=0
name='Music Capture Switch',index=0
These controls are used to attenuate samples for left and right MIDI FX-bus
accumulator. ALSA uses accumulators 4 and 5 for left and right PCM.
The result is forwarded to the ADC capture FIFO (thus to the standard capture
PCM device).
name='Surround Digital Playback Volume',index=0
This control is used to attenuate samples for left and right rear PCM FX-bus
accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples.
The result samples are forwarded to the rear I2S DACs. These DACs operate
separately (they are not inside the AC97 codec).
name='Surround Digital Capture Volume',index=0
name='Surround Digital Capture Switch',index=0
These controls are used to attenuate samples for left and right rear PCM FX-bus
accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples.
The result is forwarded to the ADC capture FIFO (thus to the standard capture
PCM device).
name='Center Playback Volume',index=0
This control is used to attenuate sample for center PCM FX-bus accumulator.
ALSA uses accumulator 6 for center PCM sample. The result sample is forwarded
to the ??rear?? right DAC PCM slot of the AC97 codec.
name='LFE Playback Volume',index=0
This control is used to attenuate sample for center PCM FX-bus accumulator.
ALSA uses accumulator 6 for center PCM sample. The result sample is forwarded
to the ??rear?? left DAC PCM slot of the AC97 codec.
name='AC97 Playback Volume',index=0
This control is used to attenuate samples for left and right front ADC PCM slots
of the AC97 codec. The result samples are forwarded to the front DAC PCM
slots of the AC97 codec.
********************************************************************************
*** Note: This control should be zero for the standard operations, otherwise ***
*** a digital loopback is activated. ***
********************************************************************************
name='AC97 Capture Volume',index=0
This control is used to attenuate samples for left and right front ADC PCM slots
of the AC97 codec. The result is forwarded to the ADC capture FIFO (thus to
the standard capture PCM device).
********************************************************************************
*** Note: This control should be 100 (maximal value), otherwise no analog ***
*** inputs of the AC97 codec can be captured (recorded). ***
********************************************************************************
name='IEC958 TTL Playback Volume',index=0
This control is used to attenuate samples from left and right IEC958 TTL
digital inputs (usually used by a CDROM drive). The result samples are
forwarded to the front DAC PCM slots of the AC97 codec.
name='IEC958 TTL Capture Volume',index=0
This control is used to attenuate samples from left and right IEC958 TTL
digital inputs (usually used by a CDROM drive). The result samples are
forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
name='Zoom Video Playback Volume',index=0
This control is used to attenuate samples from left and right zoom video
digital inputs (usually used by a CDROM drive). The result samples are
forwarded to the front DAC PCM slots of the AC97 codec.
name='Zoom Video Capture Volume',index=0
This control is used to attenuate samples from left and right zoom video
digital inputs (usually used by a CDROM drive). The result samples are
forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
name='IEC958 Optical Playback Volume',index=0
This control is used to attenuate samples from left and right IEC958 optical
digital input. The result samples are forwarded to the front DAC PCM slots
of the AC97 codec.
name='IEC958 Optical Capture Volume',index=0
This control is used to attenuate samples from left and right IEC958 optical
digital inputs. The result samples are forwarded to the ADC capture FIFO
(thus to the standard capture PCM device).
name='IEC958 Coaxial Playback Volume',index=0
This control is used to attenuate samples from left and right IEC958 coaxial
digital inputs. The result samples are forwarded to the front DAC PCM slots
of the AC97 codec.
name='IEC958 Coaxial Capture Volume',index=0
This control is used to attenuate samples from left and right IEC958 coaxial
digital inputs. The result samples are forwarded to the ADC capture FIFO
(thus to the standard capture PCM device).
name='Line LiveDrive Playback Volume',index=0
name='Line LiveDrive Playback Volume',index=1
This control is used to attenuate samples from left and right I2S ADC
inputs (on the LiveDrive). The result samples are forwarded to the front
DAC PCM slots of the AC97 codec.
name='Line LiveDrive Capture Volume',index=1
name='Line LiveDrive Capture Volume',index=1
This control is used to attenuate samples from left and right I2S ADC
inputs (on the LiveDrive). The result samples are forwarded to the ADC
capture FIFO (thus to the standard capture PCM device).
name='Tone Control - Switch',index=0
This control turns the tone control on or off. The samples for front, rear
and center / LFE outputs are affected.
name='Tone Control - Bass',index=0
This control sets the bass intensity. There is no neutral value!!
When the tone control code is activated, the samples are always modified.
The closest value to pure signal is 20.
name='Tone Control - Treble',index=0
This control sets the treble intensity. There is no neutral value!!
When the tone control code is activated, the samples are always modified.
The closest value to pure signal is 20.
name='IEC958 Optical Raw Playback Switch',index=0
If this switch is on, then the samples for the IEC958 (S/PDIF) digital
output are taken only from the raw FX8010 PCM, otherwise standard front
PCM samples are taken.
name='Headphone Playback Volume',index=1
This control attenuates the samples for the headphone output.
name='Headphone Center Playback Switch',index=1
If this switch is on, then the sample for the center PCM is put to the
left headphone output (useful for SB Live cards without separate center/LFE
output).
name='Headphone LFE Playback Switch',index=1
If this switch is on, then the sample for the center PCM is put to the
right headphone output (useful for SB Live cards without separate center/LFE
output).
3) PCM stream related controls
------------------------------
name='EMU10K1 PCM Volume',index 0-31
Channel volume attenuation in range 0-0xffff. The maximum value (no
attenuation) is default. The channel mapping for three values is
as follows:
0 - mono, default 0xffff (no attenuation)
1 - left, default 0xffff (no attenuation)
2 - right, default 0xffff (no attenuation)
name='EMU10K1 PCM Send Routing',index 0-31
This control specifies the destination - FX-bus accumulators. There are
twelve values with this mapping:
0 - mono, A destination (FX-bus 0-15), default 0
1 - mono, B destination (FX-bus 0-15), default 1
2 - mono, C destination (FX-bus 0-15), default 2
3 - mono, D destination (FX-bus 0-15), default 3
4 - left, A destination (FX-bus 0-15), default 0
5 - left, B destination (FX-bus 0-15), default 1
6 - left, C destination (FX-bus 0-15), default 2
7 - left, D destination (FX-bus 0-15), default 3
8 - right, A destination (FX-bus 0-15), default 0
9 - right, B destination (FX-bus 0-15), default 1
10 - right, C destination (FX-bus 0-15), default 2
11 - right, D destination (FX-bus 0-15), default 3
Don't forget that it's illegal to assign a channel to the same FX-bus accumulator
more than once (it means 0=0 && 1=0 is an invalid combination).
name='EMU10K1 PCM Send Volume',index 0-31
It specifies the attenuation (amount) for given destination in range 0-255.
The channel mapping is following:
0 - mono, A destination attn, default 255 (no attenuation)
1 - mono, B destination attn, default 255 (no attenuation)
2 - mono, C destination attn, default 0 (mute)
3 - mono, D destination attn, default 0 (mute)
4 - left, A destination attn, default 255 (no attenuation)
5 - left, B destination attn, default 0 (mute)
6 - left, C destination attn, default 0 (mute)
7 - left, D destination attn, default 0 (mute)
8 - right, A destination attn, default 0 (mute)
9 - right, B destination attn, default 255 (no attenuation)
10 - right, C destination attn, default 0 (mute)
11 - right, D destination attn, default 0 (mute)
4) MANUALS/PATENTS:
-------------------
ftp://opensource.creative.com/pub/doc
-------------------------------------
Files:
LM4545.pdf AC97 Codec
m2049.pdf The EMU10K1 Digital Audio Processor
hog63.ps FX8010 - A DSP Chip Architecture for Audio Effects
WIPO Patents
------------
Patent numbers:
WO 9901813 (A1) Audio Effects Processor with multiple asynchronous (Jan. 14, 1999)
streams
WO 9901814 (A1) Processor with Instruction Set for Audio Effects (Jan. 14, 1999)
WO 9901953 (A1) Audio Effects Processor having Decoupled Instruction
Execution and Audio Data Sequencing (Jan. 14, 1999)
US Patents (http://www.uspto.gov/)
----------------------------------
US 5925841 Digital Sampling Instrument employing cache memory (Jul. 20, 1999)
US 5928342 Audio Effects Processor integrated on a single chip (Jul. 27, 1999)
with a multiport memory onto which multiple asynchronous
digital sound samples can be concurrently loaded
US 5930158 Processor with Instruction Set for Audio Effects (Jul. 27, 1999)
US 6032235 Memory initialization circuit (Tram) (Feb. 29, 2000)
US 6138207 Interpolation looping of audio samples in cache connected to (Oct. 24, 2000)
system bus with prioritization and modification of bus transfers
in accordance with loop ends and minimum block sizes
US 6151670 Method for conserving memory storage using a (Nov. 21, 2000)
pool of short term memory registers
US 6195715 Interrupt control for multiple programs communicating with (Feb. 27, 2001)
a common interrupt by associating programs to GP registers,
defining interrupt register, polling GP registers, and invoking
callback routine associated with defined interrupt register
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>OSS Sequencer Emulation on ALSA</TITLE>
</HEAD>
<BODY>
<CENTER>
<H1>
<HR WIDTH="100%"></H1></CENTER>
<CENTER>
<H1>
OSS Sequencer Emulation on ALSA</H1></CENTER>
<HR WIDTH="100%">
<P>Copyright (c) 1998,1999 by Takashi Iwai
<TT><A HREF="mailto:iwai@ww.uni-erlangen.de">&lt;iwai@ww.uni-erlangen.de></A></TT>
<P>ver.0.1.8; Nov. 16, 1999
<H2>
<HR WIDTH="100%"></H2>
<H2>
1. Description</H2>
This directory contains the OSS sequencer emulation driver on ALSA. Note
that this program is still in the development state.
<P>What this does - it provides the emulation of the OSS sequencer, access
via
<TT>/dev/sequencer</TT> and <TT>/dev/music</TT> devices.
The most of applications using OSS can run if the appropriate ALSA
sequencer is prepared.
<P>The following features are emulated by this driver:
<UL>
<LI>
Normal sequencer and MIDI events:</LI>
<BR>They are converted to the ALSA sequencer events, and sent to the corresponding
port.
<LI>
Timer events:</LI>
<BR>The timer is not selectable by ioctl. The control rate is fixed to
100 regardless of HZ. That is, even on Alpha system, a tick is always
1/100 second. The base rate and tempo can be changed in <TT>/dev/music</TT>.
<LI>
Patch loading:</LI>
<BR>It purely depends on the synth drivers whether it's supported since
the patch loading is realized by callback to the synth driver.
<LI>
I/O controls:</LI>
<BR>Most of controls are accepted. Some controls
are dependent on the synth driver, as well as even on original OSS.</UL>
Furthermore, you can find the following advanced features:
<UL>
<LI>
Better queue mechanism:</LI>
<BR>The events are queued before processing them.
<LI>
Multiple applications:</LI>
<BR>You can run two or more applications simultaneously (even for OSS sequencer)!
However, each MIDI device is exclusive - that is, if a MIDI device is opened
once by some application, other applications can't use it. No such a restriction
in synth devices.
<LI>
Real-time event processing:</LI>
<BR>The events can be processed in real time without using out of bound
ioctl. To switch to real-time mode, send ABSTIME 0 event. The followed
events will be processed in real-time without queued. To switch off the
real-time mode, send RELTIME 0 event.
<LI>
<TT>/proc</TT> interface:</LI>
<BR>The status of applications and devices can be shown via <TT>/proc/asound/seq/oss</TT>
at any time. In the later version, configuration will be changed via <TT>/proc</TT>
interface, too.</UL>
<H2>
2. Installation</H2>
Run configure script with both sequencer support (<TT>--with-sequencer=yes</TT>)
and OSS emulation (<TT>--with-oss=yes</TT>) options. A module <TT>snd-seq-oss.o</TT>
will be created. If the synth module of your sound card supports for OSS
emulation (so far, only Emu8000 driver), this module will be loaded automatically.
Otherwise, you need to load this module manually.
<P>At beginning, this module probes all the MIDI ports which have been
already connected to the sequencer. Once after that, the creation and deletion
of ports are watched by announcement mechanism of ALSA sequencer.
<P>The available synth and MIDI devices can be found in proc interface.
Run "<TT>cat /proc/asound/seq/oss</TT>", and check the devices. For example,
if you use an AWE64 card, you'll see like the following:
<PRE>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OSS sequencer emulation version 0.1.8
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALSA client number 63
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALSA receiver port 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of applications: 0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of synth devices: 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synth 0: [EMU8000]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type 0x1 : subtype 0x20 : voices 32
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capabilties : ioctl enabled / load_patch enabled
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of MIDI devices: 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 0: [Emu8000 Port-0] ALSA port 65:0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability write / opened none
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 1: [Emu8000 Port-1] ALSA port 65:1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability write / opened none
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 2: [0: MPU-401 (UART)] ALSA port 64:0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability read/write / opened none</PRE>
Note that the device number may be different from the information of
<TT>/proc/asound/oss-devices</TT>
or ones of the original OSS driver. Use the device number listed in <TT>/proc/asound/seq/oss</TT>
to play via OSS sequencer emulation.
<H2>
3. Using Synthesizer Devices</H2>
Run your favorite program. I've tested playmidi-2.4, awemidi-0.4.3, gmod-3.1
and xmp-1.1.5. You can load samples via <TT>/dev/sequencer</TT> like sfxload,
too.
<P>If the lowlevel driver supports multiple access to synth devices (like
Emu8000 driver), two or more applications are allowed to run at the same
time.
<H2>
4. Using MIDI Devices</H2>
So far, only MIDI output was tested. MIDI input was not checked at all,
but hopefully it will work. Use the device number listed in <TT>/proc/asound/seq/oss</TT>.
Be aware that these numbers are mostly different from the list in
<TT>/proc/asound/oss-devices</TT>.
<H2>
5. Module Options</H2>
The following module options are available:
<UL>
<LI>
<TT>maxqlen</TT></LI>
<BR>specifies the maximum read/write queue length. This queue is private
for OSS sequencer, so that it is independent from the queue length of ALSA
sequencer. Default value is 1024.
<LI>
<TT>seq_oss_debug</TT></LI>
<BR>specifies the debug level and accepts zero (= no debug message) or
positive integer. Default value is 0.</UL>
<H2>
6. Queue Mechanism</H2>
OSS sequencer emulation uses an ALSA priority queue. The
events from <TT>/dev/sequencer</TT> are processed and put onto the queue
specified by module option.
<P>All the events from <TT>/dev/sequencer</TT> are parsed at beginning.
The timing events are also parsed at this moment, so that the events may
be processed in real-time. Sending an event ABSTIME 0 switches the operation
mode to real-time mode, and sending an event RELTIME 0 switches it off.
In the real-time mode, all events are dispatched immediately.
<P>The queued events are dispatched to the corresponding ALSA sequencer
ports after scheduled time by ALSA sequencer dispatcher.
<P>If the write-queue is full, the application sleeps until a certain amount
(as default one half) becomes empty in blocking mode. The synchronization
to write timing was implemented, too.
<P>The input from MIDI devices or echo-back events are stored on read FIFO
queue. If application reads <TT>/dev/sequencer</TT> in blocking mode, the
process will be awaked.
<H2>
7. Interface to Synthesizer Device</H2>
<H3>
7.1. Registration</H3>
To register an OSS synthesizer device, use <TT>snd_seq_oss_synth_register</TT>
function.
<PRE>int snd_seq_oss_synth_register(char *name, int type, int subtype, int nvoices,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snd_seq_oss_callback_t *oper, void *private_data)</PRE>
The arguments <TT>name</TT>, <TT>type</TT>, <TT>subtype</TT> and
<TT>nvoices</TT>
are used for making the appropriate synth_info structure for ioctl. The
return value is an index number of this device. This index must be remembered
for unregister. If registration is failed, -errno will be returned.
<P>To release this device, call <TT>snd_seq_oss_synth_unregister function</TT>:
<PRE>int snd_seq_oss_synth_unregister(int index),</PRE>
where the <TT>index</TT> is the index number returned by register function.
<H3>
7.2. Callbacks</H3>
OSS synthesizer devices have capability for sample downloading and ioctls
like sample reset. In OSS emulation, these special features are realized
by using callbacks. The registration argument oper is used to specify these
callbacks. The following callback functions must be defined:
<PRE>snd_seq_oss_callback_t:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*open)(snd_seq_oss_arg_t *p, void *closure);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*close)(snd_seq_oss_arg_t *p);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*ioctl)(snd_seq_oss_arg_t *p, unsigned int cmd, unsigned long arg);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*load_patch)(snd_seq_oss_arg_t *p, int format, const char *buf, int offs, int count);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*reset)(snd_seq_oss_arg_t *p);
Except for <TT>open</TT> and <TT>close</TT> callbacks, they are allowed
to be NULL.
<P>Each callback function takes the argument type snd_seq_oss_arg_t as the
first argument.
<PRE>struct snd_seq_oss_arg_t {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int app_index;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int file_mode;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int seq_mode;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snd_seq_addr_t addr;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *private_data;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int event_passing;
};</PRE>
The first three fields, <TT>app_index</TT>, <TT>file_mode</TT> and
<TT>seq_mode</TT>
are initialized by OSS sequencer. The <TT>app_index</TT> is the application
index which is unique to each application opening OSS sequencer. The
<TT>file_mode</TT>
is bit-flags indicating the file operation mode. See
<TT>seq_oss.h</TT>
for its meaning. The <TT>seq_mode</TT> is sequencer operation mode. In
the current version, only <TT>SND_OSSSEQ_MODE_SYNTH</TT> is used.
<P>The next two fields, <TT>addr</TT> and <TT>private_data</TT>, must be
filled by the synth driver at open callback. The <TT>addr</TT> contains
the address of ALSA sequencer port which is assigned to this device. If
the driver allocates memory for <TT>private_data</TT>, it must be released
in close callback by itself.
<P>The last field, <TT>event_passing</TT>, indicates how to translate note-on
/ off events. In <TT>PROCESS_EVENTS</TT> mode, the note 255 is regarded
as velocity change, and key pressure event is passed to the port. In <TT>PASS_EVENTS</TT>
mode, all note on/off events are passed to the port without modified. <TT>PROCESS_KEYPRESS</TT>
mode checks the note above 128 and regards it as key pressure event (mainly
for Emu8000 driver).
<H4>
7.2.1. Open Callback</H4>
The <TT>open</TT> is called at each time this device is opened by an application
using OSS sequencer. This must not be NULL. Typically, the open callback
does the following procedure:
<OL>
<LI>
Allocate private data record.</LI>
<LI>
Create an ALSA sequencer port.</LI>
<LI>
Set the new port address on arg->addr.</LI>
<LI>
Set the private data record pointer on arg->private_data.</LI>
</OL>
Note that the type bit-flags in port_info of this synth port must NOT contain
<TT>TYPE_MIDI_GENERIC</TT>
bit. Instead, <TT>TYPE_SPECIFIC</TT> should be used. Also, <TT>CAP_SUBSCRIPTION</TT>
bit should NOT be included, too. This is necessary to tell it from other
normal MIDI devices. If the open procedure succeeded, return zero. Otherwise,
return -errno.
<H4>
7.2.2 Ioctl Callback</H4>
The <TT>ioctl</TT> callback is called when the sequencer receives device-specific
ioctls. The following two ioctls should be processed by this callback:
<UL>
<LI>
<TT>IOCTL_SEQ_RESET_SAMPLES</TT></LI>
<BR>reset all samples on memory -- return 0
<LI>
<TT>IOCTL_SYNTH_MEMAVL</TT></LI>
<BR>return the available memory size
<LI>
<TT>FM_4OP_ENABLE</TT></LI>
<BR>can be ignored usually</UL>
The other ioctls are processed inside the sequencer without passing to
the lowlevel driver.
<H4>
7.2.3 Load_Patch Callback</H4>
The <TT>load_patch</TT> callback is used for sample-downloading. This callback
must read the data on user-space and transfer to each device. Return 0
if succeeded, and -errno if failed. The format argument is the patch key
in patch_info record. The buf is user-space pointer where patch_info record
is stored. The offs can be ignored. The count is total data size of this
sample data.
<H4>
7.2.4 Close Callback</H4>
The <TT>close</TT> callback is called when this device is closed by the
applicaion. If any private data was allocated in open callback, it must
be released in the close callback. The deletion of ALSA port should be
done here, too. This callback must not be NULL.
<H4>
7.2.5 Reset Callback</H4>
The <TT>reset</TT> callback is called when sequencer device is reset or
closed by applications. The callback should turn off the sounds on the
relevant port immediately, and initialize the status of the port. If this
callback is undefined, OSS seq sends a <TT>HEARTBEAT</TT> event to the
port.
<H3>
7.3 Events</H3>
Most of the events are processed by sequencer and translated to the adequate
ALSA sequencer events, so that each synth device can receive by input_event
callback of ALSA sequencer port. The following ALSA events should be implemented
by the driver:
<BR>&nbsp;
<TABLE BORDER WIDTH="75%" NOSAVE >
<TR NOSAVE>
<TD NOSAVE><B>ALSA event</B></TD>
<TD><B>Original OSS events</B></TD>
</TR>
<TR>
<TD>NOTEON</TD>
<TD>SEQ_NOTEON
<BR>MIDI_NOTEON</TD>
</TR>
<TR>
<TD>NOTE</TD>
<TD>SEQ_NOTEOFF
<BR>MIDI_NOTEOFF</TD>
</TR>
<TR NOSAVE>
<TD NOSAVE>KEYPRESS</TD>
<TD>MIDI_KEY_PRESSURE</TD>
</TR>
<TR NOSAVE>
<TD>CHANPRESS</TD>
<TD NOSAVE>SEQ_AFTERTOUCH
<BR>MIDI_CHN_PRESSURE</TD>
</TR>
<TR NOSAVE>
<TD NOSAVE>PGMCHANGE</TD>
<TD NOSAVE>SEQ_PGMCHANGE
<BR>MIDI_PGM_CHANGE</TD>
</TR>
<TR>
<TD>PITCHBEND</TD>
<TD>SEQ_CONTROLLER(CTRL_PITCH_BENDER)
<BR>MIDI_PITCH_BEND</TD>
</TR>
<TR>
<TD>CONTROLLER</TD>
<TD>MIDI_CTL_CHANGE
<BR>SEQ_BALANCE (with CTL_PAN)</TD>
</TR>
<TR>
<TD>CONTROL14</TD>
<TD>SEQ_CONTROLLER</TD>
</TR>
<TR>
<TD>REGPARAM</TD>
<TD>SEQ_CONTROLLER(CTRL_PITCH_BENDER_RANGE)</TD>
</TR>
<TR>
<TD>SYSEX</TD>
<TD>SEQ_SYSEX</TD>
</TR>
</TABLE>
<P>The most of these behavior can be realized by MIDI emulation driver
included in the Emu8000 lowlevel driver. In the future release, this module
will be independent.
<P>Some OSS events (<TT>SEQ_PRIVATE</TT> and <TT>SEQ_VOLUME</TT> events) are passed as event
type SND_SEQ_OSS_PRIVATE. The OSS sequencer passes these event 8 byte
packets without any modification. The lowlevel driver should process these
events appropriately.
<H2>
8. Interface to MIDI Device</H2>
Since the OSS emulation probes the creation and deletion of ALSA MIDI sequencer
ports automatically by receiving announcement from ALSA sequencer, the
MIDI devices don't need to be registered explicitly like synth devices.
However, the MIDI port_info registered to ALSA sequencer must include a group
name <TT>SND_SEQ_GROUP_DEVICE</TT> and a capability-bit <TT>CAP_READ</TT> or
<TT>CAP_WRITE</TT>. Also, subscription capabilities, <TT>CAP_SUBS_READ</TT> or <TT>CAP_SUBS_WRITE</TT>,
must be defined, too. If these conditions are not satisfied, the port is not
registered as OSS sequencer MIDI device.
<P>The events via MIDI devices are parsed in OSS sequencer and converted
to the corresponding ALSA sequencer events. The input from MIDI sequencer
is also converted to MIDI byte events by OSS sequencer. This works just
a reverse way of seq_midi module.
<H2>
9. Known Problems / TODO's</H2>
<UL>
<LI>
Patch loading via ALSA instrument layer is not implemented yet.</LI>
</UL>
</BODY>
</HTML>
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
* *
*/ */
#ifdef CONFIG_PM
#include <linux/sched.h> /* wake_up() and struct semaphore */
#endif
/* Typedef's */ /* Typedef's */
typedef struct timeval snd_timestamp_t; typedef struct timeval snd_timestamp_t;
typedef struct sndrv_interval snd_interval_t; typedef struct sndrv_interval snd_interval_t;
......
...@@ -78,12 +78,4 @@ void snd_wrapper_vfree(void *); ...@@ -78,12 +78,4 @@ void snd_wrapper_vfree(void *);
#include "sndmagic.h" #include "sndmagic.h"
/*
* Temporary hack, until linux/init.h is fixed.
*/
#include <linux/init.h>
#ifndef __devexit_p
#define __devexit_p(x) x
#endif
#endif /* __SOUND_DRIVER_H */ #endif /* __SOUND_DRIVER_H */
...@@ -104,6 +104,11 @@ extern int snd_info_minor_unregister(void); ...@@ -104,6 +104,11 @@ extern int snd_info_minor_unregister(void);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern snd_info_entry_t *snd_seq_root; extern snd_info_entry_t *snd_seq_root;
#ifdef CONFIG_SND_OSSEMUL
extern snd_info_entry_t *snd_oss_root;
#else
#define snd_oss_root NULL
#endif
int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3))); int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3)));
int snd_info_init(void); int snd_info_init(void);
...@@ -138,6 +143,7 @@ void snd_remove_proc_entry(struct proc_dir_entry *parent, ...@@ -138,6 +143,7 @@ void snd_remove_proc_entry(struct proc_dir_entry *parent,
#else #else
#define snd_seq_root NULL #define snd_seq_root NULL
#define snd_oss_root NULL
static inline int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) { return 0; } static inline int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) { return 0; }
static inline int snd_info_init(void) { return 0; } static inline int snd_info_init(void) { return 0; }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <sound/asound.h> #include <sound/asound.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/bitops.h>
typedef sndrv_pcm_uframes_t snd_pcm_uframes_t; typedef sndrv_pcm_uframes_t snd_pcm_uframes_t;
typedef sndrv_pcm_sframes_t snd_pcm_sframes_t; typedef sndrv_pcm_sframes_t snd_pcm_sframes_t;
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
* *
*/ */
#include <linux/bitops.h>
extern int snd_pcm_hw_param_mask(snd_pcm_substream_t *pcm, snd_pcm_hw_params_t *params, extern int snd_pcm_hw_param_mask(snd_pcm_substream_t *pcm, snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, const snd_mask_t *val); snd_pcm_hw_param_t var, const snd_mask_t *val);
extern unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params, extern unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params,
......
/* include/version.h. Generated automatically by configure. */ /* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0beta12" #define CONFIG_SND_VERSION "0.9.0beta12"
#define CONFIG_SND_DATE " (Tue Feb 26 09:34:24 2002 UTC)" #define CONFIG_SND_DATE " (Wed Mar 06 07:56:20 2002 UTC)"
CONFIG_SOUND_PRIME
Say 'Y' or 'M' to enable Open Sound System drivers.
CONFIG_SOUND_SND
Say 'Y' or 'M' to enable Advanced Linux Sound Architecture (ALSA) drivers.
You need to install also alsa-lib and alsa-utils packages available on
the ALSA website at <http://www.alsa-project.org>.
CONFIG_SND_SEQUENCER
Say 'Y' or 'M' to enable MIDI sequencer and router support. This feature
allows routing and enqueing MIDI events. Events can be processed at given
time.
CONFIG_SND_SEQ_DUMMY
Say 'Y' or 'M' to enable dummy sequencer client. This client is a simple
midi-through client. All normal input events are redirected to output port
immediately.
CONFIG_SND_OSSEMUL
Say 'Y' to enable OSS (Open Sound System) API emulation code.
CONFIG_SND_MIXER_OSS
Say 'Y' or 'M' to enable mixer OSS API emulation (/dev/mixer*).
CONFIG_SND_PCM_OSS
Say 'Y' or 'M' to enable digital audio (PCM) OSS API emulation (/dev/dsp*).
CONFIG_SND_SEQUENCER_OSS
Say 'Y' or 'M' to enable OSS sequencer emulation (both /dev/sequencer and
/dev/music interfaces).
CONFIG_SND_RTCTIMER
Say 'Y' or 'M' to enable RTC timer support for ALSA. ALSA code uses RTC
timer as precise timing source and maps the RTC timer to the ALSA's timer
interface. ALSA sequencer code can also use this timing source.
CONFIG_SND_VERBOSE_PRINTK
Say 'Y' to enable verbose log messages. These messages will help to
identify source file and position containing printed messages.
CONFIG_SND_DEBUG
Say 'Y' to enable ALSA debug code.
CONFIG_SND_DEBUG_MEMORY
Say 'Y' to enable debugging of memory allocation.
CONFIG_SND_DEBUG_DETECTION
Say 'Y' to enable debugging of hardware detection.
# ALSA soundcard-configuration # ALSA soundcard-configuration
if [ "$CONFIG_X86_64" = "y" -a "$CONFIG_IA32_EMULATION" = "y" ]; then
dep_tristate ' Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
fi
if [ "$CONFIG_PPC64" = "y" ]; then
dep_tristate ' Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
fi
if [ "$CONFIG_SPARC64" = "y" ]; then
dep_tristate ' Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
fi
dep_tristate ' Sequencer support' CONFIG_SND_SEQUENCER $CONFIG_SND dep_tristate ' Sequencer support' CONFIG_SND_SEQUENCER $CONFIG_SND
if [ "$CONFIG_SND_SEQUENCER" != "n" ]; then if [ "$CONFIG_SND_SEQUENCER" != "n" ]; then
dep_tristate ' Sequencer dummy client' CONFIG_SND_SEQ_DUMMY $CONFIG_SND_SEQUENCER dep_tristate ' Sequencer dummy client' CONFIG_SND_SEQ_DUMMY $CONFIG_SND_SEQUENCER
......
...@@ -45,6 +45,11 @@ endif ...@@ -45,6 +45,11 @@ endif
obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o
subdir-$(CONFIG_SND_BIT32_EMUL) += ioctl32
ifeq ($(CONFIG_SND_BIT32_EMUL),y)
obj-y += ioctl32/_ioctl32.o
endif
# Toplevel Module Dependency # Toplevel Module Dependency
obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
...@@ -72,8 +77,8 @@ obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o sn ...@@ -72,8 +77,8 @@ obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o sn
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
...@@ -85,7 +90,7 @@ obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi. ...@@ -85,7 +90,7 @@ obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.
obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
...@@ -100,6 +105,10 @@ obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd.o ...@@ -100,6 +105,10 @@ obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o
ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-hwdep.o
obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
......
...@@ -24,12 +24,12 @@ ...@@ -24,12 +24,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/smp_lock.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/minors.h> #include <sound/minors.h>
#include <sound/info.h> #include <sound/info.h>
#include <sound/version.h> #include <sound/version.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/smp_lock.h>
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#endif #endif
...@@ -55,7 +55,7 @@ int snd_info_check_reserved_words(const char *str) ...@@ -55,7 +55,7 @@ int snd_info_check_reserved_words(const char *str)
"memdebug", "memdebug",
"detect", "detect",
"devices", "devices",
"oss-devices", "oss",
"cards", "cards",
"timers", "timers",
"synth", "synth",
...@@ -124,6 +124,9 @@ int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) ...@@ -124,6 +124,9 @@ int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...)
struct proc_dir_entry *snd_proc_root = NULL; struct proc_dir_entry *snd_proc_root = NULL;
struct proc_dir_entry *snd_proc_dev = NULL; struct proc_dir_entry *snd_proc_dev = NULL;
snd_info_entry_t *snd_seq_root = NULL; snd_info_entry_t *snd_seq_root = NULL;
#ifdef CONFIG_SND_OSSEMUL
snd_info_entry_t *snd_oss_root = NULL;
#endif
#ifdef LINUX_2_2 #ifdef LINUX_2_2
static void snd_info_fill_inode(struct inode *inode, int fill) static void snd_info_fill_inode(struct inode *inode, int fill)
...@@ -163,11 +166,13 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) ...@@ -163,11 +166,13 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{ {
snd_info_private_data_t *data; snd_info_private_data_t *data;
struct snd_info_entry *entry; struct snd_info_entry *entry;
int ret = -EINVAL; loff_t ret;
data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO);
entry = data->entry; entry = data->entry;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3)
lock_kernel(); lock_kernel();
#endif
switch (entry->content) { switch (entry->content) {
case SNDRV_INFO_CONTENT_TEXT: case SNDRV_INFO_CONTENT_TEXT:
switch (orig) { switch (orig) {
...@@ -181,6 +186,7 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) ...@@ -181,6 +186,7 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
goto out; goto out;
case 2: /* SEEK_END */ case 2: /* SEEK_END */
default: default:
ret = -EINVAL;
goto out; goto out;
} }
break; break;
...@@ -195,7 +201,9 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) ...@@ -195,7 +201,9 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
} }
ret = -ENXIO; ret = -ENXIO;
out: out:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3)
unlock_kernel(); unlock_kernel();
#endif
return ret; return ret;
} }
...@@ -623,6 +631,19 @@ int __init snd_info_init(void) ...@@ -623,6 +631,19 @@ int __init snd_info_init(void)
if (p == NULL) if (p == NULL)
return -ENOMEM; return -ENOMEM;
snd_proc_dev = p; snd_proc_dev = p;
#ifdef CONFIG_SND_OSSEMUL
{
snd_info_entry_t *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
return -ENOMEM;
entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
return -ENOMEM;
}
snd_oss_root = entry;
}
#endif
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
{ {
snd_info_entry_t *entry; snd_info_entry_t *entry;
...@@ -663,6 +684,10 @@ int __exit snd_info_done(void) ...@@ -663,6 +684,10 @@ int __exit snd_info_done(void)
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
if (snd_seq_root) if (snd_seq_root)
snd_info_unregister(snd_seq_root); snd_info_unregister(snd_seq_root);
#endif
#ifdef CONFIG_SND_OSSEMUL
if (snd_oss_root)
snd_info_unregister(snd_oss_root);
#endif #endif
snd_remove_proc_entry(snd_proc_root, snd_proc_dev); snd_remove_proc_entry(snd_proc_root, snd_proc_dev);
snd_remove_proc_entry(&proc_root, snd_proc_root); snd_remove_proc_entry(&proc_root, snd_proc_root);
......
...@@ -114,7 +114,7 @@ int snd_info_minor_register(void) ...@@ -114,7 +114,7 @@ int snd_info_minor_register(void)
snd_info_entry_t *entry; snd_info_entry_t *entry;
memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", NULL)) != NULL) { if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
entry->content = SNDRV_INFO_CONTENT_TEXT; entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->c.text.read_size = 2048; entry->c.text.read_size = 2048;
entry->c.text.read = snd_sndstat_proc_read; entry->c.text.read = snd_sndstat_proc_read;
......
#
# Makefile for ALSA
# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
#
O_TARGET := _ioctl32.o
list-multi := snd-ioctl32.o
snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o
include $(TOPDIR)/Rules.make
snd-ioctl32.o: $(snd-ioctl32-objs)
$(LD) $(LD_RFLAG) -r -o $@ $(snd-ioctl32-objs)
/*
* 32bit -> 64bit ioctl wrapper for timer API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
#define AP(x) snd_ioctl32_##x
struct ioctl32_mapper hwdep_mappers[] = {
{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
{ SNDRV_HWDEP_IOCTL_INFO, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
{ 0 },
};
/*
* 32bit -> 64bit ioctl wrapper for control API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/smp_lock.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/control.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
/*
* register/unregister mappers
* exported for other modules
*/
int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
int unregister_ioctl32_conversion(unsigned int cmd);
int snd_ioctl32_register(struct ioctl32_mapper *mappers)
{
int err;
struct ioctl32_mapper *m;
lock_kernel();
for (m = mappers; m->cmd; m++) {
err = register_ioctl32_conversion(m->cmd, m->handler);
if (err < 0) {
unlock_kernel();
return err;
}
m->registered++;
}
return 0;
}
void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
{
struct ioctl32_mapper *m;
lock_kernel();
for (m = mappers; m->cmd; m++) {
if (m->registered) {
unregister_ioctl32_conversion(m->cmd);
m->registered = 0;
}
}
unlock_kernel();
}
/*
* Controls
*/
struct sndrv_ctl_elem_list32 {
u32 offset;
u32 space;
u32 used;
u32 count;
u32 pids;
unsigned char reserved[50];
};
#define CVT_sndrv_ctl_elem_list()\
{\
COPY(offset);\
COPY(space);\
COPY(used);\
COPY(count);\
CPTR(pids);\
}
DEFINE_ALSA_IOCTL(ctl_elem_list);
/*
* control element info
* it uses union, so the things are not easy..
*/
struct sndrv_ctl_elem_info32 {
struct sndrv_ctl_elem_id id; // the size of struct is same
s32 type;
u32 access;
u32 count;
s32 owner;
union {
struct {
s32 min;
s32 max;
s32 step;
} integer;
struct {
u32 items;
u32 item;
char name[64];
} enumerated;
unsigned char reserved[128];
} value;
unsigned char reserved[64];
};
static int snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
{
struct sndrv_ctl_elem_info data;
struct sndrv_ctl_elem_info32 data32;
int err;
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.id = data32.id;
err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
if (err < 0)
return err;
/* restore info to 32bit */
data32.type = data.type;
data32.access = data.access;
data32.count = data.count;
data32.owner = data.owner;
switch (data.type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
data32.value.integer.min = data.value.integer.min;
data32.value.integer.max = data.value.integer.min;
data32.value.integer.step = data.value.integer.step;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
data32.value.enumerated.items = data.value.enumerated.items;
data32.value.enumerated.item = data.value.enumerated.item;
memcpy(data32.value.enumerated.name, data.value.enumerated.name,
sizeof(data.value.enumerated.name));
break;
default:
break;
}
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
return -EFAULT;
return err;
}
struct sndrv_ctl_elem_value32 {
struct sndrv_ctl_elem_id id;
unsigned int indirect: 1;
union {
union {
s32 value[128];
u32 value_ptr;
} integer;
union {
u32 item[128];
u32 item_ptr;
} enumerated;
union {
unsigned char data[512];
u32 data_ptr;
} bytes;
struct sndrv_aes_iec958 iec958;
} value;
unsigned char reserved[128];
};
/* hmm, it's so hard to retrieve the value type from the control id.. */
static int get_ctl_type(struct file *file, snd_ctl_elem_id_t *id)
{
snd_ctl_file_t *ctl;
snd_kcontrol_t *kctl;
snd_ctl_elem_info_t info;
int err;
ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
read_lock(&ctl->card->control_rwlock);
kctl = snd_ctl_find_id(ctl->card, id);
if (! kctl) {
read_unlock(&ctl->card->control_rwlock);
return -ENXIO;
}
info.id = *id;
err = kctl->info(kctl, &info);
if (err >= 0)
err = info.type;
read_unlock(&ctl->card->control_rwlock);
return err;
}
static int snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
{
// too big?
struct sndrv_ctl_elem_value data;
struct sndrv_ctl_elem_value32 data32;
int err, i;
int type;
/* FIXME: check the sane ioctl.. */
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.id = data32.id;
data.indirect = data32.indirect;
if (data.indirect) /* FIXME: this is not correct for long arrays */
data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
type = get_ctl_type(file, &data.id);
if (type < 0)
return type;
if (! data.indirect) {
switch (type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
for (i = 0; i < 128; i++)
data.value.integer.value[i] = data32.value.integer.value[i];
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
for (i = 0; i < 128; i++)
data.value.enumerated.item[i] = data32.value.enumerated.item[i];
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
memcpy(data.value.bytes.data, data32.value.bytes.data,
sizeof(data.value.bytes.data));
break;
case SNDRV_CTL_ELEM_TYPE_IEC958:
data.value.iec958 = data32.value.iec958;
break;
default:
break;
}
}
err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
if (err < 0)
return err;
/* restore info to 32bit */
if (! data.indirect) {
switch (type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
for (i = 0; i < 128; i++)
data.value.integer.value[i] = data32.value.integer.value[i];
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
for (i = 0; i < 128; i++)
data.value.enumerated.item[i] = data32.value.enumerated.item[i];
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
memcpy(data.value.bytes.data, data32.value.bytes.data,
sizeof(data.value.bytes.data));
break;
case SNDRV_CTL_ELEM_TYPE_IEC958:
data.value.iec958 = data32.value.iec958;
break;
default:
break;
}
}
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
return -EFAULT;
return err;
}
/*
*/
#define AP(x) snd_ioctl32_##x
static struct ioctl32_mapper control_mappers[] = {
/* controls (without rawmidi, hwdep, timer releated ones) */
{ SNDRV_CTL_IOCTL_PVERSION, NULL },
{ SNDRV_CTL_IOCTL_CARD_INFO , NULL },
{ SNDRV_CTL_IOCTL_ELEM_LIST, AP(ctl_elem_list) },
{ SNDRV_CTL_IOCTL_ELEM_INFO, AP(ctl_elem_info) },
{ SNDRV_CTL_IOCTL_ELEM_READ, AP(ctl_elem_value) },
{ SNDRV_CTL_IOCTL_ELEM_WRITE, AP(ctl_elem_value) },
{ SNDRV_CTL_IOCTL_ELEM_LOCK, NULL },
{ SNDRV_CTL_IOCTL_ELEM_UNLOCK, NULL },
{ SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
{ SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
{ SNDRV_CTL_IOCTL_POWER, NULL },
{ SNDRV_CTL_IOCTL_POWER_STATE, NULL },
{ 0 }
};
/*
*/
extern struct ioctl32_mapper pcm_mappers[];
extern struct ioctl32_mapper rawmidi_mappers[];
extern struct ioctl32_mapper timer_mappers[];
extern struct ioctl32_mapper hwdep_mappers[];
static void snd_ioctl32_done(void)
{
snd_ioctl32_unregister(hwdep_mappers);
snd_ioctl32_unregister(timer_mappers);
snd_ioctl32_unregister(rawmidi_mappers);
snd_ioctl32_unregister(pcm_mappers);
snd_ioctl32_unregister(control_mappers);
}
static int __init snd_ioctl32_init(void)
{
int err;
err = snd_ioctl32_register(control_mappers);
if (err < 0)
return err;
err = snd_ioctl32_register(pcm_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
err = snd_ioctl32_register(rawmidi_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
err = snd_ioctl32_register(timer_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
err = snd_ioctl32_register(hwdep_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
}
module_init(snd_ioctl32_init)
module_exit(snd_ioctl32_done)
/*
* 32bit -> 64bit ioctl helpers
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* This file registers the converters from 32-bit ioctls to 64-bit ones.
* The converter assumes that a 32-bit user-pointer can be casted by A(x)
* macro to a valid 64-bit pointer which is accessible via copy_from/to_user.
*
*/
#ifndef __ALSA_IOCTL32_H
#define __ALSA_IOCTL32_H
#define TO_PTR(x) A(x)
#define COPY(x) (dst->x = src->x)
#define CPTR(x) (dst->x = (typeof(dst->x))A(src->x))
#define convert_from_32(type, dstp, srcp)\
{\
struct sndrv_##type *dst = dstp;\
struct sndrv_##type##32 *src = srcp;\
CVT_##sndrv_##type();\
}
#define convert_to_32(type, dstp, srcp)\
{\
struct sndrv_##type *src = srcp;\
struct sndrv_##type##32 *dst = dstp;\
CVT_##sndrv_##type();\
}
#define DEFINE_ALSA_IOCTL(type) \
static int snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)\
{\
struct sndrv_##type##32 data32;\
struct sndrv_##type data;\
int err;\
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))\
return -EFAULT;\
memset(&data, 0, sizeof(data));\
convert_from_32(type, &data, &data32);\
err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);\
if (err < 0)\
return err;\
if (cmd & (_IOC_READ << _IOC_DIRSHIFT)) {\
convert_to_32(type, &data32, &data);\
if (copy_to_user((void*)arg, &data32, sizeof(data32)))\
return -EFAULT;\
}\
return err;\
}
struct ioctl32_mapper {
unsigned int cmd;
int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
int registered;
};
int snd_ioctl32_register(struct ioctl32_mapper *mappers);
void snd_ioctl32_unregister(struct ioctl32_mapper *mappers);
#endif /* __ALSA_IOCTL32_H */
/*
* 32bit -> 64bit ioctl wrapper for PCM API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "ioctl32.h"
/* wrapper for sndrv_pcm_[us]frames */
struct sndrv_pcm_sframes_str {
sndrv_pcm_sframes_t val;
};
struct sndrv_pcm_sframes_str32 {
s32 val;
};
struct sndrv_pcm_uframes_str {
sndrv_pcm_uframes_t val;
};
struct sndrv_pcm_uframes_str32 {
u32 val;
};
#define CVT_sndrv_pcm_sframes_str() { COPY(val); }
#define CVT_sndrv_pcm_uframes_str() { COPY(val); }
struct sndrv_interval32 {
u32 min, max;
unsigned int openmin:1,
openmax:1,
integer:1,
empty:1;
};
struct sndrv_pcm_hw_params32 {
u32 flags;
u32 masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
u32 rmask;
u32 cmask;
u32 info;
u32 msbits;
u32 rate_num;
u32 rate_den;
u32 fifo_size;
unsigned char reserved[64];
};
#define numberof(array) (sizeof(array)/sizeof(array[0]))
#define CVT_sndrv_pcm_hw_params()\
{\
int i;\
COPY(flags);\
for (i = 0; i < numberof(dst->masks); i++)\
COPY(masks[i]);\
for (i = 0; i < numberof(dst->intervals); i++) {\
COPY(intervals[i].min);\
COPY(intervals[i].max);\
COPY(intervals[i].openmin);\
COPY(intervals[i].openmax);\
COPY(intervals[i].integer);\
COPY(intervals[i].empty);\
}\
COPY(rmask);\
COPY(cmask);\
COPY(info);\
COPY(msbits);\
COPY(rate_num);\
COPY(rate_den);\
COPY(fifo_size);\
}
struct sndrv_pcm_sw_params32 {
s32 tstamp_mode;
u32 period_step;
u32 sleep_min;
u32 avail_min;
u32 xfer_align;
u32 start_threshold;
u32 stop_threshold;
u32 silence_threshold;
u32 silence_size;
u32 boundary;
unsigned char reserved[64];
};
#define CVT_sndrv_pcm_sw_params()\
{\
COPY(tstamp_mode);\
COPY(period_step);\
COPY(sleep_min);\
COPY(avail_min);\
COPY(xfer_align);\
COPY(start_threshold);\
COPY(stop_threshold);\
COPY(silence_threshold);\
COPY(silence_size);\
COPY(boundary);\
}
struct sndrv_pcm_channel_info32 {
u32 channel;
u32 offset;
u32 first;
u32 step;
};
#define CVT_sndrv_pcm_channel_info()\
{\
COPY(channel);\
COPY(offset);\
COPY(first);\
COPY(step);\
}
struct timeval32 {
s32 tv_sec;
s32 tv_usec;
};
struct sndrv_pcm_status32 {
s32 state;
struct timeval32 trigger_tstamp;
struct timeval32 tstamp;
u32 appl_ptr;
u32 hw_ptr;
s32 delay;
u32 avail;
u32 avail_max;
u32 overrange;
s32 suspended_state;
unsigned char reserved[60];
};
#define CVT_sndrv_pcm_status()\
{\
COPY(state);\
COPY(trigger_tstamp.tv_sec);\
COPY(trigger_tstamp.tv_usec);\
COPY(tstamp.tv_sec);\
COPY(tstamp.tv_usec);\
COPY(appl_ptr);\
COPY(hw_ptr);\
COPY(delay);\
COPY(avail);\
COPY(avail_max);\
COPY(overrange);\
COPY(suspended_state);\
}
struct sndrv_xferi32 {
s32 result;
u32 buf;
u32 frames;
};
#define CVT_sndrv_xferi()\
{\
COPY(result);\
CPTR(buf);\
COPY(frames);\
}
DEFINE_ALSA_IOCTL(pcm_uframes_str);
DEFINE_ALSA_IOCTL(pcm_sframes_str);
DEFINE_ALSA_IOCTL(pcm_hw_params);
DEFINE_ALSA_IOCTL(pcm_sw_params);
DEFINE_ALSA_IOCTL(pcm_channel_info);
DEFINE_ALSA_IOCTL(pcm_status);
DEFINE_ALSA_IOCTL(xferi);
/* snd_xfern needs remapping of bufs */
struct sndrv_xfern32 {
s32 result;
u32 bufs; /* this is void **; */
u32 frames;
};
/*
* xfern ioctl nees to copy (up to) 128 pointers on stack.
* although we may pass the copied pointers through f_op->ioctl, but the ioctl
* handler there expands again the same 128 pointers on stack, so it is better
* to handle the function (calling pcm_readv/writev) directly in this handler.
*/
static int snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
{
snd_pcm_file_t *pcm_file;
snd_pcm_substream_t *substream;
struct sndrv_xfern32 data32, *srcptr = (struct sndrv_xfern32*)arg;
void *bufs[128];
int err = 0, ch, i;
u32 *bufptr;
/* FIXME: need to check whether fop->ioctl is sane */
pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO);
substream = pcm_file->substream;
snd_assert(substream != NULL && substream->runtime, return -ENXIO);
/* check validty of the command */
switch (cmd) {
case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return -EINVAL;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
case SNDRV_PCM_IOCTL_READN_FRAMES:
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return -EINVAL;
break;
}
if ((ch = substream->runtime->channels) > 128)
return -EINVAL;
if (get_user(data32.frames, &srcptr->frames))
return -EFAULT;
__get_user(data32.bufs, &srcptr->bufs);
bufptr = (u32*)TO_PTR(data32.bufs);
for (i = 0; i < ch; i++) {
u32 ptr;
if (get_user(ptr, bufptr))
return -EFAULT;
bufs[ch] = (void*)TO_PTR(ptr);
bufptr++;
}
switch (cmd) {
case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
err = snd_pcm_lib_writev(substream, bufs, data32.frames);
break;
case SNDRV_PCM_IOCTL_READN_FRAMES:
err = snd_pcm_lib_readv(substream, bufs, data32.frames);
break;
}
if (err < 0)
return err;
if (put_user(err, &srcptr->result))
return -EFAULT;
return err < 0 ? err : 0;
}
#define AP(x) snd_ioctl32_##x
struct ioctl32_mapper pcm_mappers[] = {
{ SNDRV_PCM_IOCTL_PVERSION, NULL },
{ SNDRV_PCM_IOCTL_INFO, NULL },
{ SNDRV_PCM_IOCTL_HW_REFINE, AP(pcm_hw_params) },
{ SNDRV_PCM_IOCTL_HW_PARAMS, AP(pcm_hw_params) },
{ SNDRV_PCM_IOCTL_HW_FREE, NULL },
{ SNDRV_PCM_IOCTL_SW_PARAMS, AP(pcm_sw_params) },
{ SNDRV_PCM_IOCTL_STATUS, AP(pcm_status) },
{ SNDRV_PCM_IOCTL_DELAY, AP(pcm_sframes_str) },
{ SNDRV_PCM_IOCTL_CHANNEL_INFO, AP(pcm_channel_info) },
{ SNDRV_PCM_IOCTL_PREPARE, NULL },
{ SNDRV_PCM_IOCTL_RESET, NULL },
{ SNDRV_PCM_IOCTL_START, NULL },
{ SNDRV_PCM_IOCTL_DROP, NULL },
{ SNDRV_PCM_IOCTL_DRAIN, NULL },
{ SNDRV_PCM_IOCTL_PAUSE, NULL },
{ SNDRV_PCM_IOCTL_REWIND, AP(pcm_uframes_str) },
{ SNDRV_PCM_IOCTL_RESUME, NULL },
{ SNDRV_PCM_IOCTL_XRUN, NULL },
{ SNDRV_PCM_IOCTL_WRITEI_FRAMES, AP(xferi) },
{ SNDRV_PCM_IOCTL_READI_FRAMES, AP(xferi) },
{ SNDRV_PCM_IOCTL_WRITEN_FRAMES, AP(xfern) },
{ SNDRV_PCM_IOCTL_READN_FRAMES, AP(xfern) },
{ SNDRV_PCM_IOCTL_LINK, NULL },
{ SNDRV_PCM_IOCTL_UNLINK, NULL },
{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
{ SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
{ 0 },
};
/*
* 32bit -> 64bit ioctl wrapper for raw MIDI API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
struct sndrv_rawmidi_params32 {
s32 stream;
u32 buffer_size;
u32 avail_min;
unsigned int no_active_sensing: 1;
unsigned char reserved[16];
};
#define CVT_sndrv_rawmidi_params()\
{\
COPY(stream);\
COPY(buffer_size);\
COPY(avail_min);\
COPY(no_active_sensing);\
}
struct timeval32 {
s32 tv_sec;
s32 tv_usec;
};
struct sndrv_rawmidi_status32 {
s32 stream;
struct timeval32 tstamp;
u32 avail;
u32 xruns;
unsigned char reserved[16];
};
#define CVT_sndrv_rawmidi_status()\
{\
COPY(stream);\
COPY(tstamp.tv_sec);\
COPY(tstamp.tv_usec);\
COPY(avail);\
COPY(xruns);\
}
DEFINE_ALSA_IOCTL(rawmidi_params);
DEFINE_ALSA_IOCTL(rawmidi_status);
#define AP(x) snd_ioctl32_##x
struct ioctl32_mapper rawmidi_mappers[] = {
{ SNDRV_RAWMIDI_IOCTL_PVERSION, NULL },
{ SNDRV_RAWMIDI_IOCTL_INFO, NULL },
{ SNDRV_RAWMIDI_IOCTL_PARAMS, AP(rawmidi_params) },
{ SNDRV_RAWMIDI_IOCTL_STATUS, AP(rawmidi_status) },
{ SNDRV_RAWMIDI_IOCTL_DROP, NULL },
{ SNDRV_RAWMIDI_IOCTL_DRAIN, NULL },
{ SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_RAWMIDI_INFO, NULL },
{ SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE, NULL },
{ 0 },
};
/*
* 32bit -> 64bit ioctl wrapper for timer API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
struct sndrv_timer_info32 {
u32 flags;
s32 card;
unsigned char id[64];
unsigned char name[80];
u32 ticks;
u32 resolution;
unsigned char reserved[64];
};
#define CVT_sndrv_timer_info()\
{\
COPY(flags);\
COPY(card);\
memcpy(dst->id, src->id, sizeof(src->id));\
memcpy(dst->name, src->name, sizeof(src->name));\
COPY(ticks);\
COPY(resolution);\
}
struct timeval32 {
s32 tv_sec;
s32 tv_usec;
};
struct sndrv_timer_status32 {
struct timeval32 tstamp;
u32 resolution;
u32 lost;
u32 overrun;
u32 queue;
unsigned char reserved[64];
};
#define CVT_sndrv_timer_status()\
{\
COPY(tstamp.tv_sec);\
COPY(tstamp.tv_usec);\
COPY(resolution);\
COPY(lost);\
COPY(overrun);\
COPY(queue);\
}
DEFINE_ALSA_IOCTL(timer_info);
DEFINE_ALSA_IOCTL(timer_status);
/*
*/
#define AP(x) snd_ioctl32_##x
struct ioctl32_mapper timer_mappers[] = {
{ SNDRV_TIMER_IOCTL_PVERSION, NULL },
{ SNDRV_TIMER_IOCTL_NEXT_DEVICE, NULL },
{ SNDRV_TIMER_IOCTL_SELECT, NULL },
{ SNDRV_TIMER_IOCTL_INFO, AP(timer_info) },
{ SNDRV_TIMER_IOCTL_PARAMS, NULL },
{ SNDRV_TIMER_IOCTL_STATUS, AP(timer_status) },
{ SNDRV_TIMER_IOCTL_START, NULL },
{ SNDRV_TIMER_IOCTL_STOP, NULL },
{ SNDRV_TIMER_IOCTL_CONTINUE, NULL },
{ 0 },
};
...@@ -516,7 +516,6 @@ static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream) ...@@ -516,7 +516,6 @@ static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream)
snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel) snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{ {
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
mm_segment_t fs;
int ret; int ret;
while (1) { while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN || if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
...@@ -525,11 +524,14 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char ...@@ -525,11 +524,14 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char
if (ret < 0) if (ret < 0)
break; break;
} }
if (in_kernel) if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user(); fs = snd_enter_user();
ret = snd_pcm_lib_write(substream, ptr, frames); ret = snd_pcm_lib_write(substream, ptr, frames);
if (in_kernel)
snd_leave_user(fs); snd_leave_user(fs);
} else {
ret = snd_pcm_lib_write(substream, ptr, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE) if (ret != -EPIPE && ret != -ESTRPIPE)
break; break;
/* test, if we can't store new data, because the stream */ /* test, if we can't store new data, because the stream */
...@@ -543,7 +545,6 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char ...@@ -543,7 +545,6 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char
snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel) snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{ {
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
mm_segment_t fs;
int ret; int ret;
while (1) { while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN || if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
...@@ -556,11 +557,15 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s ...@@ -556,11 +557,15 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
if (ret < 0) if (ret < 0)
break; break;
} }
if (in_kernel)
fs = snd_enter_user();
ret = snd_pcm_lib_read(substream, ptr, frames); ret = snd_pcm_lib_read(substream, ptr, frames);
if (in_kernel) if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user();
ret = snd_pcm_lib_read(substream, ptr, frames);
snd_leave_user(fs); snd_leave_user(fs);
} else {
ret = snd_pcm_lib_read(substream, ptr, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE) if (ret != -EPIPE && ret != -ESTRPIPE)
break; break;
} }
...@@ -570,7 +575,6 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s ...@@ -570,7 +575,6 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
{ {
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
mm_segment_t fs;
int ret; int ret;
while (1) { while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN || if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
...@@ -579,13 +583,17 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf ...@@ -579,13 +583,17 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf
if (ret < 0) if (ret < 0)
break; break;
} }
if (in_kernel) if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user(); fs = snd_enter_user();
ret = snd_pcm_lib_writev(substream, bufs, frames); ret = snd_pcm_lib_writev(substream, bufs, frames);
if (in_kernel)
snd_leave_user(fs); snd_leave_user(fs);
} else {
ret = snd_pcm_lib_writev(substream, bufs, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE) if (ret != -EPIPE && ret != -ESTRPIPE)
break; break;
/* test, if we can't store new data, because the stream */ /* test, if we can't store new data, because the stream */
/* has not been started */ /* has not been started */
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
...@@ -597,7 +605,6 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf ...@@ -597,7 +605,6 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf
snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
{ {
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
mm_segment_t fs;
int ret; int ret;
while (1) { while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN || if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
...@@ -610,11 +617,14 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs ...@@ -610,11 +617,14 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs
if (ret < 0) if (ret < 0)
break; break;
} }
if (in_kernel) if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user(); fs = snd_enter_user();
ret = snd_pcm_lib_readv(substream, bufs, frames); ret = snd_pcm_lib_readv(substream, bufs, frames);
if (in_kernel)
snd_leave_user(fs); snd_leave_user(fs);
} else {
ret = snd_pcm_lib_readv(substream, bufs, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE) if (ret != -EPIPE && ret != -ESTRPIPE)
break; break;
} }
......
...@@ -18,19 +18,12 @@ ...@@ -18,19 +18,12 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
*
*================================================================
* For enabling this timer, apply the patch file to your kernel.
* The configure script checks the patch automatically.
* The patches, rtc-xxx.dif, are found under utils/patches, where
* xxx is the kernel version.
*================================================================
*
*/ */
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/interrupt.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/timer.h> #include <sound/timer.h>
#include <sound/info.h> #include <sound/info.h>
...@@ -59,7 +52,7 @@ static int rtctimer_stop(snd_timer_t *t); ...@@ -59,7 +52,7 @@ static int rtctimer_stop(snd_timer_t *t);
/* /*
* The harware depenant description for this timer. * The hardware dependent description for this timer.
*/ */
static struct _snd_timer_hardware rtc_hw = { static struct _snd_timer_hardware rtc_hw = {
flags: SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO, flags: SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
...@@ -72,7 +65,7 @@ static struct _snd_timer_hardware rtc_hw = { ...@@ -72,7 +65,7 @@ static struct _snd_timer_hardware rtc_hw = {
int rtctimer_freq = RTC_FREQ; /* frequency */ int rtctimer_freq = RTC_FREQ; /* frequency */
static snd_timer_t *rtctimer; static snd_timer_t *rtctimer;
static volatile int rtc_inc = 0; static atomic_t rtc_inc = ATOMIC_INIT(0);
static rtc_task_t rtc_task; static rtc_task_t rtc_task;
/* tasklet */ /* tasklet */
...@@ -83,6 +76,10 @@ static struct tasklet_struct rtc_tq; ...@@ -83,6 +76,10 @@ static struct tasklet_struct rtc_tq;
static int static int
rtctimer_open(snd_timer_t *t) rtctimer_open(snd_timer_t *t)
{ {
err = rtc_register(&rtc_task);
if (err < 0)
return err;
t->private_data = &rtc_task;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
return 0; return 0;
} }
...@@ -90,6 +87,11 @@ rtctimer_open(snd_timer_t *t) ...@@ -90,6 +87,11 @@ rtctimer_open(snd_timer_t *t)
static int static int
rtctimer_close(snd_timer_t *t) rtctimer_close(snd_timer_t *t)
{ {
rtc_task_t *rtc = t->private_data;
if (rtc) {
rtc_unregister(rtc);
t->private_data = NULL;
}
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -101,7 +103,7 @@ rtctimer_start(snd_timer_t *timer) ...@@ -101,7 +103,7 @@ rtctimer_start(snd_timer_t *timer)
snd_assert(rtc != NULL, return -EINVAL); snd_assert(rtc != NULL, return -EINVAL);
rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq); rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
rtc_control(rtc, RTC_PIE_ON, 0); rtc_control(rtc, RTC_PIE_ON, 0);
rtc_inc = 0; atomic_set(&rtc_inc, 0);
return 0; return 0;
} }
...@@ -119,12 +121,15 @@ rtctimer_stop(snd_timer_t *timer) ...@@ -119,12 +121,15 @@ rtctimer_stop(snd_timer_t *timer)
*/ */
static void rtctimer_interrupt(void *private_data) static void rtctimer_interrupt(void *private_data)
{ {
rtc_inc++; atomic_inc(&rtc_inc);
#ifdef USE_TASKLET #ifdef USE_TASKLET
tasklet_hi_schedule(&rtc_tq); tasklet_hi_schedule(&rtc_tq);
#else #else
snd_timer_interrupt((snd_timer_t*)private_data, rtc_inc); {
rtc_inc = 0; int ticks = atomic_read(&rtc_inc);
snd_timer_interrupt((snd_timer_t*)private_data, ticks);
atomic_sub(ticks, &rtc_inc);
}
#endif /* USE_TASKLET */ #endif /* USE_TASKLET */
} }
...@@ -132,20 +137,16 @@ static void rtctimer_interrupt(void *private_data) ...@@ -132,20 +137,16 @@ static void rtctimer_interrupt(void *private_data)
static void rtctimer_interrupt2(unsigned long private_data) static void rtctimer_interrupt2(unsigned long private_data)
{ {
snd_timer_t *timer = (snd_timer_t *)private_data; snd_timer_t *timer = (snd_timer_t *)private_data;
int ticks;
snd_assert(timer != NULL, return); snd_assert(timer != NULL, return);
do { do {
snd_timer_interrupt(timer, 1); ticks = atomic_read(&rtc_inc);
} while (--rtc_inc > 0); snd_timer_interrupt(timer, ticks);
} while (!atomic_sub_and_test(ticks, &rtc_inc));
} }
#endif /* USE_TASKLET */ #endif /* USE_TASKLET */
static void rtctimer_private_free(snd_timer_t *timer)
{
rtc_task_t *rtc = timer->private_data;
if (rtc)
rtc_unregister(rtc);
}
/* /*
* ENTRY functions * ENTRY functions
...@@ -179,23 +180,16 @@ static int __init rtctimer_init(void) ...@@ -179,23 +180,16 @@ static int __init rtctimer_init(void)
timer->hw = rtc_hw; timer->hw = rtc_hw;
timer->hw.resolution = NANO_SEC / rtctimer_freq; timer->hw.resolution = NANO_SEC / rtctimer_freq;
/* register RTC callback */ /* set up RTC callback */
rtc_task.func = rtctimer_interrupt; rtc_task.func = rtctimer_interrupt;
rtc_task.private_data = timer; rtc_task.private_data = timer;
err = rtc_register(&rtc_task);
if (err < 0) {
snd_timer_global_free(timer);
return err;
}
timer->private_data = &rtc_task;
timer->private_free = rtctimer_private_free;
err = snd_timer_global_register(timer); err = snd_timer_global_register(timer);
if (err < 0) { if (err < 0) {
snd_timer_global_free(timer); snd_timer_global_free(timer);
return err; return err;
} }
rtctimer = timer; rtctimer = timer; /* remember this */
return 0; return 0;
} }
...@@ -210,7 +204,7 @@ static void __exit rtctimer_exit(void) ...@@ -210,7 +204,7 @@ static void __exit rtctimer_exit(void)
/* /*
* exported stuffs * exported stuff
*/ */
module_init(rtctimer_init) module_init(rtctimer_init)
module_exit(rtctimer_exit) module_exit(rtctimer_exit)
......
...@@ -72,6 +72,7 @@ obj-$(CONFIG_SND_ES1938) += snd-seq-device.o snd-seq-midi-emul.o snd-seq.o snd-s ...@@ -72,6 +72,7 @@ obj-$(CONFIG_SND_ES1938) += snd-seq-device.o snd-seq-midi-emul.o snd-seq.o snd-s
obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_VIA686) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_VIA686) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
......
...@@ -68,8 +68,8 @@ static struct status_event_list_t { ...@@ -68,8 +68,8 @@ static struct status_event_list_t {
event_decode_t decode; event_decode_t decode;
} status_event[] = { } status_event[] = {
/* 0x80 - 0xf0 */ /* 0x80 - 0xf0 */
{SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
{SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
{SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode},
{SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode},
{SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode},
...@@ -78,9 +78,9 @@ static struct status_event_list_t { ...@@ -78,9 +78,9 @@ static struct status_event_list_t {
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */ {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */
/* 0xf0 - 0xff */ /* 0xf0 - 0xff */
{SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */
{SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
{SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
{SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */ {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */ {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */
{SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */
...@@ -92,7 +92,7 @@ static struct status_event_list_t { ...@@ -92,7 +92,7 @@ static struct status_event_list_t {
{SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */ {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */
{SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */
{SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
}; };
static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev); static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
...@@ -128,6 +128,7 @@ int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev) ...@@ -128,6 +128,7 @@ int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev)
} }
} }
dev->bufsize = bufsize; dev->bufsize = bufsize;
dev->lastcmd = 0xff;
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
*rdev = dev; *rdev = dev;
return 0; return 0;
......
...@@ -233,8 +233,7 @@ static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream) ...@@ -233,8 +233,7 @@ static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream)
} }
vmidi->seq_mode = rdev->seq_mode; vmidi->seq_mode = rdev->seq_mode;
vmidi->client = rdev->client; vmidi->client = rdev->client;
vmidi->port = rdev->port; vmidi->port = rdev->port;
snd_midi_event_init(vmidi->parser);
snd_virmidi_init_event(vmidi, &vmidi->event); snd_virmidi_init_event(vmidi, &vmidi->event);
vmidi->rdev = rdev; vmidi->rdev = rdev;
runtime->private_data = vmidi; runtime->private_data = vmidi;
......
...@@ -212,7 +212,7 @@ int __init snd_minor_info_oss_init(void) ...@@ -212,7 +212,7 @@ int __init snd_minor_info_oss_init(void)
{ {
snd_info_entry_t *entry; snd_info_entry_t *entry;
entry = snd_info_create_module_entry(THIS_MODULE, "oss-devices", NULL); entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
if (entry) { if (entry) {
entry->content = SNDRV_INFO_CONTENT_TEXT; entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->c.text.read_size = PAGE_SIZE; entry->c.text.read_size = PAGE_SIZE;
......
CONFIG_SND_DUMMY
Say 'Y' or 'M' to include dummy driver. This driver does nothing, but
emulates various mixer controls and PCM devices.
CONFIG_SND_VIRMIDI
Say 'Y' or 'M' to include virtual MIDI driver. This driver allows to
connect applications using raw MIDI devices to sequencer.
CONFIG_SND_MTPAV
Say 'Y' or 'M' to include support for MOTU MidiTimePiece AV multiport
MIDI adapter.
CONFIG_SND_SERIAL_U16550
Say 'Y' or 'M' to include support for MIDI serial port driver. It works
with serial UARTs 16550 and better.
CONFIG_SND_MPU401
Say 'Y' or 'M' to include support for MPU401 hardware using UART access.
...@@ -37,6 +37,7 @@ obj-$(CONFIG_SND_ES1938) += snd-mpu401-uart.o ...@@ -37,6 +37,7 @@ obj-$(CONFIG_SND_ES1938) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o
obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o
obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o
obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o
obj-$(CONFIG_SND_VIA686) += snd-mpu401-uart.o obj-$(CONFIG_SND_VIA686) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/mpu401.h> #include <sound/mpu401.h>
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#define SNDRV_GET_ID #define SNDRV_GET_ID
#include <sound/initval.h> #include <sound/initval.h>
......
...@@ -29,7 +29,7 @@ obj-$(CONFIG_SND_GUSEXTREME) += snd-opl3-lib.o ...@@ -29,7 +29,7 @@ obj-$(CONFIG_SND_GUSEXTREME) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-lib.o obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-lib.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI93X) += snd-opl3-lib.o obj-$(CONFIG_SND_OPTI93X) += snd-opl3-lib.o
obj-$(CONFIG_SND_SB) += snd-opl3-lib.o obj-$(CONFIG_SND_SB8) += snd-opl3-lib.o
obj-$(CONFIG_SND_SB16) += snd-opl3-lib.o obj-$(CONFIG_SND_SB16) += snd-opl3-lib.o
obj-$(CONFIG_SND_SBAWE) += snd-opl3-lib.o obj-$(CONFIG_SND_SBAWE) += snd-opl3-lib.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-lib.o obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-lib.o
...@@ -54,7 +54,7 @@ ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) ...@@ -54,7 +54,7 @@ ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-synth.o obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-synth.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI93X) += snd-opl3-synth.o obj-$(CONFIG_SND_OPTI93X) += snd-opl3-synth.o
obj-$(CONFIG_SND_SB) += snd-opl3-synth.o obj-$(CONFIG_SND_SB8) += snd-opl3-synth.o
obj-$(CONFIG_SND_SB16) += snd-opl3-synth.o obj-$(CONFIG_SND_SB16) += snd-opl3-synth.o
obj-$(CONFIG_SND_SBAWE) += snd-opl3-synth.o obj-$(CONFIG_SND_SBAWE) += snd-opl3-synth.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-synth.o obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-synth.o
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/minors.h> #include <sound/minors.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Hannu Savolainen 1993-1996, Rob Hooft"); MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Hannu Savolainen 1993-1996, Rob Hooft");
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* *
* Usage example for MS-124T, with A-B switch in A position: * Usage example for MS-124T, with A-B switch in A position:
* setserial /dev/ttyS0 uart none * setserial /dev/ttyS0 uart none
* /sbin/modprobe snd-card-serial snd_port=0x3f8 snd_irq=4 \ * /sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
* snd_adaptor=1 snd_speed=19200 * snd_adaptor=1 snd_speed=19200
* *
* - In MS-124W S/A mode, one raw MIDI substream is supported * - In MS-124W S/A mode, one raw MIDI substream is supported
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
* *
* Usage example for S/A mode: * Usage example for S/A mode:
* setserial /dev/ttyS0 uart none * setserial /dev/ttyS0 uart none
* /sbin/modprobe snd-card-serial snd_port=0x3f8 snd_irq=4 \ * /sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
* snd_adaptor=2 * snd_adaptor=2
* *
* - In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI * - In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
* *
* Usage example for M/B mode: * Usage example for M/B mode:
* setserial /dev/ttyS0 uart none * setserial /dev/ttyS0 uart none
* /sbin/insmod snd-card-serial snd_port=0x3f8 snd_irq=4 \ * /sbin/insmod snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
* snd_adaptor=3 * snd_adaptor=3
* *
* - The MS-124W hardware's M/A mode is currently not supported. * - The MS-124W hardware's M/A mode is currently not supported.
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/rawmidi.h> #include <sound/rawmidi.h>
#define SNDRV_GET_ID #define SNDRV_GET_ID
......
...@@ -13,7 +13,7 @@ snd-i2c-objs := i2c.o ...@@ -13,7 +13,7 @@ snd-i2c-objs := i2c.o
snd-cs8427-objs := cs8427.o snd-cs8427-objs := cs8427.o
snd-tea6330t-objs := tea6330t.o snd-tea6330t-objs := tea6330t.o
# Module Dependency # Toplevel Module Dependency
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
......
CONFIG_SND_AD1816A
Say 'Y' or 'M' to include support for Analog Devices SoundPort AD1816A or
compatible sound chips.
CONFIG_SND_AD1848
Say 'Y' or 'M' to include support for AD1848 (Analog Devices) or CS4248
(Cirrus Logic - Crystal Semiconductors) chips. Please, for newer chips
from Cirrus Logic, use CS4231, CS4232 or CS4236+ driver.
CONFIG_SND_CS4231
Say 'Y' or 'M' to include support for CS4231 chips from Cirrus Logic -
Crystal Semiconductors.
CONFIG_SND_CS4232
Say 'Y' or 'M' to include support for CS4232 chips from Cirrus Logic -
Crystal Semiconductors.
CONFIG_SND_CS4236
Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239
chips from Cirrus Logic - Crystal Semiconductors.
CONFIG_SND_ES968
Say 'Y' or 'M' to include support for ESS AudioDrive ES968 chip.
CONFIG_SND_ES1688
Say 'Y' or 'M' to include support for ESS AudioDrive ES688 or ES1688 chips.
CONFIG_SND_ES18XX
Say 'Y' or 'M' to include support for ESS AudioDrive ES18xx chips.
CONFIG_SND_GUSCLASSIC
Say 'Y' or 'M' to include support for Gravis UltraSound Classic soundcard.
CONFIG_SND_GUSEXTREME
Say 'Y' or 'M' to include support for Gravis UltraSound Extreme soundcard.
CONFIG_SND_GUSMAX
Say 'Y' or 'M' to include support for Gravis UltraSound MAX soundcard.
CONFIG_SND_INTERWAVE
Say 'Y' or 'M' to include support for AMD InterWave based soundcards
(Gravis UltraSound Plug & Play, STB SoundRage32, MED3210, Dynasonic Pro,
Panasonic PCA761AW).
CONFIG_SND_INTERWAVE_STB
Say 'Y' or 'M' to include support for AMD InterWave based soundcards
with TEA6330T bass and treble regulator (UltraSound 32-Pro).
CONFIG_SND_OPTI92X_AD1848
Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
AD1848 codec.
CONFIG_SND_OPTI92X_CS4231
Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
CS4231 codec.
CONFIG_SND_OPTI93X
Say 'Y' or 'M' to include support for Opti93x soundcards.
CONFIG_SND_SB8
Say 'Y' or 'M' to include support for Sound Blaster 1.0/2.0/Pro (8-bit)
soundcards or 100% compatible from Creative.
CONFIG_SND_SB16
Say 'Y' or 'M' to include support for Sound Blaster 16 (including
Plug and Play version).
CONFIG_SND_SBAWE
Say 'Y' or 'M' to include support for Sound Blaster AWE (including
Plug and Play version).
CONFIG_SND_SB16_CSP
Say 'Y' to include support for CSP core. This special coprocessor
can do variable tasks like various compression and decompression
algorithms.
CONFIG_SND_WAVEFRONT
Say 'Y' or 'M' to include support for Turtle Beach Maui, Tropez
and Tropez+ soundcards based on Wavefront chip.
CONFIG_SND_ALS100
Say 'Y' or 'M' to include support for Avance Logic ALS100, ALS110,
ALS120 and ALS200 soundcards.
CONFIG_SND_AZT2320
Say 'Y' or 'M' to include support for Aztech Systems AZT2320 soundcard.
CONFIG_SND_CMI8330
Say 'Y' or 'M' to include support for C-Media CMI8330 based soundcards.
CONFIG_SND_DT0197H
Say 'Y' or 'M' to include support for Diamond Technologies DT-0197H
soundcards.
CONFIG_SND_OPL3SA2
Say 'Y' or 'M' to include support for Yamaha OPL3SA2 or OPL3SA3 chips.
CONFIG_SND_SGALAXY
Say 'Y' or 'M' to include support for Aztech Sound Galaxy.
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/ad1816a.h> #include <sound/ad1816a.h>
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <asm/dma.h> #include <asm/dma.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/ad1848.h> #include <sound/ad1848.h>
......
...@@ -134,7 +134,7 @@ static const struct isapnp_card_id *snd_azt2320_isapnp_id[SNDRV_CARDS] __devinit ...@@ -134,7 +134,7 @@ static const struct isapnp_card_id *snd_azt2320_isapnp_id[SNDRV_CARDS] __devinit
static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = { static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = {
/* PRO16V */ /* PRO16V */
ISAPNP_AZT2320('A','Z','T',0x1008,0x1008,0x2001), ISAPNP_AZT2320('A','Z','T',0x1008,0x1008,0x2001),
/* --- */ /* Aztech Sound Galaxy 16 */
ISAPNP_AZT2320('A','Z','T',0x2320,0x0001,0x0002), ISAPNP_AZT2320('A','Z','T',0x2320,0x0001,0x0002),
/* Packard Bell Sound III 336 AM/SP */ /* Packard Bell Sound III 336 AM/SP */
ISAPNP_AZT2320('A','Z','T',0x3000,0x1003,0x2001), ISAPNP_AZT2320('A','Z','T',0x3000,0x1003,0x2001),
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/cs4231.h> #include <sound/cs4231.h>
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/es1688.h> #include <sound/es1688.h>
#include <sound/initval.h> #include <sound/initval.h>
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/gus.h> #include <sound/gus.h>
#include <sound/control.h> #include <sound/control.h>
......
...@@ -177,7 +177,7 @@ static struct isapnp_card_id snd_opl3sa2_pnpids[] __devinitdata = { ...@@ -177,7 +177,7 @@ static struct isapnp_card_id snd_opl3sa2_pnpids[] __devinitdata = {
ISAPNP_OPL3SA2('Y','M','H',0x0020,0x0021), ISAPNP_OPL3SA2('Y','M','H',0x0020,0x0021),
/* Yamaha OPL3-SA3 (integrated on Intel's Pentium II AL440LX motherboard) */ /* Yamaha OPL3-SA3 (integrated on Intel's Pentium II AL440LX motherboard) */
ISAPNP_OPL3SA2('Y','M','H',0x0030,0x0021), ISAPNP_OPL3SA2('Y','M','H',0x0030,0x0021),
/* ??? */ /* Yamaha OPL3-SA2 */
ISAPNP_OPL3SA2('Y','M','H',0x0800,0x0021), ISAPNP_OPL3SA2('Y','M','H',0x0800,0x0021),
/* NeoMagic MagicWave 3DX */ /* NeoMagic MagicWave 3DX */
ISAPNP_OPL3SA2('N','M','X',0x2200,0x2210), ISAPNP_OPL3SA2('N','M','X',0x2200,0x2210),
......
...@@ -27,12 +27,12 @@ obj-$(CONFIG_SND_DT0197H) += snd-sb16-dsp.o snd-sb-common.o ...@@ -27,12 +27,12 @@ obj-$(CONFIG_SND_DT0197H) += snd-sb16-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
ifeq ($(CONFIG_SND_SB16_CSP),y) ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
endif endif
obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_SBAWE) += snd-emu8000-synth.o obj-$(CONFIG_SND_SBAWE) += snd-emu8000-synth.o
endif endif
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/emu8000.h> #include <sound/emu8000.h>
#include <sound/emu8000_reg.h> #include <sound/emu8000_reg.h>
......
...@@ -209,11 +209,11 @@ static void snd_sb16_csp_capture_close(sb_t *chip) ...@@ -209,11 +209,11 @@ static void snd_sb16_csp_capture_close(sb_t *chip)
#else #else
#define snd_sb16_csp_playback_prepare(chip, runtime) /*nop*/ #define snd_sb16_csp_playback_prepare(chip, runtime) /*nop*/
#define snd_sb16_csp_capture_prepare(chip, runtime) /*nop*/ #define snd_sb16_csp_capture_prepare(chip, runtime) /*nop*/
#define snd_sb16_csp_update(chip) /*nop*/ #define snd_sb16_csp_update(chip) /*nop*/
#define snd_sb16_csp_playback_open(chip, runtime) /*nop*/ #define snd_sb16_csp_playback_open(chip, runtime) /*nop*/
#define snd_sb16_csp_playback_close(chip) /*nop*/ #define snd_sb16_csp_playback_close(chip) /*nop*/
#define snd_sb16_csp_capture_open(chip, runtime) /*nop*/ #define snd_sb16_csp_capture_open(chip, runtime) /*nop*/
#define snd_sb16_csp_capture_close(chip) /*nop*/ #define snd_sb16_csp_capture_close(chip) /*nop*/
#endif #endif
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/sb.h> #include <sound/sb.h>
#include <sound/opl3.h> #include <sound/opl3.h>
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/sb.h> #include <sound/sb.h>
#include <sound/initval.h> #include <sound/initval.h>
......
...@@ -119,7 +119,7 @@ static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) ...@@ -119,7 +119,7 @@ static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
static int dma_bits[] = {1, 2, 0, 3}; static int dma_bits[] = {1, 2, 0, 3};
int tmp, tmp1; int tmp, tmp1;
unsigned int flags; unsigned long flags;
if ((tmp = inb(port + 3)) == 0xff) if ((tmp = inb(port + 3)) == 0xff)
{ {
......
...@@ -111,30 +111,6 @@ MODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test"); ...@@ -111,30 +111,6 @@ MODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test");
MODULE_PARM(osrun_time,"i"); MODULE_PARM(osrun_time,"i");
MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS"); MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
/*
* This sucks, hopefully it'll get standardised
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) && LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#define loops_per_sec loops_per_jiffy*HZ
#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0) && defined(I_DIRTY_PAGES) /* linux/fs.h */
#define loops_per_sec loops_per_jiffy*HZ
#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
#define loops_per_sec loops_per_jiffy*HZ
#endif
#if defined(__alpha__) || defined(__powerpc__)
#ifdef __SMP__
#define LOOPS_PER_SEC (cpu_data[smp_processor_id()].loops_per_sec)
#else
#define LOOPS_PER_SEC (loops_per_sec)
#endif
#endif
#if defined(__i386__)
#define LOOPS_PER_SEC (current_cpu_data.loops_per_sec)
#endif
/* if WF_DEBUG not defined, no run-time debugging messages will /* if WF_DEBUG not defined, no run-time debugging messages will
be available via the debug flag setting. Given the current be available via the debug flag setting. Given the current
beta state of the driver, this will remain set until a future beta state of the driver, this will remain set until a future
...@@ -323,26 +299,16 @@ wavefront_wait (snd_wavefront_t *dev, int mask) ...@@ -323,26 +299,16 @@ wavefront_wait (snd_wavefront_t *dev, int mask)
{ {
int i; int i;
static int short_loop_cnt = 0;
/* Compute the loop count that lets us sleep for about the
right amount of time, cache issues, bus speeds and all
other issues being unequal but largely irrelevant.
*/
if (short_loop_cnt == 0) {
short_loop_cnt = wait_usecs *
(LOOPS_PER_SEC / 1000000);
}
/* Spin for a short period of time, because >99% of all /* Spin for a short period of time, because >99% of all
requests to the WaveFront can be serviced inline like this. requests to the WaveFront can be serviced inline like this.
*/ */
for (i = 0; i < short_loop_cnt; i++) { for (i = 0; i < wait_usecs; i += 5) {
if (wavefront_status (dev) & mask) { if (wavefront_status (dev) & mask) {
return 1; return 1;
} }
udelay(5);
} }
for (i = 0; i < sleep_tries; i++) { for (i = 0; i < sleep_tries; i++) {
...@@ -1316,18 +1282,21 @@ wavefront_fetch_multisample (snd_wavefront_t *dev, ...@@ -1316,18 +1282,21 @@ wavefront_fetch_multisample (snd_wavefront_t *dev,
for (i = 0; i < num_samples; i++) { for (i = 0; i < num_samples; i++) {
char d[2]; char d[2];
int val;
if ((d[0] = wavefront_read (dev)) == -1) { if ((val = wavefront_read (dev)) == -1) {
snd_printk ("upload multisample failed " snd_printk ("upload multisample failed "
"during sample loop.\n"); "during sample loop.\n");
return -(EIO); return -(EIO);
} }
d[0] = val;
if ((d[1] = wavefront_read (dev)) == -1) { if ((val = wavefront_read (dev)) == -1) {
snd_printk ("upload multisample failed " snd_printk ("upload multisample failed "
"during sample loop.\n"); "during sample loop.\n");
return -(EIO); return -(EIO);
} }
d[1] = val;
header->hdr.ms.SampleNumber[i] = header->hdr.ms.SampleNumber[i] =
demunge_int32 ((unsigned char *) d, 2); demunge_int32 ((unsigned char *) d, 2);
......
CONFIG_SND_ALI5451
Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core.
CONFIG_SND_CS46XX
Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 /
CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips.
CONFIG_SND_CS46XX_ACCEPT_VALID
Say 'Y' to allow sample resolution for mmap() transfers.
CONFIG_SND_EMU10K1
Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
Audigy and E-mu APS (partially supported).
CONFIG_SND_KORG1212
Say 'Y' or 'M' to include support for Korg 1212IO.
CONFIG_SND_NM256
Say 'Y' or 'M' to include support for NeoMagic NM256AV/ZX chips.
CONFIG_SND_RME96
Say 'Y' or 'M' to include support for RME Digi96, Digi96/8 and
Digi96/8 PRO/PAD/PST.
CONFIG_SND_RME9652
Say 'Y' or 'M' to include support for RME Hammerfall (RME Digi9652 /
Digi9636) soundcards.
CONFIG_SND_TRIDENT
CONFIG_SND_YMFPCI
Say 'Y' or 'M' to include support for Yamaha PCI audio chips -
YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754.
CONFIG_SND_ALS4000
Say 'Y' or 'M' to include support for Avance Logic ALS4000.
CONFIG_SND_CMIPCI
Say 'Y' or 'M' to include support for C-Media CMI8338 and 8738 PCI
soundcards.
CONFIG_SND_ENS1370
Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370.
CONFIG_SND_ENS1371
Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and
Sound Blaster PCI 64 or 128 soundcards.
CONFIG_SND_ES1938
Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946)
soundcard.
CONFIG_SND_ES1968
Say 'Y' or 'M' to include support for ESS Maestro 1/2/2E.
CONFIG_SND_MAESTRO3
Say 'Y' or 'M' to include support for ESS Maestro 3 (Allegro) soundcard.
CONFIG_SND_FM801
Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards.
CONFIG_SND_ICE1712
Say 'Y' or 'M' to include support for ICE1712 (Envy24) based soundcards.
CONFIG_SND_INTEL8X0
Say 'Y' or 'M' to include support for Intel8x0 based soundcards.
CONFIG_SND_SONICVIBES
Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
CONFIG_SND_VIA686
Say 'Y' or 'M' to include support for VIA VT82C686A/B South Bridge.
CONFIG_SND_VIA8233
Say 'Y' or 'M' to include support for VIA VT8233 South Bridge.
...@@ -109,7 +109,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, ...@@ -109,7 +109,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
} }
legacy_ctrl = 0; legacy_ctrl = 0;
legacy_ctrl2 = 0; legacy_ctrl2 = 0x0800; /* SMOD = 01 */
if (id->device >= 0x0010) { /* YMF 744/754 */ if (id->device >= 0x0010) { /* YMF 744/754 */
if (snd_fm_port[dev] < 0) if (snd_fm_port[dev] < 0)
......
...@@ -15,8 +15,8 @@ export-objs := util_mem.o ...@@ -15,8 +15,8 @@ export-objs := util_mem.o
snd-util-mem-objs := util_mem.o snd-util-mem-objs := util_mem.o
# Toplevel Module Dependency # Toplevel Module Dependency
obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o
obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o
endif endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment