Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa

* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (212 commits)
  [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED
  [ALSA] version 1.0.14rc2
  [ALSA] ASoC documentation updates
  [ALSA] ca0106 - Add missing sysfs device assignment
  [ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully
  [ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880
  [ALSA] aoa: remove suspend/resume printks
  [ALSA] Fix possible deadlocks in sequencer at removal of ports
  [ALSA] emu10k1 - Fix STAC9758 front channel
  [ALSA] soc - Clean up with kmemdup()
  [ALSA] snd-ak4114: Fix two array overflows
  [ALSA] ac97_bus power management
  [ALSA] usbaudio - Add support for Edirol UA-101
  [ALSA] hda-codec - Add ALC861VD/ALC660VD support
  [ALSA] soc - ASoC 0.13 Sharp poodle machine
  [ALSA] soc - ASoC 0.13 Sharp tosa machine
  [ALSA] soc - ASoC 0.13 spitz machine
  [ALSA] soc - ASoC Sharp corgi machine
  [ALSA] soc - ASoC 0.13 pxa2xx DMA
  [ALSA] soc - ASoC 0.13 pxa2xx AC97 driver
  ...
This commit is contained in:
Linus Torvalds 2007-02-09 08:24:04 -08:00
commit 6026179519
216 changed files with 28235 additions and 3791 deletions

View file

@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
ac97_clock - AC'97 clock (default = 48000)
ac97_quirk - AC'97 workaround for strange hardware
See "AC97 Quirk Option" section below.
ac97_codec - Workaround to specify which AC'97 codec
instead of probing. If this works for you
file a bug with your `lspci -vn` output.
-2 -- Force probing.
-1 -- Default behavior.
0-2 -- Use the specified codec.
spdif_aclink - S/PDIF transfer over AC-link (default = 1)
This module supports one card and autoprobe.
@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
asus-dig ASUS with SPDIF out
asus-dig2 ASUS with SPDIF out (using GPIO2)
uniwill 3-jack
fujitsu Fujitsu Laptops (Pi1536)
F1734 2-jack
lg LG laptop (m1 express dual)
lg-lw LG LW20/LW25 laptop
@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
ALC262
fujitsu Fujitsu Laptop
hp-bpc HP xw4400/6400/8400/9400 laptops
hp-bpc-d7000 HP BPC D7000
benq Benq ED8
hippo Hippo (ATI) with jack detection, Sony UX-90s
hippo_1 Hippo (Benq) with jack detection
basic fixed pin assignment w/o SPDIF
auto auto-config reading BIOS (default)
ALC882/885
3stack-dig 3-jack with SPDIF I/O
6stck-dig 6-jack digital with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O
arima Arima W820Di1
macpro MacPro support
auto auto-config reading BIOS (default)
ALC883/888
@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
6stack-dig-demo 6-jack digital for Intel demo board
acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
medion Medion Laptops
targa-dig Targa/MSI
targa-2ch-dig Targs/MSI with 2-channel
laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
auto auto-config reading BIOS (default)
ALC861/660
@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
6stack-dig 6-jack with SPDIF I/O
3stack-660 3-jack (for ALC660)
uniwill-m31 Uniwill M31 laptop
toshiba Toshiba laptop support
asus Asus laptop support
asus-laptop ASUS F2/F3 laptops
auto auto-config reading BIOS (default)
ALC861VD/660VD
3stack 3-jack
3stack-dig 3-jack with SPDIF OUT
6stack-dig 6-jack with SPDIF OUT
3stack-660 3-jack (for ALC660VD)
auto auto-config reading BIOS (default)
CMI9880
@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
3stack 3-stack, shared surrounds
laptop 2-channel only (FSC V2060, Samsung M50)
laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J)
ultra 2-channel with EAPD (Samsung Ultra tablet PC)
AD1988
6stack 6-jack
@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
laptop 3-jack with hp-jack automute
laptop-dig ditto with SPDIF
auto auto-config reading BIOS (default)
Conexant 5045
laptop Laptop config
test for testing/debugging purpose, almost all controls
can be adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y
Conexant 5047
laptop Basic Laptop config
laptop-hp Laptop config for some HP models (subdevice 30A5)
laptop-eapd Laptop config with EAPD support
test for testing/debugging purpose, almost all controls
can be adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y
STAC9200/9205/9220/9221/9254
ref Reference board
3stack D945 3stack
5stack D945 5stack + SPDIF
STAC9202/9250/9251
ref Reference board, base config
m2-2 Some Gateway MX series laptops
m6 Some Gateway NX series laptops
STAC9227/9228/9229/927x
ref Reference board
3stack D965 3stack
@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
* MidiMan M Audio Revolution 5.1
* MidiMan M Audio Revolution 7.1
* MidiMan M Audio Audiophile 192
* AMP Ltd AUDIO2000
* TerraTec Aureon 5.1 Sky
* TerraTec Aureon 7.1 Space
@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
model - Use the given board model, one of the following:
revo51, revo71, amp2000, prodigy71, prodigy71lt,
prodigy192, aureon51, aureon71, universe,
prodigy192, aureon51, aureon71, universe, ap192,
k8x800, phase22, phase28, ms300, av710
This module supports multiple cards and autoprobe.
@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
buggy_semaphore - Enable workaround for hardwares with buggy
semaphores (e.g. on some ASUS laptops)
(default off)
spdif_aclink - Use S/PDIF over AC-link instead of direct connection
from the controller chip
(0 = off, 1 = on, -1 = default)
This module supports one chip and autoprobe.
@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple cards.
Module snd-portman2x4
---------------------
Module for Midiman Portman 2x4 parallel port MIDI interface
This module supports multiple cards.
Module snd-powermac (on ppc only)
---------------------------------

View file

@ -36,7 +36,7 @@
</bookinfo>
<chapter><title>Management of Cards and Devices</title>
<sect1><title>Card Managment</title>
<sect1><title>Card Management</title>
!Esound/core/init.c
</sect1>
<sect1><title>Device Components</title>
@ -59,7 +59,7 @@
<sect1><title>PCM Format Helpers</title>
!Esound/core/pcm_misc.c
</sect1>
<sect1><title>PCM Memory Managment</title>
<sect1><title>PCM Memory Management</title>
!Esound/core/pcm_memory.c
</sect1>
</chapter>

View file

@ -1360,8 +1360,7 @@
<informalexample>
<programlisting>
<![CDATA[
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
....
@ -2127,7 +2126,7 @@
accessible via <constant>substream-&gt;runtime</constant>.
This runtime pointer holds the various information; it holds
the copy of hw_params and sw_params configurations, the buffer
pointers, mmap records, spinlocks, etc. Almost everyhing you
pointers, mmap records, spinlocks, etc. Almost everything you
need for controlling the PCM can be found there.
</para>
@ -2340,7 +2339,7 @@ struct _snd_pcm_runtime {
<para>
When the PCM substreams can be synchronized (typically,
synchorinized start/stop of a playback and a capture streams),
synchronized start/stop of a playback and a capture streams),
you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>,
too. In this case, you'll need to check the linked-list of
PCM substreams in the trigger callback. This will be
@ -3062,8 +3061,7 @@ struct _snd_pcm_runtime {
<title>Interrupt Handler Case #1</title>
<programlisting>
<![CDATA[
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
spin_lock(&chip->lock);
@ -3106,8 +3104,7 @@ struct _snd_pcm_runtime {
<title>Interrupt Handler Case #2</title>
<programlisting>
<![CDATA[
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
spin_lock(&chip->lock);
@ -3247,7 +3244,7 @@ struct _snd_pcm_runtime {
You can even define your own constraint rules.
For example, let's suppose my_chip can manage a substream of 1 channel
if and only if the format is S16_LE, otherwise it supports any format
specified in the <structname>snd_pcm_hardware</structname> stucture (or in any
specified in the <structname>snd_pcm_hardware</structname> structure (or in any
other constraint_list). You can build a rule like this:
<example>
@ -3690,16 +3687,6 @@ struct _snd_pcm_runtime {
</example>
</para>
<para>
Here, the chip instance is retrieved via
<function>snd_kcontrol_chip()</function> macro. This macro
just accesses to kcontrol-&gt;private_data. The
kcontrol-&gt;private_data field is
given as the argument of <function>snd_ctl_new()</function>
(see the later subsection
<link linkend="control-interface-constructor"><citetitle>Constructor</citetitle></link>).
</para>
<para>
The <structfield>value</structfield> field is depending on
the type of control as well as on info callback. For example,
@ -3780,7 +3767,7 @@ struct _snd_pcm_runtime {
<para>
Like <structfield>get</structfield> callback,
when the control has more than one elements,
all elemehts must be evaluated in this callback, too.
all elements must be evaluated in this callback, too.
</para>
</section>
@ -5541,12 +5528,12 @@ struct _snd_pcm_runtime {
#ifdef CONFIG_PM
static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
{
.... /* do things for suspsend */
.... /* do things for suspend */
return 0;
}
static int snd_my_resume(struct pci_dev *pci)
{
.... /* do things for suspsend */
.... /* do things for suspend */
return 0;
}
#endif
@ -6111,7 +6098,7 @@ struct _snd_pcm_runtime {
<!-- ****************************************************** -->
<!-- Acknowledgments -->
<!-- ****************************************************** -->
<chapter id="acknowledments">
<chapter id="acknowledgments">
<title>Acknowledgments</title>
<para>
I would like to thank Phil Kerr for his help for improvement and

View file

@ -277,11 +277,11 @@ Helper Functions
snd_hda_get_codec_name() stores the codec name on the given string.
snd_hda_check_board_config() can be used to obtain the configuration
information matching with the device. Define the table with struct
hda_board_config entries (zero-terminated), and pass it to the
function. The function checks the modelname given as a module
parameter, and PCI subsystem IDs. If the matching entry is found, it
returns the config field value.
information matching with the device. Define the model string table
and the table with struct snd_pci_quirk entries (zero-terminated),
and pass it to the function. The function checks the modelname given
as a module parameter, and PCI subsystem IDs. If the matching entry
is found, it returns the config field value.
snd_hda_add_new_ctls() can be used to create and add control entries.
Pass the zero-terminated array of struct snd_kcontrol_new. The same array

View file

@ -0,0 +1,56 @@
ASoC currently supports the three main Digital Audio Interfaces (DAI) found on
SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM.
AC97
====
AC97 is a five wire interface commonly found on many PC sound cards. It is
now also popular in many portable devices. This DAI has a reset line and time
multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
frame is 21uS long and is divided into 13 time slots.
The AC97 specification can be found at :-
http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
I2S
===
I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and
Rx lines are used for audio transmision, whilst the bit clock (BCLK) and
left/right clock (LRC) synchronise the link. I2S is flexible in that either the
controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
usually varies depending on the sample rate and the master system clock
(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
ADC and DAC LRCLK's, this allows for similtanious capture and playback at
different sample rates.
I2S has several different operating modes:-
o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC
transition.
o Left Justified - MSB is transmitted on transition of LRC.
o Right Justified - MSB is transmitted sample size BCLK's before LRC
transition.
PCM
===
PCM is another 4 wire interface, very similar to I2S, that can support a more
flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used
to synchronise the link whilst the Tx and Rx lines are used to transmit and
receive the audio data. Bit clock usually varies depending on sample rate
whilst sync runs at the sample rate. PCM also supports Time Division
Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This
is sometimes referred to as network mode).
Common PCM operating modes:-
o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC.
o Mode B - MSB is transmitted on rising edge of FRAME/SYNC.

View file

@ -0,0 +1,51 @@
Audio Clocking
==============
This text describes the audio clocking terms in ASoC and digital audio in
general. Note: Audio clocking can be complex !
Master Clock
------------
Every audio subsystem is driven by a master clock (sometimes refered to as MCLK
or SYSCLK). This audio master clock can be derived from a number of sources
(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct
audio playback and capture sample rates.
Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that
their speed can be altered by software (depending on the system use and to save
power). Other master clocks are fixed at at set frequency (i.e. crystals).
DAI Clocks
----------
The Digital Audio Interface is usually driven by a Bit Clock (often referred to
as BCLK). This clock is used to drive the digital audio data across the link
between the codec and CPU.
The DAI also has a frame clock to signal the start of each audio frame. This
clock is sometimes referred to as LRC (left right clock) or FRAME. This clock
runs at exactly the sample rate (LRC = Rate).
Bit Clock can be generated as follows:-
BCLK = MCLK / x
or
BCLK = LRC * x
or
BCLK = LRC * Channels * Word Size
This relationship depends on the codec or SoC CPU in particular. In general
it's best to configure BCLK to the lowest possible speed (depending on your
rate, number of channels and wordsize) to save on power.
It's also desireable to use the codec (if possible) to drive (or master) the
audio clocks as it's usually gives more accurate sample rates than the CPU.

View file

@ -0,0 +1,197 @@
ASoC Codec Driver
=================
The codec driver is generic and hardware independent code that configures the
codec to provide audio capture and playback. It should contain no code that is
specific to the target platform or machine. All platform and machine specific
code should be added to the platform and machine drivers respectively.
Each codec driver *must* provide the following features:-
1) Codec DAI and PCM configuration
2) Codec control IO - using I2C, 3 Wire(SPI) or both API's
3) Mixers and audio controls
4) Codec audio operations
Optionally, codec drivers can also provide:-
5) DAPM description.
6) DAPM event handler.
7) DAC Digital mute control.
It's probably best to use this guide in conjuction with the existing codec
driver code in sound/soc/codecs/
ASoC Codec driver breakdown
===========================
1 - Codec DAI and PCM configuration
-----------------------------------
Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and
PCM's capablities and operations. This struct is exported so that it can be
registered with the core by your machine driver.
e.g.
struct snd_soc_codec_dai wm8731_dai = {
.name = "WM8731",
/* playback capabilities */
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
/* capture capabilities */
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
/* pcm operations - see section 4 below */
.ops = {
.prepare = wm8731_pcm_prepare,
.hw_params = wm8731_hw_params,
.shutdown = wm8731_shutdown,
},
/* DAI operations - see DAI.txt */
.dai_ops = {
.digital_mute = wm8731_mute,
.set_sysclk = wm8731_set_dai_sysclk,
.set_fmt = wm8731_set_dai_fmt,
}
};
EXPORT_SYMBOL_GPL(wm8731_dai);
2 - Codec control IO
--------------------
The codec can ususally be controlled via an I2C or SPI style interface (AC97
combines control with data in the DAI). The codec drivers will have to provide
functions to read and write the codec registers along with supplying a register
cache:-
/* IO control data and register cache */
void *control_data; /* codec control (i2c/3wire) data */
void *reg_cache;
Codec read/write should do any data formatting and call the hardware read write
below to perform the IO. These functions are called by the core and alsa when
performing DAPM or changing the mixer:-
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
Codec hardware IO functions - usually points to either the I2C, SPI or AC97
read/write:-
hw_write_t hw_write;
hw_read_t hw_read;
3 - Mixers and audio controls
-----------------------------
All the codec mixers and audio controls can be defined using the convenience
macros defined in soc.h.
#define SOC_SINGLE(xname, reg, shift, mask, invert)
Defines a single control as follows:-
xname = Control name e.g. "Playback Volume"
reg = codec register
shift = control bit(s) offset in register
mask = control bit size(s) e.g. mask of 7 = 3 bits
invert = the control is inverted
Other macros include:-
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert)
A stereo control
#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert)
A stereo control spanning 2 registers
#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)
Defines an single enumerated control as follows:-
xreg = register
xshift = control bit(s) offset in register
xmask = control bit(s) size
xtexts = pointer to array of strings that describe each setting
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)
Defines a stereo enumerated control
4 - Codec Audio Operations
--------------------------
The codec driver also supports the following alsa operations:-
/* SoC audio ops */
struct snd_soc_ops {
int (*startup)(struct snd_pcm_substream *);
void (*shutdown)(struct snd_pcm_substream *);
int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
int (*hw_free)(struct snd_pcm_substream *);
int (*prepare)(struct snd_pcm_substream *);
};
Please refer to the alsa driver PCM documentation for details.
http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
5 - DAPM description.
---------------------
The Dynamic Audio Power Management description describes the codec's power
components, their relationships and registers to the ASoC core. Please read
dapm.txt for details of building the description.
Please also see the examples in other codec drivers.
6 - DAPM event handler
----------------------
This function is a callback that handles codec domain PM calls and system
domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep
when not in use.
Power states:-
SNDRV_CTL_POWER_D0: /* full On */
/* vref/mid, clk and osc on, active */
SNDRV_CTL_POWER_D1: /* partial On */
SNDRV_CTL_POWER_D2: /* partial On */
SNDRV_CTL_POWER_D3hot: /* Off, with power */
/* everything off except vref/vmid, inactive */
SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */
7 - Codec DAC digital mute control.
------------------------------------
Most codecs have a digital mute before the DAC's that can be used to minimise
any system noise. The mute stops any digital data from entering the DAC.
A callback can be created that is called by the core for each codec DAI when the
mute is applied or freed.
i.e.
static int wm8974_mute(struct snd_soc_codec *codec,
struct snd_soc_codec_dai *dai, int mute)
{
u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
if(mute)
wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
else
wm8974_write(codec, WM8974_DAC, mute_reg);
return 0;
}

View file

@ -0,0 +1,297 @@
Dynamic Audio Power Management for Portable Devices
===================================================
1. Description
==============
Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices
to use the minimum amount of power within the audio subsystem at all times. It
is independent of other kernel PM and as such, can easily co-exist with the
other PM systems.
DAPM is also completely transparent to all user space applications as all power
switching is done within the ASoC core. No code changes or recompiling are
required for user space applications. DAPM makes power switching descisions based
upon any audio stream (capture/playback) activity and audio mixer settings
within the device.
DAPM spans the whole machine. It covers power control within the entire audio
subsystem, this includes internal codec power blocks and machine level power
systems.
There are 4 power domains within DAPM
1. Codec domain - VREF, VMID (core codec and audio power)
Usually controlled at codec probe/remove and suspend/resume, although
can be set at stream time if power is not needed for sidetone, etc.
2. Platform/Machine domain - physically connected inputs and outputs
Is platform/machine and user action specific, is configured by the
machine driver and responds to asynchronous events e.g when HP
are inserted
3. Path domain - audio susbsystem signal paths
Automatically set when mixer and mux settings are changed by the user.
e.g. alsamixer, amixer.
4. Stream domain - DAC's and ADC's.
Enabled and disabled when stream playback/capture is started and
stopped respectively. e.g. aplay, arecord.
All DAPM power switching descisons are made automatically by consulting an audio
routing map of the whole machine. This map is specific to each machine and
consists of the interconnections between every audio component (including
internal codec components). All audio components that effect power are called
widgets hereafter.
2. DAPM Widgets
===============
Audio DAPM widgets fall into a number of types:-
o Mixer - Mixes several analog signals into a single analog signal.
o Mux - An analog switch that outputs only 1 of it's inputs.
o PGA - A programmable gain amplifier or attenuation widget.
o ADC - Analog to Digital Converter
o DAC - Digital to Analog Converter
o Switch - An analog switch
o Input - A codec input pin
o Output - A codec output pin
o Headphone - Headphone (and optional Jack)
o Mic - Mic (and optional Jack)
o Line - Line Input/Output (and optional Jack)
o Speaker - Speaker
o Pre - Special PRE widget (exec before all others)
o Post - Special POST widget (exec after all others)
(Widgets are defined in include/sound/soc-dapm.h)
Widgets are usually added in the codec driver and the machine driver. There are
convience macros defined in soc-dapm.h that can be used to quickly build a
list of widgets of the codecs and machines DAPM widgets.
Most widgets have a name, register, shift and invert. Some widgets have extra
parameters for stream name and kcontrols.
2.1 Stream Domain Widgets
-------------------------
Stream Widgets relate to the stream power domain and only consist of ADC's
(analog to digital converters) and DAC's (digital to analog converters).
Stream widgets have the following format:-
SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
NOTE: the stream name must match the corresponding stream name in your codecs
snd_soc_codec_dai.
e.g. stream widgets for HiFi playback and capture
SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
2.2 Path Domain Widgets
-----------------------
Path domain widgets have a ability to control or effect the audio signal or
audio paths within the audio subsystem. They have the following form:-
SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
Any widget kcontrols can be set using the controls and num_controls members.
e.g. Mixer widget (the kcontrols are declared first)
/* Output Mixer */
static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
};
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,
ARRAY_SIZE(wm8731_output_mixer_controls)),
2.3 Platform/Machine domain Widgets
-----------------------------------
Machine widgets are different from codec widgets in that they don't have a
codec register bit associated with them. A machine widget is assigned to each
machine audio component (non codec) that can be independently powered. e.g.
o Speaker Amp
o Microphone Bias
o Jack connectors
A machine widget can have an optional call back.
e.g. Jack connector widget for an external Mic that enables Mic Bias
when the Mic is inserted:-
static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
{
if(SND_SOC_DAPM_EVENT_ON(event))
set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
else
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
return 0;
}
SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
2.4 Codec Domain
----------------
The Codec power domain has no widgets and is handled by the codecs DAPM event
handler. This handler is called when the codec powerstate is changed wrt to any
stream event or by kernel PM events.
2.5 Virtual Widgets
-------------------
Sometimes widgets exist in the codec or machine audio map that don't have any
corresponding register bit for power control. In this case it's necessary to
create a virtual widget - a widget with no control bits e.g.
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
This can be used to merge to signal paths together in software.
After all the widgets have been defined, they can then be added to the DAPM
subsystem individually with a call to snd_soc_dapm_new_control().
3. Codec Widget Interconnections
================================
Widgets are connected to each other within the codec and machine by audio
paths (called interconnections). Each interconnection must be defined in order
to create a map of all audio paths between widgets.
This is easiest with a diagram of the codec (and schematic of the machine audio
system), as it requires joining widgets together via their audio signal paths.
i.e. from the WM8731 codec's output mixer (wm8731.c)
The WM8731 output mixer has 3 inputs (sources)
1. Line Bypass Input
2. DAC (HiFi playback)
3. Mic Sidetone Input
Each input in this example has a kcontrol associated with it (defined in example
above) and is connected to the output mixer via it's kcontrol name. We can now
connect the destination widget (wrt audio signal) with it's source widgets.
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
So we have :-
Destination Widget <=== Path Name <=== Source Widget
Or:-
Sink, Path, Source
Or :-
"Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch".
When there is no path name connecting widgets (e.g. a direct connection) we
pass NULL for the path name.
Interconnections are created with a call to:-
snd_soc_dapm_connect_input(codec, sink, path, source);
Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and
interconnections have been registered with the core. This causes the core to
scan the codec and machine so that the internal DAPM state matches the
physical state of the machine.
3.1 Machine Widget Interconnections
-----------------------------------
Machine widget interconnections are created in the same way as codec ones and
directly connect the codec pins to machine level widgets.
e.g. connects the speaker out codec pins to the internal speaker.
/* ext speaker connected to codec pins LOUT2, ROUT2 */
{"Ext Spk", NULL , "ROUT2"},
{"Ext Spk", NULL , "LOUT2"},
This allows the DAPM to power on and off pins that are connected (and in use)
and pins that are NC respectively.
4 Endpoint Widgets
===================
An endpoint is a start or end point (widget) of an audio signal within the
machine and includes the codec. e.g.
o Headphone Jack
o Internal Speaker
o Internal Mic
o Mic Jack
o Codec Pins
When a codec pin is NC it can be marked as not used with a call to
snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
The last argument is 0 for inactive and 1 for active. This way the pin and its
input widget will never be powered up and consume power.
This also applies to machine widgets. e.g. if a headphone is connected to a
jack then the jack can be marked active. If the headphone is removed, then
the headphone jack can be marked inactive.
5 DAPM Widget Events
====================
Some widgets can register their interest with the DAPM core in PM events.
e.g. A Speaker with an amplifier registers a widget so the amplifier can be
powered only when the spk is in use.
/* turn speaker amplifier on/off depending on use */
static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
{
if (SND_SOC_DAPM_EVENT_ON(event))
set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
else
reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
return 0;
}
/* corgi machine dapm widgets */
static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
Please see soc-dapm.h for all other widgets that support events.
5.1 Event types
---------------
The following event types are supported by event widgets.
/* dapm event types */
#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */

View file

@ -0,0 +1,113 @@
ASoC Machine Driver
===================
The ASoC machine (or board) driver is the code that glues together the platform
and codec drivers.
The machine driver can contain codec and platform specific code. It registers
the audio subsystem with the kernel as a platform device and is represented by
the following struct:-
/* SoC machine */
struct snd_soc_machine {
char *name;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
/* the pre and post PM functions are used to do any PM work before and
* after the codec and DAI's do any PM work. */
int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
int (*resume_pre)(struct platform_device *pdev);
int (*resume_post)(struct platform_device *pdev);
/* machine stream operations */
struct snd_soc_ops *ops;
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;
};
probe()/remove()
----------------
probe/remove are optional. Do any machine specific probe here.
suspend()/resume()
------------------
The machine driver has pre and post versions of suspend and resume to take care
of any machine audio tasks that have to be done before or after the codec, DAI's
and DMA is suspended and resumed. Optional.
Machine operations
------------------
The machine specific audio operations can be set here. Again this is optional.
Machine DAI Configuration
-------------------------
The machine DAI configuration glues all the codec and CPU DAI's together. It can
also be used to set up the DAI system clock and for any machine related DAI
initialisation e.g. the machine audio map can be connected to the codec audio
map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c
for examples.
struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
/* corgi digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link corgi_dai = {
.name = "WM8731",
.stream_name = "WM8731",
.cpu_dai = &pxa_i2s_dai,
.codec_dai = &wm8731_dai,
.init = corgi_wm8731_init,
.ops = &corgi_ops,
};
struct snd_soc_machine then sets up the machine with it's DAI's. e.g.
/* corgi audio machine driver */
static struct snd_soc_machine snd_soc_machine_corgi = {
.name = "Corgi",
.dai_link = &corgi_dai,
.num_links = 1,
};
Machine Audio Subsystem
-----------------------
The machine soc device glues the platform, machine and codec driver together.
Private data can also be set here. e.g.
/* corgi audio private data */
static struct wm8731_setup_data corgi_wm8731_setup = {
.i2c_address = 0x1b,
};
/* corgi audio subsystem */
static struct snd_soc_device corgi_snd_devdata = {
.machine = &snd_soc_machine_corgi,
.platform = &pxa2xx_soc_platform,
.codec_dev = &soc_codec_dev_wm8731,
.codec_data = &corgi_wm8731_setup,
};
Machine Power Map
-----------------
The machine driver can optionally extend the codec power map and to become an
audio power map of the audio subsystem. This allows for automatic power up/down
of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack
sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for
details.
Machine Controls
----------------
Machine specific audio mixer controls can be added in the dai init function.

View file

@ -0,0 +1,83 @@
ALSA SoC Layer
==============
The overall project goal of the ALSA System on Chip (ASoC) layer is to provide
better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00,
iMX, etc) and portable audio codecs. Currently there is some support in the
kernel for SoC audio, however it has some limitations:-
* Currently, codec drivers are often tightly coupled to the underlying SoC
cpu. This is not ideal and leads to code duplication i.e. Linux now has 4
different wm8731 drivers for 4 different SoC platforms.
* There is no standard method to signal user initiated audio events.
e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion
event. These are quite common events on portable devices and ofter require
machine specific code to re route audio, enable amps etc after such an event.
* Current drivers tend to power up the entire codec when playing
(or recording) audio. This is fine for a PC, but tends to waste a lot of
power on portable devices. There is also no support for saving power via
changing codec oversampling rates, bias currents, etc.
ASoC Design
===========
The ASoC layer is designed to address these issues and provide the following
features :-
* Codec independence. Allows reuse of codec drivers on other platforms
and machines.
* Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface
and codec registers it's audio interface capabilities with the core and are
subsequently matched and configured when the application hw params are known.
* Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to
it's minimum power state at all times. This includes powering up/down
internal power blocks depending on the internal codec audio routing and any
active streams.
* Pop and click reduction. Pops and clicks can be reduced by powering the
codec up/down in the correct sequence (including using digital mute). ASoC
signals the codec when to change power states.
* Machine specific controls: Allow machines to add controls to the sound card
e.g. volume control for speaker amp.
To achieve all this, ASoC basically splits an embedded audio system into 3
components :-
* Codec driver: The codec driver is platform independent and contains audio
controls, audio interface capabilities, codec dapm definition and codec IO
functions.
* Platform driver: The platform driver contains the audio dma engine and audio
interface drivers (e.g. I2S, AC97, PCM) for that platform.
* Machine driver: The machine driver handles any machine specific controls and
audio events. i.e. turing on an amp at start of playback.
Documentation
=============
The documentation is spilt into the following sections:-
overview.txt: This file.
codec.txt: Codec driver internals.
DAI.txt: Description of Digital Audio Interface standards and how to configure
a DAI within your codec and CPU DAI drivers.
dapm.txt: Dynamic Audio Power Management
platform.txt: Platform audio DMA and DAI.
machine.txt: Machine driver internals.
pop_clicks.txt: How to minimise audio artifacts.
clocking.txt: ASoC clocking for best power performance.

View file

@ -0,0 +1,58 @@
ASoC Platform Driver
====================
An ASoC platform driver can be divided into audio DMA and SoC DAI configuration
and control. The platform drivers only target the SoC CPU and must have no board
specific code.
Audio DMA
=========
The platform DMA driver optionally supports the following alsa operations:-
/* SoC audio ops */
struct snd_soc_ops {
int (*startup)(struct snd_pcm_substream *);
void (*shutdown)(struct snd_pcm_substream *);
int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
int (*hw_free)(struct snd_pcm_substream *);
int (*prepare)(struct snd_pcm_substream *);
int (*trigger)(struct snd_pcm_substream *, int);
};
The platform driver exports it's DMA functionailty via struct snd_soc_platform:-
struct snd_soc_platform {
char *name;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
/* pcm creation and destruction */
int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
void (*pcm_free)(struct snd_pcm *);
/* platform stream ops */
struct snd_pcm_ops *pcm_ops;
};
Please refer to the alsa driver documentation for details of audio DMA.
http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
An example DMA driver is soc/pxa/pxa2xx-pcm.c
SoC DAI Drivers
===============
Each SoC DAI driver must provide the following features:-
1) Digital audio interface (DAI) description
2) Digital audio interface configuration
3) PCM's description
4) Sysclk configuration
5) Suspend and resume (optional)
Please see codec.txt for a description of items 1 - 4.

View file

@ -0,0 +1,52 @@
Audio Pops and Clicks
=====================
Pops and clicks are unwanted audio artifacts caused by the powering up and down
of components within the audio subsystem. This is noticable on PC's when an
audio module is either loaded or unloaded (at module load time the sound card is
powered up and causes a popping noise on the speakers).
Pops and clicks can be more frequent on portable systems with DAPM. This is
because the components within the subsystem are being dynamically powered
depending on the audio usage and this can subsequently cause a small pop or
click every time a component power state is changed.
Minimising Playback Pops and Clicks
===================================
Playback pops in portable audio subsystems cannot be completely eliminated atm,
however future audio codec hardware will have better pop and click supression.
Pops can be reduced within playback by powering the audio components in a
specific order. This order is different for startup and shutdown and follows
some basic rules:-
Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC
This assumes that the codec PCM output path from the DAC is via a mixer and then
a PGA (programmable gain amplifier) before being output to the speakers.
Minimising Capture Pops and Clicks
==================================
Capture artifacts are somewhat easier to get rid as we can delay activating the
ADC until all the pops have occured. This follows similar power rules to
playback in that components are powered in a sequence depending upon stream
startup or shutdown.
Startup Order - Input PGA --> Mixers --> ADC
Shutdown Order - ADC --> Mixers --> Input PGA
Zipper Noise
============
An unwanted zipper noise can occur within the audio playback or capture stream
when a volume control is changed near its maximum gain value. The zipper noise
is heard when the gain increase or decrease changes the mean audio signal
amplitude too quickly. It can be minimised by enabling the zero cross setting
for each volume control. The ZC forces the gain change to occur when the signal
crosses the zero amplitude line.

View file

@ -3037,6 +3037,12 @@ M: perex@suse.cz
L: alsa-devel@alsa-project.org
S: Maintained
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
P: Liam Girdwood
M: liam.girdwood@wolfsonmicro.com
L: alsa-devel@alsa-project.org
S: Supported
SPI SUBSYSTEM
P: David Brownell
M: dbrownell@users.sourceforge.net

View file

@ -83,7 +83,7 @@
struct ucb1400 {
ac97_t *ac97;
struct snd_ac97 *ac97;
struct input_dev *ts_idev;
int irq;

View file

@ -115,6 +115,8 @@
#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
#define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */
#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */
#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */

View file

@ -375,6 +375,7 @@
#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
#define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */
#define AC97_SCAP_POWER_SAVE (1<<11) /* capable for aggresive power-saving */
/* ac97->flags */
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
@ -425,6 +426,7 @@ struct snd_ac97_build_ops {
struct snd_ac97_bus_ops {
void (*reset) (struct snd_ac97 *ac97);
void (*warm_reset)(struct snd_ac97 *ac97);
void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg);
void (*wait) (struct snd_ac97 *ac97);
@ -501,6 +503,7 @@ struct snd_ac97 {
unsigned short id[3]; // codec IDs (lower 16-bit word)
unsigned short pcmreg[3]; // PCM registers
unsigned short codec_cfg[3]; // CODEC_CFG bits
unsigned char swap_mic_linein; // AD1986/AD1986A only
} ad18xx;
unsigned int dev_flags; /* device specific */
} spec;
@ -510,7 +513,6 @@ struct snd_ac97 {
#ifdef CONFIG_SND_AC97_POWER_SAVE
unsigned int power_up; /* power states */
struct workqueue_struct *power_workq;
struct delayed_work power_work;
#endif
struct device dev;

View file

@ -185,7 +185,7 @@ struct ad1848_mix_elem {
int index;
int type;
unsigned long private_value;
unsigned int *tlv;
const unsigned int *tlv;
};
#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \

View file

@ -181,7 +181,6 @@ struct ak4114 {
unsigned long ccrc_errors;
unsigned char rcs0;
unsigned char rcs1;
struct workqueue_struct *workqueue;
struct delayed_work work;
void *change_callback_private;
void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1);
@ -189,7 +188,7 @@ struct ak4114 {
int snd_ak4114_create(struct snd_card *card,
ak4114_read_t *read, ak4114_write_t *write,
unsigned char pgm[7], unsigned char txcsb[5],
const unsigned char pgm[7], const unsigned char txcsb[5],
void *private_data, struct ak4114 **r_ak4114);
void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val);
void snd_ak4114_reinit(struct ak4114 *ak4114);

View file

@ -178,7 +178,7 @@ struct ak4117 {
};
int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
void snd_ak4117_reinit(struct ak4117 *ak4117);
int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream);

View file

@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel {
char *name; /* capture gain volume label */
char *switch_name; /* capture switch */
unsigned int num_channels;
char *selector_name; /* capture source select label */
const char **input_names; /* capture source names (NULL terminated) */
};
struct snd_akm4xxx {
@ -69,8 +71,8 @@ struct snd_akm4xxx {
} type;
/* (array) information of combined codecs */
struct snd_akm4xxx_dac_channel *dac_info;
struct snd_akm4xxx_adc_channel *adc_info;
const struct snd_akm4xxx_dac_channel *dac_info;
const struct snd_akm4xxx_adc_channel *adc_info;
struct snd_ak4xxx_ops ops;
};

View file

@ -49,7 +49,7 @@ struct snd_kcontrol_new {
snd_kcontrol_put_t *put;
union {
snd_kcontrol_tlv_rw_t *c;
unsigned int *p;
const unsigned int *p;
} tlv;
unsigned long private_value;
};
@ -69,7 +69,7 @@ struct snd_kcontrol {
snd_kcontrol_put_t *put;
union {
snd_kcontrol_tlv_rw_t *c;
unsigned int *p;
const unsigned int *p;
} tlv;
unsigned long private_value;
void *private_data;
@ -108,7 +108,6 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol * kcontrol, unsigned int access);
struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);

View file

@ -211,9 +211,40 @@ extern struct class *sound_class;
void snd_request_card(int card);
int snd_register_device(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops, void *private_data,
const char *name);
int snd_register_device_for_dev(int type, struct snd_card *card,
int dev,
const struct file_operations *f_ops,
void *private_data,
const char *name,
struct device *device);
/**
* snd_register_device - Register the ALSA device file for the card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
* @card: the card instance
* @dev: the device index
* @f_ops: the file operations
* @private_data: user pointer for f_ops->open()
* @name: the device file name
*
* Registers an ALSA device file for the given card.
* The operators have to be set in reg parameter.
*
* This function uses the card's device pointer to link to the
* correct &struct device.
*
* Returns zero if successful, or a negative error code on failure.
*/
static inline int snd_register_device(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops,
void *private_data,
const char *name)
{
return snd_register_device_for_dev(type, card, dev, f_ops,
private_data, name,
snd_card_get_device_link(card));
}
int snd_unregister_device(int type, struct snd_card *card, int dev);
void *snd_lookup_minor_data(unsigned int minor, int type);
int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
@ -396,6 +427,29 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
#endif
#endif
#include "typedefs.h"
/* PCI quirk list helper */
struct snd_pci_quirk {
unsigned short subvendor; /* PCI subvendor ID */
unsigned short subdevice; /* PCI subdevice ID */
int value; /* value */
#ifdef CONFIG_SND_DEBUG_DETECT
const char *name; /* name of the device (optional) */
#endif
};
#define _SND_PCI_QUIRK_ID(vend,dev) \
.subvendor = (vend), .subdevice = (dev)
#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
#ifdef CONFIG_SND_DEBUG_DETECT
#define SND_PCI_QUIRK(vend,dev,xname,val) \
{_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
#else
#define SND_PCI_QUIRK(vend,dev,xname,val) \
{_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
#endif
const struct snd_pci_quirk *
snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
#endif /* __SOUND_CORE_H */

View file

@ -188,7 +188,35 @@
#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */
/* NOTE: The rest of the bits in this register */
/* _are_ relevant under Linux. */
#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */
#define HCFG_PUSH_BUTTON_ENABLE 0x00100000 /* Enables Volume Inc/Dec and Mute functions */
#define HCFG_BAUD_RATE 0x00080000 /* 0 = 48kHz, 1 = 44.1kHz */
#define HCFG_EXPANDED_MEM 0x00040000 /* 1 = any 16M of 4G addr, 0 = 32M of 2G addr */
#define HCFG_CODECFORMAT_MASK 0x00030000 /* CODEC format */
/* Specific to Alice2, CA0102 */
#define HCFG_CODECFORMAT_AC97_1 0x00000000 /* AC97 CODEC format -- Ver 1.03 */
#define HCFG_CODECFORMAT_AC97_2 0x00010000 /* AC97 CODEC format -- Ver 2.1 */
#define HCFG_AUTOMUTE_ASYNC 0x00008000 /* When set, the async sample rate convertors */
/* will automatically mute their output when */
/* they are not rate-locked to the external */
/* async audio source */
#define HCFG_AUTOMUTE_SPDIF 0x00004000 /* When set, the async sample rate convertors */
/* will automatically mute their output when */
/* the SPDIF V-bit indicates invalid audio */
#define HCFG_EMU32_SLAVE 0x00002000 /* 0 = Master, 1 = Slave. Slave for EMU1010 */
#define HCFG_SLOW_RAMP 0x00001000 /* Increases Send Smoothing time constant */
/* 0x00000800 not used on Alice2 */
#define HCFG_PHASE_TRACK_MASK 0x00000700 /* When set, forces corresponding input to */
/* phase track the previous input. */
/* I2S0 can phase track the last S/PDIF input */
#define HCFG_I2S_ASRC_ENABLE 0x00000070 /* When set, enables asynchronous sample rate */
/* conversion for the corresponding */
/* I2S format input */
/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc. */
/* Older chips */
#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */
#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */
#define HCFG_GPINPUT0 0x00004000 /* External pin112 */
@ -432,6 +460,7 @@
#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */
#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */
#define A_HR 0x0b /* High Resolution. 24bit playback from host to DSP. */
#define MAPA 0x0c /* Cache map A */
#define MAPB 0x0d /* Cache map B */
@ -439,6 +468,8 @@
#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
/* 0x0e, 0x0f: Not used */
#define ENVVOL 0x10 /* Volume envelope register */
#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */
/* 0x8000-n == 666*n usec delay */
@ -527,7 +558,7 @@
/* NOTE: All channels contain internal variables; do */
/* not write to these locations. */
/* 1f something */
/* 0x1f: not used */
#define CD0 0x20 /* Cache data 0 register */
#define CD1 0x21 /* Cache data 1 register */
@ -597,6 +628,8 @@
#define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */
#define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */
#define A_TBLSZ ` 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */
#define TCBS 0x44 /* Tank cache buffer size register */
#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
#define TCBS_BUFFSIZE_16K 0x00000000
@ -617,7 +650,7 @@
#define FXBA 0x47 /* FX Buffer Address */
#define FXBA_MASK 0xfffff000 /* 20 bit base address */
/* 0x48 something - word access, defaults to 3f */
#define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */
#define MICBS 0x49 /* Microphone buffer size register */
@ -661,6 +694,18 @@
#define ADCBS_BUFSIZE_57344 0x0000001e
#define ADCBS_BUFSIZE_65536 0x0000001f
/* Current Send B, A Amounts */
#define A_CSBA 0x4c
/* Current Send D, C Amounts */
#define A_CSDC 0x4d
/* Current Send F, E Amounts */
#define A_CSFE 0x4e
/* Current Send H, G Amounts */
#define A_CSHG 0x4f
#define CDCS 0x50 /* CD-ROM digital channel status register */
@ -668,6 +713,9 @@
#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
/* S/PDIF Input C Channel Status */
#define A_SPSC 0x52
#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
#define A_DBG 0x53
@ -708,6 +756,8 @@
#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
/* 0x57: Not used */
/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */
#define CLIEL 0x58 /* Channel loop interrupt enable low register */
@ -733,6 +783,9 @@
#define AC97SLOT_CNTR 0x10 /* Center enable */
#define AC97SLOT_LFE 0x20 /* LFE enable */
/* PCB Revision */
#define A_PCB 0x5f
// NOTE: 0x60,61,62: 64-bit
#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */
@ -780,9 +833,18 @@
#define HLIPH 0x69 /* Channel half loop interrupt pending high register */
// 0x6a,6b,6c used for some recording
// 0x6d unused
// 0x6e,6f - tanktable base / offset
/* S/PDIF Host Record Index (bypasses SRC) */
#define A_SPRI 0x6a
/* S/PDIF Host Record Address */
#define A_SPRA 0x6b
/* S/PDIF Host Record Control */
#define A_SPRC 0x6c
/* Delayed Interrupt Counter & Enable */
#define A_DICE 0x6d
/* Tank Table Base */
#define A_TTB 0x6e
/* Tank Delay Offset */
#define A_TDOF 0x6f
/* This is the MPU port on the card (via the game port) */
#define A_MUDATA1 0x70
@ -800,6 +862,7 @@
#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */
#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
/* Extended Hardware Control */
#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
#define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */
#define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */
@ -822,8 +885,20 @@
#define A_PCM_96000 0x00004000
#define A_PCM_44100 0x00008000
/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */
/* 0x7a, 0x7b - lookup tables */
/* I2S0 Sample Rate Tracker Status */
#define A_SRT3 0x77
/* I2S1 Sample Rate Tracker Status */
#define A_SRT4 0x78
/* I2S2 Sample Rate Tracker Status */
#define A_SRT5 0x79
/* - default to 0x01080000 on my audigy 2 ZS --rlrevell */
/* Tank Table DMA Address */
#define A_TTDA 0x7a
/* Tank Table DMA Data */
#define A_TTDD 0x7b
#define A_FXRT2 0x7c
#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
@ -845,7 +920,7 @@
#define A_FXRT_CHANNELC 0x003f0000
#define A_FXRT_CHANNELD 0x3f000000
/* 0x7f: Not used */
/* Each FX general purpose register is 32 bits in length, all bits are used */
#define FXGPREGBASE 0x100 /* FX general purpose registers base */
#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */
@ -886,6 +961,293 @@
#define A_HIWORD_RESULT_MASK 0x007ff000
#define A_HIWORD_OPA_MASK 0x000007ff
/************************************************************************************************/
/* EMU1010m HANA FPGA registers */
/************************************************************************************************/
#define EMU_HANA_DESTHI 0x00 /* 0000xxx 3 bits Link Destination */
#define EMU_HANA_DESTLO 0x01 /* 00xxxxx 5 bits */
#define EMU_HANA_SRCHI 0x02 /* 0000xxx 3 bits Link Source */
#define EMU_HANA_SRCLO 0x03 /* 00xxxxx 5 bits */
#define EMU_HANA_DOCK_PWR 0x04 /* 000000x 1 bits Audio Dock power */
#define EMU_HANA_DOCK_PWR_ON 0x01 /* Audio Dock power on */
#define EMU_HANA_WCLOCK 0x05 /* 0000xxx 3 bits Word Clock source select */
/* Must be written after power on to reset DLL */
/* One is unable to detect the Audio dock without this */
#define EMU_HANA_WCLOCK_SRC_MASK 0x07
#define EMU_HANA_WCLOCK_INT_48K 0x00
#define EMU_HANA_WCLOCK_INT_44_1K 0x01
#define EMU_HANA_WCLOCK_HANA_SPDIF_IN 0x02
#define EMU_HANA_WCLOCK_HANA_ADAT_IN 0x03
#define EMU_HANA_WCLOCK_SYNC_BNCN 0x04
#define EMU_HANA_WCLOCK_2ND_HANA 0x05
#define EMU_HANA_WCLOCK_SRC_RESERVED 0x06
#define EMU_HANA_WCLOCK_OFF 0x07 /* For testing, forces fallback to DEFCLOCK */
#define EMU_HANA_WCLOCK_MULT_MASK 0x18
#define EMU_HANA_WCLOCK_1X 0x00
#define EMU_HANA_WCLOCK_2X 0x08
#define EMU_HANA_WCLOCK_4X 0x10
#define EMU_HANA_WCLOCK_MULT_RESERVED 0x18
#define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */
#define EMU_HANA_DEFCLOCK_48K 0x00
#define EMU_HANA_DEFCLOCK_44_1K 0x01
#define EMU_HANA_UNMUTE 0x07 /* 000000x 1 bits Mute all audio outputs */
#define EMU_MUTE 0x00
#define EMU_UNMUTE 0x01
#define EMU_HANA_FPGA_CONFIG 0x08 /* 00000xx 2 bits Config control of FPGAs */
#define EMU_HANA_FPGA_CONFIG_AUDIODOCK 0x01 /* Set in order to program FPGA on Audio Dock */
#define EMU_HANA_FPGA_CONFIG_HANA 0x02 /* Set in order to program FPGA on Hana */
#define EMU_HANA_IRQ_ENABLE 0x09 /* 000xxxx 4 bits IRQ Enable */
#define EMU_HANA_IRQ_WCLK_CHANGED 0x01
#define EMU_HANA_IRQ_ADAT 0x02
#define EMU_HANA_IRQ_DOCK 0x04
#define EMU_HANA_IRQ_DOCK_LOST 0x08
#define EMU_HANA_SPDIF_MODE 0x0a /* 00xxxxx 5 bits SPDIF MODE */
#define EMU_HANA_SPDIF_MODE_TX_COMSUMER 0x00
#define EMU_HANA_SPDIF_MODE_TX_PRO 0x01
#define EMU_HANA_SPDIF_MODE_TX_NOCOPY 0x02
#define EMU_HANA_SPDIF_MODE_RX_COMSUMER 0x00
#define EMU_HANA_SPDIF_MODE_RX_PRO 0x04
#define EMU_HANA_SPDIF_MODE_RX_NOCOPY 0x08
#define EMU_HANA_SPDIF_MODE_RX_INVALID 0x10
#define EMU_HANA_OPTICAL_TYPE 0x0b /* 00000xx 2 bits ADAT or SPDIF in/out */
#define EMU_HANA_OPTICAL_IN_SPDIF 0x00
#define EMU_HANA_OPTICAL_IN_ADAT 0x01
#define EMU_HANA_OPTICAL_OUT_SPDIF 0x00
#define EMU_HANA_OPTICAL_OUT_ADAT 0x02
#define EMU_HANA_MIDI_IN 0x0c /* 000000x 1 bit Control MIDI */
#define EMU_HANA_MIDI_IN_FROM_HAMOA 0x00 /* HAMOA MIDI in to Alice 2 MIDI B */
#define EMU_HANA_MIDI_IN_FROM_DOCK 0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */
#define EMU_HANA_DOCK_LEDS_1 0x0d /* 000xxxx 4 bit Audio Dock LEDs */
#define EMU_HANA_DOCK_LEDS_1_MIDI1 0x01 /* MIDI 1 LED on */
#define EMU_HANA_DOCK_LEDS_1_MIDI2 0x02 /* MIDI 2 LED on */
#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN 0x04 /* SMPTE IN LED on */
#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT 0x08 /* SMPTE OUT LED on */
#define EMU_HANA_DOCK_LEDS_2 0x0e /* 0xxxxxx 6 bit Audio Dock LEDs */
#define EMU_HANA_DOCK_LEDS_2_44K 0x01 /* 44.1 kHz LED on */
#define EMU_HANA_DOCK_LEDS_2_48K 0x02 /* 48 kHz LED on */
#define EMU_HANA_DOCK_LEDS_2_96K 0x04 /* 96 kHz LED on */
#define EMU_HANA_DOCK_LEDS_2_192K 0x08 /* 192 kHz LED on */
#define EMU_HANA_DOCK_LEDS_2_LOCK 0x10 /* LOCK LED on */
#define EMU_HANA_DOCK_LEDS_2_EXT 0x20 /* EXT LED on */
#define EMU_HANA_DOCK_LEDS_3 0x0f /* 0xxxxxx 6 bit Audio Dock LEDs */
#define EMU_HANA_DOCK_LEDS_3_CLIP_A 0x01 /* Mic A Clip LED on */
#define EMU_HANA_DOCK_LEDS_3_CLIP_B 0x02 /* Mic B Clip LED on */
#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A 0x04 /* Signal A Clip LED on */
#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B 0x08 /* Signal B Clip LED on */
#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP 0x10 /* Manual Clip detection */
#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL 0x20 /* Manual Signal detection */
#define EMU_HANA_ADC_PADS 0x10 /* 0000xxx 3 bit Audio Dock ADC 14dB pads */
#define EMU_HANA_DOCK_ADC_PAD1 0x01 /* 14dB Attenuation on Audio Dock ADC 1 */
#define EMU_HANA_DOCK_ADC_PAD2 0x02 /* 14dB Attenuation on Audio Dock ADC 2 */
#define EMU_HANA_DOCK_ADC_PAD3 0x04 /* 14dB Attenuation on Audio Dock ADC 3 */
#define EMU_HANA_0202_ADC_PAD1 0x08 /* 14dB Attenuation on 0202 ADC 1 */
#define EMU_HANA_DOCK_MISC 0x11 /* 0xxxxxx 6 bit Audio Dock misc bits */
#define EMU_HANA_DOCK_DAC1_MUTE 0x01 /* DAC 1 Mute */
#define EMU_HANA_DOCK_DAC2_MUTE 0x02 /* DAC 2 Mute */
#define EMU_HANA_DOCK_DAC3_MUTE 0x04 /* DAC 3 Mute */
#define EMU_HANA_DOCK_DAC4_MUTE 0x08 /* DAC 4 Mute */
#define EMU_HANA_DOCK_PHONES_192_DAC1 0x00 /* DAC 1 Headphones source at 192kHz */
#define EMU_HANA_DOCK_PHONES_192_DAC2 0x10 /* DAC 2 Headphones source at 192kHz */
#define EMU_HANA_DOCK_PHONES_192_DAC3 0x20 /* DAC 3 Headphones source at 192kHz */
#define EMU_HANA_DOCK_PHONES_192_DAC4 0x30 /* DAC 4 Headphones source at 192kHz */
#define EMU_HANA_MIDI_OUT 0x12 /* 00xxxxx 5 bit Source for each MIDI out port */
#define EMU_HANA_MIDI_OUT_0202 0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */
#define EMU_HANA_MIDI_OUT_DOCK1 0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */
#define EMU_HANA_MIDI_OUT_DOCK2 0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */
#define EMU_HANA_MIDI_OUT_SYNC2 0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */
#define EMU_HANA_MIDI_OUT_LOOP 0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */
#define EMU_HANA_DAC_PADS 0x13 /* 00xxxxx 5 bit DAC 14dB attenuation pads */
#define EMU_HANA_DOCK_DAC_PAD1 0x01 /* 14dB Attenuation on AudioDock DAC 1. Left and Right */
#define EMU_HANA_DOCK_DAC_PAD2 0x02 /* 14dB Attenuation on AudioDock DAC 2. Left and Right */
#define EMU_HANA_DOCK_DAC_PAD3 0x04 /* 14dB Attenuation on AudioDock DAC 3. Left and Right */
#define EMU_HANA_DOCK_DAC_PAD4 0x08 /* 14dB Attenuation on AudioDock DAC 4. Left and Right */
#define EMU_HANA_0202_DAC_PAD1 0x10 /* 14dB Attenuation on 0202 DAC 1. Left and Right */
/* 0x14 - 0x1f Unused R/W registers */
#define EMU_HANA_IRQ_STATUS 0x20 /* 000xxxx 4 bits IRQ Status */
#if 0 /* Already defined for reg 0x09 IRQ_ENABLE */
#define EMU_HANA_IRQ_WCLK_CHANGED 0x01
#define EMU_HANA_IRQ_ADAT 0x02
#define EMU_HANA_IRQ_DOCK 0x04
#define EMU_HANA_IRQ_DOCK_LOST 0x08
#endif
#define EMU_HANA_OPTION_CARDS 0x21 /* 000xxxx 4 bits Presence of option cards */
#define EMU_HANA_OPTION_HAMOA 0x01 /* HAMOA card present */
#define EMU_HANA_OPTION_SYNC 0x02 /* Sync card present */
#define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio Dock online and FPGA configured */
#define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio Dock online and FPGA not configured */
#define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 */
#define EMU_HANA_MAJOR_REV 0x23 /* 0000xxx 3 bit Hana FPGA Major rev */
#define EMU_HANA_MINOR_REV 0x24 /* 0000xxx 3 bit Hana FPGA Minor rev */
#define EMU_DOCK_MAJOR_REV 0x25 /* 0000xxx 3 bit Audio Dock FPGA Major rev */
#define EMU_DOCK_MINOR_REV 0x26 /* 0000xxx 3 bit Audio Dock FPGA Minor rev */
#define EMU_DOCK_BOARD_ID 0x27 /* 00000xx 2 bits Audio Dock ID pins */
#define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */
#define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */
#define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */
#define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */
#define EMU_HANA_WC_ADAT_HI 0x2a /* 0xxxxxx 6 bit ADAT IN Word clock, upper 6 bits */
#define EMU_HANA_WC_ADAT_LO 0x2b /* 0xxxxxx 6 bit ADAT IN Word clock, lower 6 bits */
#define EMU_HANA_WC_BNC_LO 0x2c /* 0xxxxxx 6 bit BNC IN Word clock, lower 6 bits */
#define EMU_HANA_WC_BNC_HI 0x2d /* 0xxxxxx 6 bit BNC IN Word clock, upper 6 bits */
#define EMU_HANA2_WC_SPDIF_HI 0x2e /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, upper 6 bits */
#define EMU_HANA2_WC_SPDIF_LO 0x2f /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, lower 6 bits */
/* 0x30 - 0x3f Unused Read only registers */
/************************************************************************************************/
/* EMU1010m HANA Destinations */
/************************************************************************************************/
#define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_4 0x0003 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_5 0x0004 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_6 0x0005 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_7 0x0006 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_8 0x0007 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_9 0x0008 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_A 0x0009 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_B 0x000a /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_C 0x000b /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_D 0x000c /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_E 0x000d /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_F 0x000e /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_DOCK_DAC1_LEFT1 0x0100 /* Audio Dock DAC1 Left, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC1_LEFT2 0x0101 /* Audio Dock DAC1 Left, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC1_LEFT3 0x0102 /* Audio Dock DAC1 Left, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC1_LEFT4 0x0103 /* Audio Dock DAC1 Left, 4th or 192kHz */
#define EMU_DST_DOCK_DAC1_RIGHT1 0x0104 /* Audio Dock DAC1 Right, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC1_RIGHT2 0x0105 /* Audio Dock DAC1 Right, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC1_RIGHT3 0x0106 /* Audio Dock DAC1 Right, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC1_RIGHT4 0x0107 /* Audio Dock DAC1 Right, 4th or 192kHz */
#define EMU_DST_DOCK_DAC2_LEFT1 0x0108 /* Audio Dock DAC2 Left, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC2_LEFT2 0x0109 /* Audio Dock DAC2 Left, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC2_LEFT3 0x010a /* Audio Dock DAC2 Left, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC2_LEFT4 0x010b /* Audio Dock DAC2 Left, 4th or 192kHz */
#define EMU_DST_DOCK_DAC2_RIGHT1 0x010c /* Audio Dock DAC2 Right, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC2_RIGHT2 0x010d /* Audio Dock DAC2 Right, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC2_RIGHT3 0x010e /* Audio Dock DAC2 Right, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC2_RIGHT4 0x010f /* Audio Dock DAC2 Right, 4th or 192kHz */
#define EMU_DST_DOCK_DAC3_LEFT1 0x0110 /* Audio Dock DAC1 Left, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC3_LEFT2 0x0111 /* Audio Dock DAC1 Left, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC3_LEFT3 0x0112 /* Audio Dock DAC1 Left, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC3_LEFT4 0x0113 /* Audio Dock DAC1 Left, 4th or 192kHz */
#define EMU_DST_DOCK_PHONES_LEFT1 0x0112 /* Audio Dock PHONES Left, 1st or 48kHz only */
#define EMU_DST_DOCK_PHONES_LEFT2 0x0113 /* Audio Dock PHONES Left, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC3_RIGHT1 0x0114 /* Audio Dock DAC1 Right, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC3_RIGHT2 0x0115 /* Audio Dock DAC1 Right, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC3_RIGHT3 0x0116 /* Audio Dock DAC1 Right, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC3_RIGHT4 0x0117 /* Audio Dock DAC1 Right, 4th or 192kHz */
#define EMU_DST_DOCK_PHONES_RIGHT1 0x0116 /* Audio Dock PHONES Right, 1st or 48kHz only */
#define EMU_DST_DOCK_PHONES_RIGHT2 0x0117 /* Audio Dock PHONES Right, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC4_LEFT1 0x0118 /* Audio Dock DAC2 Left, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC4_LEFT2 0x0119 /* Audio Dock DAC2 Left, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC4_LEFT3 0x011a /* Audio Dock DAC2 Left, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC4_LEFT4 0x011b /* Audio Dock DAC2 Left, 4th or 192kHz */
#define EMU_DST_DOCK_SPDIF_LEFT1 0x011a /* Audio Dock SPDIF Left, 1st or 48kHz only */
#define EMU_DST_DOCK_SPDIF_LEFT2 0x011b /* Audio Dock SPDIF Left, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC4_RIGHT1 0x011c /* Audio Dock DAC2 Right, 1st or 48kHz only */
#define EMU_DST_DOCK_DAC4_RIGHT2 0x011d /* Audio Dock DAC2 Right, 2nd or 96kHz */
#define EMU_DST_DOCK_DAC4_RIGHT3 0x011e /* Audio Dock DAC2 Right, 3rd or 192kHz */
#define EMU_DST_DOCK_DAC4_RIGHT4 0x011f /* Audio Dock DAC2 Right, 4th or 192kHz */
#define EMU_DST_DOCK_SPDIF_RIGHT1 0x011e /* Audio Dock SPDIF Right, 1st or 48kHz only */
#define EMU_DST_DOCK_SPDIF_RIGHT2 0x011f /* Audio Dock SPDIF Right, 2nd or 96kHz */
#define EMU_DST_HANA_SPDIF_LEFT1 0x0200 /* Hana SPDIF Left, 1st or 48kHz only */
#define EMU_DST_HANA_SPDIF_LEFT2 0x0202 /* Hana SPDIF Left, 2nd or 96kHz */
#define EMU_DST_HANA_SPDIF_RIGHT1 0x0201 /* Hana SPDIF Right, 1st or 48kHz only */
#define EMU_DST_HANA_SPDIF_RIGHT2 0x0203 /* Hana SPDIF Right, 2nd or 96kHz */
#define EMU_DST_HAMOA_DAC_LEFT1 0x0300 /* Hamoa DAC Left, 1st or 48kHz only */
#define EMU_DST_HAMOA_DAC_LEFT2 0x0302 /* Hamoa DAC Left, 2nd or 96kHz */
#define EMU_DST_HAMOA_DAC_LEFT3 0x0304 /* Hamoa DAC Left, 3rd or 192kHz */
#define EMU_DST_HAMOA_DAC_LEFT4 0x0306 /* Hamoa DAC Left, 4th or 192kHz */
#define EMU_DST_HAMOA_DAC_RIGHT1 0x0301 /* Hamoa DAC Right, 1st or 48kHz only */
#define EMU_DST_HAMOA_DAC_RIGHT2 0x0303 /* Hamoa DAC Right, 2nd or 96kHz */
#define EMU_DST_HAMOA_DAC_RIGHT3 0x0305 /* Hamoa DAC Right, 3rd or 192kHz */
#define EMU_DST_HAMOA_DAC_RIGHT4 0x0307 /* Hamoa DAC Right, 4th or 192kHz */
#define EMU_DST_HANA_ADAT 0x0400 /* Hana ADAT 8 channel out +0 to +7 */
#define EMU_DST_ALICE_I2S0_LEFT 0x0500 /* Alice2 I2S0 Left */
#define EMU_DST_ALICE_I2S0_RIGHT 0x0501 /* Alice2 I2S0 Right */
#define EMU_DST_ALICE_I2S1_LEFT 0x0600 /* Alice2 I2S1 Left */
#define EMU_DST_ALICE_I2S1_RIGHT 0x0601 /* Alice2 I2S1 Right */
#define EMU_DST_ALICE_I2S2_LEFT 0x0700 /* Alice2 I2S2 Left */
#define EMU_DST_ALICE_I2S2_RIGHT 0x0701 /* Alice2 I2S2 Right */
/************************************************************************************************/
/* EMU1010m HANA Sources */
/************************************************************************************************/
#define EMU_SRC_SILENCE 0x0000 /* Silence */
#define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */
#define EMU_SRC_DOCK_MIC_A2 0x0101 /* Audio Dock Mic A, 2nd or 96kHz */
#define EMU_SRC_DOCK_MIC_A3 0x0102 /* Audio Dock Mic A, 3rd or 192kHz */
#define EMU_SRC_DOCK_MIC_A4 0x0103 /* Audio Dock Mic A, 4th or 192kHz */
#define EMU_SRC_DOCK_MIC_B1 0x0104 /* Audio Dock Mic B, 1st or 48kHz only */
#define EMU_SRC_DOCK_MIC_B2 0x0105 /* Audio Dock Mic B, 2nd or 96kHz */
#define EMU_SRC_DOCK_MIC_B3 0x0106 /* Audio Dock Mic B, 3rd or 192kHz */
#define EMU_SRC_DOCK_MIC_B4 0x0107 /* Audio Dock Mic B, 4th or 192kHz */
#define EMU_SRC_DOCK_ADC1_LEFT1 0x0108 /* Audio Dock ADC1 Left, 1st or 48kHz only */
#define EMU_SRC_DOCK_ADC1_LEFT2 0x0109 /* Audio Dock ADC1 Left, 2nd or 96kHz */
#define EMU_SRC_DOCK_ADC1_LEFT3 0x010a /* Audio Dock ADC1 Left, 3rd or 192kHz */
#define EMU_SRC_DOCK_ADC1_LEFT4 0x010b /* Audio Dock ADC1 Left, 4th or 192kHz */
#define EMU_SRC_DOCK_ADC1_RIGHT1 0x010c /* Audio Dock ADC1 Right, 1st or 48kHz only */
#define EMU_SRC_DOCK_ADC1_RIGHT2 0x010d /* Audio Dock ADC1 Right, 2nd or 96kHz */
#define EMU_SRC_DOCK_ADC1_RIGHT3 0x010e /* Audio Dock ADC1 Right, 3rd or 192kHz */
#define EMU_SRC_DOCK_ADC1_RIGHT4 0x010f /* Audio Dock ADC1 Right, 4th or 192kHz */
#define EMU_SRC_DOCK_ADC2_LEFT1 0x0110 /* Audio Dock ADC2 Left, 1st or 48kHz only */
#define EMU_SRC_DOCK_ADC2_LEFT2 0x0111 /* Audio Dock ADC2 Left, 2nd or 96kHz */
#define EMU_SRC_DOCK_ADC2_LEFT3 0x0112 /* Audio Dock ADC2 Left, 3rd or 192kHz */
#define EMU_SRC_DOCK_ADC2_LEFT4 0x0113 /* Audio Dock ADC2 Left, 4th or 192kHz */
#define EMU_SRC_DOCK_ADC2_RIGHT1 0x0114 /* Audio Dock ADC2 Right, 1st or 48kHz only */
#define EMU_SRC_DOCK_ADC2_RIGHT2 0x0115 /* Audio Dock ADC2 Right, 2nd or 96kHz */
#define EMU_SRC_DOCK_ADC2_RIGHT3 0x0116 /* Audio Dock ADC2 Right, 3rd or 192kHz */
#define EMU_SRC_DOCK_ADC2_RIGHT4 0x0117 /* Audio Dock ADC2 Right, 4th or 192kHz */
#define EMU_SRC_DOCK_ADC3_LEFT1 0x0118 /* Audio Dock ADC3 Left, 1st or 48kHz only */
#define EMU_SRC_DOCK_ADC3_LEFT2 0x0119 /* Audio Dock ADC3 Left, 2nd or 96kHz */
#define EMU_SRC_DOCK_ADC3_LEFT3 0x011a /* Audio Dock ADC3 Left, 3rd or 192kHz */
#define EMU_SRC_DOCK_ADC3_LEFT4 0x011b /* Audio Dock ADC3 Left, 4th or 192kHz */
#define EMU_SRC_DOCK_ADC3_RIGHT1 0x011c /* Audio Dock ADC3 Right, 1st or 48kHz only */
#define EMU_SRC_DOCK_ADC3_RIGHT2 0x011d /* Audio Dock ADC3 Right, 2nd or 96kHz */
#define EMU_SRC_DOCK_ADC3_RIGHT3 0x011e /* Audio Dock ADC3 Right, 3rd or 192kHz */
#define EMU_SRC_DOCK_ADC3_RIGHT4 0x011f /* Audio Dock ADC3 Right, 4th or 192kHz */
#define EMU_SRC_HAMOA_ADC_LEFT1 0x0200 /* Hamoa ADC Left, 1st or 48kHz only */
#define EMU_SRC_HAMOA_ADC_LEFT2 0x0202 /* Hamoa ADC Left, 2nd or 96kHz */
#define EMU_SRC_HAMOA_ADC_LEFT3 0x0204 /* Hamoa ADC Left, 3rd or 192kHz */
#define EMU_SRC_HAMOA_ADC_LEFT4 0x0206 /* Hamoa ADC Left, 4th or 192kHz */
#define EMU_SRC_HAMOA_ADC_RIGHT1 0x0201 /* Hamoa ADC Right, 1st or 48kHz only */
#define EMU_SRC_HAMOA_ADC_RIGHT2 0x0203 /* Hamoa ADC Right, 2nd or 96kHz */
#define EMU_SRC_HAMOA_ADC_RIGHT3 0x0205 /* Hamoa ADC Right, 3rd or 192kHz */
#define EMU_SRC_HAMOA_ADC_RIGHT4 0x0207 /* Hamoa ADC Right, 4th or 192kHz */
#define EMU_SRC_ALICE_EMU32A 0x0300 /* Alice2 EMU32a 16 outputs. +0 to +0xf */
#define EMU_SRC_ALICE_EMU32B 0x0310 /* Alice2 EMU32b 16 outputs. +0 to +0xf */
#define EMU_SRC_HANA_ADAT 0x0400 /* Hana ADAT 8 channel in +0 to +7 */
#define EMU_SRC_HANA_SPDIF_LEFT1 0x0500 /* Hana SPDIF Left, 1st or 48kHz only */
#define EMU_SRC_HANA_SPDIF_LEFT2 0x0502 /* Hana SPDIF Left, 2nd or 96kHz */
#define EMU_SRC_HANA_SPDIF_RIGHT1 0x0501 /* Hana SPDIF Right, 1st or 48kHz only */
#define EMU_SRC_HANA_SPDIF_RIGHT2 0x0503 /* Hana SPDIF Right, 2nd or 96kHz */
/* 0x600 and 0x700 no used */
/* ------------------- STRUCTURES -------------------- */
@ -1063,7 +1425,7 @@ struct snd_emu_chip_details {
unsigned char spdif_bug; /* Has Spdif phasing bug */
unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */
unsigned char ecard; /* APS EEPROM */
unsigned char emu1212m; /* EMU 1212m card */
unsigned char emu1010; /* EMU 1010m card */
unsigned char spi_dac; /* SPI interface for DAC */
unsigned char i2c_adc; /* I2C interface for ADC */
unsigned char adc_1361t; /* Use Philips 1361T ADC */
@ -1072,6 +1434,14 @@ struct snd_emu_chip_details {
const char *id; /* for backward compatibility - can be NULL if not needed */
};
struct snd_emu1010 {
unsigned int output_source[64];
unsigned int input_source[64];
unsigned int adc_pads; /* bit mask */
unsigned int dac_pads; /* bit mask */
unsigned int internal_clock; /* 44100 or 48000 */
};
struct snd_emu10k1 {
int irq;
@ -1079,6 +1449,7 @@ struct snd_emu10k1 {
unsigned int tos_link: 1, /* tos link detected */
rear_ac97: 1, /* rear channels are on AC'97 */
enable_ir: 1;
unsigned int support_tlv :1;
/* Contains profile of card capabilities */
const struct snd_emu_chip_details *card_capabilities;
unsigned int audigy; /* is Audigy? */
@ -1104,6 +1475,8 @@ struct snd_emu10k1 {
spinlock_t memblk_lock;
unsigned int spdif_bits[3]; /* s/pdif out setup */
unsigned int i2c_capture_source;
u8 i2c_capture_volume[4][2];
struct snd_emu10k1_fx8010 fx8010; /* FX8010 info */
int gpr_base;
@ -1132,6 +1505,7 @@ struct snd_emu10k1 {
int p16v_device_offset;
u32 p16v_capture_source;
u32 p16v_capture_channel;
struct snd_emu1010 emu1010;
struct snd_emu10k1_pcm_mixer pcm_mixer[32];
struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK];
struct snd_kcontrol *ctl_send_routing;
@ -1208,6 +1582,10 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
@ -1524,11 +1902,20 @@ struct snd_emu10k1_fx8010_control_gpr {
unsigned int value[32]; /* initial values */
unsigned int min; /* minimum range */
unsigned int max; /* maximum range */
union {
snd_kcontrol_tlv_rw_t *c;
unsigned int *p;
} tlv;
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
const unsigned int *tlv;
};
/* old ABI without TLV support */
struct snd_emu10k1_fx8010_control_old_gpr {
struct snd_ctl_elem_id id;
unsigned int vcount;
unsigned int count;
unsigned short gpr[32];
unsigned int value[32];
unsigned int min;
unsigned int max;
unsigned int translation;
};
struct snd_emu10k1_fx8010_code {
@ -1579,6 +1966,8 @@ struct snd_emu10k1_fx8010_pcm_rec {
unsigned int res2; /* reserved */
};
#define SNDRV_EMU10K1_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info)
#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code)
#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code)
@ -1587,6 +1976,7 @@ struct snd_emu10k1_fx8010_pcm_rec {
#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram)
#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec)
#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec)
#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int)
#define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80)
#define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81)
#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82)

View file

@ -56,6 +56,8 @@ struct snd_pcm_hardware {
size_t fifo_size; /* fifo size in bytes */
};
struct snd_pcm_substream;
struct snd_pcm_ops {
int (*open)(struct snd_pcm_substream *substream);
int (*close)(struct snd_pcm_substream *substream);
@ -384,6 +386,7 @@ struct snd_pcm_substream {
struct snd_info_entry *proc_sw_params_entry;
struct snd_info_entry *proc_status_entry;
struct snd_info_entry *proc_prealloc_entry;
struct snd_info_entry *proc_prealloc_max_entry;
#endif
/* misc flags */
unsigned int hw_opened: 1;
@ -427,6 +430,7 @@ struct snd_pcm {
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (struct snd_pcm *pcm);
struct device *dev; /* actual hw device this belongs to */
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
struct snd_pcm_oss oss;
#endif

37
include/sound/pt2258.h Normal file
View file

@ -0,0 +1,37 @@
/*
* ALSA Driver for the PT2258 volume controller.
*
* Copyright (c) 2006 Jochen Voss <voss@seehuhn.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
*
*/
#ifndef __SOUND_PT2258_H
#define __SOUND_PT2258_H
struct snd_pt2258 {
struct snd_card *card;
struct snd_i2c_bus *i2c_bus;
struct snd_i2c_device *i2c_dev;
unsigned char volume[6];
int mute;
};
extern int snd_pt2258_reset(struct snd_pt2258 *pt);
extern int snd_pt2258_build_controls(struct snd_pt2258 *pt);
#endif /* __SOUND_PT2258_H */

View file

@ -114,9 +114,21 @@ struct snd_sb_csp_info {
#ifdef __KERNEL__
#include "sb.h"
#include "hwdep.h"
#include <linux/firmware.h>
struct snd_sb_csp;
/* indices for the known CSP programs */
enum {
CSP_PROGRAM_MULAW,
CSP_PROGRAM_ALAW,
CSP_PROGRAM_ADPCM_INIT,
CSP_PROGRAM_ADPCM_PLAYBACK,
CSP_PROGRAM_ADPCM_CAPTURE,
CSP_PROGRAM_COUNT
};
/*
* CSP operators
*/
@ -159,6 +171,8 @@ struct snd_sb_csp {
struct snd_kcontrol *qsound_space;
struct mutex access_mutex; /* locking */
const struct firmware *csp_programs[CSP_PROGRAM_COUNT];
};
int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep);

View file

@ -85,6 +85,7 @@ struct _snd_wavefront {
char hw_version[2]; /* major = [0], minor = [1] */
char israw; /* needs Motorola microcode */
char has_fx; /* has FX processor (Tropez+) */
char fx_initialized; /* FX's register pages initialized */
char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */
char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */
char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
@ -94,6 +95,7 @@ struct _snd_wavefront {
spinlock_t irq_lock;
wait_queue_head_t interrupt_sleeper;
snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */
struct snd_card *card;
};
struct _snd_wavefront_card {

286
include/sound/soc-dapm.h Normal file
View file

@ -0,0 +1,286 @@
/*
* linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
*
* Author: Liam Girdwood
* Created: Aug 11th 2005
* Copyright: Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_SOC_DAPM_H
#define __LINUX_SND_SOC_DAPM_H
#include <linux/device.h>
#include <linux/types.h>
#include <sound/control.h>
#include <sound/soc.h>
/* widget has no PM register bit */
#define SND_SOC_NOPM -1
/*
* SoC dynamic audio power managment
*
* We can have upto 4 power domains
* 1. Codec domain - VREF, VMID
* Usually controlled at codec probe/remove, although can be set
* at stream time if power is not needed for sidetone, etc.
* 2. Platform/Machine domain - physically connected inputs and outputs
* Is platform/machine and user action specific, is set in the machine
* driver and by userspace e.g when HP are inserted
* 3. Path domain - Internal codec path mixers
* Are automatically set when mixer and mux settings are
* changed by the user.
* 4. Stream domain - DAC's and ADC's.
* Enabled when stream playback/capture is started.
*/
/* codec domain */
#define SND_SOC_DAPM_VMID(wname) \
{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0}
/* platform domain */
#define SND_SOC_DAPM_INPUT(wname) \
{ .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0}
#define SND_SOC_DAPM_OUTPUT(wname) \
{ .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0}
#define SND_SOC_DAPM_MIC(wname, wevent) \
{ .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
#define SND_SOC_DAPM_HP(wname, wevent) \
{ .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_SPK(wname, wevent) \
{ .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_LINE(wname, wevent) \
{ .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
/* path domain */
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
/* path domain with event - event handler must return 0 for success */
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
/* events that are pre and post DAPM */
#define SND_SOC_DAPM_PRE(wname, wevent) \
{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_POST(wname, wevent) \
{ .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
/* stream domain */
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
.shift = wshift, .invert = winvert}
#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
.shift = wshift, .invert = winvert}
/* dapm kcontrol types */
#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \
power) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
((mask) << 16) | ((invert) << 24) }
#define SOC_DAPM_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \
.get = snd_soc_dapm_get_enum_double, \
.put = snd_soc_dapm_put_enum_double, \
.private_value = (unsigned long)&xenum }
/* dapm stream operations */
#define SND_SOC_DAPM_STREAM_NOP 0x0
#define SND_SOC_DAPM_STREAM_START 0x1
#define SND_SOC_DAPM_STREAM_STOP 0x2
#define SND_SOC_DAPM_STREAM_SUSPEND 0x4
#define SND_SOC_DAPM_STREAM_RESUME 0x8
#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20
/* dapm event types */
#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
/* convenience event type detection */
#define SND_SOC_DAPM_EVENT_ON(e) \
(e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
#define SND_SOC_DAPM_EVENT_OFF(e) \
(e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
struct snd_soc_dapm_widget;
enum snd_soc_dapm_type;
struct snd_soc_dapm_path;
struct snd_soc_dapm_pin;
/* dapm controls */
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
const struct snd_soc_dapm_widget *widget);
/* dapm path setup */
int snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
const char *sink_name, const char *control_name, const char *src_name);
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
void snd_soc_dapm_free(struct snd_soc_device *socdev);
/* dapm events */
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
int event);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
/* dapm audio endpoint control */
int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
char *pin, int status);
int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec);
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_mixer, /* mixes several analog signals together */
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
snd_soc_dapm_adc, /* analog to digital converter */
snd_soc_dapm_dac, /* digital to analog converter */
snd_soc_dapm_micbias, /* microphone bias (power) */
snd_soc_dapm_mic, /* microphone */
snd_soc_dapm_hp, /* headphones */
snd_soc_dapm_spk, /* speaker */
snd_soc_dapm_line, /* line input/output */
snd_soc_dapm_switch, /* analog switch */
snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
snd_soc_dapm_pre, /* machine specific pre widget - exec first */
snd_soc_dapm_post, /* machine specific post widget - exec last */
};
/* dapm audio path between two widgets */
struct snd_soc_dapm_path {
char *name;
char *long_name;
/* source (input) and sink (output) widgets */
struct snd_soc_dapm_widget *source;
struct snd_soc_dapm_widget *sink;
struct snd_kcontrol *kcontrol;
/* status */
u32 connect:1; /* source and sink widgets are connected */
u32 walked:1; /* path has been walked */
struct list_head list_source;
struct list_head list_sink;
struct list_head list;
};
/* dapm widget */
struct snd_soc_dapm_widget {
enum snd_soc_dapm_type id;
char *name; /* widget name */
char *sname; /* stream name */
struct snd_soc_codec *codec;
struct list_head list;
/* dapm control */
short reg; /* negative reg = no direct dapm */
unsigned char shift; /* bits to shift */
unsigned int saved_value; /* widget saved value */
unsigned int value; /* widget current value */
unsigned char power:1; /* block power status */
unsigned char invert:1; /* invert the power bit */
unsigned char active:1; /* active stream on DAC, ADC's */
unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */
unsigned char ext:1; /* has external widgets */
unsigned char muted:1; /* muted for pop reduction */
unsigned char suspend:1; /* was active before suspend */
unsigned char pmdown:1; /* waiting for timeout */
/* external events */
unsigned short event_flags; /* flags to specify event types */
int (*event)(struct snd_soc_dapm_widget*, int);
/* kcontrols that relate to this widget */
int num_kcontrols;
const struct snd_kcontrol_new *kcontrols;
/* widget input and outputs */
struct list_head sources;
struct list_head sinks;
};
#endif

461
include/sound/soc.h Normal file
View file

@ -0,0 +1,461 @@
/*
* linux/sound/soc.h -- ALSA SoC Layer
*
* Author: Liam Girdwood
* Created: Aug 11th 2005
* Copyright: Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_SOC_H
#define __LINUX_SND_SOC_H
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/control.h>
#include <sound/ac97_codec.h>
#define SND_SOC_VERSION "0.13.0"
/*
* Convenience kcontrol builders
*/
#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
((shift) << 12) | ((mask) << 16) | ((invert) << 24))
#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
((invert) << 31))
#define SOC_SINGLE(xname, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
.put = snd_soc_put_volsw, \
.private_value = (reg) | ((shift_left) << 8) | \
((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw_2r, \
.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
.private_value = (reg_left) | ((shift) << 8) | \
((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.mask = xmask, .texts = xtexts }
#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
{ .mask = xmask, .texts = xtexts }
#define SOC_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
.info = snd_soc_info_enum_double, \
.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
.private_value = (unsigned long)&xenum }
#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_bool_ext, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = xdata }
#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_ext, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
/*
* Digital Audio Interface (DAI) types
*/
#define SND_SOC_DAI_AC97 0x1
#define SND_SOC_DAI_I2S 0x2
#define SND_SOC_DAI_PCM 0x4
/*
* DAI hardware audio formats
*/
#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */
#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */
#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */
#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */
#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */
#define SND_SOC_DAIFMT_AC97 5 /* AC97 */
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J
/*
* DAI Gating
*/
#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */
#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */
/*
* DAI hardware signal inversions
*/
#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */
#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */
#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */
#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */
/*
* DAI hardware clock masters
* This is wrt the codec, the inverse is true for the interface
* i.e. if the codec is clk and frm master then the interface is
* clk and frame slave.
*/
#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */
#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */
#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */
#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
#define SND_SOC_DAIFMT_MASTER_MASK 0xf000
/*
* Master Clock Directions
*/
#define SND_SOC_CLOCK_IN 0
#define SND_SOC_CLOCK_OUT 1
/*
* AC97 codec ID's bitmask
*/
#define SND_SOC_DAI_AC97_ID0 (1 << 0)
#define SND_SOC_DAI_AC97_ID1 (1 << 1)
#define SND_SOC_DAI_AC97_ID2 (1 << 2)
#define SND_SOC_DAI_AC97_ID3 (1 << 3)
struct snd_soc_device;
struct snd_soc_pcm_stream;
struct snd_soc_ops;
struct snd_soc_dai_mode;
struct snd_soc_pcm_runtime;
struct snd_soc_codec_dai;
struct snd_soc_cpu_dai;
struct snd_soc_codec;
struct snd_soc_machine_config;
struct soc_enum;
struct snd_soc_ac97_ops;
struct snd_soc_clock_info;
typedef int (*hw_write_t)(void *,const char* ,int);
typedef int (*hw_read_t)(void *,char* ,int);
extern struct snd_ac97_bus_ops soc_ac97_ops;
/* pcm <-> DAI connect */
void snd_soc_free_pcms(struct snd_soc_device *socdev);
int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
int snd_soc_register_card(struct snd_soc_device *socdev);
/* set runtime hw params */
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw);
/* codec IO */
#define snd_soc_read(codec, reg) codec->read(codec, reg)
#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
/* codec register bit access */
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned short mask, unsigned short value);
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned short mask, unsigned short value);
int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
struct snd_ac97_bus_ops *ops, int num);
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
/*
*Controls
*/
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
void *data, char *long_name);
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
char *stream_name;
u64 formats; /* SNDRV_PCM_FMTBIT_* */
unsigned int rates; /* SNDRV_PCM_RATE_* */
unsigned int rate_min; /* min rate */
unsigned int rate_max; /* max rate */
unsigned int channels_min; /* min channels */
unsigned int channels_max; /* max channels */
unsigned int active:1; /* stream is in use */
};
/* SoC audio ops */
struct snd_soc_ops {
int (*startup)(struct snd_pcm_substream *);
void (*shutdown)(struct snd_pcm_substream *);
int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
int (*hw_free)(struct snd_pcm_substream *);
int (*prepare)(struct snd_pcm_substream *);
int (*trigger)(struct snd_pcm_substream *, int);
};
/* ASoC codec DAI ops */
struct snd_soc_codec_ops {
/* codec DAI clocking configuration */
int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
int clk_id, unsigned int freq, int dir);
int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
int pll_id, unsigned int freq_in, unsigned int freq_out);
int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
int div_id, int div);
/* CPU DAI format configuration */
int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
unsigned int fmt);
int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
unsigned int mask, int slots);
int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
/* digital mute */
int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
};
/* ASoC cpu DAI ops */
struct snd_soc_cpu_ops {
/* CPU DAI clocking configuration */
int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
int clk_id, unsigned int freq, int dir);
int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
int div_id, int div);
int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
int pll_id, unsigned int freq_in, unsigned int freq_out);
/* CPU DAI format configuration */
int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
unsigned int fmt);
int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
unsigned int mask, int slots);
int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
};
/* SoC Codec DAI */
struct snd_soc_codec_dai {
char *name;
int id;
/* DAI capabilities */
struct snd_soc_pcm_stream playback;
struct snd_soc_pcm_stream capture;
/* DAI runtime info */
struct snd_soc_codec *codec;
unsigned int active;
unsigned char pop_wait:1;
/* ops */
struct snd_soc_ops ops;
struct snd_soc_codec_ops dai_ops;
/* DAI private data */
void *private_data;
};
/* SoC CPU DAI */
struct snd_soc_cpu_dai {
/* DAI description */
char *name;
unsigned int id;
unsigned char type;
/* DAI callbacks */
int (*probe)(struct platform_device *pdev);
void (*remove)(struct platform_device *pdev);
int (*suspend)(struct platform_device *pdev,
struct snd_soc_cpu_dai *cpu_dai);
int (*resume)(struct platform_device *pdev,
struct snd_soc_cpu_dai *cpu_dai);
/* ops */
struct snd_soc_ops ops;
struct snd_soc_cpu_ops dai_ops;
/* DAI capabilities */
struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback;
/* DAI runtime info */
struct snd_pcm_runtime *runtime;
unsigned char active:1;
void *dma_data;
/* DAI private data */
void *private_data;
};
/* SoC Audio Codec */
struct snd_soc_codec {
char *name;
struct module *owner;
struct mutex mutex;
/* callbacks */
int (*dapm_event)(struct snd_soc_codec *codec, int event);
/* runtime */
struct snd_card *card;
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int active;
unsigned int pcm_devs;
void *private_data;
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
hw_write_t hw_write;
hw_read_t hw_read;
void *reg_cache;
short reg_cache_size;
short reg_cache_step;
/* dapm */
struct list_head dapm_widgets;
struct list_head dapm_paths;
unsigned int dapm_state;
unsigned int suspend_dapm_state;
struct delayed_work delayed_work;
/* codec DAI's */
struct snd_soc_codec_dai *dai;
unsigned int num_dai;
};
/* codec device */
struct snd_soc_codec_device {
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
int (*suspend)(struct platform_device *pdev, pm_message_t state);
int (*resume)(struct platform_device *pdev);
};
/* SoC platform interface */
struct snd_soc_platform {
char *name;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
int (*suspend)(struct platform_device *pdev,
struct snd_soc_cpu_dai *cpu_dai);
int (*resume)(struct platform_device *pdev,
struct snd_soc_cpu_dai *cpu_dai);
/* pcm creation and destruction */
int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
struct snd_pcm *);
void (*pcm_free)(struct snd_pcm *);
/* platform stream ops */
struct snd_pcm_ops *pcm_ops;
};
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_dai_link {
char *name; /* Codec name */
char *stream_name; /* Stream name */
/* DAI */
struct snd_soc_codec_dai *codec_dai;
struct snd_soc_cpu_dai *cpu_dai;
/* machine stream operations */
struct snd_soc_ops *ops;
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_codec *codec);
};
/* SoC machine */
struct snd_soc_machine {
char *name;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
/* the pre and post PM functions are used to do any PM work before and
* after the codec and DAI's do any PM work. */
int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
int (*resume_pre)(struct platform_device *pdev);
int (*resume_post)(struct platform_device *pdev);
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;
};
/* SoC Device - the audio subsystem */
struct snd_soc_device {
struct device *dev;
struct snd_soc_machine *machine;
struct snd_soc_platform *platform;
struct snd_soc_codec *codec;
struct snd_soc_codec_device *codec_dev;
struct delayed_work delayed_work;
void *codec_data;
};
/* runtime channel data */
struct snd_soc_pcm_runtime {
struct snd_soc_dai_link *dai;
struct snd_soc_device *socdev;
};
/* enumerated kcontrol */
struct soc_enum {
unsigned short reg;
unsigned short reg2;
unsigned char shift_l;
unsigned char shift_r;
unsigned int mask;
const char **texts;
void *dapm;
};
#endif

View file

@ -1,173 +0,0 @@
/*
* Typedef's for backward compatibility (for out-of-kernel drivers)
*
* This file will be removed soon in future
*/
/* core stuff */
typedef struct snd_card snd_card_t;
typedef struct snd_device snd_device_t;
typedef struct snd_device_ops snd_device_ops_t;
typedef enum snd_card_type snd_card_type_t;
typedef struct snd_minor snd_minor_t;
/* info */
typedef struct snd_info_entry snd_info_entry_t;
typedef struct snd_info_buffer snd_info_buffer_t;
/* control */
typedef struct snd_ctl_file snd_ctl_file_t;
typedef struct snd_kcontrol snd_kcontrol_t;
typedef struct snd_kcontrol_new snd_kcontrol_new_t;
typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t;
typedef struct snd_kctl_event snd_kctl_event_t;
typedef struct snd_aes_iec958 snd_aes_iec958_t;
typedef struct snd_ctl_card_info snd_ctl_card_info_t;
typedef struct snd_ctl_elem_id snd_ctl_elem_id_t;
typedef struct snd_ctl_elem_list snd_ctl_elem_list_t;
typedef struct snd_ctl_elem_info snd_ctl_elem_info_t;
typedef struct snd_ctl_elem_value snd_ctl_elem_value_t;
typedef struct snd_ctl_event snd_ctl_event_t;
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
typedef struct snd_mixer_oss snd_mixer_oss_t;
#endif
/* timer */
typedef struct snd_timer snd_timer_t;
typedef struct snd_timer_instance snd_timer_instance_t;
typedef struct snd_timer_id snd_timer_id_t;
typedef struct snd_timer_ginfo snd_timer_ginfo_t;
typedef struct snd_timer_gparams snd_timer_gparams_t;
typedef struct snd_timer_gstatus snd_timer_gstatus_t;
typedef struct snd_timer_select snd_timer_select_t;
typedef struct snd_timer_info snd_timer_info_t;
typedef struct snd_timer_params snd_timer_params_t;
typedef struct snd_timer_status snd_timer_status_t;
typedef struct snd_timer_read snd_timer_read_t;
typedef struct snd_timer_tread snd_timer_tread_t;
/* PCM */
typedef struct snd_pcm snd_pcm_t;
typedef struct snd_pcm_str snd_pcm_str_t;
typedef struct snd_pcm_substream snd_pcm_substream_t;
typedef struct snd_pcm_info snd_pcm_info_t;
typedef struct snd_pcm_hw_params snd_pcm_hw_params_t;
typedef struct snd_pcm_sw_params snd_pcm_sw_params_t;
typedef struct snd_pcm_channel_info snd_pcm_channel_info_t;
typedef struct snd_pcm_status snd_pcm_status_t;
typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t;
typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t;
typedef struct snd_mask snd_mask_t;
typedef struct snd_sg_buf snd_pcm_sgbuf_t;
typedef struct snd_interval snd_interval_t;
typedef struct snd_xferi snd_xferi_t;
typedef struct snd_xfern snd_xfern_t;
typedef struct snd_xferv snd_xferv_t;
typedef struct snd_pcm_file snd_pcm_file_t;
typedef struct snd_pcm_runtime snd_pcm_runtime_t;
typedef struct snd_pcm_hardware snd_pcm_hardware_t;
typedef struct snd_pcm_ops snd_pcm_ops_t;
typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t;
typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t;
typedef struct snd_ratnum ratnum_t;
typedef struct snd_ratden ratden_t;
typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t;
typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t;
typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t;
typedef struct snd_pcm_group snd_pcm_group_t;
typedef struct snd_pcm_notify snd_pcm_notify_t;
/* rawmidi */
typedef struct snd_rawmidi snd_rawmidi_t;
typedef struct snd_rawmidi_info snd_rawmidi_info_t;
typedef struct snd_rawmidi_params snd_rawmidi_params_t;
typedef struct snd_rawmidi_status snd_rawmidi_status_t;
typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t;
typedef struct snd_rawmidi_substream snd_rawmidi_substream_t;
typedef struct snd_rawmidi_str snd_rawmidi_str_t;
typedef struct snd_rawmidi_ops snd_rawmidi_ops_t;
typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t;
typedef struct snd_rawmidi_file snd_rawmidi_file_t;
/* hwdep */
typedef struct snd_hwdep snd_hwdep_t;
typedef struct snd_hwdep_info snd_hwdep_info_t;
typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t;
typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t;
typedef struct snd_hwdep_ops snd_hwdep_ops_t;
/* sequencer */
typedef struct snd_seq_port_info snd_seq_port_info_t;
typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t;
typedef struct snd_seq_event snd_seq_event_t;
typedef struct snd_seq_addr snd_seq_addr_t;
typedef struct snd_seq_ev_volume snd_seq_ev_volume_t;
typedef struct snd_seq_ev_loop snd_seq_ev_loop_t;
typedef struct snd_seq_remove_events snd_seq_remove_events_t;
typedef struct snd_seq_query_subs snd_seq_query_subs_t;
typedef struct snd_seq_system_info snd_seq_system_info_t;
typedef struct snd_seq_client_info snd_seq_client_info_t;
typedef struct snd_seq_queue_info snd_seq_queue_info_t;
typedef struct snd_seq_queue_status snd_seq_queue_status_t;
typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t;
typedef struct snd_seq_queue_owner snd_seq_queue_owner_t;
typedef struct snd_seq_queue_timer snd_seq_queue_timer_t;
typedef struct snd_seq_queue_client snd_seq_queue_client_t;
typedef struct snd_seq_client_pool snd_seq_client_pool_t;
typedef struct snd_seq_instr snd_seq_instr_t;
typedef struct snd_seq_instr_data snd_seq_instr_data_t;
typedef struct snd_seq_instr_header snd_seq_instr_header_t;
typedef struct snd_seq_user_client user_client_t;
typedef struct snd_seq_kernel_client kernel_client_t;
typedef struct snd_seq_client client_t;
typedef struct snd_seq_queue queue_t;
/* seq_device */
typedef struct snd_seq_device snd_seq_device_t;
typedef struct snd_seq_dev_ops snd_seq_dev_ops_t;
/* seq_midi */
typedef struct snd_midi_event snd_midi_event_t;
/* seq_midi_emul */
typedef struct snd_midi_channel snd_midi_channel_t;
typedef struct snd_midi_channel_set snd_midi_channel_set_t;
typedef struct snd_midi_op snd_midi_op_t;
/* seq_oss */
typedef struct snd_seq_oss_arg snd_seq_oss_arg_t;
typedef struct snd_seq_oss_callback snd_seq_oss_callback_t;
typedef struct snd_seq_oss_reg snd_seq_oss_reg_t;
/* virmidi */
typedef struct snd_virmidi_dev snd_virmidi_dev_t;
typedef struct snd_virmidi snd_virmidi_t;
/* seq_instr */
typedef struct snd_seq_kcluster snd_seq_kcluster_t;
typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t;
typedef struct snd_seq_kinstr snd_seq_kinstr_t;
typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t;
/* ac97 */
typedef struct snd_ac97_bus ac97_bus_t;
typedef struct snd_ac97_bus_ops ac97_bus_ops_t;
typedef struct snd_ac97_template ac97_template_t;
typedef struct snd_ac97 ac97_t;
/* opl3/4 */
typedef struct snd_opl3 opl3_t;
typedef struct snd_opl4 opl4_t;
/* mpu401 */
typedef struct snd_mpu401 mpu401_t;
/* i2c */
typedef struct snd_i2c_device snd_i2c_device_t;
typedef struct snd_i2c_bus snd_i2c_bus_t;
typedef struct snd_ak4531 ak4531_t;

View file

@ -1,3 +1,3 @@
/* include/version.h. Generated by alsa/ksync script. */
#define CONFIG_SND_VERSION "1.0.14rc1"
#define CONFIG_SND_DATE " (Tue Jan 09 09:56:17 2007 UTC)"
#define CONFIG_SND_VERSION "1.0.14rc2"
#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)"

View file

@ -128,7 +128,7 @@ struct snd_vx_hardware {
unsigned int num_ins;
unsigned int num_outs;
unsigned int output_level_max;
unsigned int *output_level_db_scale;
const unsigned int *output_level_db_scale;
};
/* hwdep id string */

View file

@ -270,6 +270,7 @@ struct snd_ymfpci_pcm {
struct snd_pcm_substream *substream;
struct snd_ymfpci_voice *voices[2]; /* playback only */
unsigned int running: 1,
use_441_slot: 1,
output_front: 1,
output_rear: 1,
swap_rear: 1;
@ -324,6 +325,7 @@ struct snd_ymfpci {
u32 active_bank;
struct snd_ymfpci_voice voices[64];
int src441_used;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97 *ac97;
@ -346,7 +348,7 @@ struct snd_ymfpci {
int mode_dup4ch;
int rear_opened;
int spdif_opened;
struct {
struct snd_ymfpci_pcm_mixer {
u16 left;
u16 right;
struct snd_kcontrol *ctl;
@ -357,6 +359,8 @@ struct snd_ymfpci {
wait_queue_head_t interrupt_sleep;
atomic_t interrupt_sleep_count;
struct snd_info_entry *proc_entry;
const struct firmware *dsp_microcode;
const struct firmware *controller_microcode;
#ifdef CONFIG_PM
u32 *saved_regs;

View file

@ -76,6 +76,8 @@ source "sound/sparc/Kconfig"
source "sound/parisc/Kconfig"
source "sound/soc/Kconfig"
endmenu
menu "Open Sound System"

View file

@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out

View file

@ -26,6 +26,7 @@ static int ac97_bus_match(struct device *dev, struct device_driver *drv)
return 1;
}
#ifdef CONFIG_PM
static int ac97_bus_suspend(struct device *dev, pm_message_t state)
{
int ret = 0;
@ -45,12 +46,15 @@ static int ac97_bus_resume(struct device *dev)
return ret;
}
#endif /* CONFIG_PM */
struct bus_type ac97_bus_type = {
.name = "ac97",
.match = ac97_bus_match,
#ifdef CONFIG_PM
.suspend = ac97_bus_suspend,
.resume = ac97_bus_resume,
#endif /* CONFIG_PM */
};
static int __init ac97_bus_init(void)

View file

@ -99,7 +99,7 @@ struct aoa_fabric {
* that are not assigned yet are passed to the fabric
* again for reconsideration. */
extern int
aoa_fabric_register(struct aoa_fabric *fabric);
aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev);
/* it is vital to call this when the fabric exits!
* When calling, the remove_codec will be called

View file

@ -825,7 +825,16 @@ static int onyx_resume(struct codec_info_item *cii)
int err = -ENXIO;
mutex_lock(&onyx->mutex);
/* take codec out of suspend */
/* reset codec */
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
msleep(1);
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
msleep(1);
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
msleep(1);
/* take codec out of suspend (if it still is after reset) */
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
goto out_unlock;
onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));

View file

@ -14,7 +14,7 @@ MODULE_PARM_DESC(index, "index for AOA sound card.");
static struct aoa_card *aoa_card;
int aoa_alsa_init(char *name, struct module *mod)
int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
{
struct snd_card *alsa_card;
int err;
@ -28,6 +28,7 @@ int aoa_alsa_init(char *name, struct module *mod)
return -ENOMEM;
aoa_card = alsa_card->private_data;
aoa_card->alsa_card = alsa_card;
alsa_card->dev = dev;
strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
@ -59,7 +60,7 @@ void aoa_alsa_cleanup(void)
}
int aoa_snd_device_new(snd_device_type_t type,
void * device_data, struct snd_device_ops * ops)
void * device_data, struct snd_device_ops * ops)
{
struct snd_card *card = aoa_get_card();
int err;

View file

@ -10,7 +10,7 @@
#define __SND_AOA_ALSA_H
#include "../aoa.h"
extern int aoa_alsa_init(char *name, struct module *mod);
extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev);
extern void aoa_alsa_cleanup(void);
#endif /* __SND_AOA_ALSA_H */

View file

@ -82,7 +82,7 @@ void aoa_codec_unregister(struct aoa_codec *codec)
}
EXPORT_SYMBOL_GPL(aoa_codec_unregister);
int aoa_fabric_register(struct aoa_fabric *new_fabric)
int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
{
struct aoa_codec *c;
int err;
@ -98,7 +98,7 @@ int aoa_fabric_register(struct aoa_fabric *new_fabric)
if (!new_fabric)
return -EINVAL;
err = aoa_alsa_init(new_fabric->name, new_fabric->owner);
err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
if (err)
return err;

View file

@ -1014,7 +1014,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
ldev->gpio.methods->init(&ldev->gpio);
err = aoa_fabric_register(&layout_fabric);
err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
if (err && err != -EALREADY) {
printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
" another fabric is active!\n");
@ -1034,9 +1034,9 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
list_del(&ldev->list);
layouts_list_items--;
outnodev:
if (sound) of_node_put(sound);
of_node_put(sound);
layout_device = NULL;
if (ldev) kfree(ldev);
kfree(ldev);
return -ENODEV;
}
@ -1077,8 +1077,6 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta
{
struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
printk("aoa_fabric_layout_suspend()\n");
if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
ldev->gpio.methods->all_amps_off(&ldev->gpio);
@ -1089,8 +1087,6 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
{
struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
printk("aoa_fabric_layout_resume()\n");
if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
ldev->gpio.methods->all_amps_restore(&ldev->gpio);
@ -1107,6 +1103,9 @@ static struct soundbus_driver aoa_soundbus_driver = {
.suspend = aoa_fabric_layout_suspend,
.resume = aoa_fabric_layout_resume,
#endif
.driver = {
.owner = THIS_MODULE,
}
};
static int __init aoa_fabric_layout_init(void)

View file

@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
struct dbdma_command_mem *r,
int numcmds)
{
/* one more for rounding */
r->size = (numcmds+1) * sizeof(struct dbdma_cmd);
/* one more for rounding, one for branch back, one for stop command */
r->size = (numcmds + 3) * sizeof(struct dbdma_cmd);
/* We use the PCI APIs for now until the generic one gets fixed
* enough or until we get some macio-specific versions
*/
@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
if (i2sdev->sound.pcm) {
/* Suspend PCM streams */
snd_pcm_suspend_all(i2sdev->sound.pcm);
/* Probably useless as we handle
* power transitions ourselves */
snd_power_change_state(i2sdev->sound.pcm->card,
SNDRV_CTL_POWER_D3hot);
}
/* Notify codecs */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
err = 0;
@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
if (err)
ret = err;
}
/* wait until streams are stopped */
i2sbus_wait_for_stop_both(i2sdev);
}
return ret;
}
@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev)
int err, ret = 0;
list_for_each_entry(i2sdev, &control->list, item) {
/* reset i2s bus format etc. */
i2sbus_pcm_prepare_both(i2sdev);
/* Notify codecs so they can re-initialize */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
err = 0;
@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev)
if (err)
ret = err;
}
/* Notify Alsa */
if (i2sdev->sound.pcm) {
/* Same comment as above, probably useless */
snd_power_change_state(i2sdev->sound.pcm->card,
SNDRV_CTL_POWER_D0);
}
}
return ret;

View file

@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
}
/* bus dependent stuff */
hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_JOINT_DUPLEX;
CHECK_RATE(5512);
CHECK_RATE(8000);
@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
return err;
}
static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
struct pcm_info *pi)
{
unsigned long flags;
struct completion done;
long timeout;
spin_lock_irqsave(&i2sdev->low_lock, flags);
if (pi->dbdma_ring.stopping) {
init_completion(&done);
pi->stop_completion = &done;
spin_unlock_irqrestore(&i2sdev->low_lock, flags);
timeout = wait_for_completion_timeout(&done, HZ);
spin_lock_irqsave(&i2sdev->low_lock, flags);
pi->stop_completion = NULL;
if (timeout == 0) {
/* timeout expired, stop dbdma forcefully */
printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
/* make sure RUN, PAUSE and S0 bits are cleared */
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
pi->dbdma_ring.stopping = 0;
timeout = 10;
while (in_le32(&pi->dbdma->status) & ACTIVE) {
if (--timeout <= 0)
break;
udelay(1);
}
}
}
spin_unlock_irqrestore(&i2sdev->low_lock, flags);
}
#ifdef CONFIG_PM
void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
{
struct pcm_info *pi;
get_pcm_info(i2sdev, 0, &pi, NULL);
i2sbus_wait_for_stop(i2sdev, pi);
get_pcm_info(i2sdev, 1, &pi, NULL);
i2sbus_wait_for_stop(i2sdev, pi);
}
#endif
static int i2sbus_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
static int i2sbus_hw_free(struct snd_pcm_substream *substream)
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
struct pcm_info *pi;
get_pcm_info(i2sdev, in, &pi, NULL);
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
snd_pcm_lib_free_pages(substream);
return 0;
}
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 0);
}
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 1);
}
static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
{
/* whee. Hard work now. The user has selected a bitrate
@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
* I2S controller appropriately. */
struct snd_pcm_runtime *runtime;
struct dbdma_cmd *command;
int i, periodsize;
int i, periodsize, nperiods;
dma_addr_t offset;
struct bus_info bi;
struct codec_info_item *cii;
@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
struct pcm_info *pi, *other;
int cnt;
int result = 0;
unsigned int cmd, stopaddr;
mutex_lock(&i2sdev->lock);
@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
result = -EBUSY;
goto out_unlock;
}
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
if (!pi->substream || !pi->substream->runtime) {
result = -EINVAL;
goto out_unlock;
}
runtime = pi->substream->runtime;
pi->active = 1;
@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
i2sdev->rate = runtime->rate;
periodsize = snd_pcm_lib_period_bytes(pi->substream);
nperiods = pi->substream->runtime->periods;
pi->current_period = 0;
/* generate dbdma command ring first */
command = pi->dbdma_ring.cmds;
memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
/* commands to DMA to/from the ring */
/*
* For input, we need to do a graceful stop; if we abort
* the DMA, we end up with leftover bytes that corrupt
* the next recording. To do this we set the S0 status
* bit and wait for the DMA controller to stop. Each
* command has a branch condition to
* make it branch to a stop command if S0 is set.
* On input we also need to wait for the S7 bit to be
* set before turning off the DMA controller.
* In fact we do the graceful stop for output as well.
*/
offset = runtime->dma_addr;
for (i = 0; i < pi->substream->runtime->periods;
i++, command++, offset += periodsize) {
memset(command, 0, sizeof(struct dbdma_cmd));
command->command =
cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
stopaddr = pi->dbdma_ring.bus_cmd_start +
(nperiods + 1) * sizeof(struct dbdma_cmd);
for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
command->command = cpu_to_le16(cmd);
command->cmd_dep = cpu_to_le32(stopaddr);
command->phy_addr = cpu_to_le32(offset);
command->req_count = cpu_to_le16(periodsize);
command->xfer_status = cpu_to_le16(0);
}
/* last one branches back to first */
command--;
command->command |= cpu_to_le16(BR_ALWAYS);
/* branch back to beginning of ring */
command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
command++;
/* set stop command */
command->command = cpu_to_le16(DBDMA_STOP);
/* ok, let's set the serial format and stuff */
switch (runtime->format) {
@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
return result;
}
static struct dbdma_cmd STOP_CMD = {
.command = __constant_cpu_to_le16(DBDMA_STOP),
};
#ifdef CONFIG_PM
void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
{
i2sbus_pcm_prepare(i2sdev, 0);
i2sbus_pcm_prepare(i2sdev, 1);
}
#endif
static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
{
struct codec_info_item *cii;
struct pcm_info *pi;
int timeout;
struct dbdma_cmd tmp;
int result = 0;
unsigned long flags;
@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
cii->codec->start(cii, pi->substream);
pi->dbdma_ring.running = 1;
/* reset dma engine */
out_le32(&pi->dbdma->control,
0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
timeout = 100;
while (in_le32(&pi->dbdma->status) & RUN && timeout--)
udelay(1);
if (timeout <= 0) {
printk(KERN_ERR
"i2sbus: error waiting for dma reset\n");
result = -ENXIO;
goto out_unlock;
if (pi->dbdma_ring.stopping) {
/* Clear the S0 bit, then see if we stopped yet */
out_le32(&pi->dbdma->control, 1 << 16);
if (in_le32(&pi->dbdma->status) & ACTIVE) {
/* possible race here? */
udelay(10);
if (in_le32(&pi->dbdma->status) & ACTIVE) {
pi->dbdma_ring.stopping = 0;
goto out_unlock; /* keep running */
}
}
}
/* make sure RUN, PAUSE and S0 bits are cleared */
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
/* set branch condition select register */
out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
/* write dma command buffer address to the dbdma chip */
out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
/* post PCI write */
mb();
(void)in_le32(&pi->dbdma->status);
/* change first command to STOP */
tmp = *pi->dbdma_ring.cmds;
*pi->dbdma_ring.cmds = STOP_CMD;
/* set running state, remember that the first command is STOP */
out_le32(&pi->dbdma->control, RUN | (RUN << 16));
timeout = 100;
/* wait for STOP to be executed */
while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
udelay(1);
if (timeout <= 0) {
printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
result = -ENXIO;
goto out_unlock;
}
/* again, write dma command buffer address to the dbdma chip,
* this time of the first real command */
*pi->dbdma_ring.cmds = tmp;
out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
/* post write */
mb();
(void)in_le32(&pi->dbdma->status);
/* reset dma engine again */
out_le32(&pi->dbdma->control,
0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
timeout = 100;
while (in_le32(&pi->dbdma->status) & RUN && timeout--)
udelay(1);
if (timeout <= 0) {
printk(KERN_ERR
"i2sbus: error waiting for dma reset\n");
result = -ENXIO;
goto out_unlock;
}
/* wake up the chip with the next descriptor */
out_le32(&pi->dbdma->control,
(RUN | WAKE) | ((RUN | WAKE) << 16));
/* get the frame count */
/* initialize the frame count and current period */
pi->current_period = 0;
pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
/* set the DMA controller running */
out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
/* off you go! */
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!pi->dbdma_ring.running) {
result = -EALREADY;
goto out_unlock;
}
/* turn off all relevant bits */
out_le32(&pi->dbdma->control,
(RUN | WAKE | FLUSH | PAUSE) << 16);
{
/* FIXME: move to own function */
int timeout = 5000;
while ((in_le32(&pi->dbdma->status) & RUN)
&& --timeout > 0)
udelay(1);
if (!timeout)
printk(KERN_ERR
"i2sbus: timed out turning "
"off dbdma engine!\n");
}
pi->dbdma_ring.running = 0;
/* Set the S0 bit to make the DMA branch to the stop cmd */
out_le32(&pi->dbdma->control, (1 << 16) | 1);
pi->dbdma_ring.stopping = 1;
list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
if (cii->codec->stop)
cii->codec->stop(cii, pi->substream);
@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
fc = in_le32(&i2sdev->intfregs->frame_count);
fc = fc - pi->frame_count;
return (bytes_to_frames(pi->substream->runtime,
pi->current_period *
snd_pcm_lib_period_bytes(pi->substream))
+ fc) % pi->substream->runtime->buffer_size;
if (fc >= pi->substream->runtime->buffer_size)
fc %= pi->substream->runtime->buffer_size;
return fc;
}
static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
{
struct pcm_info *pi;
u32 fc;
u32 delta;
u32 fc, nframes;
u32 status;
int timeout, i;
int dma_stopped = 0;
struct snd_pcm_runtime *runtime;
spin_lock(&i2sdev->low_lock);
get_pcm_info(i2sdev, in, &pi, NULL);
if (!pi->dbdma_ring.running) {
/* there was still an interrupt pending
* while we stopped. or maybe another
* processor (not the one that was stopping
* the DMA engine) was spinning above
* waiting for the lock. */
if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
goto out_unlock;
}
fc = in_le32(&i2sdev->intfregs->frame_count);
/* a counter overflow does not change the calculation. */
delta = fc - pi->frame_count;
i = pi->current_period;
runtime = pi->substream->runtime;
while (pi->dbdma_ring.cmds[i].xfer_status) {
if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
/*
* BT is the branch taken bit. If it took a branch
* it is because we set the S0 bit to make it
* branch to the stop command.
*/
dma_stopped = 1;
pi->dbdma_ring.cmds[i].xfer_status = 0;
/* update current_period */
while (delta >= pi->substream->runtime->period_size) {
pi->current_period++;
delta = delta - pi->substream->runtime->period_size;
}
if (unlikely(delta)) {
/* Some interrupt came late, so check the dbdma.
* This special case exists to syncronize the frame_count with
* the dbdma transfer, but is hit every once in a while. */
int period;
period = (in_le32(&pi->dbdma->cmdptr)
- pi->dbdma_ring.bus_cmd_start)
/ sizeof(struct dbdma_cmd);
pi->current_period = pi->current_period
% pi->substream->runtime->periods;
while (pi->current_period != period) {
pi->current_period++;
pi->current_period %= pi->substream->runtime->periods;
/* Set delta to zero, as the frame_count value is too
* high (otherwise the code path will not be executed).
* This corrects the fact that the frame_count is too
* low at the beginning due to buffering. */
delta = 0;
if (++i >= runtime->periods) {
i = 0;
pi->frame_count += runtime->buffer_size;
}
pi->current_period = i;
/*
* Check the frame count. The DMA tends to get a bit
* ahead of the frame counter, which confuses the core.
*/
fc = in_le32(&i2sdev->intfregs->frame_count);
nframes = i * runtime->period_size;
if (fc < pi->frame_count + nframes)
pi->frame_count = fc - nframes;
}
pi->frame_count = fc - delta;
pi->current_period %= pi->substream->runtime->periods;
if (dma_stopped) {
timeout = 1000;
for (;;) {
status = in_le32(&pi->dbdma->status);
if (!(status & ACTIVE) && (!in || (status & 0x80)))
break;
if (--timeout <= 0) {
printk(KERN_ERR "i2sbus: timed out "
"waiting for DMA to stop!\n");
break;
}
udelay(1);
}
/* Turn off DMA controller, clear S0 bit */
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
pi->dbdma_ring.stopping = 0;
if (pi->stop_completion)
complete(pi->stop_completion);
}
if (!pi->dbdma_ring.running)
goto out_unlock;
spin_unlock(&i2sdev->low_lock);
/* may call _trigger again, hence needs to be unlocked */
snd_pcm_period_elapsed(pi->substream);
return;
out_unlock:
spin_unlock(&i2sdev->low_lock);
}
@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = {
.close = i2sbus_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = i2sbus_hw_params,
.hw_free = i2sbus_hw_free,
.hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger,
.pointer = i2sbus_playback_pointer,
@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = {
.close = i2sbus_record_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = i2sbus_hw_params,
.hw_free = i2sbus_hw_free,
.hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger,
.pointer = i2sbus_record_pointer,
@ -812,7 +872,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm)
module_put(THIS_MODULE);
}
/* FIXME: this function needs an error handling strategy with labels */
int
i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
struct codec_info *ci, void *data)
@ -880,41 +939,31 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
if (!cii->sdev) {
printk(KERN_DEBUG
"i2sbus: failed to get soundbus dev reference\n");
kfree(cii);
return -ENODEV;
err = -ENODEV;
goto out_free_cii;
}
if (!try_module_get(THIS_MODULE)) {
printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
soundbus_dev_put(dev);
kfree(cii);
return -EBUSY;
err = -EBUSY;
goto out_put_sdev;
}
if (!try_module_get(ci->owner)) {
printk(KERN_DEBUG
"i2sbus: failed to get module reference to codec owner!\n");
module_put(THIS_MODULE);
soundbus_dev_put(dev);
kfree(cii);
return -EBUSY;
err = -EBUSY;
goto out_put_this_module;
}
if (!dev->pcm) {
err = snd_pcm_new(card,
dev->pcmname,
dev->pcmid,
0,
0,
err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0,
&dev->pcm);
if (err) {
printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
kfree(cii);
module_put(ci->owner);
soundbus_dev_put(dev);
module_put(THIS_MODULE);
return err;
goto out_put_ci_module;
}
dev->pcm->dev = &dev->ofdev.dev;
}
/* ALSA yet again sucks.
@ -926,20 +975,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
/* eh? */
printk(KERN_ERR
"Can't attach same bus to different cards!\n");
module_put(ci->owner);
kfree(cii);
soundbus_dev_put(dev);
module_put(THIS_MODULE);
return -EINVAL;
}
if ((err =
snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
module_put(ci->owner);
kfree(cii);
soundbus_dev_put(dev);
module_put(THIS_MODULE);
return err;
err = -EINVAL;
goto out_put_ci_module;
}
err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
if (err)
goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
&i2sbus_playback_ops);
i2sdev->out.created = 1;
@ -949,20 +990,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
if (dev->pcm->card != card) {
printk(KERN_ERR
"Can't attach same bus to different cards!\n");
module_put(ci->owner);
kfree(cii);
soundbus_dev_put(dev);
module_put(THIS_MODULE);
return -EINVAL;
}
if ((err =
snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
module_put(ci->owner);
kfree(cii);
soundbus_dev_put(dev);
module_put(THIS_MODULE);
return err;
goto out_put_ci_module;
}
err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
if (err)
goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
&i2sbus_record_ops);
i2sdev->in.created = 1;
@ -977,11 +1009,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
err = snd_device_register(card, dev->pcm);
if (err) {
printk(KERN_ERR "i2sbus: error registering new pcm\n");
module_put(ci->owner);
kfree(cii);
soundbus_dev_put(dev);
module_put(THIS_MODULE);
return err;
goto out_put_ci_module;
}
/* no errors any more, so let's add this to our list */
list_add(&cii->list, &dev->codec_list);
@ -996,6 +1024,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
64 * 1024, 64 * 1024);
return 0;
out_put_ci_module:
module_put(ci->owner);
out_put_this_module:
module_put(THIS_MODULE);
out_put_sdev:
soundbus_dev_put(dev);
out_free_cii:
kfree(cii);
return err;
}
void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)

View file

@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <sound/pcm.h>
@ -34,6 +35,7 @@ struct dbdma_command_mem {
void *space;
int size;
u32 running:1;
u32 stopping:1;
};
struct pcm_info {
@ -45,6 +47,7 @@ struct pcm_info {
u32 frame_count;
struct dbdma_command_mem dbdma_ring;
volatile struct dbdma_regs __iomem *dbdma;
struct completion *stop_completion;
};
enum {
@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid);
extern irqreturn_t
i2sbus_rx_intr(int irq, void *devid);
extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev);
extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev);
/* control specific functions */
extern int i2sbus_control_init(struct macio_dev* dev,
struct i2sbus_control **c);

View file

@ -228,7 +228,7 @@ struct aaci {
/* AC'97 */
struct mutex ac97_sem;
ac97_bus_t *ac97_bus;
struct snd_ac97_bus *ac97_bus;
u32 maincr;
spinlock_t lock;

View file

@ -108,7 +108,6 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
static int snd_ctl_release(struct inode *inode, struct file *file)
{
unsigned long flags;
struct list_head *list;
struct snd_card *card;
struct snd_ctl_file *ctl;
struct snd_kcontrol *control;
@ -122,12 +121,10 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
list_del(&ctl->list);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
down_write(&card->controls_rwsem);
list_for_each(list, &card->controls) {
control = snd_kcontrol(list);
list_for_each_entry(control, &card->controls, list)
for (idx = 0; idx < control->count; idx++)
if (control->vd[idx].owner == ctl)
control->vd[idx].owner = NULL;
}
up_write(&card->controls_rwsem);
snd_ctl_empty_read_queue(ctl);
kfree(ctl);
@ -140,7 +137,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{
unsigned long flags;
struct list_head *flist;
struct snd_ctl_file *ctl;
struct snd_kctl_event *ev;
@ -149,14 +145,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
card->mixer_oss_change_count++;
#endif
list_for_each(flist, &card->ctl_files) {
struct list_head *elist;
ctl = snd_ctl_file(flist);
list_for_each_entry(ctl, &card->ctl_files, list) {
if (!ctl->subscribed)
continue;
spin_lock_irqsave(&ctl->read_lock, flags);
list_for_each(elist, &ctl->events) {
ev = snd_kctl_event(elist);
list_for_each_entry(ev, &ctl->events, list) {
if (ev->id.numid == id->numid) {
ev->mask |= mask;
goto _found;
@ -190,7 +183,8 @@ EXPORT_SYMBOL(snd_ctl_notify);
*
* Returns the pointer of the new instance, or NULL on failure.
*/
struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access)
static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
unsigned int access)
{
struct snd_kcontrol *kctl;
unsigned int idx;
@ -208,8 +202,6 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce
return kctl;
}
EXPORT_SYMBOL(snd_ctl_new);
/**
* snd_ctl_new1 - create a control instance from the template
* @ncontrol: the initialization record
@ -277,11 +269,9 @@ EXPORT_SYMBOL(snd_ctl_free_one);
static unsigned int snd_ctl_hole_check(struct snd_card *card,
unsigned int count)
{
struct list_head *list;
struct snd_kcontrol *kctl;
list_for_each(list, &card->controls) {
kctl = snd_kcontrol(list);
list_for_each_entry(kctl, &card->controls, list) {
if ((kctl->id.numid <= card->last_numid &&
kctl->id.numid + kctl->count > card->last_numid) ||
(kctl->id.numid <= card->last_numid + count - 1 &&
@ -498,12 +488,10 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
*/
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
{
struct list_head *list;
struct snd_kcontrol *kctl;
snd_assert(card != NULL && numid != 0, return NULL);
list_for_each(list, &card->controls) {
kctl = snd_kcontrol(list);
list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
return kctl;
}
@ -527,14 +515,12 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
struct snd_ctl_elem_id *id)
{
struct list_head *list;
struct snd_kcontrol *kctl;
snd_assert(card != NULL && id != NULL, return NULL);
if (id->numid != 0)
return snd_ctl_find_numid(card, id->numid);
list_for_each(list, &card->controls) {
kctl = snd_kcontrol(list);
list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.iface != id->iface)
continue;
if (kctl->id.device != id->device)
@ -1182,7 +1168,6 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
{
struct snd_ctl_file *ctl;
struct snd_card *card;
struct list_head *list;
struct snd_kctl_ioctl *p;
void __user *argp = (void __user *)arg;
int __user *ip = argp;
@ -1232,8 +1217,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
#endif
}
down_read(&snd_ioctl_rwsem);
list_for_each(list, &snd_control_ioctls) {
p = list_entry(list, struct snd_kctl_ioctl, list);
list_for_each_entry(p, &snd_control_ioctls, list) {
err = p->fioctl(card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
up_read(&snd_ioctl_rwsem);
@ -1357,13 +1341,11 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
struct list_head *lists)
{
struct list_head *list;
struct snd_kctl_ioctl *p;
snd_assert(fcn != NULL, return -EINVAL);
down_write(&snd_ioctl_rwsem);
list_for_each(list, lists) {
p = list_entry(list, struct snd_kctl_ioctl, list);
list_for_each_entry(p, lists, list) {
if (p->fioctl == fcn) {
list_del(&p->list);
up_write(&snd_ioctl_rwsem);
@ -1453,7 +1435,6 @@ static int snd_ctl_dev_register(struct snd_device *device)
static int snd_ctl_dev_disconnect(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct list_head *flist;
struct snd_ctl_file *ctl;
int err, cardnum;
@ -1462,8 +1443,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
down_read(&card->controls_rwsem);
list_for_each(flist, &card->ctl_files) {
ctl = snd_ctl_file(flist);
list_for_each_entry(ctl, &card->ctl_files, list) {
wake_up(&ctl->change_sleep);
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
}

View file

@ -392,7 +392,7 @@ enum {
static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
struct snd_ctl_file *ctl;
struct list_head *list;
struct snd_kctl_ioctl *p;
void __user *argp = compat_ptr(arg);
int err;
@ -427,8 +427,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
}
down_read(&snd_ioctl_rwsem);
list_for_each(list, &snd_control_compat_ioctls) {
struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list);
list_for_each_entry(p, &snd_control_compat_ioctls, list) {
if (p->fioctl) {
err = p->fioctl(ctl->card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {

View file

@ -79,13 +79,11 @@ EXPORT_SYMBOL(snd_device_new);
*/
int snd_device_free(struct snd_card *card, void *device_data)
{
struct list_head *list;
struct snd_device *dev;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
list_for_each_entry(dev, &card->devices, list) {
if (dev->device_data != device_data)
continue;
/* unlink */
@ -124,13 +122,11 @@ EXPORT_SYMBOL(snd_device_free);
*/
int snd_device_disconnect(struct snd_card *card, void *device_data)
{
struct list_head *list;
struct snd_device *dev;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
list_for_each_entry(dev, &card->devices, list) {
if (dev->device_data != device_data)
continue;
if (dev->state == SNDRV_DEV_REGISTERED &&
@ -161,14 +157,12 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
*/
int snd_device_register(struct snd_card *card, void *device_data)
{
struct list_head *list;
struct snd_device *dev;
int err;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
list_for_each_entry(dev, &card->devices, list) {
if (dev->device_data != device_data)
continue;
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
@ -192,13 +186,11 @@ EXPORT_SYMBOL(snd_device_register);
*/
int snd_device_register_all(struct snd_card *card)
{
struct list_head *list;
struct snd_device *dev;
int err;
snd_assert(card != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
list_for_each_entry(dev, &card->devices, list) {
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
if ((err = dev->ops->dev_register(dev)) < 0)
return err;
@ -215,12 +207,10 @@ int snd_device_register_all(struct snd_card *card)
int snd_device_disconnect_all(struct snd_card *card)
{
struct snd_device *dev;
struct list_head *list;
int err = 0;
snd_assert(card != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
list_for_each_entry(dev, &card->devices, list) {
if (snd_device_disconnect(card, dev->device_data) < 0)
err = -ENXIO;
}
@ -234,7 +224,6 @@ int snd_device_disconnect_all(struct snd_card *card)
int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
{
struct snd_device *dev;
struct list_head *list;
int err;
unsigned int range_low, range_high;
@ -242,8 +231,7 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
__again:
list_for_each(list, &card->devices) {
dev = snd_device(list);
list_for_each_entry(dev, &card->devices, list) {
if (dev->type >= range_low && dev->type <= range_high) {
if ((err = snd_device_free(card, dev->device_data)) < 0)
return err;

View file

@ -47,14 +47,11 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device);
static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
{
struct list_head *p;
struct snd_hwdep *hwdep;
list_for_each(p, &snd_hwdep_devices) {
hwdep = list_entry(p, struct snd_hwdep, list);
list_for_each_entry(hwdep, &snd_hwdep_devices, list)
if (hwdep->card == card && hwdep->device == device)
return hwdep;
}
return NULL;
}
@ -159,15 +156,16 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
int err = -ENXIO;
struct snd_hwdep *hw = file->private_data;
struct module *mod = hw->card->module;
mutex_lock(&hw->open_mutex);
if (hw->ops.release) {
if (hw->ops.release)
err = hw->ops.release(hw, file);
wake_up(&hw->open_wait);
}
if (hw->used > 0)
hw->used--;
snd_card_file_remove(hw->card, file);
mutex_unlock(&hw->open_mutex);
wake_up(&hw->open_wait);
snd_card_file_remove(hw->card, file);
module_put(mod);
return err;
}
@ -468,15 +466,12 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
static void snd_hwdep_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct list_head *p;
struct snd_hwdep *hwdep;
mutex_lock(&register_mutex);
list_for_each(p, &snd_hwdep_devices) {
hwdep = list_entry(p, struct snd_hwdep, list);
list_for_each_entry(hwdep, &snd_hwdep_devices, list)
snd_iprintf(buffer, "%02i-%02i: %s\n",
hwdep->card->number, hwdep->device, hwdep->name);
}
mutex_unlock(&register_mutex);
}

View file

@ -114,22 +114,28 @@ struct snd_card *snd_card_new(int idx, const char *xid,
if (idx < 0) {
int idx2;
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
/* idx == -1 == 0xffff means: take any free slot */
if (~snd_cards_lock & idx & 1<<idx2) {
idx = idx2;
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1;
break;
}
} else if (idx < snd_ecards_limit) {
if (snd_cards_lock & (1 << idx))
err = -ENODEV; /* invalid */
} else if (idx < SNDRV_CARDS)
snd_ecards_limit = idx + 1; /* increase the limit */
else
err = -ENODEV;
} else {
if (idx < snd_ecards_limit) {
if (snd_cards_lock & (1 << idx))
err = -EBUSY; /* invalid */
} else {
if (idx < SNDRV_CARDS)
snd_ecards_limit = idx + 1; /* increase the limit */
else
err = -ENODEV;
}
}
if (idx < 0 || err < 0) {
mutex_unlock(&snd_card_mutex);
snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
idx, snd_ecards_limit - 1, err);
goto __error;
}
snd_cards_lock |= 1 << idx; /* lock it */

View file

@ -406,19 +406,17 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
*/
size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
{
struct list_head *p;
struct snd_mem_list *mem;
snd_assert(dmab, return 0);
mutex_lock(&list_mutex);
list_for_each(p, &mem_list_head) {
mem = list_entry(p, struct snd_mem_list, list);
list_for_each_entry(mem, &mem_list_head, list) {
if (mem->id == id &&
(mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
struct device *dev = dmab->dev.dev;
list_del(p);
list_del(&mem->list);
*dmab = mem->buffer;
if (dmab->dev.dev == NULL)
dmab->dev.dev = dev;
@ -488,7 +486,6 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
{
int len = 0;
long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
struct list_head *p;
struct snd_mem_list *mem;
int devno;
static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
@ -498,8 +495,7 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
"pages : %li bytes (%li pages per %likB)\n",
pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
devno = 0;
list_for_each(p, &mem_list_head) {
mem = list_entry(p, struct snd_mem_list, list);
list_for_each_entry(mem, &mem_list_head, list) {
devno++;
len += snprintf(page + len, count - len,
"buffer %d : ID %08x : type %s\n",

View file

@ -78,3 +78,31 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
EXPORT_SYMBOL(snd_verbose_printd);
#endif
#ifdef CONFIG_PCI
#include <linux/pci.h>
/**
* snd_pci_quirk_lookup - look up a PCI SSID quirk list
* @pci: pci_dev handle
* @list: quirk list, terminated by a null entry
*
* Look through the given quirk list and finds a matching entry
* with the same PCI SSID. When subdevice is 0, all subdevice
* values may match.
*
* Returns the matched entry pointer, or NULL if nothing matched.
*/
const struct snd_pci_quirk *
snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
{
const struct snd_pci_quirk *q;
for (q = list; q->subvendor; q++)
if (q->subvendor == pci->subsystem_vendor &&
(!q->subdevice || q->subdevice == pci->subsystem_device))
return q;
return NULL;
}
EXPORT_SYMBOL(snd_pci_quirk_lookup);
#endif

View file

@ -45,11 +45,9 @@ static int snd_pcm_dev_disconnect(struct snd_device *device);
static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
{
struct list_head *p;
struct snd_pcm *pcm;
list_for_each(p, &snd_pcm_devices) {
pcm = list_entry(p, struct snd_pcm, list);
list_for_each_entry(pcm, &snd_pcm_devices, list) {
if (pcm->card == card && pcm->device == device)
return pcm;
}
@ -782,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
struct snd_pcm_runtime *runtime;
struct snd_ctl_file *kctl;
struct snd_card *card;
struct list_head *list;
int prefer_subdevice = -1;
size_t size;
@ -795,8 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
card = pcm->card;
down_read(&card->controls_rwsem);
list_for_each(list, &card->ctl_files) {
kctl = snd_ctl_file(list);
list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == current->pid) {
prefer_subdevice = kctl->prefer_pcm_subdevice;
if (prefer_subdevice != -1)
@ -941,9 +937,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
struct snd_pcm_substream *substream;
struct list_head *list;
struct snd_pcm_notify *notify;
char str[16];
struct snd_pcm *pcm = device->device_data;
struct device *dev;
snd_assert(pcm != NULL && device != NULL, return -ENXIO);
mutex_lock(&register_mutex);
@ -966,11 +963,18 @@ static int snd_pcm_dev_register(struct snd_device *device)
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
if ((err = snd_register_device(devtype, pcm->card,
pcm->device,
&snd_pcm_f_ops[cidx],
pcm, str)) < 0)
{
/* device pointer to use, pcm->dev takes precedence if
* it is assigned, otherwise fall back to card's device
* if possible */
dev = pcm->dev;
if (!dev)
dev = snd_card_get_device_link(pcm->card);
/* register pcm */
err = snd_register_device_for_dev(devtype, pcm->card,
pcm->device,
&snd_pcm_f_ops[cidx],
pcm, str, dev);
if (err < 0) {
list_del(&pcm->list);
mutex_unlock(&register_mutex);
return err;
@ -980,11 +984,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
list_for_each(list, &snd_pcm_notify_list) {
struct snd_pcm_notify *notify;
notify = list_entry(list, struct snd_pcm_notify, list);
list_for_each_entry(notify, &snd_pcm_notify_list, list)
notify->n_register(pcm);
}
mutex_unlock(&register_mutex);
return 0;
}
@ -1027,7 +1030,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
struct list_head *p;
struct snd_pcm *pcm;
snd_assert(notify != NULL &&
notify->n_register != NULL &&
@ -1036,13 +1039,12 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
mutex_lock(&register_mutex);
if (nfree) {
list_del(&notify->list);
list_for_each(p, &snd_pcm_devices)
notify->n_unregister(list_entry(p,
struct snd_pcm, list));
list_for_each_entry(pcm, &snd_pcm_devices, list)
notify->n_unregister(pcm);
} else {
list_add_tail(&notify->list, &snd_pcm_notify_list);
list_for_each(p, &snd_pcm_devices)
notify->n_register(list_entry(p, struct snd_pcm, list));
list_for_each_entry(pcm, &snd_pcm_devices, list)
notify->n_register(pcm);
}
mutex_unlock(&register_mutex);
return 0;
@ -1058,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify);
static void snd_pcm_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct list_head *p;
struct snd_pcm *pcm;
mutex_lock(&register_mutex);
list_for_each(p, &snd_pcm_devices) {
pcm = list_entry(p, struct snd_pcm, list);
list_for_each_entry(pcm, &snd_pcm_devices, list) {
snd_iprintf(buffer, "%02i-%02i: %s : %s",
pcm->card->number, pcm->device, pcm->id, pcm->name);
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)

View file

@ -781,6 +781,11 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *
{
unsigned int k;
int changed = 0;
if (!count) {
i->empty = 1;
return -EINVAL;
}
for (k = 0; k < count; k++) {
if (mask && !(mask & (1 << k)))
continue;

View file

@ -101,6 +101,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_preallocate_dma_free(substream);
#ifdef CONFIG_SND_VERBOSE_PROCFS
snd_info_free_entry(substream->proc_prealloc_max_entry);
substream->proc_prealloc_max_entry = NULL;
snd_info_free_entry(substream->proc_prealloc_entry);
substream->proc_prealloc_entry = NULL;
#endif
@ -141,6 +143,18 @@ static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_buffer.bytes / 1024);
}
/*
* read callback for prealloc_max proc file
*
* prints the maximum allowed size in kB.
*/
static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_pcm_substream *substream = entry->private_data;
snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024);
}
/*
* write callback for prealloc proc file
*
@ -203,6 +217,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream)
}
}
substream->proc_prealloc_entry = entry;
if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {
entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;
entry->private_data = substream;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
}
}
substream->proc_prealloc_max_entry = entry;
}
#else /* !CONFIG_SND_VERBOSE_PROCFS */

View file

@ -61,14 +61,11 @@ static DEFINE_MUTEX(register_mutex);
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
struct list_head *p;
struct snd_rawmidi *rawmidi;
list_for_each(p, &snd_rawmidi_devices) {
rawmidi = list_entry(p, struct snd_rawmidi, list);
list_for_each_entry(rawmidi, &snd_rawmidi_devices, list)
if (rawmidi->card == card && rawmidi->device == device)
return rawmidi;
}
return NULL;
}
@ -389,7 +386,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
struct snd_rawmidi *rmidi;
struct snd_rawmidi_file *rawmidi_file;
wait_queue_t wait;
struct list_head *list;
struct snd_ctl_file *kctl;
if (maj == snd_major) {
@ -426,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
while (1) {
subdevice = -1;
down_read(&card->controls_rwsem);
list_for_each(list, &card->ctl_files) {
kctl = snd_ctl_file(list);
list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == current->pid) {
subdevice = kctl->prefer_rawmidi_subdevice;
if (subdevice != -1)
@ -575,7 +570,6 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *pstr;
struct snd_rawmidi_substream *substream;
struct list_head *list;
mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, info->device);
@ -589,8 +583,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
return -ENOENT;
if (info->subdevice >= pstr->substream_count)
return -ENXIO;
list_for_each(list, &pstr->substreams) {
substream = list_entry(list, struct snd_rawmidi_substream, list);
list_for_each_entry(substream, &pstr->substreams, list) {
if ((unsigned int)substream->number == info->subdevice)
return snd_rawmidi_info(substream, info);
}
@ -1313,14 +1306,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *substream;
struct snd_rawmidi_runtime *runtime;
struct list_head *list;
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
mutex_lock(&rmidi->open_mutex);
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
substream = list_entry(list, struct snd_rawmidi_substream, list);
list_for_each_entry(substream,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
list) {
snd_iprintf(buffer,
"Output %d\n"
" Tx bytes : %lu\n",
@ -1339,8 +1332,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
}
}
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
substream = list_entry(list, struct snd_rawmidi_substream, list);
list_for_each_entry(substream,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
list) {
snd_iprintf(buffer,
"Input %d\n"
" Rx bytes : %lu\n",
@ -1625,13 +1619,10 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
struct snd_rawmidi_ops *ops)
{
struct list_head *list;
struct snd_rawmidi_substream *substream;
list_for_each(list, &rmidi->streams[stream].substreams) {
substream = list_entry(list, struct snd_rawmidi_substream, list);
list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
substream->ops = ops;
}
}
/*

View file

@ -659,7 +659,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
int err = 0, num_ev = 0;
struct snd_seq_event event_saved;
struct snd_seq_client_port *src_port;
struct list_head *p;
struct snd_seq_port_subs_info *grp;
src_port = snd_seq_port_use_ptr(client, event->source.port);
@ -674,8 +673,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
read_lock(&grp->list_lock);
else
down_read(&grp->list_mutex);
list_for_each(p, &grp->list_head) {
subs = list_entry(p, struct snd_seq_subscribers, src_list);
list_for_each_entry(subs, &grp->list_head, src_list) {
event->dest = subs->info.dest;
if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
/* convert time according to flag with subscription */
@ -709,15 +707,14 @@ static int port_broadcast_event(struct snd_seq_client *client,
{
int num_ev = 0, err = 0;
struct snd_seq_client *dest_client;
struct list_head *p;
struct snd_seq_client_port *port;
dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
if (dest_client == NULL)
return 0; /* no matching destination */
read_lock(&dest_client->ports_lock);
list_for_each(p, &dest_client->ports_list_head) {
struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
list_for_each_entry(port, &dest_client->ports_list_head, list) {
event->dest.port = port->addr.port;
/* pass NULL as source client to avoid error bounce */
err = snd_seq_deliver_single_event(NULL, event,
@ -2473,11 +2470,10 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
struct snd_seq_client *client)
{
struct list_head *l;
struct snd_seq_client_port *p;
mutex_lock(&client->ports_mutex);
list_for_each(l, &client->ports_list_head) {
struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
list_for_each_entry(p, &client->ports_list_head, list) {
snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
p->addr.port, p->name,
FLAG_PERM_RD(p->capability),

View file

@ -106,11 +106,10 @@ static void remove_drivers(void);
static void snd_seq_device_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct list_head *head;
struct ops_list *ops;
mutex_lock(&ops_mutex);
list_for_each(head, &opslist) {
struct ops_list *ops = list_entry(head, struct ops_list, list);
list_for_each_entry(ops, &opslist, list) {
snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
ops->id,
ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
@ -143,7 +142,7 @@ void snd_seq_autoload_unlock(void)
void snd_seq_device_load_drivers(void)
{
#ifdef CONFIG_KMOD
struct list_head *head;
struct ops_list *ops;
/* Calling request_module during module_init()
* may cause blocking.
@ -155,8 +154,7 @@ void snd_seq_device_load_drivers(void)
return;
mutex_lock(&ops_mutex);
list_for_each(head, &opslist) {
struct ops_list *ops = list_entry(head, struct ops_list, list);
list_for_each_entry(ops, &opslist, list) {
if (! (ops->driver & DRIVER_LOADED) &&
! (ops->driver & DRIVER_REQUESTED)) {
ops->used++;
@ -314,8 +312,8 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
int argsize)
{
struct list_head *head;
struct ops_list *ops;
struct snd_seq_device *dev;
if (id == NULL || entry == NULL ||
entry->init_device == NULL || entry->free_device == NULL)
@ -341,8 +339,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
ops->argsize = argsize;
/* initialize existing devices if necessary */
list_for_each(head, &ops->dev_list) {
struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
list_for_each_entry(dev, &ops->dev_list, list) {
init_device(dev, ops);
}
mutex_unlock(&ops->reg_mutex);
@ -394,8 +391,8 @@ static struct ops_list * create_driver(char *id)
*/
int snd_seq_device_unregister_driver(char *id)
{
struct list_head *head;
struct ops_list *ops;
struct snd_seq_device *dev;
ops = find_driver(id, 0);
if (ops == NULL)
@ -411,8 +408,7 @@ int snd_seq_device_unregister_driver(char *id)
/* close and release all devices associated with this driver */
mutex_lock(&ops->reg_mutex);
ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
list_for_each(head, &ops->dev_list) {
struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
list_for_each_entry(dev, &ops->dev_list, list) {
free_device(dev, ops);
}
@ -512,11 +508,10 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
*/
static struct ops_list * find_driver(char *id, int create_if_empty)
{
struct list_head *head;
struct ops_list *ops;
mutex_lock(&ops_mutex);
list_for_each(head, &opslist) {
struct ops_list *ops = list_entry(head, struct ops_list, list);
list_for_each_entry(ops, &opslist, list) {
if (strcmp(ops->id, id) == 0) {
ops->used++;
mutex_unlock(&ops_mutex);

View file

@ -59,14 +59,12 @@ much elements are in array.
struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
int num)
{
struct list_head *p;
struct snd_seq_client_port *port;
if (client == NULL)
return NULL;
read_lock(&client->ports_lock);
list_for_each(p, &client->ports_list_head) {
port = list_entry(p, struct snd_seq_client_port, list);
list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
@ -85,14 +83,12 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
struct snd_seq_port_info *pinfo)
{
int num;
struct list_head *p;
struct snd_seq_client_port *port, *found;
num = pinfo->addr.port;
found = NULL;
read_lock(&client->ports_lock);
list_for_each(p, &client->ports_list_head) {
port = list_entry(p, struct snd_seq_client_port, list);
list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port < num)
continue;
if (port->addr.port == num) {
@ -131,8 +127,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
int port)
{
unsigned long flags;
struct snd_seq_client_port *new_port;
struct list_head *l;
struct snd_seq_client_port *new_port, *p;
int num = -1;
/* sanity check */
@ -161,15 +156,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
num = port >= 0 ? port : 0;
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
list_for_each(l, &client->ports_list_head) {
struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port > num)
break;
if (port < 0) /* auto-probe mode */
num = p->addr.port + 1;
}
/* insert the new port */
list_add_tail(&new_port->list, l);
list_add_tail(&new_port->list, &p->list);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
write_unlock_irqrestore(&client->ports_lock, flags);
@ -251,9 +245,9 @@ static void clear_subscriber_list(struct snd_seq_client *client,
list_del(&subs->dest_list);
else
list_del(&subs->src_list);
up_write(&agrp->list_mutex);
unsubscribe_port(c, aport, agrp, &subs->info, 1);
kfree(subs);
up_write(&agrp->list_mutex);
snd_seq_port_unlock(aport);
snd_seq_client_unlock(c);
}
@ -287,16 +281,14 @@ static int port_delete(struct snd_seq_client *client,
int snd_seq_delete_port(struct snd_seq_client *client, int port)
{
unsigned long flags;
struct list_head *l;
struct snd_seq_client_port *found = NULL;
struct snd_seq_client_port *found = NULL, *p;
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
list_for_each(l, &client->ports_list_head) {
struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
list_del(l);
list_del(&p->list);
client->num_ports--;
found = p;
break;
@ -314,7 +306,8 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
int snd_seq_delete_all_ports(struct snd_seq_client *client)
{
unsigned long flags;
struct list_head deleted_list, *p, *n;
struct list_head deleted_list;
struct snd_seq_client_port *port, *tmp;
/* move the port list to deleted_list, and
* clear the port list in the client data.
@ -331,9 +324,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
write_unlock_irqrestore(&client->ports_lock, flags);
/* remove each port in deleted_list */
list_for_each_safe(p, n, &deleted_list) {
struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
list_del(p);
list_for_each_entry_safe(port, tmp, &deleted_list, list) {
list_del(&port->list);
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
@ -500,8 +492,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
{
struct snd_seq_port_subs_info *src = &src_port->c_src;
struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
struct snd_seq_subscribers *subs;
struct list_head *p;
struct snd_seq_subscribers *subs, *s;
int err, src_called = 0;
unsigned long flags;
int exclusive;
@ -525,13 +516,11 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
if (src->exclusive || dest->exclusive)
goto __error;
/* check whether already exists */
list_for_each(p, &src->list_head) {
struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list);
list_for_each_entry(s, &src->list_head, src_list) {
if (match_subs_info(info, &s->info))
goto __error;
}
list_for_each(p, &dest->list_head) {
struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list);
list_for_each_entry(s, &dest->list_head, dest_list) {
if (match_subs_info(info, &s->info))
goto __error;
}
@ -582,7 +571,6 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
struct snd_seq_port_subs_info *src = &src_port->c_src;
struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
struct snd_seq_subscribers *subs;
struct list_head *p;
int err = -ENOENT;
unsigned long flags;
@ -590,8 +578,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
/* look for the connection */
list_for_each(p, &src->list_head) {
subs = list_entry(p, struct snd_seq_subscribers, src_list);
list_for_each_entry(subs, &src->list_head, src_list) {
if (match_subs_info(info, &subs->info)) {
write_lock_irqsave(&src->list_lock, flags);
// write_lock(&dest->list_lock); // no lock yet
@ -620,12 +607,10 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr)
{
struct list_head *p;
struct snd_seq_subscribers *s, *found = NULL;
down_read(&src_grp->list_mutex);
list_for_each(p, &src_grp->list_head) {
s = list_entry(p, struct snd_seq_subscribers, src_list);
list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
found = s;
break;

View file

@ -81,13 +81,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
struct snd_seq_event *ev)
{
struct snd_virmidi *vmidi;
struct list_head *list;
unsigned char msg[4];
int len;
read_lock(&rdev->filelist_lock);
list_for_each(list, &rdev->filelist) {
vmidi = list_entry(list, struct snd_virmidi, list);
list_for_each_entry(vmidi, &rdev->filelist, list) {
if (!vmidi->trigger)
continue;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {

View file

@ -219,26 +219,27 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
#endif
/**
* snd_register_device - Register the ALSA device file for the card
* snd_register_device_for_dev - Register the ALSA device file for the card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
* @card: the card instance
* @dev: the device index
* @f_ops: the file operations
* @private_data: user pointer for f_ops->open()
* @name: the device file name
* @device: the &struct device to link this new device to
*
* Registers an ALSA device file for the given card.
* The operators have to be set in reg parameter.
*
* Retrurns zero if successful, or a negative error code on failure.
* Returns zero if successful, or a negative error code on failure.
*/
int snd_register_device(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops, void *private_data,
const char *name)
int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops,
void *private_data,
const char *name, struct device *device)
{
int minor;
struct snd_minor *preg;
struct device *device = snd_card_get_device_link(card);
snd_assert(name, return -EINVAL);
preg = kmalloc(sizeof *preg, GFP_KERNEL);
@ -272,7 +273,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
return 0;
}
EXPORT_SYMBOL(snd_register_device);
EXPORT_SYMBOL(snd_register_device_for_dev);
/* find the matching minor record
* return the index of snd_minor, or -1 if not found

View file

@ -35,9 +35,6 @@
#include <sound/minors.h>
#include <sound/initval.h>
#include <linux/kmod.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
#define DEFAULT_TIMER_LIMIT 3
@ -130,11 +127,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner,
static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
{
struct snd_timer *timer = NULL;
struct list_head *p;
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
list_for_each_entry(timer, &snd_timer_list, device_list) {
if (timer->tmr_class != tid->dev_class)
continue;
if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
@ -184,13 +178,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
{
struct snd_timer *timer;
struct snd_timer_instance *master;
struct list_head *p, *q;
/* FIXME: it's really dumb to look up all entries.. */
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
list_for_each(q, &timer->open_list_head) {
master = list_entry(q, struct snd_timer_instance, open_list);
list_for_each_entry(timer, &snd_timer_list, device_list) {
list_for_each_entry(master, &timer->open_list_head, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
list_del(&slave->open_list);
@ -214,16 +205,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
*/
static void snd_timer_check_master(struct snd_timer_instance *master)
{
struct snd_timer_instance *slave;
struct list_head *p, *n;
struct snd_timer_instance *slave, *tmp;
/* check all pending slaves */
list_for_each_safe(p, n, &snd_timer_slave_list) {
slave = list_entry(p, struct snd_timer_instance, open_list);
list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
list_del(p);
list_add_tail(p, &master->slave_list_head);
list_move_tail(&slave->open_list, &master->slave_list_head);
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
@ -317,8 +305,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri,
int snd_timer_close(struct snd_timer_instance *timeri)
{
struct snd_timer *timer = NULL;
struct list_head *p, *n;
struct snd_timer_instance *slave;
struct snd_timer_instance *slave, *tmp;
snd_assert(timeri != NULL, return -ENXIO);
@ -353,12 +340,11 @@ int snd_timer_close(struct snd_timer_instance *timeri)
timer->hw.close)
timer->hw.close(timer);
/* remove slave links */
list_for_each_safe(p, n, &timeri->slave_list_head) {
slave = list_entry(p, struct snd_timer_instance, open_list);
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) {
spin_lock_irq(&slave_active_lock);
_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
list_del(p);
list_add_tail(p, &snd_timer_slave_list);
list_move_tail(&slave->open_list, &snd_timer_slave_list);
slave->master = NULL;
slave->timer = NULL;
spin_unlock_irq(&slave_active_lock);
@ -394,7 +380,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
unsigned long flags;
unsigned long resolution = 0;
struct snd_timer_instance *ts;
struct list_head *n;
struct timespec tstamp;
getnstimeofday(&tstamp);
@ -413,11 +398,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
return;
spin_lock_irqsave(&timer->lock, flags);
list_for_each(n, &ti->slave_active_head) {
ts = list_entry(n, struct snd_timer_instance, active_list);
list_for_each_entry(ts, &ti->slave_active_head, active_list)
if (ts->ccallback)
ts->ccallback(ti, event + 100, &tstamp, resolution);
}
spin_unlock_irqrestore(&timer->lock, flags);
}
@ -593,10 +576,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
{
struct snd_timer_instance *ti;
unsigned long ticks = ~0UL;
struct list_head *p;
list_for_each(p, &timer->active_list_head) {
ti = list_entry(p, struct snd_timer_instance, active_list);
list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->flags & SNDRV_TIMER_IFLG_START) {
ti->flags &= ~SNDRV_TIMER_IFLG_START;
ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
@ -661,9 +642,9 @@ static void snd_timer_tasklet(unsigned long arg)
*/
void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
{
struct snd_timer_instance *ti, *ts;
struct snd_timer_instance *ti, *ts, *tmp;
unsigned long resolution, ticks;
struct list_head *p, *q, *n, *ack_list_head;
struct list_head *p, *ack_list_head;
unsigned long flags;
int use_tasklet = 0;
@ -679,12 +660,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
resolution = timer->hw.resolution;
/* loop for all active instances
* Here we cannot use list_for_each because the active_list of a
* Here we cannot use list_for_each_entry because the active_list of a
* processed instance is relinked to done_list_head before the callback
* is called.
*/
list_for_each_safe(p, n, &timer->active_list_head) {
ti = list_entry(p, struct snd_timer_instance, active_list);
list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
active_list) {
if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
continue;
ti->pticks += ticks_left;
@ -700,7 +681,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
} else {
ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (--timer->running)
list_del(p);
list_del(&ti->active_list);
}
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
(ti->flags & SNDRV_TIMER_IFLG_FAST))
@ -709,8 +690,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
ack_list_head = &timer->sack_list_head;
if (list_empty(&ti->ack_list))
list_add_tail(&ti->ack_list, ack_list_head);
list_for_each(q, &ti->slave_active_head) {
ts = list_entry(q, struct snd_timer_instance, active_list);
list_for_each_entry(ts, &ti->slave_active_head, active_list) {
ts->pticks = ti->pticks;
ts->resolution = resolution;
if (list_empty(&ts->ack_list))
@ -844,7 +824,6 @@ static int snd_timer_dev_register(struct snd_device *dev)
{
struct snd_timer *timer = dev->device_data;
struct snd_timer *timer1;
struct list_head *p;
snd_assert(timer != NULL && timer->hw.start != NULL &&
timer->hw.stop != NULL, return -ENXIO);
@ -853,8 +832,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
return -EINVAL;
mutex_lock(&register_mutex);
list_for_each(p, &snd_timer_list) {
timer1 = list_entry(p, struct snd_timer, device_list);
list_for_each_entry(timer1, &snd_timer_list, device_list) {
if (timer1->tmr_class > timer->tmr_class)
break;
if (timer1->tmr_class < timer->tmr_class)
@ -877,7 +855,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
mutex_unlock(&register_mutex);
return -EBUSY;
}
list_add_tail(&timer->device_list, p);
list_add_tail(&timer->device_list, &timer1->device_list);
mutex_unlock(&register_mutex);
return 0;
}
@ -896,7 +874,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
unsigned long flags;
unsigned long resolution = 0;
struct snd_timer_instance *ti, *ts;
struct list_head *p, *n;
if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
return;
@ -911,15 +888,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
else
resolution = timer->hw.resolution;
}
list_for_each(p, &timer->active_list_head) {
ti = list_entry(p, struct snd_timer_instance, active_list);
list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->ccallback)
ti->ccallback(ti, event, tstamp, resolution);
list_for_each(n, &ti->slave_active_head) {
ts = list_entry(n, struct snd_timer_instance, active_list);
list_for_each_entry(ts, &ti->slave_active_head, active_list)
if (ts->ccallback)
ts->ccallback(ts, event, tstamp, resolution);
}
}
spin_unlock_irqrestore(&timer->lock, flags);
}
@ -1057,11 +1031,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
{
struct snd_timer *timer;
struct snd_timer_instance *ti;
struct list_head *p, *q;
mutex_lock(&register_mutex);
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
list_for_each_entry(timer, &snd_timer_list, device_list) {
switch (timer->tmr_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
snd_iprintf(buffer, "G%i: ", timer->tmr_device);
@ -1088,14 +1060,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
snd_iprintf(buffer, "\n");
list_for_each(q, &timer->open_list_head) {
ti = list_entry(q, struct snd_timer_instance, open_list);
list_for_each_entry(ti, &timer->open_list_head, open_list)
snd_iprintf(buffer, " Client %s : %s\n",
ti->owner ? ti->owner : "unknown",
ti->flags & (SNDRV_TIMER_IFLG_START |
SNDRV_TIMER_IFLG_RUNNING)
? "running" : "stopped");
}
}
mutex_unlock(&register_mutex);
}

View file

@ -109,4 +109,15 @@ config SND_MPU401
To compile this driver as a module, choose M here: the module
will be called snd-mpu401.
config SND_PORTMAN2X4
tristate "Portman 2x4 driver"
depends on SND && PARPORT
select SND_RAWMIDI
help
Say Y here to include support for Midiman Portman 2x4 parallel
port MIDI device.
To compile this driver as a module, choose M here: the module
will be called snd-portman2x4.
endmenu

View file

@ -6,6 +6,7 @@
snd-dummy-objs := dummy.o
snd-mtpav-objs := mtpav.o
snd-mts64-objs := mts64.o
snd-portman2x4-objs := portman2x4.o
snd-serial-u16550-objs := serial-u16550.o
snd-virmidi-objs := virmidi.o
@ -15,5 +16,6 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
obj-$(CONFIG_SND_MTS64) += snd-mts64.o
obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/

View file

@ -501,7 +501,7 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
#define DUMMY_CAPSRC(xname, xindex, addr) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \

876
sound/drivers/portman2x4.c Normal file
View file

@ -0,0 +1,876 @@
/*
* Driver for Midiman Portman2x4 parallel port midi interface
*
* Copyright (c) by Levent Guendogdu <levon@feature-it.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* ChangeLog
* Jan 24 2007 Matthias Koenig <mkoenig@suse.de>
* - cleanup and rewrite
* Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk>
* - source code cleanup
* Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk>
* - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES,
* MODULE_PARM_SYNTAX and changed MODULE_DEVICES to
* MODULE_SUPPORTED_DEVICE)
* Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk>
* - added 2.6 kernel support
* Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk>
* - added parport_unregister_driver to the startup routine if the driver fails to detect a portman
* - added support for all 4 output ports in portman_putmidi
* Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk>
* - added checks for opened input device in interrupt handler
* Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk>
* - ported from alsa 0.5 to 1.0
*/
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/parport.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include <sound/control.h>
#define CARD_NAME "Portman 2x4"
#define DRIVER_NAME "portman"
#define PLATFORM_DRIVER "snd_portman2x4"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static struct platform_device *platform_devices[SNDRV_CARDS];
static int device_count;
module_param_array(index, int, NULL, S_IRUGO);
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
module_param_array(id, charp, NULL, S_IRUGO);
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
module_param_array(enable, bool, NULL, S_IRUGO);
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig");
MODULE_DESCRIPTION("Midiman Portman2x4");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}");
/*********************************************************************
* Chip specific
*********************************************************************/
#define PORTMAN_NUM_INPUT_PORTS 2
#define PORTMAN_NUM_OUTPUT_PORTS 4
struct portman {
spinlock_t reg_lock;
struct snd_card *card;
struct snd_rawmidi *rmidi;
struct pardevice *pardev;
int pardev_claimed;
int open_count;
int mode[PORTMAN_NUM_INPUT_PORTS];
struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS];
};
static int portman_free(struct portman *pm)
{
kfree(pm);
return 0;
}
static int __devinit portman_create(struct snd_card *card,
struct pardevice *pardev,
struct portman **rchip)
{
struct portman *pm;
*rchip = NULL;
pm = kzalloc(sizeof(struct portman), GFP_KERNEL);
if (pm == NULL)
return -ENOMEM;
/* Init chip specific data */
spin_lock_init(&pm->reg_lock);
pm->card = card;
pm->pardev = pardev;
*rchip = pm;
return 0;
}
/*********************************************************************
* HW related constants
*********************************************************************/
/* Standard PC parallel port status register equates. */
#define PP_STAT_BSY 0x80 /* Busy status. Inverted. */
#define PP_STAT_ACK 0x40 /* Acknowledge. Non-Inverted. */
#define PP_STAT_POUT 0x20 /* Paper Out. Non-Inverted. */
#define PP_STAT_SEL 0x10 /* Select. Non-Inverted. */
#define PP_STAT_ERR 0x08 /* Error. Non-Inverted. */
/* Standard PC parallel port command register equates. */
#define PP_CMD_IEN 0x10 /* IRQ Enable. Non-Inverted. */
#define PP_CMD_SELI 0x08 /* Select Input. Inverted. */
#define PP_CMD_INIT 0x04 /* Init Printer. Non-Inverted. */
#define PP_CMD_FEED 0x02 /* Auto Feed. Inverted. */
#define PP_CMD_STB 0x01 /* Strobe. Inverted. */
/* Parallel Port Command Register as implemented by PCP2x4. */
#define INT_EN PP_CMD_IEN /* Interrupt enable. */
#define STROBE PP_CMD_STB /* Command strobe. */
/* The parallel port command register field (b1..b3) selects the
* various "registers" within the PC/P 2x4. These are the internal
* address of these "registers" that must be written to the parallel
* port command register.
*/
#define RXDATA0 (0 << 1) /* PCP RxData channel 0. */
#define RXDATA1 (1 << 1) /* PCP RxData channel 1. */
#define GEN_CTL (2 << 1) /* PCP General Control Register. */
#define SYNC_CTL (3 << 1) /* PCP Sync Control Register. */
#define TXDATA0 (4 << 1) /* PCP TxData channel 0. */
#define TXDATA1 (5 << 1) /* PCP TxData channel 1. */
#define TXDATA2 (6 << 1) /* PCP TxData channel 2. */
#define TXDATA3 (7 << 1) /* PCP TxData channel 3. */
/* Parallel Port Status Register as implemented by PCP2x4. */
#define ESTB PP_STAT_POUT /* Echoed strobe. */
#define INT_REQ PP_STAT_ACK /* Input data int request. */
#define BUSY PP_STAT_ERR /* Interface Busy. */
/* Parallel Port Status Register BUSY and SELECT lines are multiplexed
* between several functions. Depending on which 2x4 "register" is
* currently selected (b1..b3), the BUSY and SELECT lines are
* assigned as follows:
*
* SELECT LINE: A3 A2 A1
* --------
*/
#define RXAVAIL PP_STAT_SEL /* Rx Available, channel 0. 0 0 0 */
// RXAVAIL1 PP_STAT_SEL /* Rx Available, channel 1. 0 0 1 */
#define SYNC_STAT PP_STAT_SEL /* Reserved - Sync Status. 0 1 0 */
// /* Reserved. 0 1 1 */
#define TXEMPTY PP_STAT_SEL /* Tx Empty, channel 0. 1 0 0 */
// TXEMPTY1 PP_STAT_SEL /* Tx Empty, channel 1. 1 0 1 */
// TXEMPTY2 PP_STAT_SEL /* Tx Empty, channel 2. 1 1 0 */
// TXEMPTY3 PP_STAT_SEL /* Tx Empty, channel 3. 1 1 1 */
/* BUSY LINE: A3 A2 A1
* --------
*/
#define RXDATA PP_STAT_BSY /* Rx Input Data, channel 0. 0 0 0 */
// RXDATA1 PP_STAT_BSY /* Rx Input Data, channel 1. 0 0 1 */
#define SYNC_DATA PP_STAT_BSY /* Reserved - Sync Data. 0 1 0 */
/* Reserved. 0 1 1 */
#define DATA_ECHO PP_STAT_BSY /* Parallel Port Data Echo. 1 0 0 */
#define A0_ECHO PP_STAT_BSY /* Address 0 Echo. 1 0 1 */
#define A1_ECHO PP_STAT_BSY /* Address 1 Echo. 1 1 0 */
#define A2_ECHO PP_STAT_BSY /* Address 2 Echo. 1 1 1 */
#define PORTMAN2X4_MODE_INPUT_TRIGGERED 0x01
/*********************************************************************
* Hardware specific functions
*********************************************************************/
static inline void portman_write_command(struct portman *pm, u8 value)
{
parport_write_control(pm->pardev->port, value);
}
static inline u8 portman_read_command(struct portman *pm)
{
return parport_read_control(pm->pardev->port);
}
static inline u8 portman_read_status(struct portman *pm)
{
return parport_read_status(pm->pardev->port);
}
static inline u8 portman_read_data(struct portman *pm)
{
return parport_read_data(pm->pardev->port);
}
static inline void portman_write_data(struct portman *pm, u8 value)
{
parport_write_data(pm->pardev->port, value);
}
static void portman_write_midi(struct portman *pm,
int port, u8 mididata)
{
int command = ((port + 4) << 1);
/* Get entering data byte and port number in BL and BH respectively.
* Set up Tx Channel address field for use with PP Cmd Register.
* Store address field in BH register.
* Inputs: AH = Output port number (0..3).
* AL = Data byte.
* command = TXDATA0 | INT_EN;
* Align port num with address field (b1...b3),
* set address for TXDatax, Strobe=0
*/
command |= INT_EN;
/* Disable interrupts so that the process is not interrupted, then
* write the address associated with the current Tx channel to the
* PP Command Reg. Do not set the Strobe signal yet.
*/
do {
portman_write_command(pm, command);
/* While the address lines settle, write parallel output data to
* PP Data Reg. This has no effect until Strobe signal is asserted.
*/
portman_write_data(pm, mididata);
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
* Status Register), then go write data. Else go back and wait.
*/
} while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
/* TxEmpty is set. Maintain PC/P destination address and assert
* Strobe through the PP Command Reg. This will Strobe data into
* the PC/P transmitter and set the PC/P BUSY signal.
*/
portman_write_command(pm, command | STROBE);
/* Wait for strobe line to settle and echo back through hardware.
* Once it has echoed back, assume that the address and data lines
* have settled!
*/
while ((portman_read_status(pm) & ESTB) == 0)
cpu_relax();
/* Release strobe and immediately re-allow interrupts. */
portman_write_command(pm, command);
while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax();
/* PC/P BUSY is now set. We must wait until BUSY resets itself.
* We'll reenable ints while we're waiting.
*/
while ((portman_read_status(pm) & BUSY) == BUSY)
cpu_relax();
/* Data sent. */
}
/*
* Read MIDI byte from port
* Attempt to read input byte from specified hardware input port (0..).
* Return -1 if no data
*/
static int portman_read_midi(struct portman *pm, int port)
{
unsigned char midi_data = 0;
unsigned char cmdout; /* Saved address+IE bit. */
/* Make sure clocking edge is down before starting... */
portman_write_data(pm, 0); /* Make sure edge is down. */
/* Set destination address to PCP. */
cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */
portman_write_command(pm, cmdout);
while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax(); /* Wait for strobe echo. */
/* After the address lines settle, check multiplexed RxAvail signal.
* If data is available, read it.
*/
if ((portman_read_status(pm) & RXAVAIL) == 0)
return -1; /* No data. */
/* Set the Strobe signal to enable the Rx clocking circuitry. */
portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */
while ((portman_read_status(pm) & ESTB) == 0)
cpu_relax(); /* Wait for strobe echo. */
/* The first data bit (msb) is already sitting on the input line. */
midi_data = (portman_read_status(pm) & 128);
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 6. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 1) & 64;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 5. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 2) & 32;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 4. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 3) & 16;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 3. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 4) & 8;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 2. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 5) & 4;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 1. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 6) & 2;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 0. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 7) & 1;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
portman_write_data(pm, 0); /* Return data clock low. */
/* De-assert Strobe and return data. */
portman_write_command(pm, cmdout); /* Output saved address+IE. */
/* Wait for strobe echo. */
while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax();
return (midi_data & 255); /* Shift back and return value. */
}
/*
* Checks if any input data on the given channel is available
* Checks RxAvail
*/
static int portman_data_avail(struct portman *pm, int channel)
{
int command = INT_EN;
switch (channel) {
case 0:
command |= RXDATA0;
break;
case 1:
command |= RXDATA1;
break;
}
/* Write hardware (assumme STROBE=0) */
portman_write_command(pm, command);
/* Check multiplexed RxAvail signal */
if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL)
return 1; /* Data available */
/* No Data available */
return 0;
}
/*
* Flushes any input
*/
static void portman_flush_input(struct portman *pm, unsigned char port)
{
/* Local variable for counting things */
unsigned int i = 0;
unsigned char command = 0;
switch (port) {
case 0:
command = RXDATA0;
break;
case 1:
command = RXDATA1;
break;
default:
snd_printk(KERN_WARNING
"portman_flush_input() Won't flush port %i\n",
port);
return;
}
/* Set address for specified channel in port and allow to settle. */
portman_write_command(pm, command);
/* Assert the Strobe and wait for echo back. */
portman_write_command(pm, command | STROBE);
/* Wait for ESTB */
while ((portman_read_status(pm) & ESTB) == 0)
cpu_relax();
/* Output clock cycles to the Rx circuitry. */
portman_write_data(pm, 0);
/* Flush 250 bits... */
for (i = 0; i < 250; i++) {
portman_write_data(pm, 1);
portman_write_data(pm, 0);
}
/* Deassert the Strobe signal of the port and wait for it to settle. */
portman_write_command(pm, command | INT_EN);
/* Wait for settling */
while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax();
}
static int portman_probe(struct parport *p)
{
/* Initialize the parallel port data register. Will set Rx clocks
* low in case we happen to be addressing the Rx ports at this time.
*/
/* 1 */
parport_write_data(p, 0);
/* Initialize the parallel port command register, thus initializing
* hardware handshake lines to midi box:
*
* Strobe = 0
* Interrupt Enable = 0
*/
/* 2 */
parport_write_control(p, 0);
/* Check if Portman PC/P 2x4 is out there. */
/* 3 */
parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */
/* Check for ESTB to be clear */
/* 4 */
if ((parport_read_status(p) & ESTB) == ESTB)
return 1; /* CODE 1 - Strobe Failure. */
/* Set for RXDATA0 where no damage will be done. */
/* 5 */
parport_write_control(p, RXDATA0 + STROBE); /* Write Strobe=1 to command reg. */
/* 6 */
if ((parport_read_status(p) & ESTB) != ESTB)
return 1; /* CODE 1 - Strobe Failure. */
/* 7 */
parport_write_control(p, 0); /* Reset Strobe=0. */
/* Check if Tx circuitry is functioning properly. If initialized
* unit TxEmpty is false, send out char and see if if goes true.
*/
/* 8 */
parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
* Status Register), then go write data. Else go back and wait.
*/
/* 9 */
if ((parport_read_status(p) & TXEMPTY) == 0)
return 2;
/* Return OK status. */
return 0;
}
static int portman_device_init(struct portman *pm)
{
portman_flush_input(pm, 0);
portman_flush_input(pm, 1);
return 0;
}
/*********************************************************************
* Rawmidi
*********************************************************************/
static int snd_portman_midi_open(struct snd_rawmidi_substream *substream)
{
return 0;
}
static int snd_portman_midi_close(struct snd_rawmidi_substream *substream)
{
return 0;
}
static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream,
int up)
{
struct portman *pm = substream->rmidi->private_data;
unsigned long flags;
spin_lock_irqsave(&pm->reg_lock, flags);
if (up)
pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;
else
pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;
spin_unlock_irqrestore(&pm->reg_lock, flags);
}
static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,
int up)
{
struct portman *pm = substream->rmidi->private_data;
unsigned long flags;
unsigned char byte;
spin_lock_irqsave(&pm->reg_lock, flags);
if (up) {
while ((snd_rawmidi_transmit(substream, &byte, 1) == 1))
portman_write_midi(pm, substream->number, byte);
}
spin_unlock_irqrestore(&pm->reg_lock, flags);
}
static struct snd_rawmidi_ops snd_portman_midi_output = {
.open = snd_portman_midi_open,
.close = snd_portman_midi_close,
.trigger = snd_portman_midi_output_trigger,
};
static struct snd_rawmidi_ops snd_portman_midi_input = {
.open = snd_portman_midi_open,
.close = snd_portman_midi_close,
.trigger = snd_portman_midi_input_trigger,
};
/* Create and initialize the rawmidi component */
static int __devinit snd_portman_rawmidi_create(struct snd_card *card)
{
struct portman *pm = card->private_data;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *substream;
int err;
err = snd_rawmidi_new(card, CARD_NAME, 0,
PORTMAN_NUM_OUTPUT_PORTS,
PORTMAN_NUM_INPUT_PORTS,
&rmidi);
if (err < 0)
return err;
rmidi->private_data = pm;
strcpy(rmidi->name, CARD_NAME);
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
pm->rmidi = rmidi;
/* register rawmidi ops */
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&snd_portman_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
&snd_portman_midi_input);
/* name substreams */
/* output */
list_for_each_entry(substream,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
list) {
sprintf(substream->name,
"Portman2x4 %d", substream->number+1);
}
/* input */
list_for_each_entry(substream,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
list) {
pm->midi_input[substream->number] = substream;
sprintf(substream->name,
"Portman2x4 %d", substream->number+1);
}
return err;
}
/*********************************************************************
* parport stuff
*********************************************************************/
static void snd_portman_interrupt(int irq, void *userdata)
{
unsigned char midivalue = 0;
struct portman *pm = ((struct snd_card*)userdata)->private_data;
spin_lock(&pm->reg_lock);
/* While any input data is waiting */
while ((portman_read_status(pm) & INT_REQ) == INT_REQ) {
/* If data available on channel 0,
read it and stuff it into the queue. */
if (portman_data_avail(pm, 0)) {
/* Read Midi */
midivalue = portman_read_midi(pm, 0);
/* put midi into queue... */
if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
snd_rawmidi_receive(pm->midi_input[0],
&midivalue, 1);
}
/* If data available on channel 1,
read it and stuff it into the queue. */
if (portman_data_avail(pm, 1)) {
/* Read Midi */
midivalue = portman_read_midi(pm, 1);
/* put midi into queue... */
if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
snd_rawmidi_receive(pm->midi_input[1],
&midivalue, 1);
}
}
spin_unlock(&pm->reg_lock);
}
static int __devinit snd_portman_probe_port(struct parport *p)
{
struct pardevice *pardev;
int res;
pardev = parport_register_device(p, DRIVER_NAME,
NULL, NULL, NULL,
0, NULL);
if (!pardev)
return -EIO;
if (parport_claim(pardev)) {
parport_unregister_device(pardev);
return -EIO;
}
res = portman_probe(p);
parport_release(pardev);
parport_unregister_device(pardev);
return res;
}
static void __devinit snd_portman_attach(struct parport *p)
{
struct platform_device *device;
device = platform_device_alloc(PLATFORM_DRIVER, device_count);
if (!device)
return;
/* Temporary assignment to forward the parport */
platform_set_drvdata(device, p);
if (platform_device_register(device) < 0) {
platform_device_put(device);
return;
}
/* Since we dont get the return value of probe
* We need to check if device probing succeeded or not */
if (!platform_get_drvdata(device)) {
platform_device_unregister(device);
return;
}
/* register device in global table */
platform_devices[device_count] = device;
device_count++;
}
static void snd_portman_detach(struct parport *p)
{
/* nothing to do here */
}
static struct parport_driver portman_parport_driver = {
.name = "portman2x4",
.attach = snd_portman_attach,
.detach = snd_portman_detach
};
/*********************************************************************
* platform stuff
*********************************************************************/
static void snd_portman_card_private_free(struct snd_card *card)
{
struct portman *pm = card->private_data;
struct pardevice *pardev = pm->pardev;
if (pardev) {
if (pm->pardev_claimed)
parport_release(pardev);
parport_unregister_device(pardev);
}
portman_free(pm);
}
static int __devinit snd_portman_probe(struct platform_device *pdev)
{
struct pardevice *pardev;
struct parport *p;
int dev = pdev->id;
struct snd_card *card = NULL;
struct portman *pm = NULL;
int err;
p = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev])
return -ENOENT;
if ((err = snd_portman_probe_port(p)) < 0)
return err;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL) {
snd_printd("Cannot create card\n");
return -ENOMEM;
}
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, CARD_NAME);
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, p->base, p->irq);
pardev = parport_register_device(p, /* port */
DRIVER_NAME, /* name */
NULL, /* preempt */
NULL, /* wakeup */
snd_portman_interrupt, /* ISR */
PARPORT_DEV_EXCL, /* flags */
(void *)card); /* private */
if (pardev == NULL) {
snd_printd("Cannot register pardevice\n");
err = -EIO;
goto __err;
}
if ((err = portman_create(card, pardev, &pm)) < 0) {
snd_printd("Cannot create main component\n");
parport_unregister_device(pardev);
goto __err;
}
card->private_data = pm;
card->private_free = snd_portman_card_private_free;
if ((err = snd_portman_rawmidi_create(card)) < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto __err;
}
pm->pardev_claimed = 1;
/* init device */
if ((err = portman_device_init(pm)) < 0)
goto __err;
platform_set_drvdata(pdev, card);
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
snd_printd("Cannot register card\n");
goto __err;
}
snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);
return 0;
__err:
snd_card_free(card);
return err;
}
static int snd_portman_remove(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
if (card)
snd_card_free(card);
return 0;
}
static struct platform_driver snd_portman_driver = {
.probe = snd_portman_probe,
.remove = snd_portman_remove,
.driver = {
.name = PLATFORM_DRIVER
}
};
/*********************************************************************
* module init stuff
*********************************************************************/
static void snd_portman_unregister_all(void)
{
int i;
for (i = 0; i < SNDRV_CARDS; ++i) {
if (platform_devices[i]) {
platform_device_unregister(platform_devices[i]);
platform_devices[i] = NULL;
}
}
platform_driver_unregister(&snd_portman_driver);
parport_unregister_driver(&portman_parport_driver);
}
static int __init snd_portman_module_init(void)
{
int err;
if ((err = platform_driver_register(&snd_portman_driver)) < 0)
return err;
if (parport_register_driver(&portman_parport_driver) != 0) {
platform_driver_unregister(&snd_portman_driver);
return -EIO;
}
if (device_count == 0) {
snd_portman_unregister_all();
return -ENODEV;
}
return 0;
}
static void __exit snd_portman_module_exit(void)
{
snd_portman_unregister_all();
}
module_init(snd_portman_module_init);
module_exit(snd_portman_module_exit);

View file

@ -117,13 +117,13 @@ MODULE_PARM_DESC(adaptor, "Type of adaptor.");
#define SERIAL_MODE_INPUT_TRIGGERED (1 << 2)
#define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3)
typedef struct _snd_uart16550 {
struct snd_uart16550 {
struct snd_card *card;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS];
struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS];
int filemode; //open status of file
int filemode; /* open status of file */
spinlock_t open_lock;
@ -140,39 +140,39 @@ typedef struct _snd_uart16550 {
unsigned char old_divisor_msb;
unsigned char old_line_ctrl_reg;
// parameter for using of write loop
short int fifo_limit; //used in uart16550
short int fifo_count; //used in uart16550
/* parameter for using of write loop */
short int fifo_limit; /* used in uart16550 */
short int fifo_count; /* used in uart16550 */
// type of adaptor
/* type of adaptor */
int adaptor;
// inputs
/* inputs */
int prev_in;
unsigned char rstatus;
// outputs
/* outputs */
int prev_out;
unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS];
// write buffer and its writing/reading position
/* write buffer and its writing/reading position */
unsigned char tx_buff[TX_BUFF_SIZE];
int buff_in_count;
int buff_in;
int buff_out;
int drop_on_full;
// wait timer
/* wait timer */
unsigned int timer_running:1;
struct timer_list buffer_timer;
} snd_uart16550_t;
};
static struct platform_device *devices[SNDRV_CARDS];
static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
{
if (! uart->timer_running) {
if (!uart->timer_running) {
/* timer 38600bps * 10bit * 16byte */
uart->buffer_timer.expires = jiffies + (HZ+255)/256;
uart->timer_running = 1;
@ -180,7 +180,7 @@ static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
}
}
static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart)
{
if (uart->timer_running) {
del_timer(&uart->buffer_timer);
@ -189,10 +189,10 @@ static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
}
/* This macro is only used in snd_uart16550_io_loop */
static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart)
{
unsigned short buff_out = uart->buff_out;
if( uart->buff_in_count > 0 ) {
if (uart->buff_in_count > 0) {
outb(uart->tx_buff[buff_out], uart->base + UART_TX);
uart->fifo_count++;
buff_out++;
@ -206,7 +206,7 @@ static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
* We don't want to interrupt this,
* as we're already handling an interrupt
*/
static void snd_uart16550_io_loop(snd_uart16550_t * uart)
static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
{
unsigned char c, status;
int substream;
@ -220,9 +220,8 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
c = inb(uart->base + UART_RX);
/* keep track of last status byte */
if (c & 0x80) {
if (c & 0x80)
uart->rstatus = c;
}
/* handle stream switch */
if (uart->adaptor == SNDRV_SERIAL_GENERIC) {
@ -230,14 +229,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
if (c <= SNDRV_SERIAL_MAX_INS && c > 0)
substream = c - 1;
if (c != 0xf5)
uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */
}
else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
}
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
/* prevent future bytes from being
interpreted as streams */
uart->rstatus = 0;
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN)
&& uart->midi_input[substream])
snd_rawmidi_receive(uart->midi_input[substream],
&c, 1);
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) &&
uart->midi_input[substream])
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
}
if (status & UART_LSR_OE)
snd_printk("%s: Overrun on device at 0x%lx\n",
@ -250,21 +251,20 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
/* no need of check SERIAL_MODE_OUTPUT_OPEN because if not,
buffer is never filled. */
/* Check write status */
if (status & UART_LSR_THRE) {
if (status & UART_LSR_THRE)
uart->fifo_count = 0;
}
if (uart->adaptor == SNDRV_SERIAL_MS124W_SA
|| uart->adaptor == SNDRV_SERIAL_GENERIC) {
/* Can't use FIFO, must send only when CTS is true */
status = inb(uart->base + UART_MSR);
while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) &&
(uart->buff_in_count > 0) ) {
while (uart->fifo_count == 0 && (status & UART_MSR_CTS) &&
uart->buff_in_count > 0) {
snd_uart16550_buffer_output(uart);
status = inb( uart->base + UART_MSR );
status = inb(uart->base + UART_MSR);
}
} else {
/* Write loop */
while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
&& uart->buff_in_count > 0) /* Do we want to? */
snd_uart16550_buffer_output(uart);
}
@ -294,15 +294,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
*/
static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
{
snd_uart16550_t *uart;
struct snd_uart16550 *uart;
uart = (snd_uart16550_t *) dev_id;
uart = dev_id;
spin_lock(&uart->open_lock);
if (uart->filemode == SERIAL_MODE_NOT_OPENED) {
spin_unlock(&uart->open_lock);
return IRQ_NONE;
}
inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */
/* indicate to the UART that the interrupt has been serviced */
inb(uart->base + UART_IIR);
snd_uart16550_io_loop(uart);
spin_unlock(&uart->open_lock);
return IRQ_HANDLED;
@ -312,9 +313,9 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
static void snd_uart16550_buffer_timer(unsigned long data)
{
unsigned long flags;
snd_uart16550_t *uart;
struct snd_uart16550 *uart;
uart = (snd_uart16550_t *)data;
uart = (struct snd_uart16550 *)data;
spin_lock_irqsave(&uart->open_lock, flags);
snd_uart16550_del_timer(uart);
snd_uart16550_io_loop(uart);
@ -326,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data)
* return 0 if found
* return negative error if not found
*/
static int __init snd_uart16550_detect(snd_uart16550_t *uart)
static int __init snd_uart16550_detect(struct snd_uart16550 *uart)
{
unsigned long io_base = uart->base;
int ok;
@ -343,7 +344,8 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart)
return -EBUSY;
}
ok = 1; /* uart detected unless one of the following tests should fail */
/* uart detected unless one of the following tests should fail */
ok = 1;
/* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */
outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */
c = inb(io_base + UART_IER);
@ -368,7 +370,7 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart)
return ok;
}
static void snd_uart16550_do_open(snd_uart16550_t * uart)
static void snd_uart16550_do_open(struct snd_uart16550 * uart)
{
char byte;
@ -460,7 +462,7 @@ static void snd_uart16550_do_open(snd_uart16550_t * uart)
inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */
}
static void snd_uart16550_do_close(snd_uart16550_t * uart)
static void snd_uart16550_do_close(struct snd_uart16550 * uart)
{
if (uart->irq < 0)
snd_uart16550_del_timer(uart);
@ -514,7 +516,7 @@ static void snd_uart16550_do_close(snd_uart16550_t * uart)
static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
@ -528,7 +530,7 @@ static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
@ -539,24 +541,24 @@ static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
return 0;
}
static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up)
static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream,
int up)
{
unsigned long flags;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (up) {
if (up)
uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED;
} else {
else
uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED;
}
spin_unlock_irqrestore(&uart->open_lock, flags);
}
static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
@ -570,7 +572,7 @@ static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN;
@ -581,18 +583,20 @@ static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
return 0;
};
static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart,
int Num)
{
if( uart->buff_in_count + Num < TX_BUFF_SIZE )
if (uart->buff_in_count + Num < TX_BUFF_SIZE)
return 1;
else
return 0;
}
static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart,
unsigned char byte)
{
unsigned short buff_in = uart->buff_in;
if( uart->buff_in_count < TX_BUFF_SIZE ) {
if (uart->buff_in_count < TX_BUFF_SIZE) {
uart->tx_buff[buff_in] = byte;
buff_in++;
buff_in &= TX_BUFF_MASK;
@ -605,12 +609,14 @@ static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned cha
return 0;
}
static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte)
static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
struct snd_rawmidi_substream *substream,
unsigned char midi_byte)
{
if (uart->buff_in_count == 0 /* Buffer empty? */
if (uart->buff_in_count == 0 /* Buffer empty? */
&& ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
uart->adaptor != SNDRV_SERIAL_GENERIC) ||
(uart->fifo_count == 0 /* FIFO empty? */
(uart->fifo_count == 0 /* FIFO empty? */
&& (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */
/* Tx Buffer Empty - try to write immediately */
@ -623,12 +629,13 @@ static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_s
uart->fifo_count++;
outb(midi_byte, uart->base + UART_TX);
} else {
/* Cannot write (buffer empty) - put char in buffer */
/* Cannot write (buffer empty) -
* put char in buffer */
snd_uart16550_write_buffer(uart, midi_byte);
}
}
} else {
if( !snd_uart16550_write_buffer(uart, midi_byte) ) {
if (!snd_uart16550_write_buffer(uart, midi_byte)) {
snd_printk("%s: Buffer overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
return 0;
@ -642,9 +649,9 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
unsigned char midi_byte, addr_byte;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
char first;
static unsigned long lasttime=0;
static unsigned long lasttime = 0;
/* Interupts are disabled during the updating of the tx_buff,
* since it is 'bad' to have two processes updating the same
@ -653,7 +660,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->irq < 0) //polling
if (uart->irq < 0) /* polling */
snd_uart16550_io_loop(uart);
if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) {
@ -671,7 +678,8 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
/* select any combination of the four ports */
addr_byte = (substream->number << 4) | 0x08;
/* ...except none */
if (addr_byte == 0x08) addr_byte = 0xf8;
if (addr_byte == 0x08)
addr_byte = 0xf8;
#endif
snd_uart16550_output_byte(uart, substream, addr_byte);
/* send midi byte */
@ -679,31 +687,42 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
}
} else {
first = 0;
while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) {
/* Also send F5 after 3 seconds with no data to handle device disconnect */
if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
uart->adaptor == SNDRV_SERIAL_GENERIC) &&
(uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) {
while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) {
/* Also send F5 after 3 seconds with no data
* to handle device disconnect */
if (first == 0 &&
(uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
uart->adaptor == SNDRV_SERIAL_GENERIC) &&
(uart->prev_out != substream->number ||
jiffies-lasttime > 3*HZ)) {
if( snd_uart16550_buffer_can_write( uart, 3 ) ) {
if (snd_uart16550_buffer_can_write(uart, 3)) {
/* Roland Soundcanvas part selection */
/* If this substream of the data is different previous
substream in this uart, send the change part event */
/* If this substream of the data is
* different previous substream
* in this uart, send the change part
* event
*/
uart->prev_out = substream->number;
/* change part */
snd_uart16550_output_byte(uart, substream, 0xf5);
snd_uart16550_output_byte(uart, substream,
0xf5);
/* data */
snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
/* If midi_byte is a data byte, send the previous status byte */
if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
snd_uart16550_output_byte(uart, substream,
uart->prev_out + 1);
/* If midi_byte is a data byte,
* send the previous status byte */
if (midi_byte < 0x80 &&
uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)
snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
} else if( !uart->drop_on_full )
} else if (!uart->drop_on_full)
break;
}
/* send midi byte */
if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full )
if (!snd_uart16550_output_byte(uart, substream, midi_byte) &&
!uart->drop_on_full )
break;
if (midi_byte >= 0x80 && midi_byte < 0xf0)
@ -717,17 +736,17 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
spin_unlock_irqrestore(&uart->open_lock, flags);
}
static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up)
static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream,
int up)
{
unsigned long flags;
snd_uart16550_t *uart = substream->rmidi->private_data;
struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (up) {
if (up)
uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;
} else {
else
uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;
}
spin_unlock_irqrestore(&uart->open_lock, flags);
if (up)
snd_uart16550_output_write(substream);
@ -747,10 +766,10 @@ static struct snd_rawmidi_ops snd_uart16550_input =
.trigger = snd_uart16550_input_trigger,
};
static int snd_uart16550_free(snd_uart16550_t *uart)
static int snd_uart16550_free(struct snd_uart16550 *uart)
{
if (uart->irq >= 0)
free_irq(uart->irq, (void *)uart);
free_irq(uart->irq, uart);
release_and_free_resource(uart->res_base);
kfree(uart);
return 0;
@ -758,7 +777,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart)
static int snd_uart16550_dev_free(struct snd_device *device)
{
snd_uart16550_t *uart = device->device_data;
struct snd_uart16550 *uart = device->device_data;
return snd_uart16550_free(uart);
}
@ -769,12 +788,12 @@ static int __init snd_uart16550_create(struct snd_card *card,
unsigned int base,
int adaptor,
int droponfull,
snd_uart16550_t **ruart)
struct snd_uart16550 **ruart)
{
static struct snd_device_ops ops = {
.dev_free = snd_uart16550_dev_free,
};
snd_uart16550_t *uart;
struct snd_uart16550 *uart;
int err;
@ -795,7 +814,7 @@ static int __init snd_uart16550_create(struct snd_card *card,
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
if (request_irq(irq, snd_uart16550_interrupt,
IRQF_DISABLED, "Serial MIDI", (void *) uart)) {
IRQF_DISABLED, "Serial MIDI", uart)) {
snd_printk("irq %d busy. Using Polling.\n", irq);
} else {
uart->irq = irq;
@ -843,23 +862,28 @@ static int __init snd_uart16550_create(struct snd_card *card,
static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream)
{
struct list_head *list;
struct snd_rawmidi_substream *substream;
list_for_each(list, &stream->substreams) {
struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
list_for_each_entry(substream, &stream->substreams, list) {
sprintf(substream->name, "Serial MIDI %d", substream->number + 1);
}
}
static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi)
static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device,
int outs, int ins,
struct snd_rawmidi **rmidi)
{
struct snd_rawmidi *rrawmidi;
int err;
if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0)
err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device,
outs, ins, &rrawmidi);
if (err < 0)
return err;
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT,
&snd_uart16550_input);
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&snd_uart16550_output);
strcpy(rrawmidi->name, "Serial MIDI");
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
@ -875,7 +899,7 @@ static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int out
static int __init snd_serial_probe(struct platform_device *devptr)
{
struct snd_card *card;
snd_uart16550_t *uart;
struct snd_uart16550 *uart;
int err;
int dev = devptr->id;
@ -929,7 +953,8 @@ static int __init snd_serial_probe(struct platform_device *devptr)
&uart)) < 0)
goto _err;
if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0)
err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);
if (err < 0)
goto _err;
sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d",

View file

@ -716,7 +716,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
return 0;
}
static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
static struct snd_kcontrol_new vx_control_audio_gain = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,

View file

@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/
# Toplevel Module Dependency
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
obj-$(CONFIG_SND_ICE1724) += snd-i2c.o

View file

@ -6,11 +6,11 @@
snd-ak4114-objs := ak4114.o
snd-ak4117-objs := ak4117.o
snd-ak4xxx-adda-objs := ak4xxx-adda.o
snd-pt2258-objs := pt2258.o
snd-tea575x-tuner-objs := tea575x-tuner.o
# Module Dependency
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o
obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o

View file

@ -42,8 +42,8 @@ static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char va
ak4114->write(ak4114->private_data, reg, val);
if (reg <= AK4114_REG_INT1_MASK)
ak4114->regmap[reg] = val;
else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4)
ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val;
else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val;
}
static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg)
@ -66,10 +66,8 @@ static void snd_ak4114_free(struct ak4114 *chip)
{
chip->init = 1; /* don't schedule new work */
mb();
if (chip->workqueue != NULL) {
flush_workqueue(chip->workqueue);
destroy_workqueue(chip->workqueue);
}
cancel_delayed_work(&chip->work);
flush_scheduled_work();
kfree(chip);
}
@ -82,7 +80,7 @@ static int snd_ak4114_dev_free(struct snd_device *device)
int snd_ak4114_create(struct snd_card *card,
ak4114_read_t *read, ak4114_write_t *write,
unsigned char pgm[7], unsigned char txcsb[5],
const unsigned char pgm[7], const unsigned char txcsb[5],
void *private_data, struct ak4114 **r_ak4114)
{
struct ak4114 *chip;
@ -100,18 +98,13 @@ int snd_ak4114_create(struct snd_card *card,
chip->read = read;
chip->write = write;
chip->private_data = private_data;
INIT_DELAYED_WORK(&chip->work, ak4114_stats);
for (reg = 0; reg < 7; reg++)
chip->regmap[reg] = pgm[reg];
for (reg = 0; reg < 5; reg++)
chip->txcsb[reg] = txcsb[reg];
chip->workqueue = create_workqueue("snd-ak4114");
if (chip->workqueue == NULL) {
kfree(chip);
return -ENOMEM;
}
snd_ak4114_reinit(chip);
chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
@ -134,7 +127,8 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char
if (reg <= AK4114_REG_INT1_MASK)
reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val);
reg_write(chip, reg,
(chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val);
}
void snd_ak4114_reinit(struct ak4114 *chip)
@ -143,7 +137,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
chip->init = 1;
mb();
flush_workqueue(chip->workqueue);
flush_scheduled_work();
/* bring the chip to reset state and powerdown state */
reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN));
udelay(200);
@ -158,8 +152,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN);
/* bring up statistics / event queing */
chip->init = 0;
INIT_DELAYED_WORK(&chip->work, ak4114_stats);
queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
schedule_delayed_work(&chip->work, HZ / 10);
}
static unsigned int external_rate(unsigned char rcs1)
@ -568,7 +561,7 @@ static void ak4114_stats(struct work_struct *work)
if (chip->init)
return;
snd_ak4114_check_rate_and_errors(chip, 0);
queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
schedule_delayed_work(&chip->work, HZ / 10);
}
EXPORT_SYMBOL(snd_ak4114_create);

View file

@ -74,7 +74,7 @@ static int snd_ak4117_dev_free(struct snd_device *device)
}
int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
{
struct ak4117 *chip;
int err = 0;

View file

@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
* Used for AK4524 input/ouput attenuation, AK4528, and
* AK5365 input attenuation
*/
static unsigned char vol_cvt_datt[128] = {
static const unsigned char vol_cvt_datt[128] = {
0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = {
/*
* dB tables
*/
static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
/*
* initialize all the ak4xxx chips
*/
void snd_akm4xxx_init(struct snd_akm4xxx *ak)
{
static unsigned char inits_ak4524[] = {
static const unsigned char inits_ak4524[] = {
0x00, 0x07, /* 0: all power up */
0x01, 0x00, /* 1: ADC/DAC reset */
0x02, 0x60, /* 2: 24bit I2S */
@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x07, 0x00, /* 7: DAC right muted */
0xff, 0xff
};
static unsigned char inits_ak4528[] = {
static const unsigned char inits_ak4528[] = {
0x00, 0x07, /* 0: all power up */
0x01, 0x00, /* 1: ADC/DAC reset */
0x02, 0x60, /* 2: 24bit I2S */
@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x05, 0x00, /* 5: ADC right muted */
0xff, 0xff
};
static unsigned char inits_ak4529[] = {
static const unsigned char inits_ak4529[] = {
0x09, 0x01, /* 9: ATS=0, RSTN=1 */
0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x08, 0x55, /* 8: deemphasis all off */
0xff, 0xff
};
static unsigned char inits_ak4355[] = {
static const unsigned char inits_ak4355[] = {
0x01, 0x02, /* 1: reset and soft-mute */
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
* disable DZF, sharp roll-off, RSTN#=0 */
@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x01, 0x01, /* 1: un-reset, unmute */
0xff, 0xff
};
static unsigned char inits_ak4358[] = {
static const unsigned char inits_ak4358[] = {
0x01, 0x02, /* 1: reset and soft-mute */
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
* disable DZF, sharp roll-off, RSTN#=0 */
@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x01, 0x01, /* 1: un-reset, unmute */
0xff, 0xff
};
static unsigned char inits_ak4381[] = {
static const unsigned char inits_ak4381[] = {
0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
0x01, 0x02, /* 1: de-emphasis off, normal speed,
* sharp roll-off, DZF off */
@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
};
int chip, num_chips;
unsigned char *ptr, reg, data, *inits;
const unsigned char *ptr, *inits;
unsigned char reg, data;
memset(ak->images, 0, sizeof(ak->images));
memset(ak->volumes, 0, sizeof(ak->volumes));
@ -513,6 +514,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
return change;
}
#define AK5365_NUM_INPUTS 5
static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
const char **input_names;
int num_names, idx;
input_names = ak->adc_info[mixer_ch].input_names;
num_names = 0;
while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
++num_names;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = num_names;
idx = uinfo->value.enumerated.item;
if (idx >= num_names)
return -EINVAL;
strncpy(uinfo->value.enumerated.name, input_names[idx],
sizeof(uinfo->value.enumerated.name));
return 0;
}
static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char val;
val = snd_akm4xxx_get(ak, chip, addr) & mask;
ucontrol->value.enumerated.item[0] = val;
return 0;
}
static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char oval, val;
oval = snd_akm4xxx_get(ak, chip, addr);
val = oval & ~mask;
val |= ucontrol->value.enumerated.item[0] & mask;
if (val != oval) {
snd_akm4xxx_write(ak, chip, addr, val);
return 1;
}
return 0;
}
/*
* build AK4xxx controls
*/
@ -647,9 +708,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
if (ak->type == SND_AK5365 && (idx % 2) == 0) {
if (! ak->adc_info ||
! ak->adc_info[mixer_ch].switch_name)
! ak->adc_info[mixer_ch].switch_name) {
knew.name = "Capture Switch";
else
knew.index = mixer_ch + ak->idx_offset * 2;
} else
knew.name = ak->adc_info[mixer_ch].switch_name;
knew.info = ak4xxx_switch_info;
knew.get = ak4xxx_switch_get;
@ -662,6 +724,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
if (err < 0)
return err;
memset(&knew, 0, sizeof(knew));
knew.name = ak->adc_info[mixer_ch].selector_name;
if (!knew.name) {
knew.name = "Capture Channel";
knew.index = mixer_ch + ak->idx_offset * 2;
}
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
knew.info = ak4xxx_capture_source_info;
knew.get = ak4xxx_capture_source_get;
knew.put = ak4xxx_capture_source_put;
knew.access = 0;
/* input selector control: reg. 1, bits 0-2.
* mis-use 'shift' to pass mixer_ch */
knew.private_value
= AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
if (err < 0)
return err;
}
idx += num_stereo;

233
sound/i2c/other/pt2258.c Normal file
View file

@ -0,0 +1,233 @@
/*
* ALSA Driver for the PT2258 volume controller.
*
* Copyright (c) 2006 Jochen Voss <voss@seehuhn.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
*
*/
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>
#include <sound/i2c.h>
#include <sound/pt2258.h>
MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
MODULE_LICENSE("GPL");
#define PT2258_CMD_RESET 0xc0
#define PT2258_CMD_UNMUTE 0xf8
#define PT2258_CMD_MUTE 0xf9
static const unsigned char pt2258_channel_code[12] = {
0x80, 0x90, /* channel 1: -10dB, -1dB */
0x40, 0x50, /* channel 2: -10dB, -1dB */
0x00, 0x10, /* channel 3: -10dB, -1dB */
0x20, 0x30, /* channel 4: -10dB, -1dB */
0x60, 0x70, /* channel 5: -10dB, -1dB */
0xa0, 0xb0 /* channel 6: -10dB, -1dB */
};
int snd_pt2258_reset(struct snd_pt2258 *pt)
{
unsigned char bytes[2];
int i;
/* reset chip */
bytes[0] = PT2258_CMD_RESET;
snd_i2c_lock(pt->i2c_bus);
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
goto __error;
snd_i2c_unlock(pt->i2c_bus);
/* mute all channels */
pt->mute = 1;
bytes[0] = PT2258_CMD_MUTE;
snd_i2c_lock(pt->i2c_bus);
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
goto __error;
snd_i2c_unlock(pt->i2c_bus);
/* set all channels to 0dB */
for (i = 0; i < 6; ++i)
pt->volume[i] = 0;
bytes[0] = 0xd0;
bytes[1] = 0xe0;
snd_i2c_lock(pt->i2c_bus);
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
goto __error;
snd_i2c_unlock(pt->i2c_bus);
return 0;
__error:
snd_i2c_unlock(pt->i2c_bus);
snd_printk(KERN_ERR "PT2258 reset failed\n");
return -EIO;
}
static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 79;
return 0;
}
static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pt2258 *pt = kcontrol->private_data;
int base = kcontrol->private_value;
/* chip does not support register reads */
ucontrol->value.integer.value[0] = 79 - pt->volume[base];
ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
return 0;
}
static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pt2258 *pt = kcontrol->private_data;
int base = kcontrol->private_value;
unsigned char bytes[2];
int val0, val1;
val0 = 79 - ucontrol->value.integer.value[0];
val1 = 79 - ucontrol->value.integer.value[1];
if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
return 0;
pt->volume[base] = val0;
bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
snd_i2c_lock(pt->i2c_bus);
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
goto __error;
snd_i2c_unlock(pt->i2c_bus);
pt->volume[base + 1] = val1;
bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
snd_i2c_lock(pt->i2c_bus);
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
goto __error;
snd_i2c_unlock(pt->i2c_bus);
return 1;
__error:
snd_i2c_unlock(pt->i2c_bus);
snd_printk(KERN_ERR "PT2258 access failed\n");
return -EIO;
}
static int pt2258_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pt2258 *pt = kcontrol->private_data;
ucontrol->value.integer.value[0] = !pt->mute;
return 0;
}
static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pt2258 *pt = kcontrol->private_data;
unsigned char bytes[2];
int val;
val = !ucontrol->value.integer.value[0];
if (pt->mute == val)
return 0;
pt->mute = val;
bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
snd_i2c_lock(pt->i2c_bus);
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
goto __error;
snd_i2c_unlock(pt->i2c_bus);
return 1;
__error:
snd_i2c_unlock(pt->i2c_bus);
snd_printk(KERN_ERR "PT2258 access failed 2\n");
return -EIO;
}
static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
int snd_pt2258_build_controls(struct snd_pt2258 *pt)
{
struct snd_kcontrol_new knew;
char *names[3] = {
"Mic Loopback Playback Volume",
"Line Loopback Playback Volume",
"CD Loopback Playback Volume"
};
int i, err;
for (i = 0; i < 3; ++i) {
memset(&knew, 0, sizeof(knew));
knew.name = names[i];
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
knew.count = 1;
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
knew.private_value = 2 * i;
knew.info = pt2258_stereo_volume_info;
knew.get = pt2258_stereo_volume_get;
knew.put = pt2258_stereo_volume_put;
knew.tlv.p = pt2258_db_scale;
err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
if (err < 0)
return err;
}
memset(&knew, 0, sizeof(knew));
knew.name = "Loopback Switch";
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
knew.info = pt2258_switch_info;
knew.get = pt2258_switch_get;
knew.put = pt2258_switch_put;
knew.access = 0;
err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
if (err < 0)
return err;
return 0;
}
EXPORT_SYMBOL(snd_pt2258_reset);
EXPORT_SYMBOL(snd_pt2258_build_controls);

View file

@ -358,6 +358,7 @@ config SND_SBAWE
config SND_SB16_CSP
bool "Sound Blaster 16/AWE CSP support"
depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC)
select FW_LOADER
help
Say Y here to include support for the CSP core. This special
coprocessor can do variable tasks like various compression and
@ -390,6 +391,7 @@ config SND_SSCAPE
config SND_WAVEFRONT
tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
depends on SND
select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_CS4231_LIB

View file

@ -906,11 +906,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),

View file

@ -1223,9 +1223,9 @@ int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip,
EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static struct ad1848_mix_elem snd_ad1848_controls[] = {
AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),

View file

@ -294,10 +294,10 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
gus->mix_cntrl_reg |= 4; /* enable MIC */
}
dma1 = gus->gf1.dma1;
dma1 = dma1 < 0 ? -dma1 : dma1;
dma1 = abs(dma1);
dma1 = dmas[dma1 & 7];
dma2 = gus->gf1.dma2;
dma2 = dma2 < 0 ? -dma2 : dma2;
dma2 = abs(dma2);
dma2 = dmas[dma2 & 7];
dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
@ -306,7 +306,7 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
return -EINVAL;
}
irq = gus->gf1.irq;
irq = irq < 0 ? -irq : irq;
irq = abs(irq);
irq = irqs[irq & 0x0f];
if (irq == 0) {
snd_printk(KERN_ERR "Error! IRQ isn't defined.\n");

View file

@ -486,8 +486,8 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),

View file

@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
*/
static void snd_sb_csp_free(struct snd_hwdep *hwdep)
{
int i;
struct snd_sb_csp *p = hwdep->private_data;
if (p) {
if (p->running & SNDRV_SB_CSP_ST_RUNNING)
snd_sb_csp_stop(p);
for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i)
release_firmware(p->csp_programs[i]);
kfree(p);
}
}
@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use
return err;
}
#define FIRMWARE_IN_THE_KERNEL
#ifdef FIRMWARE_IN_THE_KERNEL
#include "sb16_csp_codecs.h"
static const struct firmware snd_sb_csp_static_programs[] = {
{ .data = mulaw_main, .size = sizeof mulaw_main },
{ .data = alaw_main, .size = sizeof alaw_main },
{ .data = ima_adpcm_init, .size = sizeof ima_adpcm_init },
{ .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback },
{ .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture },
};
#endif
static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
{
static const char *const names[] = {
"sb16/mulaw_main.csp",
"sb16/alaw_main.csp",
"sb16/ima_adpcm_init.csp",
"sb16/ima_adpcm_playback.csp",
"sb16/ima_adpcm_capture.csp",
};
const struct firmware *program;
int err;
BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
program = p->csp_programs[index];
if (!program) {
err = request_firmware(&program, names[index],
p->chip->card->dev);
if (err >= 0)
p->csp_programs[index] = program;
else {
#ifdef FIRMWARE_IN_THE_KERNEL
program = &snd_sb_csp_static_programs[index];
#else
return err;
#endif
}
}
return snd_sb_csp_load(p, program->data, program->size, flags);
}
/*
* autoload hardware codec if necessary
* return 0 if CSP is loaded and ready to run (p->running != 0)
@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec
} else {
switch (pcm_sfmt) {
case SNDRV_PCM_FORMAT_MU_LAW:
err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);
err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);
p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
break;
case SNDRV_PCM_FORMAT_A_LAW:
err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);
err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);
p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
break;
case SNDRV_PCM_FORMAT_IMA_ADPCM:
err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),
SNDRV_SB_CSP_LOAD_INITBLOCK);
err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,
SNDRV_SB_CSP_LOAD_INITBLOCK);
if (err)
break;
if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
err = snd_sb_csp_load(p, &ima_adpcm_playback[0],
sizeof(ima_adpcm_playback), 0);
err = snd_sb_csp_firmware_load
(p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);
p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
} else {
err = snd_sb_csp_load(p, &ima_adpcm_capture[0],
sizeof(ima_adpcm_capture), 0);
err = snd_sb_csp_firmware_load
(p, CSP_PROGRAM_ADPCM_CAPTURE, 0);
p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
}
p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;

View file

@ -402,6 +402,7 @@ static struct snd_card *snd_wavefront_card_new(int dev)
init_waitqueue_head(&acard->wavefront.interrupt_sleeper);
spin_lock_init(&acard->wavefront.midi.open);
spin_lock_init(&acard->wavefront.midi.virtual);
acard->wavefront.card = card;
card->private_free = snd_wavefront_free;
return card;

View file

@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/snd_wavefront.h>
#include <sound/initval.h>
@ -32,325 +33,17 @@
#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
/* weird stuff, derived from port I/O tracing with dosemu */
#define WAIT_IDLE 0xff
static unsigned char page_zero[] __devinitdata = {
0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
0x1d, 0x02, 0xdf
};
#define FIRMWARE_IN_THE_KERNEL
static unsigned char page_one[] __devinitdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
0x60, 0x00, 0x1b
};
static unsigned char page_two[] __devinitdata = {
0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
};
static unsigned char page_three[] __devinitdata = {
0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
};
static unsigned char page_four[] __devinitdata = {
0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
};
static unsigned char page_six[] __devinitdata = {
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
0x80, 0x00, 0x7e, 0x80, 0x80
};
static unsigned char page_seven[] __devinitdata = {
0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00
};
static unsigned char page_zero_v2[] __devinitdata = {
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char page_one_v2[] __devinitdata = {
0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char page_two_v2[] __devinitdata = {
0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
static unsigned char page_three_v2[] __devinitdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
static unsigned char page_four_v2[] __devinitdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
static unsigned char page_seven_v2[] __devinitdata = {
0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char mod_v2[] __devinitdata = {
0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
};
static unsigned char coefficients[] __devinitdata = {
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
0xba
};
static unsigned char coefficients2[] __devinitdata = {
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
};
static unsigned char coefficients3[] __devinitdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
#ifdef FIRMWARE_IN_THE_KERNEL
#include "yss225.c"
static const struct firmware yss225_registers_firmware = {
.data = (u8 *)yss225_registers,
.size = sizeof yss225_registers
};
#endif
static int
wavefront_fx_idle (snd_wavefront_t *dev)
@ -555,465 +248,56 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
of the port I/O done, using the Yamaha faxback document as a guide
to add more logic to the code. Its really pretty weird.
There was an alternative approach of just dumping the whole I/O
This is the approach of just dumping the whole I/O
sequence as a series of port/value pairs and a simple loop
that output it. However, I hope that eventually I'll get more
control over what this code does, and so I tried to stick with
a somewhat "algorithmic" approach.
that outputs it.
*/
int __devinit
snd_wavefront_fx_start (snd_wavefront_t *dev)
{
unsigned int i, j;
unsigned int i;
int err;
const struct firmware *firmware;
/* Set all bits for all channels on the MOD unit to zero */
/* XXX But why do this twice ? */
if (dev->fx_initialized)
return 0;
for (j = 0; j < 2; j++) {
for (i = 0x10; i <= 0xff; i++) {
if (!wavefront_fx_idle (dev)) {
return (-1);
err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
dev->card->dev);
if (err < 0) {
#ifdef FIRMWARE_IN_THE_KERNEL
firmware = &yss225_registers_firmware;
#else
err = -1;
goto out;
#endif
}
for (i = 0; i + 1 < firmware->size; i += 2) {
if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
outb(firmware->data[i + 1],
dev->base + firmware->data[i]);
} else if (firmware->data[i] == WAIT_IDLE) {
if (!wavefront_fx_idle(dev)) {
err = -1;
goto out;
}
outb (i, dev->fx_mod_addr);
outb (0x0, dev->fx_mod_data);
} else {
snd_printk(KERN_ERR "invalid address"
" in register data\n");
err = -1;
goto out;
}
}
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x02, dev->fx_op); /* mute on */
dev->fx_initialized = 1;
err = 0;
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x44, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x42, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x43, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x7c, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x7e, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x46, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x49, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x47, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x4a, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
/* either because of stupidity by TB's programmers, or because it
actually does something, rezero the MOD page.
*/
for (i = 0x10; i <= 0xff; i++) {
if (!wavefront_fx_idle (dev)) {
return (-1);
}
outb (i, dev->fx_mod_addr);
outb (0x0, dev->fx_mod_data);
}
/* load page zero */
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x00, dev->fx_dsp_page);
outb (0x00, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_zero); i += 2) {
outb (page_zero[i], dev->fx_dsp_msb);
outb (page_zero[i+1], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
/* Now load page one */
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x01, dev->fx_dsp_page);
outb (0x00, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_one); i += 2) {
outb (page_one[i], dev->fx_dsp_msb);
outb (page_one[i+1], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x02, dev->fx_dsp_page);
outb (0x00, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_two); i++) {
outb (page_two[i], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x03, dev->fx_dsp_page);
outb (0x00, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_three); i++) {
outb (page_three[i], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x04, dev->fx_dsp_page);
outb (0x00, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_four); i++) {
outb (page_four[i], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
/* Load memory area (page six) */
outb (FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x06, dev->fx_dsp_page);
for (i = 0; i < sizeof (page_six); i += 3) {
outb (page_six[i], dev->fx_dsp_addr);
outb (page_six[i+1], dev->fx_dsp_msb);
outb (page_six[i+2], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x07, dev->fx_dsp_page);
outb (0x00, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_seven); i += 2) {
outb (page_seven[i], dev->fx_dsp_msb);
outb (page_seven[i+1], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
/* Now setup the MOD area. We do this algorithmically in order to
save a little data space. It could be done in the same fashion
as the "pages".
*/
for (i = 0x00; i <= 0x0f; i++) {
outb (0x01, dev->fx_mod_addr);
outb (i, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x02, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0xb0; i <= 0xbf; i++) {
outb (i, dev->fx_mod_addr);
outb (0x20, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0xf0; i <= 0xff; i++) {
outb (i, dev->fx_mod_addr);
outb (0x20, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0x10; i <= 0x1d; i++) {
outb (i, dev->fx_mod_addr);
outb (0xff, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0x1e, dev->fx_mod_addr);
outb (0x40, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
for (i = 0x1f; i <= 0x2d; i++) {
outb (i, dev->fx_mod_addr);
outb (0xff, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0x2e, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
for (i = 0x2f; i <= 0x3e; i++) {
outb (i, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0x3f, dev->fx_mod_addr);
outb (0x20, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
for (i = 0x40; i <= 0x4d; i++) {
outb (i, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0x4e, dev->fx_mod_addr);
outb (0x0e, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x4f, dev->fx_mod_addr);
outb (0x0e, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
for (i = 0x50; i <= 0x6b; i++) {
outb (i, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0x6c, dev->fx_mod_addr);
outb (0x40, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x6d, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x6e, dev->fx_mod_addr);
outb (0x40, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x6f, dev->fx_mod_addr);
outb (0x40, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
for (i = 0x70; i <= 0x7f; i++) {
outb (i, dev->fx_mod_addr);
outb (0xc0, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0x80; i <= 0xaf; i++) {
outb (i, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0xc0; i <= 0xdd; i++) {
outb (i, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0xde, dev->fx_mod_addr);
outb (0x10, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0xdf, dev->fx_mod_addr);
outb (0x10, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
for (i = 0xe0; i <= 0xef; i++) {
outb (i, dev->fx_mod_addr);
outb (0x00, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0x00; i <= 0x0f; i++) {
outb (0x01, dev->fx_mod_addr);
outb (i, dev->fx_mod_data);
outb (0x02, dev->fx_mod_addr);
outb (0x01, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (0x02, dev->fx_op); /* mute on */
/* Now set the coefficients and so forth for the programs above */
for (i = 0; i < sizeof (coefficients); i += 4) {
outb (coefficients[i], dev->fx_dsp_page);
outb (coefficients[i+1], dev->fx_dsp_addr);
outb (coefficients[i+2], dev->fx_dsp_msb);
outb (coefficients[i+3], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
/* Some settings (?) that are too small to bundle into loops */
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x1e, dev->fx_mod_addr);
outb (0x14, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0xde, dev->fx_mod_addr);
outb (0x20, dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0xdf, dev->fx_mod_addr);
outb (0x20, dev->fx_mod_data);
/* some more coefficients */
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x06, dev->fx_dsp_page);
outb (0x78, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x40, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x03, dev->fx_dsp_addr);
outb (0x0f, dev->fx_dsp_msb);
outb (0xff, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x0b, dev->fx_dsp_addr);
outb (0x0f, dev->fx_dsp_msb);
outb (0xff, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x02, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x0a, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x46, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
outb (0x07, dev->fx_dsp_page);
outb (0x49, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
/* Now, for some strange reason, lets reload every page
and all the coefficients over again. I have *NO* idea
why this is done. I do know that no sound is produced
is this phase is omitted.
*/
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x00, dev->fx_dsp_page);
outb (0x10, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_zero_v2); i += 2) {
outb (page_zero_v2[i], dev->fx_dsp_msb);
outb (page_zero_v2[i+1], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x01, dev->fx_dsp_page);
outb (0x10, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_one_v2); i += 2) {
outb (page_one_v2[i], dev->fx_dsp_msb);
outb (page_one_v2[i+1], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
if (!wavefront_fx_idle (dev)) return (-1);
if (!wavefront_fx_idle (dev)) return (-1);
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x02, dev->fx_dsp_page);
outb (0x10, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_two_v2); i++) {
outb (page_two_v2[i], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x03, dev->fx_dsp_page);
outb (0x10, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_three_v2); i++) {
outb (page_three_v2[i], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x04, dev->fx_dsp_page);
outb (0x10, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_four_v2); i++) {
outb (page_four_v2[i], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x06, dev->fx_dsp_page);
/* Page six v.2 is algorithmic */
for (i = 0x10; i <= 0x3e; i += 2) {
outb (i, dev->fx_dsp_addr);
outb (0x00, dev->fx_dsp_msb);
outb (0x00, dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
outb (0x07, dev->fx_dsp_page);
outb (0x10, dev->fx_dsp_addr);
for (i = 0; i < sizeof (page_seven_v2); i += 2) {
outb (page_seven_v2[i], dev->fx_dsp_msb);
outb (page_seven_v2[i+1], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0x00; i < sizeof(mod_v2); i += 2) {
outb (mod_v2[i], dev->fx_mod_addr);
outb (mod_v2[i+1], dev->fx_mod_data);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0; i < sizeof (coefficients2); i += 4) {
outb (coefficients2[i], dev->fx_dsp_page);
outb (coefficients2[i+1], dev->fx_dsp_addr);
outb (coefficients2[i+2], dev->fx_dsp_msb);
outb (coefficients2[i+3], dev->fx_dsp_lsb);
if (!wavefront_fx_idle (dev)) return (-1);
}
for (i = 0; i < sizeof (coefficients3); i += 2) {
int x;
outb (0x07, dev->fx_dsp_page);
x = (i % 4) ? 0x4e : 0x4c;
outb (x, dev->fx_dsp_addr);
outb (coefficients3[i], dev->fx_dsp_msb);
outb (coefficients3[i+1], dev->fx_dsp_lsb);
}
outb (0x00, dev->fx_op); /* mute off */
if (!wavefront_fx_idle (dev)) return (-1);
return (0);
out:
#ifdef FIRMWARE_IN_THE_KERNEL
if (firmware != &yss225_registers_firmware)
#endif
release_firmware(firmware);
return err;
}

2739
sound/isa/wavefront/yss225.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -236,7 +236,7 @@ config SND_CS5535AUDIO
config SND_DARLA20
tristate "(Echoaudio) Darla20"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Darla.
@ -247,7 +247,7 @@ config SND_DARLA20
config SND_GINA20
tristate "(Echoaudio) Gina20"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Gina.
@ -258,7 +258,7 @@ config SND_GINA20
config SND_LAYLA20
tristate "(Echoaudio) Layla20"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@ -270,7 +270,7 @@ config SND_LAYLA20
config SND_DARLA24
tristate "(Echoaudio) Darla24"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Darla24.
@ -281,7 +281,7 @@ config SND_DARLA24
config SND_GINA24
tristate "(Echoaudio) Gina24"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Gina24.
@ -292,7 +292,7 @@ config SND_GINA24
config SND_LAYLA24
tristate "(Echoaudio) Layla24"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@ -304,7 +304,7 @@ config SND_LAYLA24
config SND_MONA
tristate "(Echoaudio) Mona"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@ -316,7 +316,7 @@ config SND_MONA
config SND_MIA
tristate "(Echoaudio) Mia"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@ -328,7 +328,7 @@ config SND_MIA
config SND_ECHO3G
tristate "(Echoaudio) 3G cards"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@ -340,7 +340,7 @@ config SND_ECHO3G
config SND_INDIGO
tristate "(Echoaudio) Indigo"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo.
@ -351,7 +351,7 @@ config SND_INDIGO
config SND_INDIGOIO
tristate "(Echoaudio) Indigo IO"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
@ -362,7 +362,7 @@ config SND_INDIGOIO
config SND_INDIGODJ
tristate "(Echoaudio) Indigo DJ"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
@ -373,6 +373,7 @@ config SND_INDIGODJ
config SND_EMU10K1
tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
depends on SND
select FW_LOADER
select SND_HWDEP
select SND_RAWMIDI
select SND_AC97_CODEC
@ -575,6 +576,7 @@ config SND_INTEL8X0M
config SND_KORG1212
tristate "Korg 1212 IO"
depends on SND
select FW_LOADER
select SND_PCM
help
Say Y here to include support for Korg 1212IO soundcards.
@ -585,6 +587,7 @@ config SND_KORG1212
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
depends on SND
select FW_LOADER
select SND_AC97_CODEC
help
Say Y here to include support for soundcards based on ESS Maestro 3
@ -629,7 +632,7 @@ config SND_PCXHR
config SND_RIPTIDE
tristate "Conexant Riptide"
depends on SND
depends on FW_LOADER
select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
@ -734,6 +737,7 @@ config SND_VX222
config SND_YMFPCI
tristate "Yamaha YMF724/740/744/754"
depends on SND
select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC

View file

@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL },
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL },
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL },
{ 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL },
{ 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL },
{ 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL },
{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */
@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
static void update_power_regs(struct snd_ac97 *ac97);
#ifdef CONFIG_SND_AC97_POWER_SAVE
#define ac97_is_power_save_mode(ac97) \
((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save)
#else
#define ac97_is_power_save_mode(ac97) 0
#endif
/*
* I/O routines
@ -982,8 +989,8 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
{
if (ac97) {
#ifdef CONFIG_SND_AC97_POWER_SAVE
if (ac97->power_workq)
destroy_workqueue(ac97->power_workq);
cancel_delayed_work(&ac97->power_work);
flush_scheduled_work();
#endif
snd_ac97_proc_done(ac97);
if (ac97->bus)
@ -1184,13 +1191,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
/*
* set dB information
*/
static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static unsigned int *find_db_scale(unsigned int maxval)
static const unsigned int *find_db_scale(unsigned int maxval)
{
switch (maxval) {
case 0x0f: return db_scale_4bit;
@ -1200,8 +1207,8 @@ static unsigned int *find_db_scale(unsigned int maxval)
return NULL;
}
static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
{
static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv)
{
kctl->tlv.p = tlv;
if (tlv)
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
@ -1989,7 +1996,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
mutex_init(&ac97->reg_mutex);
mutex_init(&ac97->page_mutex);
#ifdef CONFIG_SND_AC97_POWER_SAVE
ac97->power_workq = create_workqueue("ac97");
INIT_DELAYED_WORK(&ac97->power_work, do_update_power);
#endif
@ -2275,15 +2281,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
udelay(100);
power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
snd_ac97_write(ac97, AC97_POWERDOWN, power);
#ifdef CONFIG_SND_AC97_POWER_SAVE
if (power_save) {
if (ac97_is_power_save_mode(ac97)) {
udelay(100);
/* AC-link powerdown, internal Clk disable */
/* FIXME: this may cause click noises on some boards */
power |= AC97_PD_PR4 | AC97_PD_PR5;
snd_ac97_write(ac97, AC97_POWERDOWN, power);
}
#endif
}
@ -2337,14 +2341,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
}
}
if (power_save && !powerup && ac97->power_workq)
if (ac97_is_power_save_mode(ac97) && !powerup)
/* adjust power-down bits after two seconds delay
* (for avoiding loud click noises for many (OSS) apps
* that open/close frequently)
*/
queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
else
schedule_delayed_work(&ac97->power_work, HZ*2);
else {
cancel_delayed_work(&ac97->power_work);
update_power_regs(ac97);
}
return 0;
}
@ -2357,19 +2363,15 @@ static void update_power_regs(struct snd_ac97 *ac97)
unsigned int power_up, bits;
int i;
power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
power_up |= (1 << PWIDX_MIC);
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
power_up |= (1 << PWIDX_SURR);
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
power_up |= (1 << PWIDX_CLFE);
#ifdef CONFIG_SND_AC97_POWER_SAVE
if (power_save)
if (ac97_is_power_save_mode(ac97))
power_up = ac97->power_up;
else {
#endif
power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
power_up |= (1 << PWIDX_MIC);
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
power_up |= (1 << PWIDX_SURR);
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
power_up |= (1 << PWIDX_CLFE);
#ifdef CONFIG_SND_AC97_POWER_SAVE
}
#endif
if (power_up) {
if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
@ -2414,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
return;
if (ac97->build_ops->suspend)
ac97->build_ops->suspend(ac97);
#ifdef CONFIG_SND_AC97_POWER_SAVE
cancel_delayed_work(&ac97->power_work);
flush_scheduled_work();
#endif
snd_ac97_powerdown(ac97);
}

View file

@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
/* replace with a new TLV */
static void reset_tlv(struct snd_ac97 *ac97, const char *name,
unsigned int *tlv)
const unsigned int *tlv)
{
struct snd_ctl_elem_id sid;
struct snd_kcontrol *kctl;
@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97)
return ac97->channel_mode >= 2;
}
static inline int is_shared_linein(struct snd_ac97 *ac97)
/* system has shared jacks with surround out enabled */
static inline int is_shared_surrout(struct snd_ac97 *ac97)
{
return ! ac97->indep_surround && is_surround_on(ac97);
return !ac97->indep_surround && is_surround_on(ac97);
}
/* system has shared jacks with center/lfe out enabled */
static inline int is_shared_clfeout(struct snd_ac97 *ac97)
{
return !ac97->indep_surround && is_clfe_on(ac97);
}
/* system has shared jacks with line in enabled */
static inline int is_shared_linein(struct snd_ac97 *ac97)
{
return !ac97->indep_surround && !is_surround_on(ac97);
}
/* system has shared jacks with mic in enabled */
static inline int is_shared_micin(struct snd_ac97 *ac97)
{
return ! ac97->indep_surround && is_clfe_on(ac97);
return !ac97->indep_surround && !is_clfe_on(ac97);
}
@ -941,6 +955,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97)
{
int err;
/* the register bit is writable, but the function is not implemented: */
snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL);
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
return err;
@ -1552,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = {
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
};
static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
static int patch_ad1885_specific(struct snd_ac97 * ac97)
{
@ -1609,19 +1626,22 @@ int patch_ad1886(struct snd_ac97 * ac97)
return 0;
}
/* MISC bits */
/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */
#define AC97_AD198X_MBC 0x0003 /* mic boost */
#define AC97_AD198X_MBC_20 0x0000 /* +20dB */
#define AC97_AD198X_MBC_10 0x0001 /* +10dB */
#define AC97_AD198X_MBC_30 0x0002 /* +30dB */
#define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */
#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */
#define AC97_AD198X_VREF_0 0x000c /* 0V */
#define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */
#define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */
#define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD)
#define AC97_AD198X_VREF_SHIFT 2
#define AC97_AD198X_SRU 0x0010 /* sample rate unlock */
#define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */
#define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */
#define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */
#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */
#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */
/* 0 = 6-to-4, 1 = 6-to-2 downmix */
#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */
#define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */
#define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */
@ -1630,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97)
#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */
#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */
/* MISC 1 bits (AD1986 register 0x76) */
#define AC97_AD1986_MBC 0x0003 /* mic boost */
#define AC97_AD1986_MBC_20 0x0000 /* +20dB */
#define AC97_AD1986_MBC_10 0x0001 /* +10dB */
#define AC97_AD1986_MBC_30 0x0002 /* +30dB */
#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */
#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */
#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)
#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */
#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */
#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */
#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */
#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */
#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */
#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */
#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */
/* 0 = 6-to-4, 1 = 6-to-2 downmix */
#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */
#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */
#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */
#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */
#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */
#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */
/* MISC 2 bits (AD1986 register 0x70) */
#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */
#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */
#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */
#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */
#define AC97_AD1986_CVREF_MASK \
(AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)
#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */
#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */
#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */
#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */
#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */
#define AC97_AD1986_MVREF_MASK \
(AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)
/* MISC 3 bits (AD1986 register 0x7a) */
#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */
#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */
#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */
#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */
#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */
#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */
#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */
#define AC97_AD1986_LVREF_MASK \
(AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)
#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */
#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */
#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */
/* input select Surround DACs */
#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */
/* select C/LFE DACs */
#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */
/* Serial Config bits (AD1986 register 0x74) (incomplete) */
#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */
#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */
#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */
#define AC97_AD1986_OMS_MASK \
(AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)
#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */
#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */
#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */
#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */
/* are MIC sources */
#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */
/* are MIC sources */
#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */
/* are MIC sources */
#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */
/* are MIC sources */
static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@ -1952,8 +2049,80 @@ int patch_ad1980(struct snd_ac97 * ac97)
return 0;
}
static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 4;
if (uinfo->value.enumerated.item > 3)
uinfo->value.enumerated.item = 3;
strcpy(uinfo->value.enumerated.name,
texts[uinfo->value.enumerated.item]);
return 0;
}
static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
static const int reg2ctrl[4] = {2, 0, 1, 3};
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK)
>> AC97_AD198X_VREF_SHIFT;
ucontrol->value.enumerated.item[0] = reg2ctrl[val];
return 0;
}
static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
static const int ctrl2reg[4] = {1, 2, 0, 3};
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
if (ucontrol->value.enumerated.item[0] > 3
|| ucontrol->value.enumerated.item[0] < 0)
return -EINVAL;
val = ctrl2reg[ucontrol->value.enumerated.item[0]]
<< AC97_AD198X_VREF_SHIFT;
return snd_ac97_update_bits(ac97, AC97_AD_MISC,
AC97_AD198X_VREF_MASK, val);
}
static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = {
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Exchange Front/Surround",
.info = snd_ac97_ad1888_lohpsel_info,
.get = snd_ac97_ad1888_lohpsel_get,
.put = snd_ac97_ad1888_lohpsel_put
},
AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
AC97_SINGLE("Spread Front to Surround and Center/LFE",
AC97_AD_MISC, 7, 1, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Downmix",
.info = snd_ac97_ad1888_downmix_info,
.get = snd_ac97_ad1888_downmix_get,
.put = snd_ac97_ad1888_downmix_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "V_REFOUT",
.info = snd_ac97_ad1985_vrefout_info,
.get = snd_ac97_ad1985_vrefout_get,
.put = snd_ac97_ad1985_vrefout_put
},
AC97_SURROUND_JACK_MODE_CTL,
AC97_CHANNEL_MODE_CTL,
AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
};
static void ad1985_update_jacks(struct snd_ac97 *ac97)
@ -1967,9 +2136,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97)
{
int err;
if ((err = patch_ad1980_specific(ac97)) < 0)
/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
snd_ac97_rename_vol_ctl(ac97, "Master Playback",
"Master Surround Playback");
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
return err;
return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls));
return patch_build_controls(ac97, snd_ac97_ad1985_controls,
ARRAY_SIZE(snd_ac97_ad1985_controls));
}
static struct snd_ac97_build_ops patch_ad1985_build_ops = {
@ -1989,24 +2165,311 @@ int patch_ad1985(struct snd_ac97 * ac97)
ac97->build_ops = &patch_ad1985_build_ops;
misc = snd_ac97_read(ac97, AC97_AD_MISC);
/* switch front/surround line-out/hp-out */
/* center/LFE, mic in 3.75V mode */
/* AD-compatible mode */
/* Stereo mutes enabled */
/* in accordance with ADI driver: misc | 0x5c28 */
snd_ac97_write_cache(ac97, AC97_AD_MISC, misc |
AC97_AD198X_VREFH |
AC97_AD198X_LOSEL |
AC97_AD198X_HPSEL |
AC97_AD198X_CLDIS |
AC97_AD198X_LODIS |
AC97_AD198X_MSPLT |
AC97_AD198X_AC97NC);
ac97->flags |= AC97_STEREO_MUTES;
/* update current jack configuration */
ad1985_update_jacks(ac97);
/* on AD1985 rev. 3, AC'97 revision bits are zero */
ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23;
return 0;
}
static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
val = ac97->regs[AC97_AD_MISC3];
ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0;
return 0;
}
static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
int ret0;
int ret1;
int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0;
ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL,
ucontrol->value.integer.value[0] != 0
? AC97_AD1986_LOSEL : 0);
if (ret0 < 0)
return ret0;
/* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
(ucontrol->value.integer.value[0] != 0
|| sprd)
? AC97_AD1986_SOSEL : 0);
if (ret1 < 0)
return ret1;
return (ret0 > 0 || ret1 > 0) ? 1 : 0;
}
static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
val = ac97->regs[AC97_AD_MISC];
ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0;
return 0;
}
static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
int ret0;
int ret1;
int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0;
ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD,
ucontrol->value.integer.value[0] != 0
? AC97_AD1986_SPRD : 0);
if (ret0 < 0)
return ret0;
/* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
(ucontrol->value.integer.value[0] != 0
|| sprd)
? AC97_AD1986_SOSEL : 0);
if (ret1 < 0)
return ret1;
return (ret0 > 0 || ret1 > 0) ? 1 : 0;
}
static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein;
return 0;
}
static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned char swap = ucontrol->value.integer.value[0] != 0;
if (swap != ac97->spec.ad18xx.swap_mic_linein) {
ac97->spec.ad18xx.swap_mic_linein = swap;
if (ac97->build_ops->update_jacks)
ac97->build_ops->update_jacks(ac97);
return 1;
}
return 0;
}
static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Use MIC_1/2 V_REFOUT as the "get" value */
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
unsigned short reg = ac97->regs[AC97_AD_MISC2];
if ((reg & AC97_AD1986_MVREF0) != 0)
val = 2;
else if ((reg & AC97_AD1986_MVREF1) != 0)
val = 3;
else if ((reg & AC97_AD1986_MVREF2) != 0)
val = 1;
else
val = 0;
ucontrol->value.enumerated.item[0] = val;
return 0;
}
static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short cval;
unsigned short lval;
unsigned short mval;
int cret;
int lret;
int mret;
switch (ucontrol->value.enumerated.item[0])
{
case 0: /* High-Z */
cval = 0;
lval = 0;
mval = 0;
break;
case 1: /* 3.7 V */
cval = AC97_AD1986_CVREF2;
lval = AC97_AD1986_LVREF2;
mval = AC97_AD1986_MVREF2;
break;
case 2: /* 2.25 V */
cval = AC97_AD1986_CVREF0;
lval = AC97_AD1986_LVREF0;
mval = AC97_AD1986_MVREF0;
break;
case 3: /* 0 V */
cval = AC97_AD1986_CVREF1;
lval = AC97_AD1986_LVREF1;
mval = AC97_AD1986_MVREF1;
break;
default:
return -EINVAL;
}
cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
AC97_AD1986_CVREF_MASK, cval);
if (cret < 0)
return cret;
lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3,
AC97_AD1986_LVREF_MASK, lval);
if (lret < 0)
return lret;
mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
AC97_AD1986_MVREF_MASK, mval);
if (mret < 0)
return mret;
return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0;
}
static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = {
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Exchange Front/Surround",
.info = snd_ac97_ad1986_bool_info,
.get = snd_ac97_ad1986_lososel_get,
.put = snd_ac97_ad1986_lososel_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Exchange Mic/Line In",
.info = snd_ac97_ad1986_bool_info,
.get = snd_ac97_ad1986_miclisel_get,
.put = snd_ac97_ad1986_miclisel_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Spread Front to Surround and Center/LFE",
.info = snd_ac97_ad1986_bool_info,
.get = snd_ac97_ad1986_spread_get,
.put = snd_ac97_ad1986_spread_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Downmix",
.info = snd_ac97_ad1888_downmix_info,
.get = snd_ac97_ad1888_downmix_get,
.put = snd_ac97_ad1888_downmix_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "V_REFOUT",
.info = snd_ac97_ad1985_vrefout_info,
.get = snd_ac97_ad1986_vrefout_get,
.put = snd_ac97_ad1986_vrefout_put
},
AC97_SURROUND_JACK_MODE_CTL,
AC97_CHANNEL_MODE_CTL,
AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0)
};
static void ad1986_update_jacks(struct snd_ac97 *ac97)
{
unsigned short misc_val = 0;
unsigned short ser_val;
/* disable SURROUND and CENTER/LFE if not surround mode */
if (! is_surround_on(ac97))
misc_val |= AC97_AD1986_SODIS;
if (! is_clfe_on(ac97))
misc_val |= AC97_AD1986_CLDIS;
/* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
if (is_shared_linein(ac97))
misc_val |= AC97_AD1986_LISEL_SURR;
else if (ac97->spec.ad18xx.swap_mic_linein != 0)
misc_val |= AC97_AD1986_LISEL_MIC;
snd_ac97_update_bits(ac97, AC97_AD_MISC,
AC97_AD1986_SODIS | AC97_AD1986_CLDIS |
AC97_AD1986_LISEL_MASK,
misc_val);
/* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */
if (is_shared_micin(ac97))
ser_val = AC97_AD1986_OMS_C;
else if (ac97->spec.ad18xx.swap_mic_linein != 0)
ser_val = AC97_AD1986_OMS_L;
else
ser_val = AC97_AD1986_OMS_M;
snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG,
AC97_AD1986_OMS_MASK,
ser_val);
}
static int patch_ad1986_specific(struct snd_ac97 *ac97)
{
int err;
if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
return err;
return patch_build_controls(ac97, snd_ac97_ad1986_controls,
ARRAY_SIZE(snd_ac97_ad1985_controls));
}
static struct snd_ac97_build_ops patch_ad1986_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1986_specific,
#ifdef CONFIG_PM
.resume = ad18xx_resume,
#endif
.update_jacks = ad1986_update_jacks,
};
int patch_ad1986(struct snd_ac97 * ac97)
{
patch_ad1881(ac97);
ac97->build_ops = &patch_ad1986_build_ops;
ac97->flags |= AC97_STEREO_MUTES;
/* update current jack configuration */
ad1986_update_jacks(ac97);
return 0;
}
/*
* realtek ALC65x/850 codecs
*/
@ -2014,12 +2477,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)
{
int shared;
/* shared Line-In */
shared = is_shared_linein(ac97);
/* shared Line-In / Surround Out */
shared = is_shared_surrout(ac97);
snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
shared ? (1 << 9) : 0);
/* update shared Mic */
shared = is_shared_micin(ac97);
/* update shared Mic In / Center/LFE Out */
shared = is_shared_clfeout(ac97);
/* disable/enable vref */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
shared ? (1 << 12) : 0);
@ -2064,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = {
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
};
static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
static int patch_alc650_specific(struct snd_ac97 * ac97)
{
@ -2149,12 +2612,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97)
{
int shared;
/* shared Line-In */
shared = is_shared_linein(ac97);
/* shared Line-In / Surround Out */
shared = is_shared_surrout(ac97);
ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
shared ? (1 << 9) : 0, 0);
/* update shared mic */
shared = is_shared_micin(ac97);
/* update shared Mic In / Center/LFE Out */
shared = is_shared_clfeout(ac97);
/* misc control; vrefout disable */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
shared ? (1 << 12) : 0);
@ -2264,7 +2727,8 @@ int patch_alc655(struct snd_ac97 * ac97)
if (ac97->subsystem_vendor == 0x1462 &&
(ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
ac97->subsystem_device == 0x0161 || /* LG K1 Express */
ac97->subsystem_device == 0x0351)) /* MSI L725 laptop */
ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */
ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
else
val |= (1 << 1); /* Pin 47 is spdif input pin */
@ -2297,16 +2761,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97)
{
int shared;
/* shared Line-In */
shared = is_shared_linein(ac97);
/* shared Line-In / Surround Out */
shared = is_shared_surrout(ac97);
/* SURR 1kOhm (bit4), Amp (bit5) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
shared ? (1<<5) : (1<<4));
/* LINE-IN = 0, SURROUND = 2 */
snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
shared ? (2<<12) : (0<<12));
/* update shared mic */
shared = is_shared_micin(ac97);
/* update shared Mic In / Center/LFE Out */
shared = is_shared_clfeout(ac97);
/* Vref disable (bit12), 1kOhm (bit13) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
shared ? (1<<12) : (1<<13));
@ -2379,9 +2843,9 @@ int patch_alc850(struct snd_ac97 *ac97)
*/
static void cm9738_update_jacks(struct snd_ac97 *ac97)
{
/* shared Line-In */
/* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
is_shared_linein(ac97) ? (1 << 10) : 0);
is_shared_surrout(ac97) ? (1 << 10) : 0);
}
static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = {
@ -2463,12 +2927,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = {
static void cm9739_update_jacks(struct snd_ac97 *ac97)
{
/* shared Line-In */
/* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
is_shared_linein(ac97) ? (1 << 10) : 0);
/* shared Mic */
is_shared_surrout(ac97) ? (1 << 10) : 0);
/* shared Mic In / Center/LFE Out **/
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
is_shared_micin(ac97) ? 0x1000 : 0x2000);
is_shared_clfeout(ac97) ? 0x1000 : 0x2000);
}
static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = {
@ -2580,8 +3044,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97)
val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)];
val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)];
val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)];
val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)];
val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)];
val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)];
snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val);
}
@ -2821,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97)
snd_ac97_write_cache(ac97, 0x5c, 0x20);
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
ac97->build_ops = &patch_vt1616_ops;
return 0;
}
@ -2828,12 +3293,12 @@ int patch_vt1617a(struct snd_ac97 * ac97)
*/
static void it2646_update_jacks(struct snd_ac97 *ac97)
{
/* shared Line-In */
/* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, 0x76, 1 << 9,
is_shared_linein(ac97) ? (1<<9) : 0);
/* shared Mic */
is_shared_surrout(ac97) ? (1<<9) : 0);
/* shared Mic / Center/LFE Out */
snd_ac97_update_bits(ac97, 0x76, 1 << 10,
is_shared_micin(ac97) ? (1<<10) : 0);
is_shared_clfeout(ac97) ? (1<<10) : 0);
}
static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = {

View file

@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97);
int patch_ad1981a(struct snd_ac97 * ac97);
int patch_ad1981b(struct snd_ac97 * ac97);
int patch_ad1985(struct snd_ac97 * ac97);
int patch_ad1986(struct snd_ac97 * ac97);
int patch_alc650(struct snd_ac97 * ac97);
int patch_alc655(struct snd_ac97 * ac97);
int patch_alc850(struct snd_ac97 * ac97);

View file

@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
return change;
}
static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
static struct snd_kcontrol_new snd_ak4531_controls[] = {

View file

@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream)
}
static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream,
snd_pcm_hw_params_t * hw_params)
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip)
snd_als300_dbgcallleave();
}
static int __devinit snd_als300_create(snd_card_t *card,
static int __devinit snd_als300_create(struct snd_card *card,
struct pci_dev *pci, int chip_type,
struct snd_als300 **rchip)
{
@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card,
void *irq_handler;
int err;
static snd_device_ops_t ops = {
static struct snd_device_ops ops = {
.dev_free = snd_als300_dev_free,
};
*rchip = NULL;

View file

@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static int ac97_clock = 48000;
static char *ac97_quirk;
static int spdif_aclink = 1;
static int ac97_codec = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444);
MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
module_param(ac97_quirk, charp, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
module_param(ac97_codec, int, 0444);
MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing.");
module_param(spdif_aclink, bool, 0444);
MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
@ -293,6 +296,10 @@ static struct pci_device_id snd_atiixp_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
static struct snd_pci_quirk atiixp_quirks[] __devinitdata = {
SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0),
{ } /* terminator */
};
/*
* lowlevel functions
@ -553,11 +560,33 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
ATI_REG_ISR_CODEC2_NOT_READY)
#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
static int ac97_probing_bugs(struct pci_dev *pci)
{
const struct snd_pci_quirk *q;
q = snd_pci_quirk_lookup(pci, atiixp_quirks);
if (q) {
snd_printdd(KERN_INFO "Atiixp quirk for %s. "
"Forcing codec %d\n", q->name, q->value);
return q->value;
}
/* this hardware doesn't need workarounds. Probe for codec */
return -1;
}
static int snd_atiixp_codec_detect(struct atiixp *chip)
{
int timeout;
chip->codec_not_ready_bits = 0;
if (ac97_codec == -1)
ac97_codec = ac97_probing_bugs(chip->pci);
if (ac97_codec >= 0) {
chip->codec_not_ready_bits |=
CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10));
return 0;
}
atiixp_write(chip, IER, CODEC_CHECK_BITS);
/* wait for the interrupts */
timeout = 50;
@ -1396,7 +1425,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
ac97.private_data = chip;
ac97.pci = chip->pci;
ac97.num = i;
ac97.scaps = AC97_SCAP_SKIP_MODEM;
ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if (! chip->spdif_over_aclink)
ac97.scaps |= AC97_SCAP_NO_SPDIF;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {

View file

@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
ac97.private_data = chip;
ac97.pci = chip->pci;
ac97.num = i;
ac97.scaps = AC97_SCAP_SKIP_AUDIO;
ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
chip->ac97[i] = NULL; /* to be sure */
snd_printdd("atiixp-modem: codec %d not available for modem\n", i);

View file

@ -1382,7 +1382,6 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
chip->spdif_enable = 0; /* Set digital SPDIF output off */
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */
@ -1402,8 +1401,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */
}
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
if (chip->details->i2c_adc == 1) {
/* Select MIC, Line in, TAD in, AUX in */
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
/* Default to CAPTURE_SOURCE to i2s in */
chip->capture_source = 3;
} else if (chip->details->ac97 == 1) {
/* Default to AC97 in */
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
/* Default to CAPTURE_SOURCE to AC97 in */
chip->capture_source = 4;
} else {
/* Select MIC, Line in, TAD in, AUX in */
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
/* Default to Set CAPTURE_SOURCE to i2s in */
chip->capture_source = 3;
}
if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
@ -1605,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
snd_ca0106_proc_init(chip);
#endif
snd_card_set_dev(card, &pci->dev);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;

View file

@ -74,8 +74,8 @@
#include "ca0106.h"
static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
.private_value = ((chid) << 8) | (reg) \
}
#define I2C_VOLUME(xname,chid) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
.info = snd_ca0106_i2c_volume_info, \
.get = snd_ca0106_i2c_volume_get, \
.put = snd_ca0106_i2c_volume_put, \
.tlv = { .p = snd_ca0106_db_scale2 }, \
.private_value = chid \
}
static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("Analog Front Playback Volume",
CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("CAPTURE feedback Playback Volume",
1, CAPTURE_CONTROL),
I2C_VOLUME("Phone Capture Volume", 0),
I2C_VOLUME("Mic Capture Volume", 1),
I2C_VOLUME("Line in Capture Volume", 2),
I2C_VOLUME("Aux Capture Volume", 3),
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@ -539,14 +521,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Capture Source",
.name = "Digital Source Capture Enum",
.info = snd_ca0106_capture_source_info,
.get = snd_ca0106_capture_source_get,
.put = snd_ca0106_capture_source_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.name = "Analog Source Capture Enum",
.info = snd_ca0106_i2c_capture_source_info,
.get = snd_ca0106_i2c_capture_source_get,
.put = snd_ca0106_i2c_capture_source_put
@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
};
#define I2C_VOLUME(xname,chid) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
.info = snd_ca0106_i2c_volume_info, \
.get = snd_ca0106_i2c_volume_get, \
.put = snd_ca0106_i2c_volume_put, \
.tlv = { .p = snd_ca0106_db_scale2 }, \
.private_value = chid \
}
static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
I2C_VOLUME("Phone Capture Volume", 0),
I2C_VOLUME("Mic Capture Volume", 1),
I2C_VOLUME("Line in Capture Volume", 2),
I2C_VOLUME("Aux Capture Volume", 3),
};
static int __devinit remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
return err;
}
if (emu->details->i2c_adc == 1) {
for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
if (err < 0)
return err;
}
if (emu->details->gpio_type == 1)
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
else /* gpio_type == 2 */

View file

@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
return change;
}
static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
static struct snd_kcontrol_new snd_cs4281_fm_vol =
{

View file

@ -47,6 +47,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>

View file

@ -51,6 +51,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>

View file

@ -58,6 +58,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>

View file

@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on);
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
char force);
#include <linux/irq.h>
#include <linux/interrupt.h>
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{

View file

@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
static int get_firmware(const struct firmware **fw_entry,
const struct firmware *frm, struct echoaudio *chip)
@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
.name = "Line Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_output_gain_info,
.get = snd_echo_output_gain_get,
.put = snd_echo_output_gain_put,
.tlv = {.p = db_scale_output_gain},
};
#else
static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
.name = "PCM Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_output_gain_info,
.get = snd_echo_output_gain_get,
.put = snd_echo_output_gain_put,
.tlv = {.p = db_scale_output_gain},
};
#endif
@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
return changed;
}
static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
.name = "Line Capture Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_input_gain_info,
.get = snd_echo_input_gain_get,
.put = snd_echo_input_gain_put,
.tlv = {.p = db_scale_input_gain},
};
#endif /* ECHOCARD_HAS_INPUT_GAIN */
@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
.name = "Monitor Mixer Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_mixer_info,
.get = snd_echo_mixer_get,
.put = snd_echo_mixer_put,
.tlv = {.p = db_scale_output_gain},
};
#endif /* ECHOCARD_HAS_MONITOR */
@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
.name = "VMixer Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_vmixer_info,
.get = snd_echo_vmixer_get,
.put = snd_echo_vmixer_put,
.tlv = {.p = db_scale_output_gain},
};
#endif /* ECHOCARD_HAS_VMIXER */
@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
.name = "VU-meters",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.access = SNDRV_CTL_ELEM_ACCESS_READ |
SNDRV_CTL_ELEM_ACCESS_VOLATILE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_vumeters_info,
.get = snd_echo_vumeters_get,
.tlv = {.p = db_scale_output_gain},
};

Some files were not shown because too many files have changed in this diff Show more