Commit 60261795 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents d27146dd c2902c8a
......@@ -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)
---------------------------------
......
......@@ -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>
......
......@@ -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
......
......@@ -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
......
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.
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.
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;
}
This diff is collapsed.
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.
\ No newline at end of file
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.
\ No newline at end of file
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.
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.
......@@ -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
......
......@@ -83,7 +83,7 @@
struct ucb1400 {
ac97_t *ac97;
struct snd_ac97 *ac97;
struct input_dev *ts_idev;
int irq;
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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) \
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
};
......
......@@ -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);
......
......@@ -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 */
This diff is collapsed.
......@@ -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
......
/*
* 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 */
......@@ -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);
......
......@@ -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 {
......
This diff is collapsed.
This diff is collapsed.
/*
* 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;
/* 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)"
......@@ -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 */
......
......@@ -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;
......
......@@ -76,6 +76,8 @@ source "sound/sparc/Kconfig"
source "sound/parisc/Kconfig"
source "sound/soc/Kconfig"
endmenu
menu "Open Sound System"
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
......@@ -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));
......
......@@ -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;
......
......@@ -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 */
......@@ -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;
......
......@@ -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)
......
......@@ -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;
......
This diff is collapsed.
......@@ -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);
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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 */
......
......@@ -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",
......
......@@ -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
......@@ -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)
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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;
}
}
/*
......
......@@ -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),
......
......@@ -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);
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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
......
This diff is collapsed.
......@@ -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
......@@ -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/
......@@ -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, \
......
This diff is collapsed.
This diff is collapsed.
......@@ -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,
......
......@@ -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
......@@ -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
......@@ -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);
......
......@@ -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;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -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),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment