Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (212 commits) [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED [ALSA] version 1.0.14rc2 [ALSA] ASoC documentation updates [ALSA] ca0106 - Add missing sysfs device assignment [ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully [ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880 [ALSA] aoa: remove suspend/resume printks [ALSA] Fix possible deadlocks in sequencer at removal of ports [ALSA] emu10k1 - Fix STAC9758 front channel [ALSA] soc - Clean up with kmemdup() [ALSA] snd-ak4114: Fix two array overflows [ALSA] ac97_bus power management [ALSA] usbaudio - Add support for Edirol UA-101 [ALSA] hda-codec - Add ALC861VD/ALC660VD support [ALSA] soc - ASoC 0.13 Sharp poodle machine [ALSA] soc - ASoC 0.13 Sharp tosa machine [ALSA] soc - ASoC 0.13 spitz machine [ALSA] soc - ASoC Sharp corgi machine [ALSA] soc - ASoC 0.13 pxa2xx DMA [ALSA] soc - ASoC 0.13 pxa2xx AC97 driver ...
This commit is contained in:
commit
6026179519
216 changed files with 28235 additions and 3791 deletions
|
@ -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->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->private_data. The
|
||||
kcontrol->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
|
||||
|
|
56
Documentation/sound/alsa/soc/DAI.txt
Normal file
56
Documentation/sound/alsa/soc/DAI.txt
Normal file
|
@ -0,0 +1,56 @@
|
|||
ASoC currently supports the three main Digital Audio Interfaces (DAI) found on
|
||||
SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM.
|
||||
|
||||
|
||||
AC97
|
||||
====
|
||||
|
||||
AC97 is a five wire interface commonly found on many PC sound cards. It is
|
||||
now also popular in many portable devices. This DAI has a reset line and time
|
||||
multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
|
||||
The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
|
||||
frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
|
||||
frame is 21uS long and is divided into 13 time slots.
|
||||
|
||||
The AC97 specification can be found at :-
|
||||
http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
|
||||
|
||||
|
||||
I2S
|
||||
===
|
||||
|
||||
I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and
|
||||
Rx lines are used for audio transmision, whilst the bit clock (BCLK) and
|
||||
left/right clock (LRC) synchronise the link. I2S is flexible in that either the
|
||||
controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
|
||||
usually varies depending on the sample rate and the master system clock
|
||||
(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
|
||||
ADC and DAC LRCLK's, this allows for similtanious capture and playback at
|
||||
different sample rates.
|
||||
|
||||
I2S has several different operating modes:-
|
||||
|
||||
o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC
|
||||
transition.
|
||||
|
||||
o Left Justified - MSB is transmitted on transition of LRC.
|
||||
|
||||
o Right Justified - MSB is transmitted sample size BCLK's before LRC
|
||||
transition.
|
||||
|
||||
PCM
|
||||
===
|
||||
|
||||
PCM is another 4 wire interface, very similar to I2S, that can support a more
|
||||
flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used
|
||||
to synchronise the link whilst the Tx and Rx lines are used to transmit and
|
||||
receive the audio data. Bit clock usually varies depending on sample rate
|
||||
whilst sync runs at the sample rate. PCM also supports Time Division
|
||||
Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This
|
||||
is sometimes referred to as network mode).
|
||||
|
||||
Common PCM operating modes:-
|
||||
|
||||
o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC.
|
||||
|
||||
o Mode B - MSB is transmitted on rising edge of FRAME/SYNC.
|
51
Documentation/sound/alsa/soc/clocking.txt
Normal file
51
Documentation/sound/alsa/soc/clocking.txt
Normal file
|
@ -0,0 +1,51 @@
|
|||
Audio Clocking
|
||||
==============
|
||||
|
||||
This text describes the audio clocking terms in ASoC and digital audio in
|
||||
general. Note: Audio clocking can be complex !
|
||||
|
||||
|
||||
Master Clock
|
||||
------------
|
||||
|
||||
Every audio subsystem is driven by a master clock (sometimes refered to as MCLK
|
||||
or SYSCLK). This audio master clock can be derived from a number of sources
|
||||
(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct
|
||||
audio playback and capture sample rates.
|
||||
|
||||
Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that
|
||||
their speed can be altered by software (depending on the system use and to save
|
||||
power). Other master clocks are fixed at at set frequency (i.e. crystals).
|
||||
|
||||
|
||||
DAI Clocks
|
||||
----------
|
||||
The Digital Audio Interface is usually driven by a Bit Clock (often referred to
|
||||
as BCLK). This clock is used to drive the digital audio data across the link
|
||||
between the codec and CPU.
|
||||
|
||||
The DAI also has a frame clock to signal the start of each audio frame. This
|
||||
clock is sometimes referred to as LRC (left right clock) or FRAME. This clock
|
||||
runs at exactly the sample rate (LRC = Rate).
|
||||
|
||||
Bit Clock can be generated as follows:-
|
||||
|
||||
BCLK = MCLK / x
|
||||
|
||||
or
|
||||
|
||||
BCLK = LRC * x
|
||||
|
||||
or
|
||||
|
||||
BCLK = LRC * Channels * Word Size
|
||||
|
||||
This relationship depends on the codec or SoC CPU in particular. In general
|
||||
it's best to configure BCLK to the lowest possible speed (depending on your
|
||||
rate, number of channels and wordsize) to save on power.
|
||||
|
||||
It's also desireable to use the codec (if possible) to drive (or master) the
|
||||
audio clocks as it's usually gives more accurate sample rates than the CPU.
|
||||
|
||||
|
||||
|
197
Documentation/sound/alsa/soc/codec.txt
Normal file
197
Documentation/sound/alsa/soc/codec.txt
Normal file
|
@ -0,0 +1,197 @@
|
|||
ASoC Codec Driver
|
||||
=================
|
||||
|
||||
The codec driver is generic and hardware independent code that configures the
|
||||
codec to provide audio capture and playback. It should contain no code that is
|
||||
specific to the target platform or machine. All platform and machine specific
|
||||
code should be added to the platform and machine drivers respectively.
|
||||
|
||||
Each codec driver *must* provide the following features:-
|
||||
|
||||
1) Codec DAI and PCM configuration
|
||||
2) Codec control IO - using I2C, 3 Wire(SPI) or both API's
|
||||
3) Mixers and audio controls
|
||||
4) Codec audio operations
|
||||
|
||||
Optionally, codec drivers can also provide:-
|
||||
|
||||
5) DAPM description.
|
||||
6) DAPM event handler.
|
||||
7) DAC Digital mute control.
|
||||
|
||||
It's probably best to use this guide in conjuction with the existing codec
|
||||
driver code in sound/soc/codecs/
|
||||
|
||||
ASoC Codec driver breakdown
|
||||
===========================
|
||||
|
||||
1 - Codec DAI and PCM configuration
|
||||
-----------------------------------
|
||||
Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and
|
||||
PCM's capablities and operations. This struct is exported so that it can be
|
||||
registered with the core by your machine driver.
|
||||
|
||||
e.g.
|
||||
|
||||
struct snd_soc_codec_dai wm8731_dai = {
|
||||
.name = "WM8731",
|
||||
/* playback capabilities */
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = WM8731_RATES,
|
||||
.formats = WM8731_FORMATS,},
|
||||
/* capture capabilities */
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = WM8731_RATES,
|
||||
.formats = WM8731_FORMATS,},
|
||||
/* pcm operations - see section 4 below */
|
||||
.ops = {
|
||||
.prepare = wm8731_pcm_prepare,
|
||||
.hw_params = wm8731_hw_params,
|
||||
.shutdown = wm8731_shutdown,
|
||||
},
|
||||
/* DAI operations - see DAI.txt */
|
||||
.dai_ops = {
|
||||
.digital_mute = wm8731_mute,
|
||||
.set_sysclk = wm8731_set_dai_sysclk,
|
||||
.set_fmt = wm8731_set_dai_fmt,
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm8731_dai);
|
||||
|
||||
|
||||
2 - Codec control IO
|
||||
--------------------
|
||||
The codec can ususally be controlled via an I2C or SPI style interface (AC97
|
||||
combines control with data in the DAI). The codec drivers will have to provide
|
||||
functions to read and write the codec registers along with supplying a register
|
||||
cache:-
|
||||
|
||||
/* IO control data and register cache */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
void *reg_cache;
|
||||
|
||||
Codec read/write should do any data formatting and call the hardware read write
|
||||
below to perform the IO. These functions are called by the core and alsa when
|
||||
performing DAPM or changing the mixer:-
|
||||
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
|
||||
Codec hardware IO functions - usually points to either the I2C, SPI or AC97
|
||||
read/write:-
|
||||
|
||||
hw_write_t hw_write;
|
||||
hw_read_t hw_read;
|
||||
|
||||
|
||||
3 - Mixers and audio controls
|
||||
-----------------------------
|
||||
All the codec mixers and audio controls can be defined using the convenience
|
||||
macros defined in soc.h.
|
||||
|
||||
#define SOC_SINGLE(xname, reg, shift, mask, invert)
|
||||
|
||||
Defines a single control as follows:-
|
||||
|
||||
xname = Control name e.g. "Playback Volume"
|
||||
reg = codec register
|
||||
shift = control bit(s) offset in register
|
||||
mask = control bit size(s) e.g. mask of 7 = 3 bits
|
||||
invert = the control is inverted
|
||||
|
||||
Other macros include:-
|
||||
|
||||
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert)
|
||||
|
||||
A stereo control
|
||||
|
||||
#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert)
|
||||
|
||||
A stereo control spanning 2 registers
|
||||
|
||||
#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)
|
||||
|
||||
Defines an single enumerated control as follows:-
|
||||
|
||||
xreg = register
|
||||
xshift = control bit(s) offset in register
|
||||
xmask = control bit(s) size
|
||||
xtexts = pointer to array of strings that describe each setting
|
||||
|
||||
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)
|
||||
|
||||
Defines a stereo enumerated control
|
||||
|
||||
|
||||
4 - Codec Audio Operations
|
||||
--------------------------
|
||||
The codec driver also supports the following alsa operations:-
|
||||
|
||||
/* SoC audio ops */
|
||||
struct snd_soc_ops {
|
||||
int (*startup)(struct snd_pcm_substream *);
|
||||
void (*shutdown)(struct snd_pcm_substream *);
|
||||
int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
|
||||
int (*hw_free)(struct snd_pcm_substream *);
|
||||
int (*prepare)(struct snd_pcm_substream *);
|
||||
};
|
||||
|
||||
Please refer to the alsa driver PCM documentation for details.
|
||||
http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
|
||||
|
||||
|
||||
5 - DAPM description.
|
||||
---------------------
|
||||
The Dynamic Audio Power Management description describes the codec's power
|
||||
components, their relationships and registers to the ASoC core. Please read
|
||||
dapm.txt for details of building the description.
|
||||
|
||||
Please also see the examples in other codec drivers.
|
||||
|
||||
|
||||
6 - DAPM event handler
|
||||
----------------------
|
||||
This function is a callback that handles codec domain PM calls and system
|
||||
domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep
|
||||
when not in use.
|
||||
|
||||
Power states:-
|
||||
|
||||
SNDRV_CTL_POWER_D0: /* full On */
|
||||
/* vref/mid, clk and osc on, active */
|
||||
|
||||
SNDRV_CTL_POWER_D1: /* partial On */
|
||||
SNDRV_CTL_POWER_D2: /* partial On */
|
||||
|
||||
SNDRV_CTL_POWER_D3hot: /* Off, with power */
|
||||
/* everything off except vref/vmid, inactive */
|
||||
|
||||
SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */
|
||||
|
||||
|
||||
7 - Codec DAC digital mute control.
|
||||
------------------------------------
|
||||
Most codecs have a digital mute before the DAC's that can be used to minimise
|
||||
any system noise. The mute stops any digital data from entering the DAC.
|
||||
|
||||
A callback can be created that is called by the core for each codec DAI when the
|
||||
mute is applied or freed.
|
||||
|
||||
i.e.
|
||||
|
||||
static int wm8974_mute(struct snd_soc_codec *codec,
|
||||
struct snd_soc_codec_dai *dai, int mute)
|
||||
{
|
||||
u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
|
||||
if(mute)
|
||||
wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
|
||||
else
|
||||
wm8974_write(codec, WM8974_DAC, mute_reg);
|
||||
return 0;
|
||||
}
|
297
Documentation/sound/alsa/soc/dapm.txt
Normal file
297
Documentation/sound/alsa/soc/dapm.txt
Normal file
|
@ -0,0 +1,297 @@
|
|||
Dynamic Audio Power Management for Portable Devices
|
||||
===================================================
|
||||
|
||||
1. Description
|
||||
==============
|
||||
|
||||
Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices
|
||||
to use the minimum amount of power within the audio subsystem at all times. It
|
||||
is independent of other kernel PM and as such, can easily co-exist with the
|
||||
other PM systems.
|
||||
|
||||
DAPM is also completely transparent to all user space applications as all power
|
||||
switching is done within the ASoC core. No code changes or recompiling are
|
||||
required for user space applications. DAPM makes power switching descisions based
|
||||
upon any audio stream (capture/playback) activity and audio mixer settings
|
||||
within the device.
|
||||
|
||||
DAPM spans the whole machine. It covers power control within the entire audio
|
||||
subsystem, this includes internal codec power blocks and machine level power
|
||||
systems.
|
||||
|
||||
There are 4 power domains within DAPM
|
||||
|
||||
1. Codec domain - VREF, VMID (core codec and audio power)
|
||||
Usually controlled at codec probe/remove and suspend/resume, although
|
||||
can be set at stream time if power is not needed for sidetone, etc.
|
||||
|
||||
2. Platform/Machine domain - physically connected inputs and outputs
|
||||
Is platform/machine and user action specific, is configured by the
|
||||
machine driver and responds to asynchronous events e.g when HP
|
||||
are inserted
|
||||
|
||||
3. Path domain - audio susbsystem signal paths
|
||||
Automatically set when mixer and mux settings are changed by the user.
|
||||
e.g. alsamixer, amixer.
|
||||
|
||||
4. Stream domain - DAC's and ADC's.
|
||||
Enabled and disabled when stream playback/capture is started and
|
||||
stopped respectively. e.g. aplay, arecord.
|
||||
|
||||
All DAPM power switching descisons are made automatically by consulting an audio
|
||||
routing map of the whole machine. This map is specific to each machine and
|
||||
consists of the interconnections between every audio component (including
|
||||
internal codec components). All audio components that effect power are called
|
||||
widgets hereafter.
|
||||
|
||||
|
||||
2. DAPM Widgets
|
||||
===============
|
||||
|
||||
Audio DAPM widgets fall into a number of types:-
|
||||
|
||||
o Mixer - Mixes several analog signals into a single analog signal.
|
||||
o Mux - An analog switch that outputs only 1 of it's inputs.
|
||||
o PGA - A programmable gain amplifier or attenuation widget.
|
||||
o ADC - Analog to Digital Converter
|
||||
o DAC - Digital to Analog Converter
|
||||
o Switch - An analog switch
|
||||
o Input - A codec input pin
|
||||
o Output - A codec output pin
|
||||
o Headphone - Headphone (and optional Jack)
|
||||
o Mic - Mic (and optional Jack)
|
||||
o Line - Line Input/Output (and optional Jack)
|
||||
o Speaker - Speaker
|
||||
o Pre - Special PRE widget (exec before all others)
|
||||
o Post - Special POST widget (exec after all others)
|
||||
|
||||
(Widgets are defined in include/sound/soc-dapm.h)
|
||||
|
||||
Widgets are usually added in the codec driver and the machine driver. There are
|
||||
convience macros defined in soc-dapm.h that can be used to quickly build a
|
||||
list of widgets of the codecs and machines DAPM widgets.
|
||||
|
||||
Most widgets have a name, register, shift and invert. Some widgets have extra
|
||||
parameters for stream name and kcontrols.
|
||||
|
||||
|
||||
2.1 Stream Domain Widgets
|
||||
-------------------------
|
||||
|
||||
Stream Widgets relate to the stream power domain and only consist of ADC's
|
||||
(analog to digital converters) and DAC's (digital to analog converters).
|
||||
|
||||
Stream widgets have the following format:-
|
||||
|
||||
SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
|
||||
|
||||
NOTE: the stream name must match the corresponding stream name in your codecs
|
||||
snd_soc_codec_dai.
|
||||
|
||||
e.g. stream widgets for HiFi playback and capture
|
||||
|
||||
SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
|
||||
SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
|
||||
|
||||
|
||||
2.2 Path Domain Widgets
|
||||
-----------------------
|
||||
|
||||
Path domain widgets have a ability to control or effect the audio signal or
|
||||
audio paths within the audio subsystem. They have the following form:-
|
||||
|
||||
SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
|
||||
|
||||
Any widget kcontrols can be set using the controls and num_controls members.
|
||||
|
||||
e.g. Mixer widget (the kcontrols are declared first)
|
||||
|
||||
/* Output Mixer */
|
||||
static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
|
||||
};
|
||||
|
||||
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,
|
||||
ARRAY_SIZE(wm8731_output_mixer_controls)),
|
||||
|
||||
|
||||
2.3 Platform/Machine domain Widgets
|
||||
-----------------------------------
|
||||
|
||||
Machine widgets are different from codec widgets in that they don't have a
|
||||
codec register bit associated with them. A machine widget is assigned to each
|
||||
machine audio component (non codec) that can be independently powered. e.g.
|
||||
|
||||
o Speaker Amp
|
||||
o Microphone Bias
|
||||
o Jack connectors
|
||||
|
||||
A machine widget can have an optional call back.
|
||||
|
||||
e.g. Jack connector widget for an external Mic that enables Mic Bias
|
||||
when the Mic is inserted:-
|
||||
|
||||
static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
|
||||
{
|
||||
if(SND_SOC_DAPM_EVENT_ON(event))
|
||||
set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
|
||||
else
|
||||
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
|
||||
|
||||
|
||||
2.4 Codec Domain
|
||||
----------------
|
||||
|
||||
The Codec power domain has no widgets and is handled by the codecs DAPM event
|
||||
handler. This handler is called when the codec powerstate is changed wrt to any
|
||||
stream event or by kernel PM events.
|
||||
|
||||
|
||||
2.5 Virtual Widgets
|
||||
-------------------
|
||||
|
||||
Sometimes widgets exist in the codec or machine audio map that don't have any
|
||||
corresponding register bit for power control. In this case it's necessary to
|
||||
create a virtual widget - a widget with no control bits e.g.
|
||||
|
||||
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
This can be used to merge to signal paths together in software.
|
||||
|
||||
After all the widgets have been defined, they can then be added to the DAPM
|
||||
subsystem individually with a call to snd_soc_dapm_new_control().
|
||||
|
||||
|
||||
3. Codec Widget Interconnections
|
||||
================================
|
||||
|
||||
Widgets are connected to each other within the codec and machine by audio
|
||||
paths (called interconnections). Each interconnection must be defined in order
|
||||
to create a map of all audio paths between widgets.
|
||||
This is easiest with a diagram of the codec (and schematic of the machine audio
|
||||
system), as it requires joining widgets together via their audio signal paths.
|
||||
|
||||
i.e. from the WM8731 codec's output mixer (wm8731.c)
|
||||
|
||||
The WM8731 output mixer has 3 inputs (sources)
|
||||
|
||||
1. Line Bypass Input
|
||||
2. DAC (HiFi playback)
|
||||
3. Mic Sidetone Input
|
||||
|
||||
Each input in this example has a kcontrol associated with it (defined in example
|
||||
above) and is connected to the output mixer via it's kcontrol name. We can now
|
||||
connect the destination widget (wrt audio signal) with it's source widgets.
|
||||
|
||||
/* output mixer */
|
||||
{"Output Mixer", "Line Bypass Switch", "Line Input"},
|
||||
{"Output Mixer", "HiFi Playback Switch", "DAC"},
|
||||
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
|
||||
|
||||
So we have :-
|
||||
|
||||
Destination Widget <=== Path Name <=== Source Widget
|
||||
|
||||
Or:-
|
||||
|
||||
Sink, Path, Source
|
||||
|
||||
Or :-
|
||||
|
||||
"Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch".
|
||||
|
||||
When there is no path name connecting widgets (e.g. a direct connection) we
|
||||
pass NULL for the path name.
|
||||
|
||||
Interconnections are created with a call to:-
|
||||
|
||||
snd_soc_dapm_connect_input(codec, sink, path, source);
|
||||
|
||||
Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and
|
||||
interconnections have been registered with the core. This causes the core to
|
||||
scan the codec and machine so that the internal DAPM state matches the
|
||||
physical state of the machine.
|
||||
|
||||
|
||||
3.1 Machine Widget Interconnections
|
||||
-----------------------------------
|
||||
Machine widget interconnections are created in the same way as codec ones and
|
||||
directly connect the codec pins to machine level widgets.
|
||||
|
||||
e.g. connects the speaker out codec pins to the internal speaker.
|
||||
|
||||
/* ext speaker connected to codec pins LOUT2, ROUT2 */
|
||||
{"Ext Spk", NULL , "ROUT2"},
|
||||
{"Ext Spk", NULL , "LOUT2"},
|
||||
|
||||
This allows the DAPM to power on and off pins that are connected (and in use)
|
||||
and pins that are NC respectively.
|
||||
|
||||
|
||||
4 Endpoint Widgets
|
||||
===================
|
||||
An endpoint is a start or end point (widget) of an audio signal within the
|
||||
machine and includes the codec. e.g.
|
||||
|
||||
o Headphone Jack
|
||||
o Internal Speaker
|
||||
o Internal Mic
|
||||
o Mic Jack
|
||||
o Codec Pins
|
||||
|
||||
When a codec pin is NC it can be marked as not used with a call to
|
||||
|
||||
snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
|
||||
|
||||
The last argument is 0 for inactive and 1 for active. This way the pin and its
|
||||
input widget will never be powered up and consume power.
|
||||
|
||||
This also applies to machine widgets. e.g. if a headphone is connected to a
|
||||
jack then the jack can be marked active. If the headphone is removed, then
|
||||
the headphone jack can be marked inactive.
|
||||
|
||||
|
||||
5 DAPM Widget Events
|
||||
====================
|
||||
|
||||
Some widgets can register their interest with the DAPM core in PM events.
|
||||
e.g. A Speaker with an amplifier registers a widget so the amplifier can be
|
||||
powered only when the spk is in use.
|
||||
|
||||
/* turn speaker amplifier on/off depending on use */
|
||||
static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
|
||||
{
|
||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
||||
set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
|
||||
else
|
||||
reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* corgi machine dapm widgets */
|
||||
static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
|
||||
SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
|
||||
|
||||
Please see soc-dapm.h for all other widgets that support events.
|
||||
|
||||
|
||||
5.1 Event types
|
||||
---------------
|
||||
|
||||
The following event types are supported by event widgets.
|
||||
|
||||
/* dapm event types */
|
||||
#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
|
||||
#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
|
||||
#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
|
||||
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
|
||||
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
|
||||
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
|
113
Documentation/sound/alsa/soc/machine.txt
Normal file
113
Documentation/sound/alsa/soc/machine.txt
Normal file
|
@ -0,0 +1,113 @@
|
|||
ASoC Machine Driver
|
||||
===================
|
||||
|
||||
The ASoC machine (or board) driver is the code that glues together the platform
|
||||
and codec drivers.
|
||||
|
||||
The machine driver can contain codec and platform specific code. It registers
|
||||
the audio subsystem with the kernel as a platform device and is represented by
|
||||
the following struct:-
|
||||
|
||||
/* SoC machine */
|
||||
struct snd_soc_machine {
|
||||
char *name;
|
||||
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
|
||||
/* the pre and post PM functions are used to do any PM work before and
|
||||
* after the codec and DAI's do any PM work. */
|
||||
int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
|
||||
int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
|
||||
int (*resume_pre)(struct platform_device *pdev);
|
||||
int (*resume_post)(struct platform_device *pdev);
|
||||
|
||||
/* machine stream operations */
|
||||
struct snd_soc_ops *ops;
|
||||
|
||||
/* CPU <--> Codec DAI links */
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int num_links;
|
||||
};
|
||||
|
||||
probe()/remove()
|
||||
----------------
|
||||
probe/remove are optional. Do any machine specific probe here.
|
||||
|
||||
|
||||
suspend()/resume()
|
||||
------------------
|
||||
The machine driver has pre and post versions of suspend and resume to take care
|
||||
of any machine audio tasks that have to be done before or after the codec, DAI's
|
||||
and DMA is suspended and resumed. Optional.
|
||||
|
||||
|
||||
Machine operations
|
||||
------------------
|
||||
The machine specific audio operations can be set here. Again this is optional.
|
||||
|
||||
|
||||
Machine DAI Configuration
|
||||
-------------------------
|
||||
The machine DAI configuration glues all the codec and CPU DAI's together. It can
|
||||
also be used to set up the DAI system clock and for any machine related DAI
|
||||
initialisation e.g. the machine audio map can be connected to the codec audio
|
||||
map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c
|
||||
for examples.
|
||||
|
||||
struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
|
||||
|
||||
/* corgi digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link corgi_dai = {
|
||||
.name = "WM8731",
|
||||
.stream_name = "WM8731",
|
||||
.cpu_dai = &pxa_i2s_dai,
|
||||
.codec_dai = &wm8731_dai,
|
||||
.init = corgi_wm8731_init,
|
||||
.ops = &corgi_ops,
|
||||
};
|
||||
|
||||
struct snd_soc_machine then sets up the machine with it's DAI's. e.g.
|
||||
|
||||
/* corgi audio machine driver */
|
||||
static struct snd_soc_machine snd_soc_machine_corgi = {
|
||||
.name = "Corgi",
|
||||
.dai_link = &corgi_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
|
||||
Machine Audio Subsystem
|
||||
-----------------------
|
||||
|
||||
The machine soc device glues the platform, machine and codec driver together.
|
||||
Private data can also be set here. e.g.
|
||||
|
||||
/* corgi audio private data */
|
||||
static struct wm8731_setup_data corgi_wm8731_setup = {
|
||||
.i2c_address = 0x1b,
|
||||
};
|
||||
|
||||
/* corgi audio subsystem */
|
||||
static struct snd_soc_device corgi_snd_devdata = {
|
||||
.machine = &snd_soc_machine_corgi,
|
||||
.platform = &pxa2xx_soc_platform,
|
||||
.codec_dev = &soc_codec_dev_wm8731,
|
||||
.codec_data = &corgi_wm8731_setup,
|
||||
};
|
||||
|
||||
|
||||
Machine Power Map
|
||||
-----------------
|
||||
|
||||
The machine driver can optionally extend the codec power map and to become an
|
||||
audio power map of the audio subsystem. This allows for automatic power up/down
|
||||
of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack
|
||||
sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for
|
||||
details.
|
||||
|
||||
|
||||
Machine Controls
|
||||
----------------
|
||||
|
||||
Machine specific audio mixer controls can be added in the dai init function.
|
83
Documentation/sound/alsa/soc/overview.txt
Normal file
83
Documentation/sound/alsa/soc/overview.txt
Normal file
|
@ -0,0 +1,83 @@
|
|||
ALSA SoC Layer
|
||||
==============
|
||||
|
||||
The overall project goal of the ALSA System on Chip (ASoC) layer is to provide
|
||||
better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00,
|
||||
iMX, etc) and portable audio codecs. Currently there is some support in the
|
||||
kernel for SoC audio, however it has some limitations:-
|
||||
|
||||
* Currently, codec drivers are often tightly coupled to the underlying SoC
|
||||
cpu. This is not ideal and leads to code duplication i.e. Linux now has 4
|
||||
different wm8731 drivers for 4 different SoC platforms.
|
||||
|
||||
* There is no standard method to signal user initiated audio events.
|
||||
e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion
|
||||
event. These are quite common events on portable devices and ofter require
|
||||
machine specific code to re route audio, enable amps etc after such an event.
|
||||
|
||||
* Current drivers tend to power up the entire codec when playing
|
||||
(or recording) audio. This is fine for a PC, but tends to waste a lot of
|
||||
power on portable devices. There is also no support for saving power via
|
||||
changing codec oversampling rates, bias currents, etc.
|
||||
|
||||
|
||||
ASoC Design
|
||||
===========
|
||||
|
||||
The ASoC layer is designed to address these issues and provide the following
|
||||
features :-
|
||||
|
||||
* Codec independence. Allows reuse of codec drivers on other platforms
|
||||
and machines.
|
||||
|
||||
* Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface
|
||||
and codec registers it's audio interface capabilities with the core and are
|
||||
subsequently matched and configured when the application hw params are known.
|
||||
|
||||
* Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to
|
||||
it's minimum power state at all times. This includes powering up/down
|
||||
internal power blocks depending on the internal codec audio routing and any
|
||||
active streams.
|
||||
|
||||
* Pop and click reduction. Pops and clicks can be reduced by powering the
|
||||
codec up/down in the correct sequence (including using digital mute). ASoC
|
||||
signals the codec when to change power states.
|
||||
|
||||
* Machine specific controls: Allow machines to add controls to the sound card
|
||||
e.g. volume control for speaker amp.
|
||||
|
||||
To achieve all this, ASoC basically splits an embedded audio system into 3
|
||||
components :-
|
||||
|
||||
* Codec driver: The codec driver is platform independent and contains audio
|
||||
controls, audio interface capabilities, codec dapm definition and codec IO
|
||||
functions.
|
||||
|
||||
* Platform driver: The platform driver contains the audio dma engine and audio
|
||||
interface drivers (e.g. I2S, AC97, PCM) for that platform.
|
||||
|
||||
* Machine driver: The machine driver handles any machine specific controls and
|
||||
audio events. i.e. turing on an amp at start of playback.
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
The documentation is spilt into the following sections:-
|
||||
|
||||
overview.txt: This file.
|
||||
|
||||
codec.txt: Codec driver internals.
|
||||
|
||||
DAI.txt: Description of Digital Audio Interface standards and how to configure
|
||||
a DAI within your codec and CPU DAI drivers.
|
||||
|
||||
dapm.txt: Dynamic Audio Power Management
|
||||
|
||||
platform.txt: Platform audio DMA and DAI.
|
||||
|
||||
machine.txt: Machine driver internals.
|
||||
|
||||
pop_clicks.txt: How to minimise audio artifacts.
|
||||
|
||||
clocking.txt: ASoC clocking for best power performance.
|
58
Documentation/sound/alsa/soc/platform.txt
Normal file
58
Documentation/sound/alsa/soc/platform.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
ASoC Platform Driver
|
||||
====================
|
||||
|
||||
An ASoC platform driver can be divided into audio DMA and SoC DAI configuration
|
||||
and control. The platform drivers only target the SoC CPU and must have no board
|
||||
specific code.
|
||||
|
||||
Audio DMA
|
||||
=========
|
||||
|
||||
The platform DMA driver optionally supports the following alsa operations:-
|
||||
|
||||
/* SoC audio ops */
|
||||
struct snd_soc_ops {
|
||||
int (*startup)(struct snd_pcm_substream *);
|
||||
void (*shutdown)(struct snd_pcm_substream *);
|
||||
int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
|
||||
int (*hw_free)(struct snd_pcm_substream *);
|
||||
int (*prepare)(struct snd_pcm_substream *);
|
||||
int (*trigger)(struct snd_pcm_substream *, int);
|
||||
};
|
||||
|
||||
The platform driver exports it's DMA functionailty via struct snd_soc_platform:-
|
||||
|
||||
struct snd_soc_platform {
|
||||
char *name;
|
||||
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
|
||||
int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* platform stream ops */
|
||||
struct snd_pcm_ops *pcm_ops;
|
||||
};
|
||||
|
||||
Please refer to the alsa driver documentation for details of audio DMA.
|
||||
http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
|
||||
|
||||
An example DMA driver is soc/pxa/pxa2xx-pcm.c
|
||||
|
||||
|
||||
SoC DAI Drivers
|
||||
===============
|
||||
|
||||
Each SoC DAI driver must provide the following features:-
|
||||
|
||||
1) Digital audio interface (DAI) description
|
||||
2) Digital audio interface configuration
|
||||
3) PCM's description
|
||||
4) Sysclk configuration
|
||||
5) Suspend and resume (optional)
|
||||
|
||||
Please see codec.txt for a description of items 1 - 4.
|
52
Documentation/sound/alsa/soc/pops_clicks.txt
Normal file
52
Documentation/sound/alsa/soc/pops_clicks.txt
Normal file
|
@ -0,0 +1,52 @@
|
|||
Audio Pops and Clicks
|
||||
=====================
|
||||
|
||||
Pops and clicks are unwanted audio artifacts caused by the powering up and down
|
||||
of components within the audio subsystem. This is noticable on PC's when an
|
||||
audio module is either loaded or unloaded (at module load time the sound card is
|
||||
powered up and causes a popping noise on the speakers).
|
||||
|
||||
Pops and clicks can be more frequent on portable systems with DAPM. This is
|
||||
because the components within the subsystem are being dynamically powered
|
||||
depending on the audio usage and this can subsequently cause a small pop or
|
||||
click every time a component power state is changed.
|
||||
|
||||
|
||||
Minimising Playback Pops and Clicks
|
||||
===================================
|
||||
|
||||
Playback pops in portable audio subsystems cannot be completely eliminated atm,
|
||||
however future audio codec hardware will have better pop and click supression.
|
||||
Pops can be reduced within playback by powering the audio components in a
|
||||
specific order. This order is different for startup and shutdown and follows
|
||||
some basic rules:-
|
||||
|
||||
Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
|
||||
|
||||
Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC
|
||||
|
||||
This assumes that the codec PCM output path from the DAC is via a mixer and then
|
||||
a PGA (programmable gain amplifier) before being output to the speakers.
|
||||
|
||||
|
||||
Minimising Capture Pops and Clicks
|
||||
==================================
|
||||
|
||||
Capture artifacts are somewhat easier to get rid as we can delay activating the
|
||||
ADC until all the pops have occured. This follows similar power rules to
|
||||
playback in that components are powered in a sequence depending upon stream
|
||||
startup or shutdown.
|
||||
|
||||
Startup Order - Input PGA --> Mixers --> ADC
|
||||
|
||||
Shutdown Order - ADC --> Mixers --> Input PGA
|
||||
|
||||
|
||||
Zipper Noise
|
||||
============
|
||||
An unwanted zipper noise can occur within the audio playback or capture stream
|
||||
when a volume control is changed near its maximum gain value. The zipper noise
|
||||
is heard when the gain increase or decrease changes the mean audio signal
|
||||
amplitude too quickly. It can be minimised by enabling the zero cross setting
|
||||
for each volume control. The ZC forces the gain change to occur when the signal
|
||||
crosses the zero amplitude line.
|
|
@ -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 */
|
||||
|
|
|
@ -188,7 +188,35 @@
|
|||
#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */
|
||||
/* NOTE: The rest of the bits in this register */
|
||||
/* _are_ relevant under Linux. */
|
||||
#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */
|
||||
#define HCFG_PUSH_BUTTON_ENABLE 0x00100000 /* Enables Volume Inc/Dec and Mute functions */
|
||||
#define HCFG_BAUD_RATE 0x00080000 /* 0 = 48kHz, 1 = 44.1kHz */
|
||||
#define HCFG_EXPANDED_MEM 0x00040000 /* 1 = any 16M of 4G addr, 0 = 32M of 2G addr */
|
||||
#define HCFG_CODECFORMAT_MASK 0x00030000 /* CODEC format */
|
||||
|
||||
/* Specific to Alice2, CA0102 */
|
||||
#define HCFG_CODECFORMAT_AC97_1 0x00000000 /* AC97 CODEC format -- Ver 1.03 */
|
||||
#define HCFG_CODECFORMAT_AC97_2 0x00010000 /* AC97 CODEC format -- Ver 2.1 */
|
||||
#define HCFG_AUTOMUTE_ASYNC 0x00008000 /* When set, the async sample rate convertors */
|
||||
/* will automatically mute their output when */
|
||||
/* they are not rate-locked to the external */
|
||||
/* async audio source */
|
||||
#define HCFG_AUTOMUTE_SPDIF 0x00004000 /* When set, the async sample rate convertors */
|
||||
/* will automatically mute their output when */
|
||||
/* the SPDIF V-bit indicates invalid audio */
|
||||
#define HCFG_EMU32_SLAVE 0x00002000 /* 0 = Master, 1 = Slave. Slave for EMU1010 */
|
||||
#define HCFG_SLOW_RAMP 0x00001000 /* Increases Send Smoothing time constant */
|
||||
/* 0x00000800 not used on Alice2 */
|
||||
#define HCFG_PHASE_TRACK_MASK 0x00000700 /* When set, forces corresponding input to */
|
||||
/* phase track the previous input. */
|
||||
/* I2S0 can phase track the last S/PDIF input */
|
||||
#define HCFG_I2S_ASRC_ENABLE 0x00000070 /* When set, enables asynchronous sample rate */
|
||||
/* conversion for the corresponding */
|
||||
/* I2S format input */
|
||||
/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc. */
|
||||
|
||||
|
||||
|
||||
/* Older chips */
|
||||
#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */
|
||||
#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */
|
||||
#define HCFG_GPINPUT0 0x00004000 /* External pin112 */
|
||||
|
@ -432,6 +460,7 @@
|
|||
#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */
|
||||
#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */
|
||||
|
||||
#define A_HR 0x0b /* High Resolution. 24bit playback from host to DSP. */
|
||||
#define MAPA 0x0c /* Cache map A */
|
||||
|
||||
#define MAPB 0x0d /* Cache map B */
|
||||
|
@ -439,6 +468,8 @@
|
|||
#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
|
||||
#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
|
||||
|
||||
/* 0x0e, 0x0f: Not used */
|
||||
|
||||
#define ENVVOL 0x10 /* Volume envelope register */
|
||||
#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */
|
||||
/* 0x8000-n == 666*n usec delay */
|
||||
|
@ -527,7 +558,7 @@
|
|||
/* NOTE: All channels contain internal variables; do */
|
||||
/* not write to these locations. */
|
||||
|
||||
/* 1f something */
|
||||
/* 0x1f: not used */
|
||||
|
||||
#define CD0 0x20 /* Cache data 0 register */
|
||||
#define CD1 0x21 /* Cache data 1 register */
|
||||
|
@ -597,6 +628,8 @@
|
|||
#define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */
|
||||
#define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */
|
||||
|
||||
#define A_TBLSZ ` 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */
|
||||
|
||||
#define TCBS 0x44 /* Tank cache buffer size register */
|
||||
#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
|
||||
#define TCBS_BUFFSIZE_16K 0x00000000
|
||||
|
@ -617,7 +650,7 @@
|
|||
#define FXBA 0x47 /* FX Buffer Address */
|
||||
#define FXBA_MASK 0xfffff000 /* 20 bit base address */
|
||||
|
||||
/* 0x48 something - word access, defaults to 3f */
|
||||
#define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */
|
||||
|
||||
#define MICBS 0x49 /* Microphone buffer size register */
|
||||
|
||||
|
@ -661,6 +694,18 @@
|
|||
#define ADCBS_BUFSIZE_57344 0x0000001e
|
||||
#define ADCBS_BUFSIZE_65536 0x0000001f
|
||||
|
||||
/* Current Send B, A Amounts */
|
||||
#define A_CSBA 0x4c
|
||||
|
||||
/* Current Send D, C Amounts */
|
||||
#define A_CSDC 0x4d
|
||||
|
||||
/* Current Send F, E Amounts */
|
||||
#define A_CSFE 0x4e
|
||||
|
||||
/* Current Send H, G Amounts */
|
||||
#define A_CSHG 0x4f
|
||||
|
||||
|
||||
#define CDCS 0x50 /* CD-ROM digital channel status register */
|
||||
|
||||
|
@ -668,6 +713,9 @@
|
|||
|
||||
#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
|
||||
|
||||
/* S/PDIF Input C Channel Status */
|
||||
#define A_SPSC 0x52
|
||||
|
||||
#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
|
||||
|
||||
#define A_DBG 0x53
|
||||
|
@ -708,6 +756,8 @@
|
|||
#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
|
||||
#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
|
||||
|
||||
/* 0x57: Not used */
|
||||
|
||||
/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */
|
||||
#define CLIEL 0x58 /* Channel loop interrupt enable low register */
|
||||
|
||||
|
@ -733,6 +783,9 @@
|
|||
#define AC97SLOT_CNTR 0x10 /* Center enable */
|
||||
#define AC97SLOT_LFE 0x20 /* LFE enable */
|
||||
|
||||
/* PCB Revision */
|
||||
#define A_PCB 0x5f
|
||||
|
||||
// NOTE: 0x60,61,62: 64-bit
|
||||
#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */
|
||||
|
||||
|
@ -780,9 +833,18 @@
|
|||
|
||||
#define HLIPH 0x69 /* Channel half loop interrupt pending high register */
|
||||
|
||||
// 0x6a,6b,6c used for some recording
|
||||
// 0x6d unused
|
||||
// 0x6e,6f - tanktable base / offset
|
||||
/* S/PDIF Host Record Index (bypasses SRC) */
|
||||
#define A_SPRI 0x6a
|
||||
/* S/PDIF Host Record Address */
|
||||
#define A_SPRA 0x6b
|
||||
/* S/PDIF Host Record Control */
|
||||
#define A_SPRC 0x6c
|
||||
/* Delayed Interrupt Counter & Enable */
|
||||
#define A_DICE 0x6d
|
||||
/* Tank Table Base */
|
||||
#define A_TTB 0x6e
|
||||
/* Tank Delay Offset */
|
||||
#define A_TDOF 0x6f
|
||||
|
||||
/* This is the MPU port on the card (via the game port) */
|
||||
#define A_MUDATA1 0x70
|
||||
|
@ -800,6 +862,7 @@
|
|||
#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */
|
||||
#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
|
||||
|
||||
/* Extended Hardware Control */
|
||||
#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
|
||||
#define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */
|
||||
#define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */
|
||||
|
@ -822,8 +885,20 @@
|
|||
#define A_PCM_96000 0x00004000
|
||||
#define A_PCM_44100 0x00008000
|
||||
|
||||
/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */
|
||||
/* 0x7a, 0x7b - lookup tables */
|
||||
/* I2S0 Sample Rate Tracker Status */
|
||||
#define A_SRT3 0x77
|
||||
|
||||
/* I2S1 Sample Rate Tracker Status */
|
||||
#define A_SRT4 0x78
|
||||
|
||||
/* I2S2 Sample Rate Tracker Status */
|
||||
#define A_SRT5 0x79
|
||||
/* - default to 0x01080000 on my audigy 2 ZS --rlrevell */
|
||||
|
||||
/* Tank Table DMA Address */
|
||||
#define A_TTDA 0x7a
|
||||
/* Tank Table DMA Data */
|
||||
#define A_TTDD 0x7b
|
||||
|
||||
#define A_FXRT2 0x7c
|
||||
#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
|
||||
|
@ -845,7 +920,7 @@
|
|||
#define A_FXRT_CHANNELC 0x003f0000
|
||||
#define A_FXRT_CHANNELD 0x3f000000
|
||||
|
||||
|
||||
/* 0x7f: Not used */
|
||||
/* Each FX general purpose register is 32 bits in length, all bits are used */
|
||||
#define FXGPREGBASE 0x100 /* FX general purpose registers base */
|
||||
#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */
|
||||
|
@ -886,6 +961,293 @@
|
|||
#define A_HIWORD_RESULT_MASK 0x007ff000
|
||||
#define A_HIWORD_OPA_MASK 0x000007ff
|
||||
|
||||
/************************************************************************************************/
|
||||
/* EMU1010m HANA FPGA registers */
|
||||
/************************************************************************************************/
|
||||
#define EMU_HANA_DESTHI 0x00 /* 0000xxx 3 bits Link Destination */
|
||||
#define EMU_HANA_DESTLO 0x01 /* 00xxxxx 5 bits */
|
||||
#define EMU_HANA_SRCHI 0x02 /* 0000xxx 3 bits Link Source */
|
||||
#define EMU_HANA_SRCLO 0x03 /* 00xxxxx 5 bits */
|
||||
#define EMU_HANA_DOCK_PWR 0x04 /* 000000x 1 bits Audio Dock power */
|
||||
#define EMU_HANA_DOCK_PWR_ON 0x01 /* Audio Dock power on */
|
||||
#define EMU_HANA_WCLOCK 0x05 /* 0000xxx 3 bits Word Clock source select */
|
||||
/* Must be written after power on to reset DLL */
|
||||
/* One is unable to detect the Audio dock without this */
|
||||
#define EMU_HANA_WCLOCK_SRC_MASK 0x07
|
||||
#define EMU_HANA_WCLOCK_INT_48K 0x00
|
||||
#define EMU_HANA_WCLOCK_INT_44_1K 0x01
|
||||
#define EMU_HANA_WCLOCK_HANA_SPDIF_IN 0x02
|
||||
#define EMU_HANA_WCLOCK_HANA_ADAT_IN 0x03
|
||||
#define EMU_HANA_WCLOCK_SYNC_BNCN 0x04
|
||||
#define EMU_HANA_WCLOCK_2ND_HANA 0x05
|
||||
#define EMU_HANA_WCLOCK_SRC_RESERVED 0x06
|
||||
#define EMU_HANA_WCLOCK_OFF 0x07 /* For testing, forces fallback to DEFCLOCK */
|
||||
#define EMU_HANA_WCLOCK_MULT_MASK 0x18
|
||||
#define EMU_HANA_WCLOCK_1X 0x00
|
||||
#define EMU_HANA_WCLOCK_2X 0x08
|
||||
#define EMU_HANA_WCLOCK_4X 0x10
|
||||
#define EMU_HANA_WCLOCK_MULT_RESERVED 0x18
|
||||
|
||||
#define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */
|
||||
#define EMU_HANA_DEFCLOCK_48K 0x00
|
||||
#define EMU_HANA_DEFCLOCK_44_1K 0x01
|
||||
|
||||
#define EMU_HANA_UNMUTE 0x07 /* 000000x 1 bits Mute all audio outputs */
|
||||
#define EMU_MUTE 0x00
|
||||
#define EMU_UNMUTE 0x01
|
||||
|
||||
#define EMU_HANA_FPGA_CONFIG 0x08 /* 00000xx 2 bits Config control of FPGAs */
|
||||
#define EMU_HANA_FPGA_CONFIG_AUDIODOCK 0x01 /* Set in order to program FPGA on Audio Dock */
|
||||
#define EMU_HANA_FPGA_CONFIG_HANA 0x02 /* Set in order to program FPGA on Hana */
|
||||
|
||||
#define EMU_HANA_IRQ_ENABLE 0x09 /* 000xxxx 4 bits IRQ Enable */
|
||||
#define EMU_HANA_IRQ_WCLK_CHANGED 0x01
|
||||
#define EMU_HANA_IRQ_ADAT 0x02
|
||||
#define EMU_HANA_IRQ_DOCK 0x04
|
||||
#define EMU_HANA_IRQ_DOCK_LOST 0x08
|
||||
|
||||
#define EMU_HANA_SPDIF_MODE 0x0a /* 00xxxxx 5 bits SPDIF MODE */
|
||||
#define EMU_HANA_SPDIF_MODE_TX_COMSUMER 0x00
|
||||
#define EMU_HANA_SPDIF_MODE_TX_PRO 0x01
|
||||
#define EMU_HANA_SPDIF_MODE_TX_NOCOPY 0x02
|
||||
#define EMU_HANA_SPDIF_MODE_RX_COMSUMER 0x00
|
||||
#define EMU_HANA_SPDIF_MODE_RX_PRO 0x04
|
||||
#define EMU_HANA_SPDIF_MODE_RX_NOCOPY 0x08
|
||||
#define EMU_HANA_SPDIF_MODE_RX_INVALID 0x10
|
||||
|
||||
#define EMU_HANA_OPTICAL_TYPE 0x0b /* 00000xx 2 bits ADAT or SPDIF in/out */
|
||||
#define EMU_HANA_OPTICAL_IN_SPDIF 0x00
|
||||
#define EMU_HANA_OPTICAL_IN_ADAT 0x01
|
||||
#define EMU_HANA_OPTICAL_OUT_SPDIF 0x00
|
||||
#define EMU_HANA_OPTICAL_OUT_ADAT 0x02
|
||||
|
||||
#define EMU_HANA_MIDI_IN 0x0c /* 000000x 1 bit Control MIDI */
|
||||
#define EMU_HANA_MIDI_IN_FROM_HAMOA 0x00 /* HAMOA MIDI in to Alice 2 MIDI B */
|
||||
#define EMU_HANA_MIDI_IN_FROM_DOCK 0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */
|
||||
|
||||
#define EMU_HANA_DOCK_LEDS_1 0x0d /* 000xxxx 4 bit Audio Dock LEDs */
|
||||
#define EMU_HANA_DOCK_LEDS_1_MIDI1 0x01 /* MIDI 1 LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_1_MIDI2 0x02 /* MIDI 2 LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN 0x04 /* SMPTE IN LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT 0x08 /* SMPTE OUT LED on */
|
||||
|
||||
#define EMU_HANA_DOCK_LEDS_2 0x0e /* 0xxxxxx 6 bit Audio Dock LEDs */
|
||||
#define EMU_HANA_DOCK_LEDS_2_44K 0x01 /* 44.1 kHz LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_2_48K 0x02 /* 48 kHz LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_2_96K 0x04 /* 96 kHz LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_2_192K 0x08 /* 192 kHz LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_2_LOCK 0x10 /* LOCK LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_2_EXT 0x20 /* EXT LED on */
|
||||
|
||||
#define EMU_HANA_DOCK_LEDS_3 0x0f /* 0xxxxxx 6 bit Audio Dock LEDs */
|
||||
#define EMU_HANA_DOCK_LEDS_3_CLIP_A 0x01 /* Mic A Clip LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_3_CLIP_B 0x02 /* Mic B Clip LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A 0x04 /* Signal A Clip LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B 0x08 /* Signal B Clip LED on */
|
||||
#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP 0x10 /* Manual Clip detection */
|
||||
#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL 0x20 /* Manual Signal detection */
|
||||
|
||||
#define EMU_HANA_ADC_PADS 0x10 /* 0000xxx 3 bit Audio Dock ADC 14dB pads */
|
||||
#define EMU_HANA_DOCK_ADC_PAD1 0x01 /* 14dB Attenuation on Audio Dock ADC 1 */
|
||||
#define EMU_HANA_DOCK_ADC_PAD2 0x02 /* 14dB Attenuation on Audio Dock ADC 2 */
|
||||
#define EMU_HANA_DOCK_ADC_PAD3 0x04 /* 14dB Attenuation on Audio Dock ADC 3 */
|
||||
#define EMU_HANA_0202_ADC_PAD1 0x08 /* 14dB Attenuation on 0202 ADC 1 */
|
||||
|
||||
#define EMU_HANA_DOCK_MISC 0x11 /* 0xxxxxx 6 bit Audio Dock misc bits */
|
||||
#define EMU_HANA_DOCK_DAC1_MUTE 0x01 /* DAC 1 Mute */
|
||||
#define EMU_HANA_DOCK_DAC2_MUTE 0x02 /* DAC 2 Mute */
|
||||
#define EMU_HANA_DOCK_DAC3_MUTE 0x04 /* DAC 3 Mute */
|
||||
#define EMU_HANA_DOCK_DAC4_MUTE 0x08 /* DAC 4 Mute */
|
||||
#define EMU_HANA_DOCK_PHONES_192_DAC1 0x00 /* DAC 1 Headphones source at 192kHz */
|
||||
#define EMU_HANA_DOCK_PHONES_192_DAC2 0x10 /* DAC 2 Headphones source at 192kHz */
|
||||
#define EMU_HANA_DOCK_PHONES_192_DAC3 0x20 /* DAC 3 Headphones source at 192kHz */
|
||||
#define EMU_HANA_DOCK_PHONES_192_DAC4 0x30 /* DAC 4 Headphones source at 192kHz */
|
||||
|
||||
#define EMU_HANA_MIDI_OUT 0x12 /* 00xxxxx 5 bit Source for each MIDI out port */
|
||||
#define EMU_HANA_MIDI_OUT_0202 0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */
|
||||
#define EMU_HANA_MIDI_OUT_DOCK1 0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */
|
||||
#define EMU_HANA_MIDI_OUT_DOCK2 0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */
|
||||
#define EMU_HANA_MIDI_OUT_SYNC2 0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */
|
||||
#define EMU_HANA_MIDI_OUT_LOOP 0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */
|
||||
|
||||
#define EMU_HANA_DAC_PADS 0x13 /* 00xxxxx 5 bit DAC 14dB attenuation pads */
|
||||
#define EMU_HANA_DOCK_DAC_PAD1 0x01 /* 14dB Attenuation on AudioDock DAC 1. Left and Right */
|
||||
#define EMU_HANA_DOCK_DAC_PAD2 0x02 /* 14dB Attenuation on AudioDock DAC 2. Left and Right */
|
||||
#define EMU_HANA_DOCK_DAC_PAD3 0x04 /* 14dB Attenuation on AudioDock DAC 3. Left and Right */
|
||||
#define EMU_HANA_DOCK_DAC_PAD4 0x08 /* 14dB Attenuation on AudioDock DAC 4. Left and Right */
|
||||
#define EMU_HANA_0202_DAC_PAD1 0x10 /* 14dB Attenuation on 0202 DAC 1. Left and Right */
|
||||
|
||||
/* 0x14 - 0x1f Unused R/W registers */
|
||||
#define EMU_HANA_IRQ_STATUS 0x20 /* 000xxxx 4 bits IRQ Status */
|
||||
#if 0 /* Already defined for reg 0x09 IRQ_ENABLE */
|
||||
#define EMU_HANA_IRQ_WCLK_CHANGED 0x01
|
||||
#define EMU_HANA_IRQ_ADAT 0x02
|
||||
#define EMU_HANA_IRQ_DOCK 0x04
|
||||
#define EMU_HANA_IRQ_DOCK_LOST 0x08
|
||||
#endif
|
||||
|
||||
#define EMU_HANA_OPTION_CARDS 0x21 /* 000xxxx 4 bits Presence of option cards */
|
||||
#define EMU_HANA_OPTION_HAMOA 0x01 /* HAMOA card present */
|
||||
#define EMU_HANA_OPTION_SYNC 0x02 /* Sync card present */
|
||||
#define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio Dock online and FPGA configured */
|
||||
#define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio Dock online and FPGA not configured */
|
||||
|
||||
#define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 */
|
||||
|
||||
#define EMU_HANA_MAJOR_REV 0x23 /* 0000xxx 3 bit Hana FPGA Major rev */
|
||||
#define EMU_HANA_MINOR_REV 0x24 /* 0000xxx 3 bit Hana FPGA Minor rev */
|
||||
|
||||
#define EMU_DOCK_MAJOR_REV 0x25 /* 0000xxx 3 bit Audio Dock FPGA Major rev */
|
||||
#define EMU_DOCK_MINOR_REV 0x26 /* 0000xxx 3 bit Audio Dock FPGA Minor rev */
|
||||
|
||||
#define EMU_DOCK_BOARD_ID 0x27 /* 00000xx 2 bits Audio Dock ID pins */
|
||||
#define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */
|
||||
#define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */
|
||||
|
||||
#define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */
|
||||
#define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */
|
||||
|
||||
#define EMU_HANA_WC_ADAT_HI 0x2a /* 0xxxxxx 6 bit ADAT IN Word clock, upper 6 bits */
|
||||
#define EMU_HANA_WC_ADAT_LO 0x2b /* 0xxxxxx 6 bit ADAT IN Word clock, lower 6 bits */
|
||||
|
||||
#define EMU_HANA_WC_BNC_LO 0x2c /* 0xxxxxx 6 bit BNC IN Word clock, lower 6 bits */
|
||||
#define EMU_HANA_WC_BNC_HI 0x2d /* 0xxxxxx 6 bit BNC IN Word clock, upper 6 bits */
|
||||
|
||||
#define EMU_HANA2_WC_SPDIF_HI 0x2e /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, upper 6 bits */
|
||||
#define EMU_HANA2_WC_SPDIF_LO 0x2f /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, lower 6 bits */
|
||||
/* 0x30 - 0x3f Unused Read only registers */
|
||||
|
||||
/************************************************************************************************/
|
||||
/* EMU1010m HANA Destinations */
|
||||
/************************************************************************************************/
|
||||
#define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_4 0x0003 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_5 0x0004 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_6 0x0005 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_7 0x0006 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_8 0x0007 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_9 0x0008 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_A 0x0009 /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_B 0x000a /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_C 0x000b /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_D 0x000c /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_E 0x000d /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_ALICE2_EMU32_F 0x000e /* 16 EMU32 channels to Alice2 +0 to +0xf */
|
||||
#define EMU_DST_DOCK_DAC1_LEFT1 0x0100 /* Audio Dock DAC1 Left, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC1_LEFT2 0x0101 /* Audio Dock DAC1 Left, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC1_LEFT3 0x0102 /* Audio Dock DAC1 Left, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC1_LEFT4 0x0103 /* Audio Dock DAC1 Left, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC1_RIGHT1 0x0104 /* Audio Dock DAC1 Right, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC1_RIGHT2 0x0105 /* Audio Dock DAC1 Right, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC1_RIGHT3 0x0106 /* Audio Dock DAC1 Right, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC1_RIGHT4 0x0107 /* Audio Dock DAC1 Right, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC2_LEFT1 0x0108 /* Audio Dock DAC2 Left, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC2_LEFT2 0x0109 /* Audio Dock DAC2 Left, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC2_LEFT3 0x010a /* Audio Dock DAC2 Left, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC2_LEFT4 0x010b /* Audio Dock DAC2 Left, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC2_RIGHT1 0x010c /* Audio Dock DAC2 Right, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC2_RIGHT2 0x010d /* Audio Dock DAC2 Right, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC2_RIGHT3 0x010e /* Audio Dock DAC2 Right, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC2_RIGHT4 0x010f /* Audio Dock DAC2 Right, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC3_LEFT1 0x0110 /* Audio Dock DAC1 Left, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC3_LEFT2 0x0111 /* Audio Dock DAC1 Left, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC3_LEFT3 0x0112 /* Audio Dock DAC1 Left, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC3_LEFT4 0x0113 /* Audio Dock DAC1 Left, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_PHONES_LEFT1 0x0112 /* Audio Dock PHONES Left, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_PHONES_LEFT2 0x0113 /* Audio Dock PHONES Left, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC3_RIGHT1 0x0114 /* Audio Dock DAC1 Right, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC3_RIGHT2 0x0115 /* Audio Dock DAC1 Right, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC3_RIGHT3 0x0116 /* Audio Dock DAC1 Right, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC3_RIGHT4 0x0117 /* Audio Dock DAC1 Right, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_PHONES_RIGHT1 0x0116 /* Audio Dock PHONES Right, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_PHONES_RIGHT2 0x0117 /* Audio Dock PHONES Right, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC4_LEFT1 0x0118 /* Audio Dock DAC2 Left, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC4_LEFT2 0x0119 /* Audio Dock DAC2 Left, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC4_LEFT3 0x011a /* Audio Dock DAC2 Left, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC4_LEFT4 0x011b /* Audio Dock DAC2 Left, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_SPDIF_LEFT1 0x011a /* Audio Dock SPDIF Left, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_SPDIF_LEFT2 0x011b /* Audio Dock SPDIF Left, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC4_RIGHT1 0x011c /* Audio Dock DAC2 Right, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_DAC4_RIGHT2 0x011d /* Audio Dock DAC2 Right, 2nd or 96kHz */
|
||||
#define EMU_DST_DOCK_DAC4_RIGHT3 0x011e /* Audio Dock DAC2 Right, 3rd or 192kHz */
|
||||
#define EMU_DST_DOCK_DAC4_RIGHT4 0x011f /* Audio Dock DAC2 Right, 4th or 192kHz */
|
||||
#define EMU_DST_DOCK_SPDIF_RIGHT1 0x011e /* Audio Dock SPDIF Right, 1st or 48kHz only */
|
||||
#define EMU_DST_DOCK_SPDIF_RIGHT2 0x011f /* Audio Dock SPDIF Right, 2nd or 96kHz */
|
||||
#define EMU_DST_HANA_SPDIF_LEFT1 0x0200 /* Hana SPDIF Left, 1st or 48kHz only */
|
||||
#define EMU_DST_HANA_SPDIF_LEFT2 0x0202 /* Hana SPDIF Left, 2nd or 96kHz */
|
||||
#define EMU_DST_HANA_SPDIF_RIGHT1 0x0201 /* Hana SPDIF Right, 1st or 48kHz only */
|
||||
#define EMU_DST_HANA_SPDIF_RIGHT2 0x0203 /* Hana SPDIF Right, 2nd or 96kHz */
|
||||
#define EMU_DST_HAMOA_DAC_LEFT1 0x0300 /* Hamoa DAC Left, 1st or 48kHz only */
|
||||
#define EMU_DST_HAMOA_DAC_LEFT2 0x0302 /* Hamoa DAC Left, 2nd or 96kHz */
|
||||
#define EMU_DST_HAMOA_DAC_LEFT3 0x0304 /* Hamoa DAC Left, 3rd or 192kHz */
|
||||
#define EMU_DST_HAMOA_DAC_LEFT4 0x0306 /* Hamoa DAC Left, 4th or 192kHz */
|
||||
#define EMU_DST_HAMOA_DAC_RIGHT1 0x0301 /* Hamoa DAC Right, 1st or 48kHz only */
|
||||
#define EMU_DST_HAMOA_DAC_RIGHT2 0x0303 /* Hamoa DAC Right, 2nd or 96kHz */
|
||||
#define EMU_DST_HAMOA_DAC_RIGHT3 0x0305 /* Hamoa DAC Right, 3rd or 192kHz */
|
||||
#define EMU_DST_HAMOA_DAC_RIGHT4 0x0307 /* Hamoa DAC Right, 4th or 192kHz */
|
||||
#define EMU_DST_HANA_ADAT 0x0400 /* Hana ADAT 8 channel out +0 to +7 */
|
||||
#define EMU_DST_ALICE_I2S0_LEFT 0x0500 /* Alice2 I2S0 Left */
|
||||
#define EMU_DST_ALICE_I2S0_RIGHT 0x0501 /* Alice2 I2S0 Right */
|
||||
#define EMU_DST_ALICE_I2S1_LEFT 0x0600 /* Alice2 I2S1 Left */
|
||||
#define EMU_DST_ALICE_I2S1_RIGHT 0x0601 /* Alice2 I2S1 Right */
|
||||
#define EMU_DST_ALICE_I2S2_LEFT 0x0700 /* Alice2 I2S2 Left */
|
||||
#define EMU_DST_ALICE_I2S2_RIGHT 0x0701 /* Alice2 I2S2 Right */
|
||||
|
||||
/************************************************************************************************/
|
||||
/* EMU1010m HANA Sources */
|
||||
/************************************************************************************************/
|
||||
#define EMU_SRC_SILENCE 0x0000 /* Silence */
|
||||
#define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_MIC_A2 0x0101 /* Audio Dock Mic A, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_MIC_A3 0x0102 /* Audio Dock Mic A, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_MIC_A4 0x0103 /* Audio Dock Mic A, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_MIC_B1 0x0104 /* Audio Dock Mic B, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_MIC_B2 0x0105 /* Audio Dock Mic B, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_MIC_B3 0x0106 /* Audio Dock Mic B, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_MIC_B4 0x0107 /* Audio Dock Mic B, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC1_LEFT1 0x0108 /* Audio Dock ADC1 Left, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_ADC1_LEFT2 0x0109 /* Audio Dock ADC1 Left, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_ADC1_LEFT3 0x010a /* Audio Dock ADC1 Left, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC1_LEFT4 0x010b /* Audio Dock ADC1 Left, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC1_RIGHT1 0x010c /* Audio Dock ADC1 Right, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_ADC1_RIGHT2 0x010d /* Audio Dock ADC1 Right, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_ADC1_RIGHT3 0x010e /* Audio Dock ADC1 Right, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC1_RIGHT4 0x010f /* Audio Dock ADC1 Right, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC2_LEFT1 0x0110 /* Audio Dock ADC2 Left, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_ADC2_LEFT2 0x0111 /* Audio Dock ADC2 Left, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_ADC2_LEFT3 0x0112 /* Audio Dock ADC2 Left, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC2_LEFT4 0x0113 /* Audio Dock ADC2 Left, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC2_RIGHT1 0x0114 /* Audio Dock ADC2 Right, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_ADC2_RIGHT2 0x0115 /* Audio Dock ADC2 Right, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_ADC2_RIGHT3 0x0116 /* Audio Dock ADC2 Right, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC2_RIGHT4 0x0117 /* Audio Dock ADC2 Right, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC3_LEFT1 0x0118 /* Audio Dock ADC3 Left, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_ADC3_LEFT2 0x0119 /* Audio Dock ADC3 Left, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_ADC3_LEFT3 0x011a /* Audio Dock ADC3 Left, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC3_LEFT4 0x011b /* Audio Dock ADC3 Left, 4th or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC3_RIGHT1 0x011c /* Audio Dock ADC3 Right, 1st or 48kHz only */
|
||||
#define EMU_SRC_DOCK_ADC3_RIGHT2 0x011d /* Audio Dock ADC3 Right, 2nd or 96kHz */
|
||||
#define EMU_SRC_DOCK_ADC3_RIGHT3 0x011e /* Audio Dock ADC3 Right, 3rd or 192kHz */
|
||||
#define EMU_SRC_DOCK_ADC3_RIGHT4 0x011f /* Audio Dock ADC3 Right, 4th or 192kHz */
|
||||
#define EMU_SRC_HAMOA_ADC_LEFT1 0x0200 /* Hamoa ADC Left, 1st or 48kHz only */
|
||||
#define EMU_SRC_HAMOA_ADC_LEFT2 0x0202 /* Hamoa ADC Left, 2nd or 96kHz */
|
||||
#define EMU_SRC_HAMOA_ADC_LEFT3 0x0204 /* Hamoa ADC Left, 3rd or 192kHz */
|
||||
#define EMU_SRC_HAMOA_ADC_LEFT4 0x0206 /* Hamoa ADC Left, 4th or 192kHz */
|
||||
#define EMU_SRC_HAMOA_ADC_RIGHT1 0x0201 /* Hamoa ADC Right, 1st or 48kHz only */
|
||||
#define EMU_SRC_HAMOA_ADC_RIGHT2 0x0203 /* Hamoa ADC Right, 2nd or 96kHz */
|
||||
#define EMU_SRC_HAMOA_ADC_RIGHT3 0x0205 /* Hamoa ADC Right, 3rd or 192kHz */
|
||||
#define EMU_SRC_HAMOA_ADC_RIGHT4 0x0207 /* Hamoa ADC Right, 4th or 192kHz */
|
||||
#define EMU_SRC_ALICE_EMU32A 0x0300 /* Alice2 EMU32a 16 outputs. +0 to +0xf */
|
||||
#define EMU_SRC_ALICE_EMU32B 0x0310 /* Alice2 EMU32b 16 outputs. +0 to +0xf */
|
||||
#define EMU_SRC_HANA_ADAT 0x0400 /* Hana ADAT 8 channel in +0 to +7 */
|
||||
#define EMU_SRC_HANA_SPDIF_LEFT1 0x0500 /* Hana SPDIF Left, 1st or 48kHz only */
|
||||
#define EMU_SRC_HANA_SPDIF_LEFT2 0x0502 /* Hana SPDIF Left, 2nd or 96kHz */
|
||||
#define EMU_SRC_HANA_SPDIF_RIGHT1 0x0501 /* Hana SPDIF Right, 1st or 48kHz only */
|
||||
#define EMU_SRC_HANA_SPDIF_RIGHT2 0x0503 /* Hana SPDIF Right, 2nd or 96kHz */
|
||||
/* 0x600 and 0x700 no used */
|
||||
|
||||
/* ------------------- STRUCTURES -------------------- */
|
||||
|
||||
|
@ -1063,7 +1425,7 @@ struct snd_emu_chip_details {
|
|||
unsigned char spdif_bug; /* Has Spdif phasing bug */
|
||||
unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */
|
||||
unsigned char ecard; /* APS EEPROM */
|
||||
unsigned char emu1212m; /* EMU 1212m card */
|
||||
unsigned char emu1010; /* EMU 1010m card */
|
||||
unsigned char spi_dac; /* SPI interface for DAC */
|
||||
unsigned char i2c_adc; /* I2C interface for ADC */
|
||||
unsigned char adc_1361t; /* Use Philips 1361T ADC */
|
||||
|
@ -1072,6 +1434,14 @@ struct snd_emu_chip_details {
|
|||
const char *id; /* for backward compatibility - can be NULL if not needed */
|
||||
};
|
||||
|
||||
struct snd_emu1010 {
|
||||
unsigned int output_source[64];
|
||||
unsigned int input_source[64];
|
||||
unsigned int adc_pads; /* bit mask */
|
||||
unsigned int dac_pads; /* bit mask */
|
||||
unsigned int internal_clock; /* 44100 or 48000 */
|
||||
};
|
||||
|
||||
struct snd_emu10k1 {
|
||||
int irq;
|
||||
|
||||
|
@ -1079,6 +1449,7 @@ struct snd_emu10k1 {
|
|||
unsigned int tos_link: 1, /* tos link detected */
|
||||
rear_ac97: 1, /* rear channels are on AC'97 */
|
||||
enable_ir: 1;
|
||||
unsigned int support_tlv :1;
|
||||
/* Contains profile of card capabilities */
|
||||
const struct snd_emu_chip_details *card_capabilities;
|
||||
unsigned int audigy; /* is Audigy? */
|
||||
|
@ -1104,6 +1475,8 @@ struct snd_emu10k1 {
|
|||
spinlock_t memblk_lock;
|
||||
|
||||
unsigned int spdif_bits[3]; /* s/pdif out setup */
|
||||
unsigned int i2c_capture_source;
|
||||
u8 i2c_capture_volume[4][2];
|
||||
|
||||
struct snd_emu10k1_fx8010 fx8010; /* FX8010 info */
|
||||
int gpr_base;
|
||||
|
@ -1132,6 +1505,7 @@ struct snd_emu10k1 {
|
|||
int p16v_device_offset;
|
||||
u32 p16v_capture_source;
|
||||
u32 p16v_capture_channel;
|
||||
struct snd_emu1010 emu1010;
|
||||
struct snd_emu10k1_pcm_mixer pcm_mixer[32];
|
||||
struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK];
|
||||
struct snd_kcontrol *ctl_send_routing;
|
||||
|
@ -1208,6 +1582,10 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
|
|||
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
|
||||
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
|
||||
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
|
||||
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
|
||||
int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
|
||||
int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
|
||||
int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
|
||||
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
|
||||
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
|
||||
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
|
||||
|
@ -1524,11 +1902,20 @@ struct snd_emu10k1_fx8010_control_gpr {
|
|||
unsigned int value[32]; /* initial values */
|
||||
unsigned int min; /* minimum range */
|
||||
unsigned int max; /* maximum range */
|
||||
union {
|
||||
snd_kcontrol_tlv_rw_t *c;
|
||||
unsigned int *p;
|
||||
} tlv;
|
||||
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
||||
const unsigned int *tlv;
|
||||
};
|
||||
|
||||
/* old ABI without TLV support */
|
||||
struct snd_emu10k1_fx8010_control_old_gpr {
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int vcount;
|
||||
unsigned int count;
|
||||
unsigned short gpr[32];
|
||||
unsigned int value[32];
|
||||
unsigned int min;
|
||||
unsigned int max;
|
||||
unsigned int translation;
|
||||
};
|
||||
|
||||
struct snd_emu10k1_fx8010_code {
|
||||
|
@ -1579,6 +1966,8 @@ struct snd_emu10k1_fx8010_pcm_rec {
|
|||
unsigned int res2; /* reserved */
|
||||
};
|
||||
|
||||
#define SNDRV_EMU10K1_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
|
||||
|
||||
#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info)
|
||||
#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code)
|
||||
#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code)
|
||||
|
@ -1587,6 +1976,7 @@ struct snd_emu10k1_fx8010_pcm_rec {
|
|||
#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram)
|
||||
#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec)
|
||||
#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec)
|
||||
#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int)
|
||||
#define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80)
|
||||
#define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81)
|
||||
#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82)
|
||||
|
|
|
@ -56,6 +56,8 @@ struct snd_pcm_hardware {
|
|||
size_t fifo_size; /* fifo size in bytes */
|
||||
};
|
||||
|
||||
struct snd_pcm_substream;
|
||||
|
||||
struct snd_pcm_ops {
|
||||
int (*open)(struct snd_pcm_substream *substream);
|
||||
int (*close)(struct snd_pcm_substream *substream);
|
||||
|
@ -384,6 +386,7 @@ struct snd_pcm_substream {
|
|||
struct snd_info_entry *proc_sw_params_entry;
|
||||
struct snd_info_entry *proc_status_entry;
|
||||
struct snd_info_entry *proc_prealloc_entry;
|
||||
struct snd_info_entry *proc_prealloc_max_entry;
|
||||
#endif
|
||||
/* misc flags */
|
||||
unsigned int hw_opened: 1;
|
||||
|
@ -427,6 +430,7 @@ struct snd_pcm {
|
|||
wait_queue_head_t open_wait;
|
||||
void *private_data;
|
||||
void (*private_free) (struct snd_pcm *pcm);
|
||||
struct device *dev; /* actual hw device this belongs to */
|
||||
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
|
||||
struct snd_pcm_oss oss;
|
||||
#endif
|
||||
|
|
37
include/sound/pt2258.h
Normal file
37
include/sound/pt2258.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* ALSA Driver for the PT2258 volume controller.
|
||||
*
|
||||
* Copyright (c) 2006 Jochen Voss <voss@seehuhn.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_PT2258_H
|
||||
#define __SOUND_PT2258_H
|
||||
|
||||
struct snd_pt2258 {
|
||||
struct snd_card *card;
|
||||
struct snd_i2c_bus *i2c_bus;
|
||||
struct snd_i2c_device *i2c_dev;
|
||||
|
||||
unsigned char volume[6];
|
||||
int mute;
|
||||
};
|
||||
|
||||
extern int snd_pt2258_reset(struct snd_pt2258 *pt);
|
||||
extern int snd_pt2258_build_controls(struct snd_pt2258 *pt);
|
||||
|
||||
#endif /* __SOUND_PT2258_H */
|
|
@ -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 {
|
||||
|
|
286
include/sound/soc-dapm.h
Normal file
286
include/sound/soc-dapm.h
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
|
||||
*
|
||||
* Author: Liam Girdwood
|
||||
* Created: Aug 11th 2005
|
||||
* Copyright: Wolfson Microelectronics. PLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SND_SOC_DAPM_H
|
||||
#define __LINUX_SND_SOC_DAPM_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
/* widget has no PM register bit */
|
||||
#define SND_SOC_NOPM -1
|
||||
|
||||
/*
|
||||
* SoC dynamic audio power managment
|
||||
*
|
||||
* We can have upto 4 power domains
|
||||
* 1. Codec domain - VREF, VMID
|
||||
* Usually controlled at codec probe/remove, although can be set
|
||||
* at stream time if power is not needed for sidetone, etc.
|
||||
* 2. Platform/Machine domain - physically connected inputs and outputs
|
||||
* Is platform/machine and user action specific, is set in the machine
|
||||
* driver and by userspace e.g when HP are inserted
|
||||
* 3. Path domain - Internal codec path mixers
|
||||
* Are automatically set when mixer and mux settings are
|
||||
* changed by the user.
|
||||
* 4. Stream domain - DAC's and ADC's.
|
||||
* Enabled when stream playback/capture is started.
|
||||
*/
|
||||
|
||||
/* codec domain */
|
||||
#define SND_SOC_DAPM_VMID(wname) \
|
||||
{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0}
|
||||
|
||||
/* platform domain */
|
||||
#define SND_SOC_DAPM_INPUT(wname) \
|
||||
{ .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0}
|
||||
#define SND_SOC_DAPM_OUTPUT(wname) \
|
||||
{ .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0}
|
||||
#define SND_SOC_DAPM_MIC(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
|
||||
#define SND_SOC_DAPM_HP(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
|
||||
#define SND_SOC_DAPM_SPK(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
|
||||
#define SND_SOC_DAPM_LINE(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
|
||||
|
||||
/* path domain */
|
||||
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
|
||||
wcontrols, wncontrols) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
|
||||
wcontrols, wncontrols)\
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
|
||||
#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
|
||||
|
||||
/* path domain with event - event handler must return 0 for success */
|
||||
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
|
||||
/* events that are pre and post DAPM */
|
||||
#define SND_SOC_DAPM_PRE(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
|
||||
#define SND_SOC_DAPM_POST(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
|
||||
.num_kcontrols = 0, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
|
||||
|
||||
/* stream domain */
|
||||
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert}
|
||||
#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert}
|
||||
|
||||
/* dapm kcontrol types */
|
||||
#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
|
||||
#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \
|
||||
power) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
|
||||
((mask) << 16) | ((invert) << 24) }
|
||||
#define SOC_DAPM_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = snd_soc_dapm_get_enum_double, \
|
||||
.put = snd_soc_dapm_put_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
|
||||
/* dapm stream operations */
|
||||
#define SND_SOC_DAPM_STREAM_NOP 0x0
|
||||
#define SND_SOC_DAPM_STREAM_START 0x1
|
||||
#define SND_SOC_DAPM_STREAM_STOP 0x2
|
||||
#define SND_SOC_DAPM_STREAM_SUSPEND 0x4
|
||||
#define SND_SOC_DAPM_STREAM_RESUME 0x8
|
||||
#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
|
||||
#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20
|
||||
|
||||
/* dapm event types */
|
||||
#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
|
||||
#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
|
||||
#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
|
||||
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
|
||||
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
|
||||
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
|
||||
|
||||
/* convenience event type detection */
|
||||
#define SND_SOC_DAPM_EVENT_ON(e) \
|
||||
(e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
|
||||
#define SND_SOC_DAPM_EVENT_OFF(e) \
|
||||
(e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
|
||||
|
||||
struct snd_soc_dapm_widget;
|
||||
enum snd_soc_dapm_type;
|
||||
struct snd_soc_dapm_path;
|
||||
struct snd_soc_dapm_pin;
|
||||
|
||||
/* dapm controls */
|
||||
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
|
||||
const struct snd_soc_dapm_widget *widget);
|
||||
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
|
||||
const char *sink_name, const char *control_name, const char *src_name);
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
|
||||
void snd_soc_dapm_free(struct snd_soc_device *socdev);
|
||||
|
||||
/* dapm events */
|
||||
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
|
||||
int event);
|
||||
|
||||
/* dapm sys fs - used by the core */
|
||||
int snd_soc_dapm_sys_add(struct device *dev);
|
||||
|
||||
/* dapm audio endpoint control */
|
||||
int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
|
||||
char *pin, int status);
|
||||
int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec);
|
||||
|
||||
/* dapm widget types */
|
||||
enum snd_soc_dapm_type {
|
||||
snd_soc_dapm_input = 0, /* input pin */
|
||||
snd_soc_dapm_output, /* output pin */
|
||||
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_mixer, /* mixes several analog signals together */
|
||||
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
|
||||
snd_soc_dapm_adc, /* analog to digital converter */
|
||||
snd_soc_dapm_dac, /* digital to analog converter */
|
||||
snd_soc_dapm_micbias, /* microphone bias (power) */
|
||||
snd_soc_dapm_mic, /* microphone */
|
||||
snd_soc_dapm_hp, /* headphones */
|
||||
snd_soc_dapm_spk, /* speaker */
|
||||
snd_soc_dapm_line, /* line input/output */
|
||||
snd_soc_dapm_switch, /* analog switch */
|
||||
snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
|
||||
snd_soc_dapm_pre, /* machine specific pre widget - exec first */
|
||||
snd_soc_dapm_post, /* machine specific post widget - exec last */
|
||||
};
|
||||
|
||||
/* dapm audio path between two widgets */
|
||||
struct snd_soc_dapm_path {
|
||||
char *name;
|
||||
char *long_name;
|
||||
|
||||
/* source (input) and sink (output) widgets */
|
||||
struct snd_soc_dapm_widget *source;
|
||||
struct snd_soc_dapm_widget *sink;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
|
||||
/* status */
|
||||
u32 connect:1; /* source and sink widgets are connected */
|
||||
u32 walked:1; /* path has been walked */
|
||||
|
||||
struct list_head list_source;
|
||||
struct list_head list_sink;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/* dapm widget */
|
||||
struct snd_soc_dapm_widget {
|
||||
enum snd_soc_dapm_type id;
|
||||
char *name; /* widget name */
|
||||
char *sname; /* stream name */
|
||||
struct snd_soc_codec *codec;
|
||||
struct list_head list;
|
||||
|
||||
/* dapm control */
|
||||
short reg; /* negative reg = no direct dapm */
|
||||
unsigned char shift; /* bits to shift */
|
||||
unsigned int saved_value; /* widget saved value */
|
||||
unsigned int value; /* widget current value */
|
||||
unsigned char power:1; /* block power status */
|
||||
unsigned char invert:1; /* invert the power bit */
|
||||
unsigned char active:1; /* active stream on DAC, ADC's */
|
||||
unsigned char connected:1; /* connected codec pin */
|
||||
unsigned char new:1; /* cnew complete */
|
||||
unsigned char ext:1; /* has external widgets */
|
||||
unsigned char muted:1; /* muted for pop reduction */
|
||||
unsigned char suspend:1; /* was active before suspend */
|
||||
unsigned char pmdown:1; /* waiting for timeout */
|
||||
|
||||
/* external events */
|
||||
unsigned short event_flags; /* flags to specify event types */
|
||||
int (*event)(struct snd_soc_dapm_widget*, int);
|
||||
|
||||
/* kcontrols that relate to this widget */
|
||||
int num_kcontrols;
|
||||
const struct snd_kcontrol_new *kcontrols;
|
||||
|
||||
/* widget input and outputs */
|
||||
struct list_head sources;
|
||||
struct list_head sinks;
|
||||
};
|
||||
|
||||
#endif
|
461
include/sound/soc.h
Normal file
461
include/sound/soc.h
Normal file
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* linux/sound/soc.h -- ALSA SoC Layer
|
||||
*
|
||||
* Author: Liam Girdwood
|
||||
* Created: Aug 11th 2005
|
||||
* Copyright: Wolfson Microelectronics. PLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SND_SOC_H
|
||||
#define __LINUX_SND_SOC_H
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/driver.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
|
||||
#define SND_SOC_VERSION "0.13.0"
|
||||
|
||||
/*
|
||||
* Convenience kcontrol builders
|
||||
*/
|
||||
#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
|
||||
((shift) << 12) | ((mask) << 16) | ((invert) << 24))
|
||||
#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
|
||||
((invert) << 31))
|
||||
#define SOC_SINGLE(xname, reg, shift, mask, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
|
||||
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = (reg) | ((shift_left) << 8) | \
|
||||
((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
|
||||
#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.info = snd_soc_info_volsw_2r, \
|
||||
.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
|
||||
.private_value = (reg_left) | ((shift) << 8) | \
|
||||
((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
|
||||
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
|
||||
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
|
||||
.mask = xmask, .texts = xtexts }
|
||||
#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
|
||||
SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
|
||||
#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
|
||||
{ .mask = xmask, .texts = xtexts }
|
||||
#define SOC_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
|
||||
xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
|
||||
#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_bool_ext, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = xdata }
|
||||
#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_ext, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
|
||||
/*
|
||||
* Digital Audio Interface (DAI) types
|
||||
*/
|
||||
#define SND_SOC_DAI_AC97 0x1
|
||||
#define SND_SOC_DAI_I2S 0x2
|
||||
#define SND_SOC_DAI_PCM 0x4
|
||||
|
||||
/*
|
||||
* DAI hardware audio formats
|
||||
*/
|
||||
#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */
|
||||
#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */
|
||||
#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */
|
||||
#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */
|
||||
#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */
|
||||
#define SND_SOC_DAIFMT_AC97 5 /* AC97 */
|
||||
|
||||
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
|
||||
#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J
|
||||
|
||||
/*
|
||||
* DAI Gating
|
||||
*/
|
||||
#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */
|
||||
#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */
|
||||
|
||||
/*
|
||||
* DAI hardware signal inversions
|
||||
*/
|
||||
#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */
|
||||
#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */
|
||||
#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */
|
||||
#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */
|
||||
|
||||
/*
|
||||
* DAI hardware clock masters
|
||||
* This is wrt the codec, the inverse is true for the interface
|
||||
* i.e. if the codec is clk and frm master then the interface is
|
||||
* clk and frame slave.
|
||||
*/
|
||||
#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */
|
||||
#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */
|
||||
#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */
|
||||
#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */
|
||||
|
||||
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
|
||||
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
|
||||
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
|
||||
#define SND_SOC_DAIFMT_MASTER_MASK 0xf000
|
||||
|
||||
|
||||
/*
|
||||
* Master Clock Directions
|
||||
*/
|
||||
#define SND_SOC_CLOCK_IN 0
|
||||
#define SND_SOC_CLOCK_OUT 1
|
||||
|
||||
/*
|
||||
* AC97 codec ID's bitmask
|
||||
*/
|
||||
#define SND_SOC_DAI_AC97_ID0 (1 << 0)
|
||||
#define SND_SOC_DAI_AC97_ID1 (1 << 1)
|
||||
#define SND_SOC_DAI_AC97_ID2 (1 << 2)
|
||||
#define SND_SOC_DAI_AC97_ID3 (1 << 3)
|
||||
|
||||
struct snd_soc_device;
|
||||
struct snd_soc_pcm_stream;
|
||||
struct snd_soc_ops;
|
||||
struct snd_soc_dai_mode;
|
||||
struct snd_soc_pcm_runtime;
|
||||
struct snd_soc_codec_dai;
|
||||
struct snd_soc_cpu_dai;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_machine_config;
|
||||
struct soc_enum;
|
||||
struct snd_soc_ac97_ops;
|
||||
struct snd_soc_clock_info;
|
||||
|
||||
typedef int (*hw_write_t)(void *,const char* ,int);
|
||||
typedef int (*hw_read_t)(void *,char* ,int);
|
||||
|
||||
extern struct snd_ac97_bus_ops soc_ac97_ops;
|
||||
|
||||
/* pcm <-> DAI connect */
|
||||
void snd_soc_free_pcms(struct snd_soc_device *socdev);
|
||||
int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
|
||||
int snd_soc_register_card(struct snd_soc_device *socdev);
|
||||
|
||||
/* set runtime hw params */
|
||||
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
|
||||
const struct snd_pcm_hardware *hw);
|
||||
|
||||
/* codec IO */
|
||||
#define snd_soc_read(codec, reg) codec->read(codec, reg)
|
||||
#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
|
||||
|
||||
/* codec register bit access */
|
||||
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
|
||||
unsigned short mask, unsigned short value);
|
||||
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
|
||||
unsigned short mask, unsigned short value);
|
||||
|
||||
int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
|
||||
struct snd_ac97_bus_ops *ops, int num);
|
||||
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
|
||||
|
||||
/*
|
||||
*Controls
|
||||
*/
|
||||
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
|
||||
void *data, char *long_name);
|
||||
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
/* SoC PCM stream information */
|
||||
struct snd_soc_pcm_stream {
|
||||
char *stream_name;
|
||||
u64 formats; /* SNDRV_PCM_FMTBIT_* */
|
||||
unsigned int rates; /* SNDRV_PCM_RATE_* */
|
||||
unsigned int rate_min; /* min rate */
|
||||
unsigned int rate_max; /* max rate */
|
||||
unsigned int channels_min; /* min channels */
|
||||
unsigned int channels_max; /* max channels */
|
||||
unsigned int active:1; /* stream is in use */
|
||||
};
|
||||
|
||||
/* SoC audio ops */
|
||||
struct snd_soc_ops {
|
||||
int (*startup)(struct snd_pcm_substream *);
|
||||
void (*shutdown)(struct snd_pcm_substream *);
|
||||
int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
|
||||
int (*hw_free)(struct snd_pcm_substream *);
|
||||
int (*prepare)(struct snd_pcm_substream *);
|
||||
int (*trigger)(struct snd_pcm_substream *, int);
|
||||
};
|
||||
|
||||
/* ASoC codec DAI ops */
|
||||
struct snd_soc_codec_ops {
|
||||
/* codec DAI clocking configuration */
|
||||
int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir);
|
||||
int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
|
||||
int pll_id, unsigned int freq_in, unsigned int freq_out);
|
||||
int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
|
||||
int div_id, int div);
|
||||
|
||||
/* CPU DAI format configuration */
|
||||
int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
|
||||
unsigned int fmt);
|
||||
int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
|
||||
unsigned int mask, int slots);
|
||||
int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
|
||||
|
||||
/* digital mute */
|
||||
int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
|
||||
};
|
||||
|
||||
/* ASoC cpu DAI ops */
|
||||
struct snd_soc_cpu_ops {
|
||||
/* CPU DAI clocking configuration */
|
||||
int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
|
||||
int clk_id, unsigned int freq, int dir);
|
||||
int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
|
||||
int div_id, int div);
|
||||
int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
|
||||
int pll_id, unsigned int freq_in, unsigned int freq_out);
|
||||
|
||||
/* CPU DAI format configuration */
|
||||
int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
|
||||
unsigned int fmt);
|
||||
int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
|
||||
unsigned int mask, int slots);
|
||||
int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
|
||||
};
|
||||
|
||||
/* SoC Codec DAI */
|
||||
struct snd_soc_codec_dai {
|
||||
char *name;
|
||||
int id;
|
||||
|
||||
/* DAI capabilities */
|
||||
struct snd_soc_pcm_stream playback;
|
||||
struct snd_soc_pcm_stream capture;
|
||||
|
||||
/* DAI runtime info */
|
||||
struct snd_soc_codec *codec;
|
||||
unsigned int active;
|
||||
unsigned char pop_wait:1;
|
||||
|
||||
/* ops */
|
||||
struct snd_soc_ops ops;
|
||||
struct snd_soc_codec_ops dai_ops;
|
||||
|
||||
/* DAI private data */
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
/* SoC CPU DAI */
|
||||
struct snd_soc_cpu_dai {
|
||||
|
||||
/* DAI description */
|
||||
char *name;
|
||||
unsigned int id;
|
||||
unsigned char type;
|
||||
|
||||
/* DAI callbacks */
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
void (*remove)(struct platform_device *pdev);
|
||||
int (*suspend)(struct platform_device *pdev,
|
||||
struct snd_soc_cpu_dai *cpu_dai);
|
||||
int (*resume)(struct platform_device *pdev,
|
||||
struct snd_soc_cpu_dai *cpu_dai);
|
||||
|
||||
/* ops */
|
||||
struct snd_soc_ops ops;
|
||||
struct snd_soc_cpu_ops dai_ops;
|
||||
|
||||
/* DAI capabilities */
|
||||
struct snd_soc_pcm_stream capture;
|
||||
struct snd_soc_pcm_stream playback;
|
||||
|
||||
/* DAI runtime info */
|
||||
struct snd_pcm_runtime *runtime;
|
||||
unsigned char active:1;
|
||||
void *dma_data;
|
||||
|
||||
/* DAI private data */
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
/* SoC Audio Codec */
|
||||
struct snd_soc_codec {
|
||||
char *name;
|
||||
struct module *owner;
|
||||
struct mutex mutex;
|
||||
|
||||
/* callbacks */
|
||||
int (*dapm_event)(struct snd_soc_codec *codec, int event);
|
||||
|
||||
/* runtime */
|
||||
struct snd_card *card;
|
||||
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
|
||||
unsigned int active;
|
||||
unsigned int pcm_devs;
|
||||
void *private_data;
|
||||
|
||||
/* codec IO */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
hw_write_t hw_write;
|
||||
hw_read_t hw_read;
|
||||
void *reg_cache;
|
||||
short reg_cache_size;
|
||||
short reg_cache_step;
|
||||
|
||||
/* dapm */
|
||||
struct list_head dapm_widgets;
|
||||
struct list_head dapm_paths;
|
||||
unsigned int dapm_state;
|
||||
unsigned int suspend_dapm_state;
|
||||
struct delayed_work delayed_work;
|
||||
|
||||
/* codec DAI's */
|
||||
struct snd_soc_codec_dai *dai;
|
||||
unsigned int num_dai;
|
||||
};
|
||||
|
||||
/* codec device */
|
||||
struct snd_soc_codec_device {
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
int (*suspend)(struct platform_device *pdev, pm_message_t state);
|
||||
int (*resume)(struct platform_device *pdev);
|
||||
};
|
||||
|
||||
/* SoC platform interface */
|
||||
struct snd_soc_platform {
|
||||
char *name;
|
||||
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
int (*suspend)(struct platform_device *pdev,
|
||||
struct snd_soc_cpu_dai *cpu_dai);
|
||||
int (*resume)(struct platform_device *pdev,
|
||||
struct snd_soc_cpu_dai *cpu_dai);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
|
||||
struct snd_pcm *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* platform stream ops */
|
||||
struct snd_pcm_ops *pcm_ops;
|
||||
};
|
||||
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
struct snd_soc_dai_link {
|
||||
char *name; /* Codec name */
|
||||
char *stream_name; /* Stream name */
|
||||
|
||||
/* DAI */
|
||||
struct snd_soc_codec_dai *codec_dai;
|
||||
struct snd_soc_cpu_dai *cpu_dai;
|
||||
|
||||
/* machine stream operations */
|
||||
struct snd_soc_ops *ops;
|
||||
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_codec *codec);
|
||||
};
|
||||
|
||||
/* SoC machine */
|
||||
struct snd_soc_machine {
|
||||
char *name;
|
||||
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
|
||||
/* the pre and post PM functions are used to do any PM work before and
|
||||
* after the codec and DAI's do any PM work. */
|
||||
int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
|
||||
int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
|
||||
int (*resume_pre)(struct platform_device *pdev);
|
||||
int (*resume_post)(struct platform_device *pdev);
|
||||
|
||||
/* CPU <--> Codec DAI links */
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int num_links;
|
||||
};
|
||||
|
||||
/* SoC Device - the audio subsystem */
|
||||
struct snd_soc_device {
|
||||
struct device *dev;
|
||||
struct snd_soc_machine *machine;
|
||||
struct snd_soc_platform *platform;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_codec_device *codec_dev;
|
||||
struct delayed_work delayed_work;
|
||||
void *codec_data;
|
||||
};
|
||||
|
||||
/* runtime channel data */
|
||||
struct snd_soc_pcm_runtime {
|
||||
struct snd_soc_dai_link *dai;
|
||||
struct snd_soc_device *socdev;
|
||||
};
|
||||
|
||||
/* enumerated kcontrol */
|
||||
struct soc_enum {
|
||||
unsigned short reg;
|
||||
unsigned short reg2;
|
||||
unsigned char shift_l;
|
||||
unsigned char shift_r;
|
||||
unsigned int mask;
|
||||
const char **texts;
|
||||
void *dapm;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
* Typedef's for backward compatibility (for out-of-kernel drivers)
|
||||
*
|
||||
* This file will be removed soon in future
|
||||
*/
|
||||
|
||||
/* core stuff */
|
||||
typedef struct snd_card snd_card_t;
|
||||
typedef struct snd_device snd_device_t;
|
||||
typedef struct snd_device_ops snd_device_ops_t;
|
||||
typedef enum snd_card_type snd_card_type_t;
|
||||
typedef struct snd_minor snd_minor_t;
|
||||
|
||||
/* info */
|
||||
typedef struct snd_info_entry snd_info_entry_t;
|
||||
typedef struct snd_info_buffer snd_info_buffer_t;
|
||||
|
||||
/* control */
|
||||
typedef struct snd_ctl_file snd_ctl_file_t;
|
||||
typedef struct snd_kcontrol snd_kcontrol_t;
|
||||
typedef struct snd_kcontrol_new snd_kcontrol_new_t;
|
||||
typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t;
|
||||
typedef struct snd_kctl_event snd_kctl_event_t;
|
||||
typedef struct snd_aes_iec958 snd_aes_iec958_t;
|
||||
typedef struct snd_ctl_card_info snd_ctl_card_info_t;
|
||||
typedef struct snd_ctl_elem_id snd_ctl_elem_id_t;
|
||||
typedef struct snd_ctl_elem_list snd_ctl_elem_list_t;
|
||||
typedef struct snd_ctl_elem_info snd_ctl_elem_info_t;
|
||||
typedef struct snd_ctl_elem_value snd_ctl_elem_value_t;
|
||||
typedef struct snd_ctl_event snd_ctl_event_t;
|
||||
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
|
||||
typedef struct snd_mixer_oss snd_mixer_oss_t;
|
||||
#endif
|
||||
|
||||
/* timer */
|
||||
typedef struct snd_timer snd_timer_t;
|
||||
typedef struct snd_timer_instance snd_timer_instance_t;
|
||||
typedef struct snd_timer_id snd_timer_id_t;
|
||||
typedef struct snd_timer_ginfo snd_timer_ginfo_t;
|
||||
typedef struct snd_timer_gparams snd_timer_gparams_t;
|
||||
typedef struct snd_timer_gstatus snd_timer_gstatus_t;
|
||||
typedef struct snd_timer_select snd_timer_select_t;
|
||||
typedef struct snd_timer_info snd_timer_info_t;
|
||||
typedef struct snd_timer_params snd_timer_params_t;
|
||||
typedef struct snd_timer_status snd_timer_status_t;
|
||||
typedef struct snd_timer_read snd_timer_read_t;
|
||||
typedef struct snd_timer_tread snd_timer_tread_t;
|
||||
|
||||
/* PCM */
|
||||
typedef struct snd_pcm snd_pcm_t;
|
||||
typedef struct snd_pcm_str snd_pcm_str_t;
|
||||
typedef struct snd_pcm_substream snd_pcm_substream_t;
|
||||
typedef struct snd_pcm_info snd_pcm_info_t;
|
||||
typedef struct snd_pcm_hw_params snd_pcm_hw_params_t;
|
||||
typedef struct snd_pcm_sw_params snd_pcm_sw_params_t;
|
||||
typedef struct snd_pcm_channel_info snd_pcm_channel_info_t;
|
||||
typedef struct snd_pcm_status snd_pcm_status_t;
|
||||
typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t;
|
||||
typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t;
|
||||
typedef struct snd_mask snd_mask_t;
|
||||
typedef struct snd_sg_buf snd_pcm_sgbuf_t;
|
||||
|
||||
typedef struct snd_interval snd_interval_t;
|
||||
typedef struct snd_xferi snd_xferi_t;
|
||||
typedef struct snd_xfern snd_xfern_t;
|
||||
typedef struct snd_xferv snd_xferv_t;
|
||||
|
||||
typedef struct snd_pcm_file snd_pcm_file_t;
|
||||
typedef struct snd_pcm_runtime snd_pcm_runtime_t;
|
||||
typedef struct snd_pcm_hardware snd_pcm_hardware_t;
|
||||
typedef struct snd_pcm_ops snd_pcm_ops_t;
|
||||
typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t;
|
||||
typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t;
|
||||
typedef struct snd_ratnum ratnum_t;
|
||||
typedef struct snd_ratden ratden_t;
|
||||
typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t;
|
||||
typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t;
|
||||
typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t;
|
||||
typedef struct snd_pcm_group snd_pcm_group_t;
|
||||
typedef struct snd_pcm_notify snd_pcm_notify_t;
|
||||
|
||||
/* rawmidi */
|
||||
typedef struct snd_rawmidi snd_rawmidi_t;
|
||||
typedef struct snd_rawmidi_info snd_rawmidi_info_t;
|
||||
typedef struct snd_rawmidi_params snd_rawmidi_params_t;
|
||||
typedef struct snd_rawmidi_status snd_rawmidi_status_t;
|
||||
typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t;
|
||||
typedef struct snd_rawmidi_substream snd_rawmidi_substream_t;
|
||||
typedef struct snd_rawmidi_str snd_rawmidi_str_t;
|
||||
typedef struct snd_rawmidi_ops snd_rawmidi_ops_t;
|
||||
typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t;
|
||||
typedef struct snd_rawmidi_file snd_rawmidi_file_t;
|
||||
|
||||
/* hwdep */
|
||||
typedef struct snd_hwdep snd_hwdep_t;
|
||||
typedef struct snd_hwdep_info snd_hwdep_info_t;
|
||||
typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t;
|
||||
typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t;
|
||||
typedef struct snd_hwdep_ops snd_hwdep_ops_t;
|
||||
|
||||
/* sequencer */
|
||||
typedef struct snd_seq_port_info snd_seq_port_info_t;
|
||||
typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t;
|
||||
typedef struct snd_seq_event snd_seq_event_t;
|
||||
typedef struct snd_seq_addr snd_seq_addr_t;
|
||||
typedef struct snd_seq_ev_volume snd_seq_ev_volume_t;
|
||||
typedef struct snd_seq_ev_loop snd_seq_ev_loop_t;
|
||||
typedef struct snd_seq_remove_events snd_seq_remove_events_t;
|
||||
typedef struct snd_seq_query_subs snd_seq_query_subs_t;
|
||||
typedef struct snd_seq_system_info snd_seq_system_info_t;
|
||||
typedef struct snd_seq_client_info snd_seq_client_info_t;
|
||||
typedef struct snd_seq_queue_info snd_seq_queue_info_t;
|
||||
typedef struct snd_seq_queue_status snd_seq_queue_status_t;
|
||||
typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t;
|
||||
typedef struct snd_seq_queue_owner snd_seq_queue_owner_t;
|
||||
typedef struct snd_seq_queue_timer snd_seq_queue_timer_t;
|
||||
typedef struct snd_seq_queue_client snd_seq_queue_client_t;
|
||||
typedef struct snd_seq_client_pool snd_seq_client_pool_t;
|
||||
typedef struct snd_seq_instr snd_seq_instr_t;
|
||||
typedef struct snd_seq_instr_data snd_seq_instr_data_t;
|
||||
typedef struct snd_seq_instr_header snd_seq_instr_header_t;
|
||||
|
||||
typedef struct snd_seq_user_client user_client_t;
|
||||
typedef struct snd_seq_kernel_client kernel_client_t;
|
||||
typedef struct snd_seq_client client_t;
|
||||
typedef struct snd_seq_queue queue_t;
|
||||
|
||||
/* seq_device */
|
||||
typedef struct snd_seq_device snd_seq_device_t;
|
||||
typedef struct snd_seq_dev_ops snd_seq_dev_ops_t;
|
||||
|
||||
/* seq_midi */
|
||||
typedef struct snd_midi_event snd_midi_event_t;
|
||||
|
||||
/* seq_midi_emul */
|
||||
typedef struct snd_midi_channel snd_midi_channel_t;
|
||||
typedef struct snd_midi_channel_set snd_midi_channel_set_t;
|
||||
typedef struct snd_midi_op snd_midi_op_t;
|
||||
|
||||
/* seq_oss */
|
||||
typedef struct snd_seq_oss_arg snd_seq_oss_arg_t;
|
||||
typedef struct snd_seq_oss_callback snd_seq_oss_callback_t;
|
||||
typedef struct snd_seq_oss_reg snd_seq_oss_reg_t;
|
||||
|
||||
/* virmidi */
|
||||
typedef struct snd_virmidi_dev snd_virmidi_dev_t;
|
||||
typedef struct snd_virmidi snd_virmidi_t;
|
||||
|
||||
/* seq_instr */
|
||||
typedef struct snd_seq_kcluster snd_seq_kcluster_t;
|
||||
typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t;
|
||||
typedef struct snd_seq_kinstr snd_seq_kinstr_t;
|
||||
typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t;
|
||||
|
||||
/* ac97 */
|
||||
typedef struct snd_ac97_bus ac97_bus_t;
|
||||
typedef struct snd_ac97_bus_ops ac97_bus_ops_t;
|
||||
typedef struct snd_ac97_template ac97_template_t;
|
||||
typedef struct snd_ac97 ac97_t;
|
||||
|
||||
/* opl3/4 */
|
||||
typedef struct snd_opl3 opl3_t;
|
||||
typedef struct snd_opl4 opl4_t;
|
||||
|
||||
/* mpu401 */
|
||||
typedef struct snd_mpu401 mpu401_t;
|
||||
|
||||
/* i2c */
|
||||
typedef struct snd_i2c_device snd_i2c_device_t;
|
||||
typedef struct snd_i2c_bus snd_i2c_bus_t;
|
||||
|
||||
typedef struct snd_ak4531 ak4531_t;
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
/* include/version.h. Generated by alsa/ksync script. */
|
||||
#define CONFIG_SND_VERSION "1.0.14rc1"
|
||||
#define CONFIG_SND_DATE " (Tue Jan 09 09:56:17 2007 UTC)"
|
||||
#define CONFIG_SND_VERSION "1.0.14rc2"
|
||||
#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
|
|||
}
|
||||
/* bus dependent stuff */
|
||||
hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
|
||||
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_JOINT_DUPLEX;
|
||||
|
||||
CHECK_RATE(5512);
|
||||
CHECK_RATE(8000);
|
||||
|
@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
|
||||
struct pcm_info *pi)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct completion done;
|
||||
long timeout;
|
||||
|
||||
spin_lock_irqsave(&i2sdev->low_lock, flags);
|
||||
if (pi->dbdma_ring.stopping) {
|
||||
init_completion(&done);
|
||||
pi->stop_completion = &done;
|
||||
spin_unlock_irqrestore(&i2sdev->low_lock, flags);
|
||||
timeout = wait_for_completion_timeout(&done, HZ);
|
||||
spin_lock_irqsave(&i2sdev->low_lock, flags);
|
||||
pi->stop_completion = NULL;
|
||||
if (timeout == 0) {
|
||||
/* timeout expired, stop dbdma forcefully */
|
||||
printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
|
||||
/* make sure RUN, PAUSE and S0 bits are cleared */
|
||||
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
|
||||
pi->dbdma_ring.stopping = 0;
|
||||
timeout = 10;
|
||||
while (in_le32(&pi->dbdma->status) & ACTIVE) {
|
||||
if (--timeout <= 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&i2sdev->low_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
|
||||
{
|
||||
struct pcm_info *pi;
|
||||
|
||||
get_pcm_info(i2sdev, 0, &pi, NULL);
|
||||
i2sbus_wait_for_stop(i2sdev, pi);
|
||||
get_pcm_info(i2sdev, 1, &pi, NULL);
|
||||
i2sbus_wait_for_stop(i2sdev, pi);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int i2sbus_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
}
|
||||
|
||||
static int i2sbus_hw_free(struct snd_pcm_substream *substream)
|
||||
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
|
||||
{
|
||||
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
|
||||
struct pcm_info *pi;
|
||||
|
||||
get_pcm_info(i2sdev, in, &pi, NULL);
|
||||
if (pi->dbdma_ring.stopping)
|
||||
i2sbus_wait_for_stop(i2sdev, pi);
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return i2sbus_hw_free(substream, 0);
|
||||
}
|
||||
|
||||
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return i2sbus_hw_free(substream, 1);
|
||||
}
|
||||
|
||||
static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
{
|
||||
/* whee. Hard work now. The user has selected a bitrate
|
||||
|
@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
|||
* I2S controller appropriately. */
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct dbdma_cmd *command;
|
||||
int i, periodsize;
|
||||
int i, periodsize, nperiods;
|
||||
dma_addr_t offset;
|
||||
struct bus_info bi;
|
||||
struct codec_info_item *cii;
|
||||
|
@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
|||
struct pcm_info *pi, *other;
|
||||
int cnt;
|
||||
int result = 0;
|
||||
unsigned int cmd, stopaddr;
|
||||
|
||||
mutex_lock(&i2sdev->lock);
|
||||
|
||||
|
@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
|||
result = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
if (pi->dbdma_ring.stopping)
|
||||
i2sbus_wait_for_stop(i2sdev, pi);
|
||||
|
||||
if (!pi->substream || !pi->substream->runtime) {
|
||||
result = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
runtime = pi->substream->runtime;
|
||||
pi->active = 1;
|
||||
|
@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
|||
i2sdev->rate = runtime->rate;
|
||||
|
||||
periodsize = snd_pcm_lib_period_bytes(pi->substream);
|
||||
nperiods = pi->substream->runtime->periods;
|
||||
pi->current_period = 0;
|
||||
|
||||
/* generate dbdma command ring first */
|
||||
command = pi->dbdma_ring.cmds;
|
||||
memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
|
||||
|
||||
/* commands to DMA to/from the ring */
|
||||
/*
|
||||
* For input, we need to do a graceful stop; if we abort
|
||||
* the DMA, we end up with leftover bytes that corrupt
|
||||
* the next recording. To do this we set the S0 status
|
||||
* bit and wait for the DMA controller to stop. Each
|
||||
* command has a branch condition to
|
||||
* make it branch to a stop command if S0 is set.
|
||||
* On input we also need to wait for the S7 bit to be
|
||||
* set before turning off the DMA controller.
|
||||
* In fact we do the graceful stop for output as well.
|
||||
*/
|
||||
offset = runtime->dma_addr;
|
||||
for (i = 0; i < pi->substream->runtime->periods;
|
||||
i++, command++, offset += periodsize) {
|
||||
memset(command, 0, sizeof(struct dbdma_cmd));
|
||||
command->command =
|
||||
cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
|
||||
cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
|
||||
stopaddr = pi->dbdma_ring.bus_cmd_start +
|
||||
(nperiods + 1) * sizeof(struct dbdma_cmd);
|
||||
for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
|
||||
command->command = cpu_to_le16(cmd);
|
||||
command->cmd_dep = cpu_to_le32(stopaddr);
|
||||
command->phy_addr = cpu_to_le32(offset);
|
||||
command->req_count = cpu_to_le16(periodsize);
|
||||
command->xfer_status = cpu_to_le16(0);
|
||||
}
|
||||
/* last one branches back to first */
|
||||
command--;
|
||||
command->command |= cpu_to_le16(BR_ALWAYS);
|
||||
|
||||
/* branch back to beginning of ring */
|
||||
command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
|
||||
command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
|
||||
command++;
|
||||
|
||||
/* set stop command */
|
||||
command->command = cpu_to_le16(DBDMA_STOP);
|
||||
|
||||
/* ok, let's set the serial format and stuff */
|
||||
switch (runtime->format) {
|
||||
|
@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
|||
return result;
|
||||
}
|
||||
|
||||
static struct dbdma_cmd STOP_CMD = {
|
||||
.command = __constant_cpu_to_le16(DBDMA_STOP),
|
||||
};
|
||||
#ifdef CONFIG_PM
|
||||
void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
|
||||
{
|
||||
i2sbus_pcm_prepare(i2sdev, 0);
|
||||
i2sbus_pcm_prepare(i2sdev, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
|
||||
{
|
||||
struct codec_info_item *cii;
|
||||
struct pcm_info *pi;
|
||||
int timeout;
|
||||
struct dbdma_cmd tmp;
|
||||
int result = 0;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
|
|||
cii->codec->start(cii, pi->substream);
|
||||
pi->dbdma_ring.running = 1;
|
||||
|
||||
/* reset dma engine */
|
||||
out_le32(&pi->dbdma->control,
|
||||
0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
|
||||
timeout = 100;
|
||||
while (in_le32(&pi->dbdma->status) & RUN && timeout--)
|
||||
udelay(1);
|
||||
if (timeout <= 0) {
|
||||
printk(KERN_ERR
|
||||
"i2sbus: error waiting for dma reset\n");
|
||||
result = -ENXIO;
|
||||
goto out_unlock;
|
||||
if (pi->dbdma_ring.stopping) {
|
||||
/* Clear the S0 bit, then see if we stopped yet */
|
||||
out_le32(&pi->dbdma->control, 1 << 16);
|
||||
if (in_le32(&pi->dbdma->status) & ACTIVE) {
|
||||
/* possible race here? */
|
||||
udelay(10);
|
||||
if (in_le32(&pi->dbdma->status) & ACTIVE) {
|
||||
pi->dbdma_ring.stopping = 0;
|
||||
goto out_unlock; /* keep running */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure RUN, PAUSE and S0 bits are cleared */
|
||||
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
|
||||
|
||||
/* set branch condition select register */
|
||||
out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
|
||||
|
||||
/* write dma command buffer address to the dbdma chip */
|
||||
out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
|
||||
/* post PCI write */
|
||||
mb();
|
||||
(void)in_le32(&pi->dbdma->status);
|
||||
|
||||
/* change first command to STOP */
|
||||
tmp = *pi->dbdma_ring.cmds;
|
||||
*pi->dbdma_ring.cmds = STOP_CMD;
|
||||
|
||||
/* set running state, remember that the first command is STOP */
|
||||
out_le32(&pi->dbdma->control, RUN | (RUN << 16));
|
||||
timeout = 100;
|
||||
/* wait for STOP to be executed */
|
||||
while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
|
||||
udelay(1);
|
||||
if (timeout <= 0) {
|
||||
printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
|
||||
result = -ENXIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
/* again, write dma command buffer address to the dbdma chip,
|
||||
* this time of the first real command */
|
||||
*pi->dbdma_ring.cmds = tmp;
|
||||
out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
|
||||
/* post write */
|
||||
mb();
|
||||
(void)in_le32(&pi->dbdma->status);
|
||||
|
||||
/* reset dma engine again */
|
||||
out_le32(&pi->dbdma->control,
|
||||
0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
|
||||
timeout = 100;
|
||||
while (in_le32(&pi->dbdma->status) & RUN && timeout--)
|
||||
udelay(1);
|
||||
if (timeout <= 0) {
|
||||
printk(KERN_ERR
|
||||
"i2sbus: error waiting for dma reset\n");
|
||||
result = -ENXIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* wake up the chip with the next descriptor */
|
||||
out_le32(&pi->dbdma->control,
|
||||
(RUN | WAKE) | ((RUN | WAKE) << 16));
|
||||
/* get the frame count */
|
||||
/* initialize the frame count and current period */
|
||||
pi->current_period = 0;
|
||||
pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
|
||||
|
||||
/* set the DMA controller running */
|
||||
out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
|
||||
|
||||
/* off you go! */
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
if (!pi->dbdma_ring.running) {
|
||||
result = -EALREADY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* turn off all relevant bits */
|
||||
out_le32(&pi->dbdma->control,
|
||||
(RUN | WAKE | FLUSH | PAUSE) << 16);
|
||||
{
|
||||
/* FIXME: move to own function */
|
||||
int timeout = 5000;
|
||||
while ((in_le32(&pi->dbdma->status) & RUN)
|
||||
&& --timeout > 0)
|
||||
udelay(1);
|
||||
if (!timeout)
|
||||
printk(KERN_ERR
|
||||
"i2sbus: timed out turning "
|
||||
"off dbdma engine!\n");
|
||||
}
|
||||
|
||||
pi->dbdma_ring.running = 0;
|
||||
|
||||
/* Set the S0 bit to make the DMA branch to the stop cmd */
|
||||
out_le32(&pi->dbdma->control, (1 << 16) | 1);
|
||||
pi->dbdma_ring.stopping = 1;
|
||||
|
||||
list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
|
||||
if (cii->codec->stop)
|
||||
cii->codec->stop(cii, pi->substream);
|
||||
|
@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
|
|||
fc = in_le32(&i2sdev->intfregs->frame_count);
|
||||
fc = fc - pi->frame_count;
|
||||
|
||||
return (bytes_to_frames(pi->substream->runtime,
|
||||
pi->current_period *
|
||||
snd_pcm_lib_period_bytes(pi->substream))
|
||||
+ fc) % pi->substream->runtime->buffer_size;
|
||||
if (fc >= pi->substream->runtime->buffer_size)
|
||||
fc %= pi->substream->runtime->buffer_size;
|
||||
return fc;
|
||||
}
|
||||
|
||||
static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
|
||||
{
|
||||
struct pcm_info *pi;
|
||||
u32 fc;
|
||||
u32 delta;
|
||||
u32 fc, nframes;
|
||||
u32 status;
|
||||
int timeout, i;
|
||||
int dma_stopped = 0;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
spin_lock(&i2sdev->low_lock);
|
||||
get_pcm_info(i2sdev, in, &pi, NULL);
|
||||
|
||||
if (!pi->dbdma_ring.running) {
|
||||
/* there was still an interrupt pending
|
||||
* while we stopped. or maybe another
|
||||
* processor (not the one that was stopping
|
||||
* the DMA engine) was spinning above
|
||||
* waiting for the lock. */
|
||||
if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
fc = in_le32(&i2sdev->intfregs->frame_count);
|
||||
/* a counter overflow does not change the calculation. */
|
||||
delta = fc - pi->frame_count;
|
||||
i = pi->current_period;
|
||||
runtime = pi->substream->runtime;
|
||||
while (pi->dbdma_ring.cmds[i].xfer_status) {
|
||||
if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
|
||||
/*
|
||||
* BT is the branch taken bit. If it took a branch
|
||||
* it is because we set the S0 bit to make it
|
||||
* branch to the stop command.
|
||||
*/
|
||||
dma_stopped = 1;
|
||||
pi->dbdma_ring.cmds[i].xfer_status = 0;
|
||||
|
||||
/* update current_period */
|
||||
while (delta >= pi->substream->runtime->period_size) {
|
||||
pi->current_period++;
|
||||
delta = delta - pi->substream->runtime->period_size;
|
||||
}
|
||||
|
||||
if (unlikely(delta)) {
|
||||
/* Some interrupt came late, so check the dbdma.
|
||||
* This special case exists to syncronize the frame_count with
|
||||
* the dbdma transfer, but is hit every once in a while. */
|
||||
int period;
|
||||
|
||||
period = (in_le32(&pi->dbdma->cmdptr)
|
||||
- pi->dbdma_ring.bus_cmd_start)
|
||||
/ sizeof(struct dbdma_cmd);
|
||||
pi->current_period = pi->current_period
|
||||
% pi->substream->runtime->periods;
|
||||
|
||||
while (pi->current_period != period) {
|
||||
pi->current_period++;
|
||||
pi->current_period %= pi->substream->runtime->periods;
|
||||
/* Set delta to zero, as the frame_count value is too
|
||||
* high (otherwise the code path will not be executed).
|
||||
* This corrects the fact that the frame_count is too
|
||||
* low at the beginning due to buffering. */
|
||||
delta = 0;
|
||||
if (++i >= runtime->periods) {
|
||||
i = 0;
|
||||
pi->frame_count += runtime->buffer_size;
|
||||
}
|
||||
pi->current_period = i;
|
||||
|
||||
/*
|
||||
* Check the frame count. The DMA tends to get a bit
|
||||
* ahead of the frame counter, which confuses the core.
|
||||
*/
|
||||
fc = in_le32(&i2sdev->intfregs->frame_count);
|
||||
nframes = i * runtime->period_size;
|
||||
if (fc < pi->frame_count + nframes)
|
||||
pi->frame_count = fc - nframes;
|
||||
}
|
||||
|
||||
pi->frame_count = fc - delta;
|
||||
pi->current_period %= pi->substream->runtime->periods;
|
||||
if (dma_stopped) {
|
||||
timeout = 1000;
|
||||
for (;;) {
|
||||
status = in_le32(&pi->dbdma->status);
|
||||
if (!(status & ACTIVE) && (!in || (status & 0x80)))
|
||||
break;
|
||||
if (--timeout <= 0) {
|
||||
printk(KERN_ERR "i2sbus: timed out "
|
||||
"waiting for DMA to stop!\n");
|
||||
break;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* Turn off DMA controller, clear S0 bit */
|
||||
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
|
||||
|
||||
pi->dbdma_ring.stopping = 0;
|
||||
if (pi->stop_completion)
|
||||
complete(pi->stop_completion);
|
||||
}
|
||||
|
||||
if (!pi->dbdma_ring.running)
|
||||
goto out_unlock;
|
||||
spin_unlock(&i2sdev->low_lock);
|
||||
/* may call _trigger again, hence needs to be unlocked */
|
||||
snd_pcm_period_elapsed(pi->substream);
|
||||
return;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&i2sdev->low_lock);
|
||||
}
|
||||
|
@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = {
|
|||
.close = i2sbus_playback_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = i2sbus_hw_params,
|
||||
.hw_free = i2sbus_hw_free,
|
||||
.hw_free = i2sbus_playback_hw_free,
|
||||
.prepare = i2sbus_playback_prepare,
|
||||
.trigger = i2sbus_playback_trigger,
|
||||
.pointer = i2sbus_playback_pointer,
|
||||
|
@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = {
|
|||
.close = i2sbus_record_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = i2sbus_hw_params,
|
||||
.hw_free = i2sbus_hw_free,
|
||||
.hw_free = i2sbus_record_hw_free,
|
||||
.prepare = i2sbus_record_prepare,
|
||||
.trigger = i2sbus_record_trigger,
|
||||
.pointer = i2sbus_record_pointer,
|
||||
|
@ -812,7 +872,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm)
|
|||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/* FIXME: this function needs an error handling strategy with labels */
|
||||
int
|
||||
i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
||||
struct codec_info *ci, void *data)
|
||||
|
@ -880,41 +939,31 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
if (!cii->sdev) {
|
||||
printk(KERN_DEBUG
|
||||
"i2sbus: failed to get soundbus dev reference\n");
|
||||
kfree(cii);
|
||||
return -ENODEV;
|
||||
err = -ENODEV;
|
||||
goto out_free_cii;
|
||||
}
|
||||
|
||||
if (!try_module_get(THIS_MODULE)) {
|
||||
printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
|
||||
soundbus_dev_put(dev);
|
||||
kfree(cii);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto out_put_sdev;
|
||||
}
|
||||
|
||||
if (!try_module_get(ci->owner)) {
|
||||
printk(KERN_DEBUG
|
||||
"i2sbus: failed to get module reference to codec owner!\n");
|
||||
module_put(THIS_MODULE);
|
||||
soundbus_dev_put(dev);
|
||||
kfree(cii);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto out_put_this_module;
|
||||
}
|
||||
|
||||
if (!dev->pcm) {
|
||||
err = snd_pcm_new(card,
|
||||
dev->pcmname,
|
||||
dev->pcmid,
|
||||
0,
|
||||
0,
|
||||
err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0,
|
||||
&dev->pcm);
|
||||
if (err) {
|
||||
printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
|
||||
kfree(cii);
|
||||
module_put(ci->owner);
|
||||
soundbus_dev_put(dev);
|
||||
module_put(THIS_MODULE);
|
||||
return err;
|
||||
goto out_put_ci_module;
|
||||
}
|
||||
dev->pcm->dev = &dev->ofdev.dev;
|
||||
}
|
||||
|
||||
/* ALSA yet again sucks.
|
||||
|
@ -926,20 +975,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
/* eh? */
|
||||
printk(KERN_ERR
|
||||
"Can't attach same bus to different cards!\n");
|
||||
module_put(ci->owner);
|
||||
kfree(cii);
|
||||
soundbus_dev_put(dev);
|
||||
module_put(THIS_MODULE);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err =
|
||||
snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
|
||||
module_put(ci->owner);
|
||||
kfree(cii);
|
||||
soundbus_dev_put(dev);
|
||||
module_put(THIS_MODULE);
|
||||
return err;
|
||||
err = -EINVAL;
|
||||
goto out_put_ci_module;
|
||||
}
|
||||
err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
|
||||
if (err)
|
||||
goto out_put_ci_module;
|
||||
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
&i2sbus_playback_ops);
|
||||
i2sdev->out.created = 1;
|
||||
|
@ -949,20 +990,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
if (dev->pcm->card != card) {
|
||||
printk(KERN_ERR
|
||||
"Can't attach same bus to different cards!\n");
|
||||
module_put(ci->owner);
|
||||
kfree(cii);
|
||||
soundbus_dev_put(dev);
|
||||
module_put(THIS_MODULE);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err =
|
||||
snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
|
||||
module_put(ci->owner);
|
||||
kfree(cii);
|
||||
soundbus_dev_put(dev);
|
||||
module_put(THIS_MODULE);
|
||||
return err;
|
||||
goto out_put_ci_module;
|
||||
}
|
||||
err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
|
||||
if (err)
|
||||
goto out_put_ci_module;
|
||||
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
|
||||
&i2sbus_record_ops);
|
||||
i2sdev->in.created = 1;
|
||||
|
@ -977,11 +1009,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
err = snd_device_register(card, dev->pcm);
|
||||
if (err) {
|
||||
printk(KERN_ERR "i2sbus: error registering new pcm\n");
|
||||
module_put(ci->owner);
|
||||
kfree(cii);
|
||||
soundbus_dev_put(dev);
|
||||
module_put(THIS_MODULE);
|
||||
return err;
|
||||
goto out_put_ci_module;
|
||||
}
|
||||
/* no errors any more, so let's add this to our list */
|
||||
list_add(&cii->list, &dev->codec_list);
|
||||
|
@ -996,6 +1024,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
|
|||
64 * 1024, 64 * 1024);
|
||||
|
||||
return 0;
|
||||
out_put_ci_module:
|
||||
module_put(ci->owner);
|
||||
out_put_this_module:
|
||||
module_put(THIS_MODULE);
|
||||
out_put_sdev:
|
||||
soundbus_dev_put(dev);
|
||||
out_free_cii:
|
||||
kfree(cii);
|
||||
return err;
|
||||
}
|
||||
|
||||
void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
|
||||
|
|
|
@ -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(®ister_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(®ister_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(®ister_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(®ister_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(®ister_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(®ister_mutex);
|
||||
if (nfree) {
|
||||
list_del(¬ify->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(¬ify->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(®ister_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(®ister_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(®ister_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
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
#include <sound/minors.h>
|
||||
#include <sound/initval.h>
|
||||
#include <linux/kmod.h>
|
||||
#ifdef CONFIG_KERNELD
|
||||
#include <linux/kerneld.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
|
||||
#define DEFAULT_TIMER_LIMIT 3
|
||||
|
@ -130,11 +127,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner,
|
|||
static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
|
||||
{
|
||||
struct snd_timer *timer = NULL;
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, &snd_timer_list) {
|
||||
timer = list_entry(p, struct snd_timer, device_list);
|
||||
|
||||
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
||||
if (timer->tmr_class != tid->dev_class)
|
||||
continue;
|
||||
if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
|
||||
|
@ -184,13 +178,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
|
|||
{
|
||||
struct snd_timer *timer;
|
||||
struct snd_timer_instance *master;
|
||||
struct list_head *p, *q;
|
||||
|
||||
/* FIXME: it's really dumb to look up all entries.. */
|
||||
list_for_each(p, &snd_timer_list) {
|
||||
timer = list_entry(p, struct snd_timer, device_list);
|
||||
list_for_each(q, &timer->open_list_head) {
|
||||
master = list_entry(q, struct snd_timer_instance, open_list);
|
||||
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
||||
list_for_each_entry(master, &timer->open_list_head, open_list) {
|
||||
if (slave->slave_class == master->slave_class &&
|
||||
slave->slave_id == master->slave_id) {
|
||||
list_del(&slave->open_list);
|
||||
|
@ -214,16 +205,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
|
|||
*/
|
||||
static void snd_timer_check_master(struct snd_timer_instance *master)
|
||||
{
|
||||
struct snd_timer_instance *slave;
|
||||
struct list_head *p, *n;
|
||||
struct snd_timer_instance *slave, *tmp;
|
||||
|
||||
/* check all pending slaves */
|
||||
list_for_each_safe(p, n, &snd_timer_slave_list) {
|
||||
slave = list_entry(p, struct snd_timer_instance, open_list);
|
||||
list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
|
||||
if (slave->slave_class == master->slave_class &&
|
||||
slave->slave_id == master->slave_id) {
|
||||
list_del(p);
|
||||
list_add_tail(p, &master->slave_list_head);
|
||||
list_move_tail(&slave->open_list, &master->slave_list_head);
|
||||
spin_lock_irq(&slave_active_lock);
|
||||
slave->master = master;
|
||||
slave->timer = master->timer;
|
||||
|
@ -317,8 +305,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri,
|
|||
int snd_timer_close(struct snd_timer_instance *timeri)
|
||||
{
|
||||
struct snd_timer *timer = NULL;
|
||||
struct list_head *p, *n;
|
||||
struct snd_timer_instance *slave;
|
||||
struct snd_timer_instance *slave, *tmp;
|
||||
|
||||
snd_assert(timeri != NULL, return -ENXIO);
|
||||
|
||||
|
@ -353,12 +340,11 @@ int snd_timer_close(struct snd_timer_instance *timeri)
|
|||
timer->hw.close)
|
||||
timer->hw.close(timer);
|
||||
/* remove slave links */
|
||||
list_for_each_safe(p, n, &timeri->slave_list_head) {
|
||||
slave = list_entry(p, struct snd_timer_instance, open_list);
|
||||
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
|
||||
open_list) {
|
||||
spin_lock_irq(&slave_active_lock);
|
||||
_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
|
||||
list_del(p);
|
||||
list_add_tail(p, &snd_timer_slave_list);
|
||||
list_move_tail(&slave->open_list, &snd_timer_slave_list);
|
||||
slave->master = NULL;
|
||||
slave->timer = NULL;
|
||||
spin_unlock_irq(&slave_active_lock);
|
||||
|
@ -394,7 +380,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
|
|||
unsigned long flags;
|
||||
unsigned long resolution = 0;
|
||||
struct snd_timer_instance *ts;
|
||||
struct list_head *n;
|
||||
struct timespec tstamp;
|
||||
|
||||
getnstimeofday(&tstamp);
|
||||
|
@ -413,11 +398,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
|
|||
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
|
||||
return;
|
||||
spin_lock_irqsave(&timer->lock, flags);
|
||||
list_for_each(n, &ti->slave_active_head) {
|
||||
ts = list_entry(n, struct snd_timer_instance, active_list);
|
||||
list_for_each_entry(ts, &ti->slave_active_head, active_list)
|
||||
if (ts->ccallback)
|
||||
ts->ccallback(ti, event + 100, &tstamp, resolution);
|
||||
}
|
||||
spin_unlock_irqrestore(&timer->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -593,10 +576,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
|
|||
{
|
||||
struct snd_timer_instance *ti;
|
||||
unsigned long ticks = ~0UL;
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, &timer->active_list_head) {
|
||||
ti = list_entry(p, struct snd_timer_instance, active_list);
|
||||
list_for_each_entry(ti, &timer->active_list_head, active_list) {
|
||||
if (ti->flags & SNDRV_TIMER_IFLG_START) {
|
||||
ti->flags &= ~SNDRV_TIMER_IFLG_START;
|
||||
ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
|
||||
|
@ -661,9 +642,9 @@ static void snd_timer_tasklet(unsigned long arg)
|
|||
*/
|
||||
void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
||||
{
|
||||
struct snd_timer_instance *ti, *ts;
|
||||
struct snd_timer_instance *ti, *ts, *tmp;
|
||||
unsigned long resolution, ticks;
|
||||
struct list_head *p, *q, *n, *ack_list_head;
|
||||
struct list_head *p, *ack_list_head;
|
||||
unsigned long flags;
|
||||
int use_tasklet = 0;
|
||||
|
||||
|
@ -679,12 +660,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
resolution = timer->hw.resolution;
|
||||
|
||||
/* loop for all active instances
|
||||
* Here we cannot use list_for_each because the active_list of a
|
||||
* Here we cannot use list_for_each_entry because the active_list of a
|
||||
* processed instance is relinked to done_list_head before the callback
|
||||
* is called.
|
||||
*/
|
||||
list_for_each_safe(p, n, &timer->active_list_head) {
|
||||
ti = list_entry(p, struct snd_timer_instance, active_list);
|
||||
list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
|
||||
active_list) {
|
||||
if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
|
||||
continue;
|
||||
ti->pticks += ticks_left;
|
||||
|
@ -700,7 +681,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
} else {
|
||||
ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
|
||||
if (--timer->running)
|
||||
list_del(p);
|
||||
list_del(&ti->active_list);
|
||||
}
|
||||
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
|
||||
(ti->flags & SNDRV_TIMER_IFLG_FAST))
|
||||
|
@ -709,8 +690,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
ack_list_head = &timer->sack_list_head;
|
||||
if (list_empty(&ti->ack_list))
|
||||
list_add_tail(&ti->ack_list, ack_list_head);
|
||||
list_for_each(q, &ti->slave_active_head) {
|
||||
ts = list_entry(q, struct snd_timer_instance, active_list);
|
||||
list_for_each_entry(ts, &ti->slave_active_head, active_list) {
|
||||
ts->pticks = ti->pticks;
|
||||
ts->resolution = resolution;
|
||||
if (list_empty(&ts->ack_list))
|
||||
|
@ -844,7 +824,6 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
|||
{
|
||||
struct snd_timer *timer = dev->device_data;
|
||||
struct snd_timer *timer1;
|
||||
struct list_head *p;
|
||||
|
||||
snd_assert(timer != NULL && timer->hw.start != NULL &&
|
||||
timer->hw.stop != NULL, return -ENXIO);
|
||||
|
@ -853,8 +832,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
|||
return -EINVAL;
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
list_for_each(p, &snd_timer_list) {
|
||||
timer1 = list_entry(p, struct snd_timer, device_list);
|
||||
list_for_each_entry(timer1, &snd_timer_list, device_list) {
|
||||
if (timer1->tmr_class > timer->tmr_class)
|
||||
break;
|
||||
if (timer1->tmr_class < timer->tmr_class)
|
||||
|
@ -877,7 +855,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
|||
mutex_unlock(®ister_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
list_add_tail(&timer->device_list, p);
|
||||
list_add_tail(&timer->device_list, &timer1->device_list);
|
||||
mutex_unlock(®ister_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -896,7 +874,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
|
|||
unsigned long flags;
|
||||
unsigned long resolution = 0;
|
||||
struct snd_timer_instance *ti, *ts;
|
||||
struct list_head *p, *n;
|
||||
|
||||
if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
|
||||
return;
|
||||
|
@ -911,15 +888,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
|
|||
else
|
||||
resolution = timer->hw.resolution;
|
||||
}
|
||||
list_for_each(p, &timer->active_list_head) {
|
||||
ti = list_entry(p, struct snd_timer_instance, active_list);
|
||||
list_for_each_entry(ti, &timer->active_list_head, active_list) {
|
||||
if (ti->ccallback)
|
||||
ti->ccallback(ti, event, tstamp, resolution);
|
||||
list_for_each(n, &ti->slave_active_head) {
|
||||
ts = list_entry(n, struct snd_timer_instance, active_list);
|
||||
list_for_each_entry(ts, &ti->slave_active_head, active_list)
|
||||
if (ts->ccallback)
|
||||
ts->ccallback(ts, event, tstamp, resolution);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&timer->lock, flags);
|
||||
}
|
||||
|
@ -1057,11 +1031,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
|
|||
{
|
||||
struct snd_timer *timer;
|
||||
struct snd_timer_instance *ti;
|
||||
struct list_head *p, *q;
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
list_for_each(p, &snd_timer_list) {
|
||||
timer = list_entry(p, struct snd_timer, device_list);
|
||||
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
||||
switch (timer->tmr_class) {
|
||||
case SNDRV_TIMER_CLASS_GLOBAL:
|
||||
snd_iprintf(buffer, "G%i: ", timer->tmr_device);
|
||||
|
@ -1088,14 +1060,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
|
|||
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
|
||||
snd_iprintf(buffer, " SLAVE");
|
||||
snd_iprintf(buffer, "\n");
|
||||
list_for_each(q, &timer->open_list_head) {
|
||||
ti = list_entry(q, struct snd_timer_instance, open_list);
|
||||
list_for_each_entry(ti, &timer->open_list_head, open_list)
|
||||
snd_iprintf(buffer, " Client %s : %s\n",
|
||||
ti->owner ? ti->owner : "unknown",
|
||||
ti->flags & (SNDRV_TIMER_IFLG_START |
|
||||
SNDRV_TIMER_IFLG_RUNNING)
|
||||
? "running" : "stopped");
|
||||
}
|
||||
}
|
||||
mutex_unlock(®ister_mutex);
|
||||
}
|
||||
|
|
|
@ -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, \
|
||||
|
|
876
sound/drivers/portman2x4.c
Normal file
876
sound/drivers/portman2x4.c
Normal file
|
@ -0,0 +1,876 @@
|
|||
/*
|
||||
* Driver for Midiman Portman2x4 parallel port midi interface
|
||||
*
|
||||
* Copyright (c) by Levent Guendogdu <levon@feature-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* ChangeLog
|
||||
* Jan 24 2007 Matthias Koenig <mkoenig@suse.de>
|
||||
* - cleanup and rewrite
|
||||
* Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk>
|
||||
* - source code cleanup
|
||||
* Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk>
|
||||
* - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES,
|
||||
* MODULE_PARM_SYNTAX and changed MODULE_DEVICES to
|
||||
* MODULE_SUPPORTED_DEVICE)
|
||||
* Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk>
|
||||
* - added 2.6 kernel support
|
||||
* Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk>
|
||||
* - added parport_unregister_driver to the startup routine if the driver fails to detect a portman
|
||||
* - added support for all 4 output ports in portman_putmidi
|
||||
* Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk>
|
||||
* - added checks for opened input device in interrupt handler
|
||||
* Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk>
|
||||
* - ported from alsa 0.5 to 1.0
|
||||
*/
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/parport.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <sound/control.h>
|
||||
|
||||
#define CARD_NAME "Portman 2x4"
|
||||
#define DRIVER_NAME "portman"
|
||||
#define PLATFORM_DRIVER "snd_portman2x4"
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
|
||||
|
||||
static struct platform_device *platform_devices[SNDRV_CARDS];
|
||||
static int device_count;
|
||||
|
||||
module_param_array(index, int, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
|
||||
module_param_array(id, charp, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
|
||||
module_param_array(enable, bool, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
|
||||
|
||||
MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig");
|
||||
MODULE_DESCRIPTION("Midiman Portman2x4");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}");
|
||||
|
||||
/*********************************************************************
|
||||
* Chip specific
|
||||
*********************************************************************/
|
||||
#define PORTMAN_NUM_INPUT_PORTS 2
|
||||
#define PORTMAN_NUM_OUTPUT_PORTS 4
|
||||
|
||||
struct portman {
|
||||
spinlock_t reg_lock;
|
||||
struct snd_card *card;
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct pardevice *pardev;
|
||||
int pardev_claimed;
|
||||
|
||||
int open_count;
|
||||
int mode[PORTMAN_NUM_INPUT_PORTS];
|
||||
struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS];
|
||||
};
|
||||
|
||||
static int portman_free(struct portman *pm)
|
||||
{
|
||||
kfree(pm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit portman_create(struct snd_card *card,
|
||||
struct pardevice *pardev,
|
||||
struct portman **rchip)
|
||||
{
|
||||
struct portman *pm;
|
||||
|
||||
*rchip = NULL;
|
||||
|
||||
pm = kzalloc(sizeof(struct portman), GFP_KERNEL);
|
||||
if (pm == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Init chip specific data */
|
||||
spin_lock_init(&pm->reg_lock);
|
||||
pm->card = card;
|
||||
pm->pardev = pardev;
|
||||
|
||||
*rchip = pm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* HW related constants
|
||||
*********************************************************************/
|
||||
|
||||
/* Standard PC parallel port status register equates. */
|
||||
#define PP_STAT_BSY 0x80 /* Busy status. Inverted. */
|
||||
#define PP_STAT_ACK 0x40 /* Acknowledge. Non-Inverted. */
|
||||
#define PP_STAT_POUT 0x20 /* Paper Out. Non-Inverted. */
|
||||
#define PP_STAT_SEL 0x10 /* Select. Non-Inverted. */
|
||||
#define PP_STAT_ERR 0x08 /* Error. Non-Inverted. */
|
||||
|
||||
/* Standard PC parallel port command register equates. */
|
||||
#define PP_CMD_IEN 0x10 /* IRQ Enable. Non-Inverted. */
|
||||
#define PP_CMD_SELI 0x08 /* Select Input. Inverted. */
|
||||
#define PP_CMD_INIT 0x04 /* Init Printer. Non-Inverted. */
|
||||
#define PP_CMD_FEED 0x02 /* Auto Feed. Inverted. */
|
||||
#define PP_CMD_STB 0x01 /* Strobe. Inverted. */
|
||||
|
||||
/* Parallel Port Command Register as implemented by PCP2x4. */
|
||||
#define INT_EN PP_CMD_IEN /* Interrupt enable. */
|
||||
#define STROBE PP_CMD_STB /* Command strobe. */
|
||||
|
||||
/* The parallel port command register field (b1..b3) selects the
|
||||
* various "registers" within the PC/P 2x4. These are the internal
|
||||
* address of these "registers" that must be written to the parallel
|
||||
* port command register.
|
||||
*/
|
||||
#define RXDATA0 (0 << 1) /* PCP RxData channel 0. */
|
||||
#define RXDATA1 (1 << 1) /* PCP RxData channel 1. */
|
||||
#define GEN_CTL (2 << 1) /* PCP General Control Register. */
|
||||
#define SYNC_CTL (3 << 1) /* PCP Sync Control Register. */
|
||||
#define TXDATA0 (4 << 1) /* PCP TxData channel 0. */
|
||||
#define TXDATA1 (5 << 1) /* PCP TxData channel 1. */
|
||||
#define TXDATA2 (6 << 1) /* PCP TxData channel 2. */
|
||||
#define TXDATA3 (7 << 1) /* PCP TxData channel 3. */
|
||||
|
||||
/* Parallel Port Status Register as implemented by PCP2x4. */
|
||||
#define ESTB PP_STAT_POUT /* Echoed strobe. */
|
||||
#define INT_REQ PP_STAT_ACK /* Input data int request. */
|
||||
#define BUSY PP_STAT_ERR /* Interface Busy. */
|
||||
|
||||
/* Parallel Port Status Register BUSY and SELECT lines are multiplexed
|
||||
* between several functions. Depending on which 2x4 "register" is
|
||||
* currently selected (b1..b3), the BUSY and SELECT lines are
|
||||
* assigned as follows:
|
||||
*
|
||||
* SELECT LINE: A3 A2 A1
|
||||
* --------
|
||||
*/
|
||||
#define RXAVAIL PP_STAT_SEL /* Rx Available, channel 0. 0 0 0 */
|
||||
// RXAVAIL1 PP_STAT_SEL /* Rx Available, channel 1. 0 0 1 */
|
||||
#define SYNC_STAT PP_STAT_SEL /* Reserved - Sync Status. 0 1 0 */
|
||||
// /* Reserved. 0 1 1 */
|
||||
#define TXEMPTY PP_STAT_SEL /* Tx Empty, channel 0. 1 0 0 */
|
||||
// TXEMPTY1 PP_STAT_SEL /* Tx Empty, channel 1. 1 0 1 */
|
||||
// TXEMPTY2 PP_STAT_SEL /* Tx Empty, channel 2. 1 1 0 */
|
||||
// TXEMPTY3 PP_STAT_SEL /* Tx Empty, channel 3. 1 1 1 */
|
||||
|
||||
/* BUSY LINE: A3 A2 A1
|
||||
* --------
|
||||
*/
|
||||
#define RXDATA PP_STAT_BSY /* Rx Input Data, channel 0. 0 0 0 */
|
||||
// RXDATA1 PP_STAT_BSY /* Rx Input Data, channel 1. 0 0 1 */
|
||||
#define SYNC_DATA PP_STAT_BSY /* Reserved - Sync Data. 0 1 0 */
|
||||
/* Reserved. 0 1 1 */
|
||||
#define DATA_ECHO PP_STAT_BSY /* Parallel Port Data Echo. 1 0 0 */
|
||||
#define A0_ECHO PP_STAT_BSY /* Address 0 Echo. 1 0 1 */
|
||||
#define A1_ECHO PP_STAT_BSY /* Address 1 Echo. 1 1 0 */
|
||||
#define A2_ECHO PP_STAT_BSY /* Address 2 Echo. 1 1 1 */
|
||||
|
||||
#define PORTMAN2X4_MODE_INPUT_TRIGGERED 0x01
|
||||
|
||||
/*********************************************************************
|
||||
* Hardware specific functions
|
||||
*********************************************************************/
|
||||
static inline void portman_write_command(struct portman *pm, u8 value)
|
||||
{
|
||||
parport_write_control(pm->pardev->port, value);
|
||||
}
|
||||
|
||||
static inline u8 portman_read_command(struct portman *pm)
|
||||
{
|
||||
return parport_read_control(pm->pardev->port);
|
||||
}
|
||||
|
||||
static inline u8 portman_read_status(struct portman *pm)
|
||||
{
|
||||
return parport_read_status(pm->pardev->port);
|
||||
}
|
||||
|
||||
static inline u8 portman_read_data(struct portman *pm)
|
||||
{
|
||||
return parport_read_data(pm->pardev->port);
|
||||
}
|
||||
|
||||
static inline void portman_write_data(struct portman *pm, u8 value)
|
||||
{
|
||||
parport_write_data(pm->pardev->port, value);
|
||||
}
|
||||
|
||||
static void portman_write_midi(struct portman *pm,
|
||||
int port, u8 mididata)
|
||||
{
|
||||
int command = ((port + 4) << 1);
|
||||
|
||||
/* Get entering data byte and port number in BL and BH respectively.
|
||||
* Set up Tx Channel address field for use with PP Cmd Register.
|
||||
* Store address field in BH register.
|
||||
* Inputs: AH = Output port number (0..3).
|
||||
* AL = Data byte.
|
||||
* command = TXDATA0 | INT_EN;
|
||||
* Align port num with address field (b1...b3),
|
||||
* set address for TXDatax, Strobe=0
|
||||
*/
|
||||
command |= INT_EN;
|
||||
|
||||
/* Disable interrupts so that the process is not interrupted, then
|
||||
* write the address associated with the current Tx channel to the
|
||||
* PP Command Reg. Do not set the Strobe signal yet.
|
||||
*/
|
||||
|
||||
do {
|
||||
portman_write_command(pm, command);
|
||||
|
||||
/* While the address lines settle, write parallel output data to
|
||||
* PP Data Reg. This has no effect until Strobe signal is asserted.
|
||||
*/
|
||||
|
||||
portman_write_data(pm, mididata);
|
||||
|
||||
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
|
||||
* Status Register), then go write data. Else go back and wait.
|
||||
*/
|
||||
} while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
|
||||
|
||||
/* TxEmpty is set. Maintain PC/P destination address and assert
|
||||
* Strobe through the PP Command Reg. This will Strobe data into
|
||||
* the PC/P transmitter and set the PC/P BUSY signal.
|
||||
*/
|
||||
|
||||
portman_write_command(pm, command | STROBE);
|
||||
|
||||
/* Wait for strobe line to settle and echo back through hardware.
|
||||
* Once it has echoed back, assume that the address and data lines
|
||||
* have settled!
|
||||
*/
|
||||
|
||||
while ((portman_read_status(pm) & ESTB) == 0)
|
||||
cpu_relax();
|
||||
|
||||
/* Release strobe and immediately re-allow interrupts. */
|
||||
portman_write_command(pm, command);
|
||||
|
||||
while ((portman_read_status(pm) & ESTB) == ESTB)
|
||||
cpu_relax();
|
||||
|
||||
/* PC/P BUSY is now set. We must wait until BUSY resets itself.
|
||||
* We'll reenable ints while we're waiting.
|
||||
*/
|
||||
|
||||
while ((portman_read_status(pm) & BUSY) == BUSY)
|
||||
cpu_relax();
|
||||
|
||||
/* Data sent. */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read MIDI byte from port
|
||||
* Attempt to read input byte from specified hardware input port (0..).
|
||||
* Return -1 if no data
|
||||
*/
|
||||
static int portman_read_midi(struct portman *pm, int port)
|
||||
{
|
||||
unsigned char midi_data = 0;
|
||||
unsigned char cmdout; /* Saved address+IE bit. */
|
||||
|
||||
/* Make sure clocking edge is down before starting... */
|
||||
portman_write_data(pm, 0); /* Make sure edge is down. */
|
||||
|
||||
/* Set destination address to PCP. */
|
||||
cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */
|
||||
portman_write_command(pm, cmdout);
|
||||
|
||||
while ((portman_read_status(pm) & ESTB) == ESTB)
|
||||
cpu_relax(); /* Wait for strobe echo. */
|
||||
|
||||
/* After the address lines settle, check multiplexed RxAvail signal.
|
||||
* If data is available, read it.
|
||||
*/
|
||||
if ((portman_read_status(pm) & RXAVAIL) == 0)
|
||||
return -1; /* No data. */
|
||||
|
||||
/* Set the Strobe signal to enable the Rx clocking circuitry. */
|
||||
portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */
|
||||
|
||||
while ((portman_read_status(pm) & ESTB) == 0)
|
||||
cpu_relax(); /* Wait for strobe echo. */
|
||||
|
||||
/* The first data bit (msb) is already sitting on the input line. */
|
||||
midi_data = (portman_read_status(pm) & 128);
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 6. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 1) & 64;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 5. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 2) & 32;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 4. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 3) & 16;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 3. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 4) & 8;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 2. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 5) & 4;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 1. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 6) & 2;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
|
||||
/* Data bit 0. */
|
||||
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
|
||||
midi_data |= (portman_read_status(pm) >> 7) & 1;
|
||||
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
|
||||
portman_write_data(pm, 0); /* Return data clock low. */
|
||||
|
||||
|
||||
/* De-assert Strobe and return data. */
|
||||
portman_write_command(pm, cmdout); /* Output saved address+IE. */
|
||||
|
||||
/* Wait for strobe echo. */
|
||||
while ((portman_read_status(pm) & ESTB) == ESTB)
|
||||
cpu_relax();
|
||||
|
||||
return (midi_data & 255); /* Shift back and return value. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if any input data on the given channel is available
|
||||
* Checks RxAvail
|
||||
*/
|
||||
static int portman_data_avail(struct portman *pm, int channel)
|
||||
{
|
||||
int command = INT_EN;
|
||||
switch (channel) {
|
||||
case 0:
|
||||
command |= RXDATA0;
|
||||
break;
|
||||
case 1:
|
||||
command |= RXDATA1;
|
||||
break;
|
||||
}
|
||||
/* Write hardware (assumme STROBE=0) */
|
||||
portman_write_command(pm, command);
|
||||
/* Check multiplexed RxAvail signal */
|
||||
if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL)
|
||||
return 1; /* Data available */
|
||||
|
||||
/* No Data available */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Flushes any input
|
||||
*/
|
||||
static void portman_flush_input(struct portman *pm, unsigned char port)
|
||||
{
|
||||
/* Local variable for counting things */
|
||||
unsigned int i = 0;
|
||||
unsigned char command = 0;
|
||||
|
||||
switch (port) {
|
||||
case 0:
|
||||
command = RXDATA0;
|
||||
break;
|
||||
case 1:
|
||||
command = RXDATA1;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING
|
||||
"portman_flush_input() Won't flush port %i\n",
|
||||
port);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set address for specified channel in port and allow to settle. */
|
||||
portman_write_command(pm, command);
|
||||
|
||||
/* Assert the Strobe and wait for echo back. */
|
||||
portman_write_command(pm, command | STROBE);
|
||||
|
||||
/* Wait for ESTB */
|
||||
while ((portman_read_status(pm) & ESTB) == 0)
|
||||
cpu_relax();
|
||||
|
||||
/* Output clock cycles to the Rx circuitry. */
|
||||
portman_write_data(pm, 0);
|
||||
|
||||
/* Flush 250 bits... */
|
||||
for (i = 0; i < 250; i++) {
|
||||
portman_write_data(pm, 1);
|
||||
portman_write_data(pm, 0);
|
||||
}
|
||||
|
||||
/* Deassert the Strobe signal of the port and wait for it to settle. */
|
||||
portman_write_command(pm, command | INT_EN);
|
||||
|
||||
/* Wait for settling */
|
||||
while ((portman_read_status(pm) & ESTB) == ESTB)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static int portman_probe(struct parport *p)
|
||||
{
|
||||
/* Initialize the parallel port data register. Will set Rx clocks
|
||||
* low in case we happen to be addressing the Rx ports at this time.
|
||||
*/
|
||||
/* 1 */
|
||||
parport_write_data(p, 0);
|
||||
|
||||
/* Initialize the parallel port command register, thus initializing
|
||||
* hardware handshake lines to midi box:
|
||||
*
|
||||
* Strobe = 0
|
||||
* Interrupt Enable = 0
|
||||
*/
|
||||
/* 2 */
|
||||
parport_write_control(p, 0);
|
||||
|
||||
/* Check if Portman PC/P 2x4 is out there. */
|
||||
/* 3 */
|
||||
parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */
|
||||
|
||||
/* Check for ESTB to be clear */
|
||||
/* 4 */
|
||||
if ((parport_read_status(p) & ESTB) == ESTB)
|
||||
return 1; /* CODE 1 - Strobe Failure. */
|
||||
|
||||
/* Set for RXDATA0 where no damage will be done. */
|
||||
/* 5 */
|
||||
parport_write_control(p, RXDATA0 + STROBE); /* Write Strobe=1 to command reg. */
|
||||
|
||||
/* 6 */
|
||||
if ((parport_read_status(p) & ESTB) != ESTB)
|
||||
return 1; /* CODE 1 - Strobe Failure. */
|
||||
|
||||
/* 7 */
|
||||
parport_write_control(p, 0); /* Reset Strobe=0. */
|
||||
|
||||
/* Check if Tx circuitry is functioning properly. If initialized
|
||||
* unit TxEmpty is false, send out char and see if if goes true.
|
||||
*/
|
||||
/* 8 */
|
||||
parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */
|
||||
|
||||
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
|
||||
* Status Register), then go write data. Else go back and wait.
|
||||
*/
|
||||
/* 9 */
|
||||
if ((parport_read_status(p) & TXEMPTY) == 0)
|
||||
return 2;
|
||||
|
||||
/* Return OK status. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int portman_device_init(struct portman *pm)
|
||||
{
|
||||
portman_flush_input(pm, 0);
|
||||
portman_flush_input(pm, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Rawmidi
|
||||
*********************************************************************/
|
||||
static int snd_portman_midi_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_portman_midi_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream,
|
||||
int up)
|
||||
{
|
||||
struct portman *pm = substream->rmidi->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pm->reg_lock, flags);
|
||||
if (up)
|
||||
pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;
|
||||
else
|
||||
pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;
|
||||
spin_unlock_irqrestore(&pm->reg_lock, flags);
|
||||
}
|
||||
|
||||
static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,
|
||||
int up)
|
||||
{
|
||||
struct portman *pm = substream->rmidi->private_data;
|
||||
unsigned long flags;
|
||||
unsigned char byte;
|
||||
|
||||
spin_lock_irqsave(&pm->reg_lock, flags);
|
||||
if (up) {
|
||||
while ((snd_rawmidi_transmit(substream, &byte, 1) == 1))
|
||||
portman_write_midi(pm, substream->number, byte);
|
||||
}
|
||||
spin_unlock_irqrestore(&pm->reg_lock, flags);
|
||||
}
|
||||
|
||||
static struct snd_rawmidi_ops snd_portman_midi_output = {
|
||||
.open = snd_portman_midi_open,
|
||||
.close = snd_portman_midi_close,
|
||||
.trigger = snd_portman_midi_output_trigger,
|
||||
};
|
||||
|
||||
static struct snd_rawmidi_ops snd_portman_midi_input = {
|
||||
.open = snd_portman_midi_open,
|
||||
.close = snd_portman_midi_close,
|
||||
.trigger = snd_portman_midi_input_trigger,
|
||||
};
|
||||
|
||||
/* Create and initialize the rawmidi component */
|
||||
static int __devinit snd_portman_rawmidi_create(struct snd_card *card)
|
||||
{
|
||||
struct portman *pm = card->private_data;
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct snd_rawmidi_substream *substream;
|
||||
int err;
|
||||
|
||||
err = snd_rawmidi_new(card, CARD_NAME, 0,
|
||||
PORTMAN_NUM_OUTPUT_PORTS,
|
||||
PORTMAN_NUM_INPUT_PORTS,
|
||||
&rmidi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rmidi->private_data = pm;
|
||||
strcpy(rmidi->name, CARD_NAME);
|
||||
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
|
||||
SNDRV_RAWMIDI_INFO_INPUT |
|
||||
SNDRV_RAWMIDI_INFO_DUPLEX;
|
||||
|
||||
pm->rmidi = rmidi;
|
||||
|
||||
/* register rawmidi ops */
|
||||
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
|
||||
&snd_portman_midi_output);
|
||||
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
|
||||
&snd_portman_midi_input);
|
||||
|
||||
/* name substreams */
|
||||
/* output */
|
||||
list_for_each_entry(substream,
|
||||
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
|
||||
list) {
|
||||
sprintf(substream->name,
|
||||
"Portman2x4 %d", substream->number+1);
|
||||
}
|
||||
/* input */
|
||||
list_for_each_entry(substream,
|
||||
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
|
||||
list) {
|
||||
pm->midi_input[substream->number] = substream;
|
||||
sprintf(substream->name,
|
||||
"Portman2x4 %d", substream->number+1);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* parport stuff
|
||||
*********************************************************************/
|
||||
static void snd_portman_interrupt(int irq, void *userdata)
|
||||
{
|
||||
unsigned char midivalue = 0;
|
||||
struct portman *pm = ((struct snd_card*)userdata)->private_data;
|
||||
|
||||
spin_lock(&pm->reg_lock);
|
||||
|
||||
/* While any input data is waiting */
|
||||
while ((portman_read_status(pm) & INT_REQ) == INT_REQ) {
|
||||
/* If data available on channel 0,
|
||||
read it and stuff it into the queue. */
|
||||
if (portman_data_avail(pm, 0)) {
|
||||
/* Read Midi */
|
||||
midivalue = portman_read_midi(pm, 0);
|
||||
/* put midi into queue... */
|
||||
if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
|
||||
snd_rawmidi_receive(pm->midi_input[0],
|
||||
&midivalue, 1);
|
||||
|
||||
}
|
||||
/* If data available on channel 1,
|
||||
read it and stuff it into the queue. */
|
||||
if (portman_data_avail(pm, 1)) {
|
||||
/* Read Midi */
|
||||
midivalue = portman_read_midi(pm, 1);
|
||||
/* put midi into queue... */
|
||||
if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
|
||||
snd_rawmidi_receive(pm->midi_input[1],
|
||||
&midivalue, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
spin_unlock(&pm->reg_lock);
|
||||
}
|
||||
|
||||
static int __devinit snd_portman_probe_port(struct parport *p)
|
||||
{
|
||||
struct pardevice *pardev;
|
||||
int res;
|
||||
|
||||
pardev = parport_register_device(p, DRIVER_NAME,
|
||||
NULL, NULL, NULL,
|
||||
0, NULL);
|
||||
if (!pardev)
|
||||
return -EIO;
|
||||
|
||||
if (parport_claim(pardev)) {
|
||||
parport_unregister_device(pardev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
res = portman_probe(p);
|
||||
|
||||
parport_release(pardev);
|
||||
parport_unregister_device(pardev);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void __devinit snd_portman_attach(struct parport *p)
|
||||
{
|
||||
struct platform_device *device;
|
||||
|
||||
device = platform_device_alloc(PLATFORM_DRIVER, device_count);
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
/* Temporary assignment to forward the parport */
|
||||
platform_set_drvdata(device, p);
|
||||
|
||||
if (platform_device_register(device) < 0) {
|
||||
platform_device_put(device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since we dont get the return value of probe
|
||||
* We need to check if device probing succeeded or not */
|
||||
if (!platform_get_drvdata(device)) {
|
||||
platform_device_unregister(device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* register device in global table */
|
||||
platform_devices[device_count] = device;
|
||||
device_count++;
|
||||
}
|
||||
|
||||
static void snd_portman_detach(struct parport *p)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
static struct parport_driver portman_parport_driver = {
|
||||
.name = "portman2x4",
|
||||
.attach = snd_portman_attach,
|
||||
.detach = snd_portman_detach
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
* platform stuff
|
||||
*********************************************************************/
|
||||
static void snd_portman_card_private_free(struct snd_card *card)
|
||||
{
|
||||
struct portman *pm = card->private_data;
|
||||
struct pardevice *pardev = pm->pardev;
|
||||
|
||||
if (pardev) {
|
||||
if (pm->pardev_claimed)
|
||||
parport_release(pardev);
|
||||
parport_unregister_device(pardev);
|
||||
}
|
||||
|
||||
portman_free(pm);
|
||||
}
|
||||
|
||||
static int __devinit snd_portman_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pardevice *pardev;
|
||||
struct parport *p;
|
||||
int dev = pdev->id;
|
||||
struct snd_card *card = NULL;
|
||||
struct portman *pm = NULL;
|
||||
int err;
|
||||
|
||||
p = platform_get_drvdata(pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
if (dev >= SNDRV_CARDS)
|
||||
return -ENODEV;
|
||||
if (!enable[dev])
|
||||
return -ENOENT;
|
||||
|
||||
if ((err = snd_portman_probe_port(p)) < 0)
|
||||
return err;
|
||||
|
||||
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
|
||||
if (card == NULL) {
|
||||
snd_printd("Cannot create card\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
strcpy(card->driver, DRIVER_NAME);
|
||||
strcpy(card->shortname, CARD_NAME);
|
||||
sprintf(card->longname, "%s at 0x%lx, irq %i",
|
||||
card->shortname, p->base, p->irq);
|
||||
|
||||
pardev = parport_register_device(p, /* port */
|
||||
DRIVER_NAME, /* name */
|
||||
NULL, /* preempt */
|
||||
NULL, /* wakeup */
|
||||
snd_portman_interrupt, /* ISR */
|
||||
PARPORT_DEV_EXCL, /* flags */
|
||||
(void *)card); /* private */
|
||||
if (pardev == NULL) {
|
||||
snd_printd("Cannot register pardevice\n");
|
||||
err = -EIO;
|
||||
goto __err;
|
||||
}
|
||||
|
||||
if ((err = portman_create(card, pardev, &pm)) < 0) {
|
||||
snd_printd("Cannot create main component\n");
|
||||
parport_unregister_device(pardev);
|
||||
goto __err;
|
||||
}
|
||||
card->private_data = pm;
|
||||
card->private_free = snd_portman_card_private_free;
|
||||
|
||||
if ((err = snd_portman_rawmidi_create(card)) < 0) {
|
||||
snd_printd("Creating Rawmidi component failed\n");
|
||||
goto __err;
|
||||
}
|
||||
|
||||
/* claim parport */
|
||||
if (parport_claim(pardev)) {
|
||||
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
|
||||
err = -EIO;
|
||||
goto __err;
|
||||
}
|
||||
pm->pardev_claimed = 1;
|
||||
|
||||
/* init device */
|
||||
if ((err = portman_device_init(pm)) < 0)
|
||||
goto __err;
|
||||
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
||||
/* At this point card will be usable */
|
||||
if ((err = snd_card_register(card)) < 0) {
|
||||
snd_printd("Cannot register card\n");
|
||||
goto __err;
|
||||
}
|
||||
|
||||
snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);
|
||||
return 0;
|
||||
|
||||
__err:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_portman_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
if (card)
|
||||
snd_card_free(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct platform_driver snd_portman_driver = {
|
||||
.probe = snd_portman_probe,
|
||||
.remove = snd_portman_remove,
|
||||
.driver = {
|
||||
.name = PLATFORM_DRIVER
|
||||
}
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
* module init stuff
|
||||
*********************************************************************/
|
||||
static void snd_portman_unregister_all(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SNDRV_CARDS; ++i) {
|
||||
if (platform_devices[i]) {
|
||||
platform_device_unregister(platform_devices[i]);
|
||||
platform_devices[i] = NULL;
|
||||
}
|
||||
}
|
||||
platform_driver_unregister(&snd_portman_driver);
|
||||
parport_unregister_driver(&portman_parport_driver);
|
||||
}
|
||||
|
||||
static int __init snd_portman_module_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = platform_driver_register(&snd_portman_driver)) < 0)
|
||||
return err;
|
||||
|
||||
if (parport_register_driver(&portman_parport_driver) != 0) {
|
||||
platform_driver_unregister(&snd_portman_driver);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (device_count == 0) {
|
||||
snd_portman_unregister_all();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit snd_portman_module_exit(void)
|
||||
{
|
||||
snd_portman_unregister_all();
|
||||
}
|
||||
|
||||
module_init(snd_portman_module_init);
|
||||
module_exit(snd_portman_module_exit);
|
|
@ -117,13 +117,13 @@ MODULE_PARM_DESC(adaptor, "Type of adaptor.");
|
|||
#define SERIAL_MODE_INPUT_TRIGGERED (1 << 2)
|
||||
#define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3)
|
||||
|
||||
typedef struct _snd_uart16550 {
|
||||
struct snd_uart16550 {
|
||||
struct snd_card *card;
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS];
|
||||
struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS];
|
||||
|
||||
int filemode; //open status of file
|
||||
int filemode; /* open status of file */
|
||||
|
||||
spinlock_t open_lock;
|
||||
|
||||
|
@ -140,39 +140,39 @@ typedef struct _snd_uart16550 {
|
|||
unsigned char old_divisor_msb;
|
||||
unsigned char old_line_ctrl_reg;
|
||||
|
||||
// parameter for using of write loop
|
||||
short int fifo_limit; //used in uart16550
|
||||
short int fifo_count; //used in uart16550
|
||||
/* parameter for using of write loop */
|
||||
short int fifo_limit; /* used in uart16550 */
|
||||
short int fifo_count; /* used in uart16550 */
|
||||
|
||||
// type of adaptor
|
||||
/* type of adaptor */
|
||||
int adaptor;
|
||||
|
||||
// inputs
|
||||
/* inputs */
|
||||
int prev_in;
|
||||
unsigned char rstatus;
|
||||
|
||||
// outputs
|
||||
/* outputs */
|
||||
int prev_out;
|
||||
unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS];
|
||||
|
||||
// write buffer and its writing/reading position
|
||||
/* write buffer and its writing/reading position */
|
||||
unsigned char tx_buff[TX_BUFF_SIZE];
|
||||
int buff_in_count;
|
||||
int buff_in;
|
||||
int buff_out;
|
||||
int drop_on_full;
|
||||
|
||||
// wait timer
|
||||
/* wait timer */
|
||||
unsigned int timer_running:1;
|
||||
struct timer_list buffer_timer;
|
||||
|
||||
} snd_uart16550_t;
|
||||
};
|
||||
|
||||
static struct platform_device *devices[SNDRV_CARDS];
|
||||
|
||||
static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
|
||||
static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
|
||||
{
|
||||
if (! uart->timer_running) {
|
||||
if (!uart->timer_running) {
|
||||
/* timer 38600bps * 10bit * 16byte */
|
||||
uart->buffer_timer.expires = jiffies + (HZ+255)/256;
|
||||
uart->timer_running = 1;
|
||||
|
@ -180,7 +180,7 @@ static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
|
||||
static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart)
|
||||
{
|
||||
if (uart->timer_running) {
|
||||
del_timer(&uart->buffer_timer);
|
||||
|
@ -189,10 +189,10 @@ static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
|
|||
}
|
||||
|
||||
/* This macro is only used in snd_uart16550_io_loop */
|
||||
static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
|
||||
static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart)
|
||||
{
|
||||
unsigned short buff_out = uart->buff_out;
|
||||
if( uart->buff_in_count > 0 ) {
|
||||
if (uart->buff_in_count > 0) {
|
||||
outb(uart->tx_buff[buff_out], uart->base + UART_TX);
|
||||
uart->fifo_count++;
|
||||
buff_out++;
|
||||
|
@ -206,7 +206,7 @@ static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
|
|||
* We don't want to interrupt this,
|
||||
* as we're already handling an interrupt
|
||||
*/
|
||||
static void snd_uart16550_io_loop(snd_uart16550_t * uart)
|
||||
static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
|
||||
{
|
||||
unsigned char c, status;
|
||||
int substream;
|
||||
|
@ -220,9 +220,8 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
|
|||
c = inb(uart->base + UART_RX);
|
||||
|
||||
/* keep track of last status byte */
|
||||
if (c & 0x80) {
|
||||
if (c & 0x80)
|
||||
uart->rstatus = c;
|
||||
}
|
||||
|
||||
/* handle stream switch */
|
||||
if (uart->adaptor == SNDRV_SERIAL_GENERIC) {
|
||||
|
@ -230,14 +229,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
|
|||
if (c <= SNDRV_SERIAL_MAX_INS && c > 0)
|
||||
substream = c - 1;
|
||||
if (c != 0xf5)
|
||||
uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */
|
||||
}
|
||||
else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
|
||||
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
|
||||
}
|
||||
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
|
||||
/* prevent future bytes from being
|
||||
interpreted as streams */
|
||||
uart->rstatus = 0;
|
||||
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN)
|
||||
&& uart->midi_input[substream])
|
||||
snd_rawmidi_receive(uart->midi_input[substream],
|
||||
&c, 1);
|
||||
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) &&
|
||||
uart->midi_input[substream])
|
||||
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
|
||||
}
|
||||
|
||||
if (status & UART_LSR_OE)
|
||||
snd_printk("%s: Overrun on device at 0x%lx\n",
|
||||
|
@ -250,21 +251,20 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
|
|||
/* no need of check SERIAL_MODE_OUTPUT_OPEN because if not,
|
||||
buffer is never filled. */
|
||||
/* Check write status */
|
||||
if (status & UART_LSR_THRE) {
|
||||
if (status & UART_LSR_THRE)
|
||||
uart->fifo_count = 0;
|
||||
}
|
||||
if (uart->adaptor == SNDRV_SERIAL_MS124W_SA
|
||||
|| uart->adaptor == SNDRV_SERIAL_GENERIC) {
|
||||
/* Can't use FIFO, must send only when CTS is true */
|
||||
status = inb(uart->base + UART_MSR);
|
||||
while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) &&
|
||||
(uart->buff_in_count > 0) ) {
|
||||
while (uart->fifo_count == 0 && (status & UART_MSR_CTS) &&
|
||||
uart->buff_in_count > 0) {
|
||||
snd_uart16550_buffer_output(uart);
|
||||
status = inb( uart->base + UART_MSR );
|
||||
status = inb(uart->base + UART_MSR);
|
||||
}
|
||||
} else {
|
||||
/* Write loop */
|
||||
while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
|
||||
while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
|
||||
&& uart->buff_in_count > 0) /* Do we want to? */
|
||||
snd_uart16550_buffer_output(uart);
|
||||
}
|
||||
|
@ -294,15 +294,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
|
|||
*/
|
||||
static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
snd_uart16550_t *uart;
|
||||
struct snd_uart16550 *uart;
|
||||
|
||||
uart = (snd_uart16550_t *) dev_id;
|
||||
uart = dev_id;
|
||||
spin_lock(&uart->open_lock);
|
||||
if (uart->filemode == SERIAL_MODE_NOT_OPENED) {
|
||||
spin_unlock(&uart->open_lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */
|
||||
/* indicate to the UART that the interrupt has been serviced */
|
||||
inb(uart->base + UART_IIR);
|
||||
snd_uart16550_io_loop(uart);
|
||||
spin_unlock(&uart->open_lock);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -312,9 +313,9 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
|
|||
static void snd_uart16550_buffer_timer(unsigned long data)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart;
|
||||
struct snd_uart16550 *uart;
|
||||
|
||||
uart = (snd_uart16550_t *)data;
|
||||
uart = (struct snd_uart16550 *)data;
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
snd_uart16550_del_timer(uart);
|
||||
snd_uart16550_io_loop(uart);
|
||||
|
@ -326,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data)
|
|||
* return 0 if found
|
||||
* return negative error if not found
|
||||
*/
|
||||
static int __init snd_uart16550_detect(snd_uart16550_t *uart)
|
||||
static int __init snd_uart16550_detect(struct snd_uart16550 *uart)
|
||||
{
|
||||
unsigned long io_base = uart->base;
|
||||
int ok;
|
||||
|
@ -343,7 +344,8 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
ok = 1; /* uart detected unless one of the following tests should fail */
|
||||
/* uart detected unless one of the following tests should fail */
|
||||
ok = 1;
|
||||
/* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */
|
||||
outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */
|
||||
c = inb(io_base + UART_IER);
|
||||
|
@ -368,7 +370,7 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart)
|
|||
return ok;
|
||||
}
|
||||
|
||||
static void snd_uart16550_do_open(snd_uart16550_t * uart)
|
||||
static void snd_uart16550_do_open(struct snd_uart16550 * uart)
|
||||
{
|
||||
char byte;
|
||||
|
||||
|
@ -460,7 +462,7 @@ static void snd_uart16550_do_open(snd_uart16550_t * uart)
|
|||
inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */
|
||||
}
|
||||
|
||||
static void snd_uart16550_do_close(snd_uart16550_t * uart)
|
||||
static void snd_uart16550_do_close(struct snd_uart16550 * uart)
|
||||
{
|
||||
if (uart->irq < 0)
|
||||
snd_uart16550_del_timer(uart);
|
||||
|
@ -514,7 +516,7 @@ static void snd_uart16550_do_close(snd_uart16550_t * uart)
|
|||
static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
|
||||
|
@ -528,7 +530,7 @@ static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
|
|||
static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
|
||||
|
@ -539,24 +541,24 @@ static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up)
|
||||
static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream,
|
||||
int up)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
if (up) {
|
||||
if (up)
|
||||
uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED;
|
||||
} else {
|
||||
else
|
||||
uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED;
|
||||
}
|
||||
spin_unlock_irqrestore(&uart->open_lock, flags);
|
||||
}
|
||||
|
||||
static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
|
||||
|
@ -570,7 +572,7 @@ static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
|
|||
static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN;
|
||||
|
@ -581,18 +583,20 @@ static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
|
|||
return 0;
|
||||
};
|
||||
|
||||
static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
|
||||
static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart,
|
||||
int Num)
|
||||
{
|
||||
if( uart->buff_in_count + Num < TX_BUFF_SIZE )
|
||||
if (uart->buff_in_count + Num < TX_BUFF_SIZE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
|
||||
static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart,
|
||||
unsigned char byte)
|
||||
{
|
||||
unsigned short buff_in = uart->buff_in;
|
||||
if( uart->buff_in_count < TX_BUFF_SIZE ) {
|
||||
if (uart->buff_in_count < TX_BUFF_SIZE) {
|
||||
uart->tx_buff[buff_in] = byte;
|
||||
buff_in++;
|
||||
buff_in &= TX_BUFF_MASK;
|
||||
|
@ -605,12 +609,14 @@ static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned cha
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte)
|
||||
static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
|
||||
struct snd_rawmidi_substream *substream,
|
||||
unsigned char midi_byte)
|
||||
{
|
||||
if (uart->buff_in_count == 0 /* Buffer empty? */
|
||||
if (uart->buff_in_count == 0 /* Buffer empty? */
|
||||
&& ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
|
||||
uart->adaptor != SNDRV_SERIAL_GENERIC) ||
|
||||
(uart->fifo_count == 0 /* FIFO empty? */
|
||||
(uart->fifo_count == 0 /* FIFO empty? */
|
||||
&& (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */
|
||||
|
||||
/* Tx Buffer Empty - try to write immediately */
|
||||
|
@ -623,12 +629,13 @@ static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_s
|
|||
uart->fifo_count++;
|
||||
outb(midi_byte, uart->base + UART_TX);
|
||||
} else {
|
||||
/* Cannot write (buffer empty) - put char in buffer */
|
||||
/* Cannot write (buffer empty) -
|
||||
* put char in buffer */
|
||||
snd_uart16550_write_buffer(uart, midi_byte);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if( !snd_uart16550_write_buffer(uart, midi_byte) ) {
|
||||
if (!snd_uart16550_write_buffer(uart, midi_byte)) {
|
||||
snd_printk("%s: Buffer overrun on device at 0x%lx\n",
|
||||
uart->rmidi->name, uart->base);
|
||||
return 0;
|
||||
|
@ -642,9 +649,9 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
|
|||
{
|
||||
unsigned long flags;
|
||||
unsigned char midi_byte, addr_byte;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
char first;
|
||||
static unsigned long lasttime=0;
|
||||
static unsigned long lasttime = 0;
|
||||
|
||||
/* Interupts are disabled during the updating of the tx_buff,
|
||||
* since it is 'bad' to have two processes updating the same
|
||||
|
@ -653,7 +660,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
|
|||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
|
||||
if (uart->irq < 0) //polling
|
||||
if (uart->irq < 0) /* polling */
|
||||
snd_uart16550_io_loop(uart);
|
||||
|
||||
if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) {
|
||||
|
@ -671,7 +678,8 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
|
|||
/* select any combination of the four ports */
|
||||
addr_byte = (substream->number << 4) | 0x08;
|
||||
/* ...except none */
|
||||
if (addr_byte == 0x08) addr_byte = 0xf8;
|
||||
if (addr_byte == 0x08)
|
||||
addr_byte = 0xf8;
|
||||
#endif
|
||||
snd_uart16550_output_byte(uart, substream, addr_byte);
|
||||
/* send midi byte */
|
||||
|
@ -679,31 +687,42 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
|
|||
}
|
||||
} else {
|
||||
first = 0;
|
||||
while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) {
|
||||
/* Also send F5 after 3 seconds with no data to handle device disconnect */
|
||||
if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
|
||||
uart->adaptor == SNDRV_SERIAL_GENERIC) &&
|
||||
(uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) {
|
||||
while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) {
|
||||
/* Also send F5 after 3 seconds with no data
|
||||
* to handle device disconnect */
|
||||
if (first == 0 &&
|
||||
(uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
|
||||
uart->adaptor == SNDRV_SERIAL_GENERIC) &&
|
||||
(uart->prev_out != substream->number ||
|
||||
jiffies-lasttime > 3*HZ)) {
|
||||
|
||||
if( snd_uart16550_buffer_can_write( uart, 3 ) ) {
|
||||
if (snd_uart16550_buffer_can_write(uart, 3)) {
|
||||
/* Roland Soundcanvas part selection */
|
||||
/* If this substream of the data is different previous
|
||||
substream in this uart, send the change part event */
|
||||
/* If this substream of the data is
|
||||
* different previous substream
|
||||
* in this uart, send the change part
|
||||
* event
|
||||
*/
|
||||
uart->prev_out = substream->number;
|
||||
/* change part */
|
||||
snd_uart16550_output_byte(uart, substream, 0xf5);
|
||||
snd_uart16550_output_byte(uart, substream,
|
||||
0xf5);
|
||||
/* data */
|
||||
snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
|
||||
/* If midi_byte is a data byte, send the previous status byte */
|
||||
if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
|
||||
snd_uart16550_output_byte(uart, substream,
|
||||
uart->prev_out + 1);
|
||||
/* If midi_byte is a data byte,
|
||||
* send the previous status byte */
|
||||
if (midi_byte < 0x80 &&
|
||||
uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)
|
||||
snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
|
||||
} else if( !uart->drop_on_full )
|
||||
} else if (!uart->drop_on_full)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* send midi byte */
|
||||
if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full )
|
||||
if (!snd_uart16550_output_byte(uart, substream, midi_byte) &&
|
||||
!uart->drop_on_full )
|
||||
break;
|
||||
|
||||
if (midi_byte >= 0x80 && midi_byte < 0xf0)
|
||||
|
@ -717,17 +736,17 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
|
|||
spin_unlock_irqrestore(&uart->open_lock, flags);
|
||||
}
|
||||
|
||||
static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up)
|
||||
static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream,
|
||||
int up)
|
||||
{
|
||||
unsigned long flags;
|
||||
snd_uart16550_t *uart = substream->rmidi->private_data;
|
||||
struct snd_uart16550 *uart = substream->rmidi->private_data;
|
||||
|
||||
spin_lock_irqsave(&uart->open_lock, flags);
|
||||
if (up) {
|
||||
if (up)
|
||||
uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;
|
||||
} else {
|
||||
else
|
||||
uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;
|
||||
}
|
||||
spin_unlock_irqrestore(&uart->open_lock, flags);
|
||||
if (up)
|
||||
snd_uart16550_output_write(substream);
|
||||
|
@ -747,10 +766,10 @@ static struct snd_rawmidi_ops snd_uart16550_input =
|
|||
.trigger = snd_uart16550_input_trigger,
|
||||
};
|
||||
|
||||
static int snd_uart16550_free(snd_uart16550_t *uart)
|
||||
static int snd_uart16550_free(struct snd_uart16550 *uart)
|
||||
{
|
||||
if (uart->irq >= 0)
|
||||
free_irq(uart->irq, (void *)uart);
|
||||
free_irq(uart->irq, uart);
|
||||
release_and_free_resource(uart->res_base);
|
||||
kfree(uart);
|
||||
return 0;
|
||||
|
@ -758,7 +777,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart)
|
|||
|
||||
static int snd_uart16550_dev_free(struct snd_device *device)
|
||||
{
|
||||
snd_uart16550_t *uart = device->device_data;
|
||||
struct snd_uart16550 *uart = device->device_data;
|
||||
return snd_uart16550_free(uart);
|
||||
}
|
||||
|
||||
|
@ -769,12 +788,12 @@ static int __init snd_uart16550_create(struct snd_card *card,
|
|||
unsigned int base,
|
||||
int adaptor,
|
||||
int droponfull,
|
||||
snd_uart16550_t **ruart)
|
||||
struct snd_uart16550 **ruart)
|
||||
{
|
||||
static struct snd_device_ops ops = {
|
||||
.dev_free = snd_uart16550_dev_free,
|
||||
};
|
||||
snd_uart16550_t *uart;
|
||||
struct snd_uart16550 *uart;
|
||||
int err;
|
||||
|
||||
|
||||
|
@ -795,7 +814,7 @@ static int __init snd_uart16550_create(struct snd_card *card,
|
|||
|
||||
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
|
||||
if (request_irq(irq, snd_uart16550_interrupt,
|
||||
IRQF_DISABLED, "Serial MIDI", (void *) uart)) {
|
||||
IRQF_DISABLED, "Serial MIDI", uart)) {
|
||||
snd_printk("irq %d busy. Using Polling.\n", irq);
|
||||
} else {
|
||||
uart->irq = irq;
|
||||
|
@ -843,23 +862,28 @@ static int __init snd_uart16550_create(struct snd_card *card,
|
|||
|
||||
static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct snd_rawmidi_substream *substream;
|
||||
|
||||
list_for_each(list, &stream->substreams) {
|
||||
struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
|
||||
list_for_each_entry(substream, &stream->substreams, list) {
|
||||
sprintf(substream->name, "Serial MIDI %d", substream->number + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi)
|
||||
static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device,
|
||||
int outs, int ins,
|
||||
struct snd_rawmidi **rmidi)
|
||||
{
|
||||
struct snd_rawmidi *rrawmidi;
|
||||
int err;
|
||||
|
||||
if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0)
|
||||
err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device,
|
||||
outs, ins, &rrawmidi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
|
||||
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
|
||||
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT,
|
||||
&snd_uart16550_input);
|
||||
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
|
||||
&snd_uart16550_output);
|
||||
strcpy(rrawmidi->name, "Serial MIDI");
|
||||
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
|
||||
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
|
||||
|
@ -875,7 +899,7 @@ static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int out
|
|||
static int __init snd_serial_probe(struct platform_device *devptr)
|
||||
{
|
||||
struct snd_card *card;
|
||||
snd_uart16550_t *uart;
|
||||
struct snd_uart16550 *uart;
|
||||
int err;
|
||||
int dev = devptr->id;
|
||||
|
||||
|
@ -929,7 +953,8 @@ static int __init snd_serial_probe(struct platform_device *devptr)
|
|||
&uart)) < 0)
|
||||
goto _err;
|
||||
|
||||
if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0)
|
||||
err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);
|
||||
if (err < 0)
|
||||
goto _err;
|
||||
|
||||
sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
|
|||
* Used for AK4524 input/ouput attenuation, AK4528, and
|
||||
* AK5365 input attenuation
|
||||
*/
|
||||
static unsigned char vol_cvt_datt[128] = {
|
||||
static const unsigned char vol_cvt_datt[128] = {
|
||||
0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
|
||||
0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
|
||||
|
@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = {
|
|||
/*
|
||||
* dB tables
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
|
||||
static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
|
||||
static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
|
||||
|
||||
/*
|
||||
* initialize all the ak4xxx chips
|
||||
*/
|
||||
void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||
{
|
||||
static unsigned char inits_ak4524[] = {
|
||||
static const unsigned char inits_ak4524[] = {
|
||||
0x00, 0x07, /* 0: all power up */
|
||||
0x01, 0x00, /* 1: ADC/DAC reset */
|
||||
0x02, 0x60, /* 2: 24bit I2S */
|
||||
|
@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
0x07, 0x00, /* 7: DAC right muted */
|
||||
0xff, 0xff
|
||||
};
|
||||
static unsigned char inits_ak4528[] = {
|
||||
static const unsigned char inits_ak4528[] = {
|
||||
0x00, 0x07, /* 0: all power up */
|
||||
0x01, 0x00, /* 1: ADC/DAC reset */
|
||||
0x02, 0x60, /* 2: 24bit I2S */
|
||||
|
@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
0x05, 0x00, /* 5: ADC right muted */
|
||||
0xff, 0xff
|
||||
};
|
||||
static unsigned char inits_ak4529[] = {
|
||||
static const unsigned char inits_ak4529[] = {
|
||||
0x09, 0x01, /* 9: ATS=0, RSTN=1 */
|
||||
0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
|
||||
0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
|
||||
|
@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
0x08, 0x55, /* 8: deemphasis all off */
|
||||
0xff, 0xff
|
||||
};
|
||||
static unsigned char inits_ak4355[] = {
|
||||
static const unsigned char inits_ak4355[] = {
|
||||
0x01, 0x02, /* 1: reset and soft-mute */
|
||||
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
|
||||
* disable DZF, sharp roll-off, RSTN#=0 */
|
||||
|
@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
0x01, 0x01, /* 1: un-reset, unmute */
|
||||
0xff, 0xff
|
||||
};
|
||||
static unsigned char inits_ak4358[] = {
|
||||
static const unsigned char inits_ak4358[] = {
|
||||
0x01, 0x02, /* 1: reset and soft-mute */
|
||||
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
|
||||
* disable DZF, sharp roll-off, RSTN#=0 */
|
||||
|
@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
0x01, 0x01, /* 1: un-reset, unmute */
|
||||
0xff, 0xff
|
||||
};
|
||||
static unsigned char inits_ak4381[] = {
|
||||
static const unsigned char inits_ak4381[] = {
|
||||
0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
|
||||
0x01, 0x02, /* 1: de-emphasis off, normal speed,
|
||||
* sharp roll-off, DZF off */
|
||||
|
@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
|||
};
|
||||
|
||||
int chip, num_chips;
|
||||
unsigned char *ptr, reg, data, *inits;
|
||||
const unsigned char *ptr, *inits;
|
||||
unsigned char reg, data;
|
||||
|
||||
memset(ak->images, 0, sizeof(ak->images));
|
||||
memset(ak->volumes, 0, sizeof(ak->volumes));
|
||||
|
@ -513,6 +514,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
|
|||
return change;
|
||||
}
|
||||
|
||||
#define AK5365_NUM_INPUTS 5
|
||||
|
||||
static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||
int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
|
||||
const char **input_names;
|
||||
int num_names, idx;
|
||||
|
||||
input_names = ak->adc_info[mixer_ch].input_names;
|
||||
|
||||
num_names = 0;
|
||||
while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
|
||||
++num_names;
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = num_names;
|
||||
idx = uinfo->value.enumerated.item;
|
||||
if (idx >= num_names)
|
||||
return -EINVAL;
|
||||
strncpy(uinfo->value.enumerated.name, input_names[idx],
|
||||
sizeof(uinfo->value.enumerated.name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||
int mask = AK_GET_MASK(kcontrol->private_value);
|
||||
unsigned char val;
|
||||
|
||||
val = snd_akm4xxx_get(ak, chip, addr) & mask;
|
||||
ucontrol->value.enumerated.item[0] = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||
int mask = AK_GET_MASK(kcontrol->private_value);
|
||||
unsigned char oval, val;
|
||||
|
||||
oval = snd_akm4xxx_get(ak, chip, addr);
|
||||
val = oval & ~mask;
|
||||
val |= ucontrol->value.enumerated.item[0] & mask;
|
||||
if (val != oval) {
|
||||
snd_akm4xxx_write(ak, chip, addr, val);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* build AK4xxx controls
|
||||
*/
|
||||
|
@ -647,9 +708,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
|
|||
|
||||
if (ak->type == SND_AK5365 && (idx % 2) == 0) {
|
||||
if (! ak->adc_info ||
|
||||
! ak->adc_info[mixer_ch].switch_name)
|
||||
! ak->adc_info[mixer_ch].switch_name) {
|
||||
knew.name = "Capture Switch";
|
||||
else
|
||||
knew.index = mixer_ch + ak->idx_offset * 2;
|
||||
} else
|
||||
knew.name = ak->adc_info[mixer_ch].switch_name;
|
||||
knew.info = ak4xxx_switch_info;
|
||||
knew.get = ak4xxx_switch_get;
|
||||
|
@ -662,6 +724,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
|
|||
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
memset(&knew, 0, sizeof(knew));
|
||||
knew.name = ak->adc_info[mixer_ch].selector_name;
|
||||
if (!knew.name) {
|
||||
knew.name = "Capture Channel";
|
||||
knew.index = mixer_ch + ak->idx_offset * 2;
|
||||
}
|
||||
|
||||
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
knew.info = ak4xxx_capture_source_info;
|
||||
knew.get = ak4xxx_capture_source_get;
|
||||
knew.put = ak4xxx_capture_source_put;
|
||||
knew.access = 0;
|
||||
/* input selector control: reg. 1, bits 0-2.
|
||||
* mis-use 'shift' to pass mixer_ch */
|
||||
knew.private_value
|
||||
= AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
|
||||
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
idx += num_stereo;
|
||||
|
|
233
sound/i2c/other/pt2258.c
Normal file
233
sound/i2c/other/pt2258.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* ALSA Driver for the PT2258 volume controller.
|
||||
*
|
||||
* Copyright (c) 2006 Jochen Voss <voss@seehuhn.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/i2c.h>
|
||||
#include <sound/pt2258.h>
|
||||
|
||||
MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
|
||||
MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define PT2258_CMD_RESET 0xc0
|
||||
#define PT2258_CMD_UNMUTE 0xf8
|
||||
#define PT2258_CMD_MUTE 0xf9
|
||||
|
||||
static const unsigned char pt2258_channel_code[12] = {
|
||||
0x80, 0x90, /* channel 1: -10dB, -1dB */
|
||||
0x40, 0x50, /* channel 2: -10dB, -1dB */
|
||||
0x00, 0x10, /* channel 3: -10dB, -1dB */
|
||||
0x20, 0x30, /* channel 4: -10dB, -1dB */
|
||||
0x60, 0x70, /* channel 5: -10dB, -1dB */
|
||||
0xa0, 0xb0 /* channel 6: -10dB, -1dB */
|
||||
};
|
||||
|
||||
int snd_pt2258_reset(struct snd_pt2258 *pt)
|
||||
{
|
||||
unsigned char bytes[2];
|
||||
int i;
|
||||
|
||||
/* reset chip */
|
||||
bytes[0] = PT2258_CMD_RESET;
|
||||
snd_i2c_lock(pt->i2c_bus);
|
||||
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
|
||||
goto __error;
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
|
||||
/* mute all channels */
|
||||
pt->mute = 1;
|
||||
bytes[0] = PT2258_CMD_MUTE;
|
||||
snd_i2c_lock(pt->i2c_bus);
|
||||
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
|
||||
goto __error;
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
|
||||
/* set all channels to 0dB */
|
||||
for (i = 0; i < 6; ++i)
|
||||
pt->volume[i] = 0;
|
||||
bytes[0] = 0xd0;
|
||||
bytes[1] = 0xe0;
|
||||
snd_i2c_lock(pt->i2c_bus);
|
||||
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
|
||||
goto __error;
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
|
||||
return 0;
|
||||
|
||||
__error:
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
snd_printk(KERN_ERR "PT2258 reset failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 2;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 79;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_pt2258 *pt = kcontrol->private_data;
|
||||
int base = kcontrol->private_value;
|
||||
|
||||
/* chip does not support register reads */
|
||||
ucontrol->value.integer.value[0] = 79 - pt->volume[base];
|
||||
ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_pt2258 *pt = kcontrol->private_data;
|
||||
int base = kcontrol->private_value;
|
||||
unsigned char bytes[2];
|
||||
int val0, val1;
|
||||
|
||||
val0 = 79 - ucontrol->value.integer.value[0];
|
||||
val1 = 79 - ucontrol->value.integer.value[1];
|
||||
if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
|
||||
return 0;
|
||||
|
||||
pt->volume[base] = val0;
|
||||
bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
|
||||
bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
|
||||
snd_i2c_lock(pt->i2c_bus);
|
||||
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
|
||||
goto __error;
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
|
||||
pt->volume[base + 1] = val1;
|
||||
bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
|
||||
bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
|
||||
snd_i2c_lock(pt->i2c_bus);
|
||||
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
|
||||
goto __error;
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
|
||||
return 1;
|
||||
|
||||
__error:
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
snd_printk(KERN_ERR "PT2258 access failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int pt2258_switch_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_pt2258 *pt = kcontrol->private_data;
|
||||
|
||||
ucontrol->value.integer.value[0] = !pt->mute;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_pt2258 *pt = kcontrol->private_data;
|
||||
unsigned char bytes[2];
|
||||
int val;
|
||||
|
||||
val = !ucontrol->value.integer.value[0];
|
||||
if (pt->mute == val)
|
||||
return 0;
|
||||
|
||||
pt->mute = val;
|
||||
bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
|
||||
snd_i2c_lock(pt->i2c_bus);
|
||||
if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
|
||||
goto __error;
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
|
||||
return 1;
|
||||
|
||||
__error:
|
||||
snd_i2c_unlock(pt->i2c_bus);
|
||||
snd_printk(KERN_ERR "PT2258 access failed 2\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
|
||||
|
||||
int snd_pt2258_build_controls(struct snd_pt2258 *pt)
|
||||
{
|
||||
struct snd_kcontrol_new knew;
|
||||
char *names[3] = {
|
||||
"Mic Loopback Playback Volume",
|
||||
"Line Loopback Playback Volume",
|
||||
"CD Loopback Playback Volume"
|
||||
};
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
memset(&knew, 0, sizeof(knew));
|
||||
knew.name = names[i];
|
||||
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
knew.count = 1;
|
||||
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||
knew.private_value = 2 * i;
|
||||
knew.info = pt2258_stereo_volume_info;
|
||||
knew.get = pt2258_stereo_volume_get;
|
||||
knew.put = pt2258_stereo_volume_put;
|
||||
knew.tlv.p = pt2258_db_scale;
|
||||
|
||||
err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(&knew, 0, sizeof(knew));
|
||||
knew.name = "Loopback Switch";
|
||||
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
knew.info = pt2258_switch_info;
|
||||
knew.get = pt2258_switch_get;
|
||||
knew.put = pt2258_switch_put;
|
||||
knew.access = 0;
|
||||
err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pt2258_reset);
|
||||
EXPORT_SYMBOL(snd_pt2258_build_controls);
|
|
@ -358,6 +358,7 @@ config SND_SBAWE
|
|||
config SND_SB16_CSP
|
||||
bool "Sound Blaster 16/AWE CSP support"
|
||||
depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC)
|
||||
select FW_LOADER
|
||||
help
|
||||
Say Y here to include support for the CSP core. This special
|
||||
coprocessor can do variable tasks like various compression and
|
||||
|
@ -390,6 +391,7 @@ config SND_SSCAPE
|
|||
config SND_WAVEFRONT
|
||||
tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
|
||||
depends on SND
|
||||
select FW_LOADER
|
||||
select SND_OPL3_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_CS4231_LIB
|
||||
|
|
|
@ -906,11 +906,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
|||
return change;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
|
||||
AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -294,10 +294,10 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
|
|||
gus->mix_cntrl_reg |= 4; /* enable MIC */
|
||||
}
|
||||
dma1 = gus->gf1.dma1;
|
||||
dma1 = dma1 < 0 ? -dma1 : dma1;
|
||||
dma1 = abs(dma1);
|
||||
dma1 = dmas[dma1 & 7];
|
||||
dma2 = gus->gf1.dma2;
|
||||
dma2 = dma2 < 0 ? -dma2 : dma2;
|
||||
dma2 = abs(dma2);
|
||||
dma2 = dmas[dma2 & 7];
|
||||
dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
|
||||
|
||||
|
@ -306,7 +306,7 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
|
|||
return -EINVAL;
|
||||
}
|
||||
irq = gus->gf1.irq;
|
||||
irq = irq < 0 ? -irq : irq;
|
||||
irq = abs(irq);
|
||||
irq = irqs[irq & 0x0f];
|
||||
if (irq == 0) {
|
||||
snd_printk(KERN_ERR "Error! IRQ isn't defined.\n");
|
||||
|
|
|
@ -486,8 +486,8 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
|||
return change;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
|
||||
OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),
|
||||
|
|
|
@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
|
|||
*/
|
||||
static void snd_sb_csp_free(struct snd_hwdep *hwdep)
|
||||
{
|
||||
int i;
|
||||
struct snd_sb_csp *p = hwdep->private_data;
|
||||
if (p) {
|
||||
if (p->running & SNDRV_SB_CSP_ST_RUNNING)
|
||||
snd_sb_csp_stop(p);
|
||||
for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i)
|
||||
release_firmware(p->csp_programs[i]);
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
|
@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use
|
|||
return err;
|
||||
}
|
||||
|
||||
#define FIRMWARE_IN_THE_KERNEL
|
||||
|
||||
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||
#include "sb16_csp_codecs.h"
|
||||
|
||||
static const struct firmware snd_sb_csp_static_programs[] = {
|
||||
{ .data = mulaw_main, .size = sizeof mulaw_main },
|
||||
{ .data = alaw_main, .size = sizeof alaw_main },
|
||||
{ .data = ima_adpcm_init, .size = sizeof ima_adpcm_init },
|
||||
{ .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback },
|
||||
{ .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture },
|
||||
};
|
||||
#endif
|
||||
|
||||
static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
|
||||
{
|
||||
static const char *const names[] = {
|
||||
"sb16/mulaw_main.csp",
|
||||
"sb16/alaw_main.csp",
|
||||
"sb16/ima_adpcm_init.csp",
|
||||
"sb16/ima_adpcm_playback.csp",
|
||||
"sb16/ima_adpcm_capture.csp",
|
||||
};
|
||||
const struct firmware *program;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
|
||||
program = p->csp_programs[index];
|
||||
if (!program) {
|
||||
err = request_firmware(&program, names[index],
|
||||
p->chip->card->dev);
|
||||
if (err >= 0)
|
||||
p->csp_programs[index] = program;
|
||||
else {
|
||||
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||
program = &snd_sb_csp_static_programs[index];
|
||||
#else
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return snd_sb_csp_load(p, program->data, program->size, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* autoload hardware codec if necessary
|
||||
* return 0 if CSP is loaded and ready to run (p->running != 0)
|
||||
|
@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec
|
|||
} else {
|
||||
switch (pcm_sfmt) {
|
||||
case SNDRV_PCM_FORMAT_MU_LAW:
|
||||
err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);
|
||||
err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);
|
||||
p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
|
||||
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_A_LAW:
|
||||
err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);
|
||||
err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);
|
||||
p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
|
||||
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_IMA_ADPCM:
|
||||
err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),
|
||||
SNDRV_SB_CSP_LOAD_INITBLOCK);
|
||||
err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,
|
||||
SNDRV_SB_CSP_LOAD_INITBLOCK);
|
||||
if (err)
|
||||
break;
|
||||
if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
|
||||
err = snd_sb_csp_load(p, &ima_adpcm_playback[0],
|
||||
sizeof(ima_adpcm_playback), 0);
|
||||
err = snd_sb_csp_firmware_load
|
||||
(p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);
|
||||
p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
|
||||
} else {
|
||||
err = snd_sb_csp_load(p, &ima_adpcm_capture[0],
|
||||
sizeof(ima_adpcm_capture), 0);
|
||||
err = snd_sb_csp_firmware_load
|
||||
(p, CSP_PROGRAM_ADPCM_CAPTURE, 0);
|
||||
p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
|
||||
}
|
||||
p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
|
||||
|
|
|
@ -402,6 +402,7 @@ static struct snd_card *snd_wavefront_card_new(int dev)
|
|||
init_waitqueue_head(&acard->wavefront.interrupt_sleeper);
|
||||
spin_lock_init(&acard->wavefront.midi.open);
|
||||
spin_lock_init(&acard->wavefront.midi.virtual);
|
||||
acard->wavefront.card = card;
|
||||
card->private_free = snd_wavefront_free;
|
||||
|
||||
return card;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/snd_wavefront.h>
|
||||
#include <sound/initval.h>
|
||||
|
@ -32,325 +33,17 @@
|
|||
#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
|
||||
#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
|
||||
|
||||
/* weird stuff, derived from port I/O tracing with dosemu */
|
||||
#define WAIT_IDLE 0xff
|
||||
|
||||
static unsigned char page_zero[] __devinitdata = {
|
||||
0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
|
||||
0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
|
||||
0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
|
||||
0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
|
||||
0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
|
||||
0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
|
||||
0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
|
||||
0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
|
||||
0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
|
||||
0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
|
||||
0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
|
||||
0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
|
||||
0x1d, 0x02, 0xdf
|
||||
};
|
||||
#define FIRMWARE_IN_THE_KERNEL
|
||||
|
||||
static unsigned char page_one[] __devinitdata = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
|
||||
0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
|
||||
0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
|
||||
0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
|
||||
0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
|
||||
0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
|
||||
0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
|
||||
0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
|
||||
0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
|
||||
0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
|
||||
0x60, 0x00, 0x1b
|
||||
};
|
||||
|
||||
static unsigned char page_two[] __devinitdata = {
|
||||
0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
|
||||
0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
|
||||
0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
|
||||
0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
|
||||
0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
|
||||
0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
|
||||
0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
|
||||
0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
|
||||
};
|
||||
|
||||
static unsigned char page_three[] __devinitdata = {
|
||||
0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
|
||||
0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
|
||||
0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
|
||||
0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
|
||||
};
|
||||
|
||||
static unsigned char page_four[] __devinitdata = {
|
||||
0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
|
||||
0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
|
||||
0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
|
||||
0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
|
||||
0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
|
||||
0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
|
||||
};
|
||||
|
||||
static unsigned char page_six[] __devinitdata = {
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
|
||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
|
||||
0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
|
||||
0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
|
||||
0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
|
||||
0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
|
||||
0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
|
||||
0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
|
||||
0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
|
||||
0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
|
||||
0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
|
||||
0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
|
||||
0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
|
||||
0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
|
||||
0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
|
||||
0x80, 0x00, 0x7e, 0x80, 0x80
|
||||
};
|
||||
|
||||
static unsigned char page_seven[] __devinitdata = {
|
||||
0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
|
||||
0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
|
||||
0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
|
||||
0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
|
||||
0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
|
||||
0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
|
||||
0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
|
||||
0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
|
||||
0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
|
||||
0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
|
||||
0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00
|
||||
};
|
||||
|
||||
static unsigned char page_zero_v2[] __devinitdata = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static unsigned char page_one_v2[] __devinitdata = {
|
||||
0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static unsigned char page_two_v2[] __devinitdata = {
|
||||
0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
static unsigned char page_three_v2[] __devinitdata = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
static unsigned char page_four_v2[] __devinitdata = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static unsigned char page_seven_v2[] __devinitdata = {
|
||||
0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static unsigned char mod_v2[] __devinitdata = {
|
||||
0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
|
||||
0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
|
||||
0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
|
||||
0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
|
||||
0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
|
||||
0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
|
||||
0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
|
||||
0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
|
||||
0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
|
||||
0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
|
||||
0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
|
||||
0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
|
||||
0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
|
||||
0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
|
||||
0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
|
||||
0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
|
||||
0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
|
||||
0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
|
||||
0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
|
||||
0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
|
||||
0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
|
||||
0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
|
||||
0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
|
||||
0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
|
||||
0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
|
||||
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
|
||||
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
|
||||
0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
|
||||
};
|
||||
static unsigned char coefficients[] __devinitdata = {
|
||||
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
|
||||
0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
|
||||
0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
|
||||
0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
|
||||
0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
|
||||
0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
|
||||
0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
|
||||
0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
|
||||
0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
|
||||
0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
|
||||
0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
|
||||
0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
|
||||
0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
|
||||
0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
|
||||
0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
|
||||
0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
|
||||
0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
|
||||
0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
|
||||
0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
|
||||
0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
|
||||
0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
|
||||
0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
|
||||
0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
|
||||
0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
|
||||
0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
|
||||
0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
|
||||
0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
|
||||
0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
|
||||
0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
|
||||
0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
|
||||
0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
|
||||
0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
|
||||
0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
|
||||
0xba
|
||||
};
|
||||
static unsigned char coefficients2[] __devinitdata = {
|
||||
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
|
||||
0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
|
||||
0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
|
||||
0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
|
||||
0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
|
||||
};
|
||||
static unsigned char coefficients3[] __devinitdata = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
|
||||
0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
|
||||
0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
|
||||
0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
|
||||
0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
|
||||
0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
|
||||
0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
|
||||
0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
|
||||
0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
|
||||
0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
|
||||
0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
|
||||
0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
|
||||
0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
|
||||
0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
|
||||
0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
|
||||
0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
|
||||
0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
|
||||
0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
|
||||
0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
|
||||
0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
|
||||
0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
|
||||
0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
|
||||
0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
|
||||
0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
|
||||
0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
|
||||
0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
|
||||
0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
|
||||
0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
|
||||
0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
|
||||
0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
|
||||
0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
|
||||
0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
|
||||
0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
|
||||
0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
|
||||
0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
|
||||
0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
|
||||
0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
|
||||
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||
#include "yss225.c"
|
||||
static const struct firmware yss225_registers_firmware = {
|
||||
.data = (u8 *)yss225_registers,
|
||||
.size = sizeof yss225_registers
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
wavefront_fx_idle (snd_wavefront_t *dev)
|
||||
|
@ -555,465 +248,56 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
|
|||
of the port I/O done, using the Yamaha faxback document as a guide
|
||||
to add more logic to the code. Its really pretty weird.
|
||||
|
||||
There was an alternative approach of just dumping the whole I/O
|
||||
This is the approach of just dumping the whole I/O
|
||||
sequence as a series of port/value pairs and a simple loop
|
||||
that output it. However, I hope that eventually I'll get more
|
||||
control over what this code does, and so I tried to stick with
|
||||
a somewhat "algorithmic" approach.
|
||||
that outputs it.
|
||||
*/
|
||||
|
||||
|
||||
int __devinit
|
||||
snd_wavefront_fx_start (snd_wavefront_t *dev)
|
||||
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int i;
|
||||
int err;
|
||||
const struct firmware *firmware;
|
||||
|
||||
/* Set all bits for all channels on the MOD unit to zero */
|
||||
/* XXX But why do this twice ? */
|
||||
if (dev->fx_initialized)
|
||||
return 0;
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (i = 0x10; i <= 0xff; i++) {
|
||||
|
||||
if (!wavefront_fx_idle (dev)) {
|
||||
return (-1);
|
||||
err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
|
||||
dev->card->dev);
|
||||
if (err < 0) {
|
||||
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||
firmware = &yss225_registers_firmware;
|
||||
#else
|
||||
err = -1;
|
||||
goto out;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i + 1 < firmware->size; i += 2) {
|
||||
if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
|
||||
outb(firmware->data[i + 1],
|
||||
dev->base + firmware->data[i]);
|
||||
} else if (firmware->data[i] == WAIT_IDLE) {
|
||||
if (!wavefront_fx_idle(dev)) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x0, dev->fx_mod_data);
|
||||
} else {
|
||||
snd_printk(KERN_ERR "invalid address"
|
||||
" in register data\n");
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x02, dev->fx_op); /* mute on */
|
||||
dev->fx_initialized = 1;
|
||||
err = 0;
|
||||
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x44, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x42, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x43, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x7c, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x7e, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x46, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x49, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x47, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x4a, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
|
||||
/* either because of stupidity by TB's programmers, or because it
|
||||
actually does something, rezero the MOD page.
|
||||
*/
|
||||
for (i = 0x10; i <= 0xff; i++) {
|
||||
|
||||
if (!wavefront_fx_idle (dev)) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x0, dev->fx_mod_data);
|
||||
}
|
||||
/* load page zero */
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x00, dev->fx_dsp_page);
|
||||
outb (0x00, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_zero); i += 2) {
|
||||
outb (page_zero[i], dev->fx_dsp_msb);
|
||||
outb (page_zero[i+1], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
/* Now load page one */
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x01, dev->fx_dsp_page);
|
||||
outb (0x00, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_one); i += 2) {
|
||||
outb (page_one[i], dev->fx_dsp_msb);
|
||||
outb (page_one[i+1], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x02, dev->fx_dsp_page);
|
||||
outb (0x00, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_two); i++) {
|
||||
outb (page_two[i], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x03, dev->fx_dsp_page);
|
||||
outb (0x00, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_three); i++) {
|
||||
outb (page_three[i], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x04, dev->fx_dsp_page);
|
||||
outb (0x00, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_four); i++) {
|
||||
outb (page_four[i], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
/* Load memory area (page six) */
|
||||
|
||||
outb (FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x06, dev->fx_dsp_page);
|
||||
|
||||
for (i = 0; i < sizeof (page_six); i += 3) {
|
||||
outb (page_six[i], dev->fx_dsp_addr);
|
||||
outb (page_six[i+1], dev->fx_dsp_msb);
|
||||
outb (page_six[i+2], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x00, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_seven); i += 2) {
|
||||
outb (page_seven[i], dev->fx_dsp_msb);
|
||||
outb (page_seven[i+1], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
/* Now setup the MOD area. We do this algorithmically in order to
|
||||
save a little data space. It could be done in the same fashion
|
||||
as the "pages".
|
||||
*/
|
||||
|
||||
for (i = 0x00; i <= 0x0f; i++) {
|
||||
outb (0x01, dev->fx_mod_addr);
|
||||
outb (i, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x02, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0xb0; i <= 0xbf; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x20, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0xf0; i <= 0xff; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x20, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0x10; i <= 0x1d; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0xff, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0x1e, dev->fx_mod_addr);
|
||||
outb (0x40, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
for (i = 0x1f; i <= 0x2d; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0xff, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0x2e, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
for (i = 0x2f; i <= 0x3e; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0x3f, dev->fx_mod_addr);
|
||||
outb (0x20, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
for (i = 0x40; i <= 0x4d; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0x4e, dev->fx_mod_addr);
|
||||
outb (0x0e, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x4f, dev->fx_mod_addr);
|
||||
outb (0x0e, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
|
||||
for (i = 0x50; i <= 0x6b; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0x6c, dev->fx_mod_addr);
|
||||
outb (0x40, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
outb (0x6d, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
outb (0x6e, dev->fx_mod_addr);
|
||||
outb (0x40, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
outb (0x6f, dev->fx_mod_addr);
|
||||
outb (0x40, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
for (i = 0x70; i <= 0x7f; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0xc0, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0x80; i <= 0xaf; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0xc0; i <= 0xdd; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0xde, dev->fx_mod_addr);
|
||||
outb (0x10, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0xdf, dev->fx_mod_addr);
|
||||
outb (0x10, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
for (i = 0xe0; i <= 0xef; i++) {
|
||||
outb (i, dev->fx_mod_addr);
|
||||
outb (0x00, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0x00; i <= 0x0f; i++) {
|
||||
outb (0x01, dev->fx_mod_addr);
|
||||
outb (i, dev->fx_mod_data);
|
||||
outb (0x02, dev->fx_mod_addr);
|
||||
outb (0x01, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (0x02, dev->fx_op); /* mute on */
|
||||
|
||||
/* Now set the coefficients and so forth for the programs above */
|
||||
|
||||
for (i = 0; i < sizeof (coefficients); i += 4) {
|
||||
outb (coefficients[i], dev->fx_dsp_page);
|
||||
outb (coefficients[i+1], dev->fx_dsp_addr);
|
||||
outb (coefficients[i+2], dev->fx_dsp_msb);
|
||||
outb (coefficients[i+3], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
/* Some settings (?) that are too small to bundle into loops */
|
||||
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x1e, dev->fx_mod_addr);
|
||||
outb (0x14, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0xde, dev->fx_mod_addr);
|
||||
outb (0x20, dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0xdf, dev->fx_mod_addr);
|
||||
outb (0x20, dev->fx_mod_data);
|
||||
|
||||
/* some more coefficients */
|
||||
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x06, dev->fx_dsp_page);
|
||||
outb (0x78, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x40, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x03, dev->fx_dsp_addr);
|
||||
outb (0x0f, dev->fx_dsp_msb);
|
||||
outb (0xff, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x0b, dev->fx_dsp_addr);
|
||||
outb (0x0f, dev->fx_dsp_msb);
|
||||
outb (0xff, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x02, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x0a, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x46, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x49, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
|
||||
/* Now, for some strange reason, lets reload every page
|
||||
and all the coefficients over again. I have *NO* idea
|
||||
why this is done. I do know that no sound is produced
|
||||
is this phase is omitted.
|
||||
*/
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x00, dev->fx_dsp_page);
|
||||
outb (0x10, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_zero_v2); i += 2) {
|
||||
outb (page_zero_v2[i], dev->fx_dsp_msb);
|
||||
outb (page_zero_v2[i+1], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x01, dev->fx_dsp_page);
|
||||
outb (0x10, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_one_v2); i += 2) {
|
||||
outb (page_one_v2[i], dev->fx_dsp_msb);
|
||||
outb (page_one_v2[i+1], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x02, dev->fx_dsp_page);
|
||||
outb (0x10, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_two_v2); i++) {
|
||||
outb (page_two_v2[i], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x03, dev->fx_dsp_page);
|
||||
outb (0x10, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_three_v2); i++) {
|
||||
outb (page_three_v2[i], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x04, dev->fx_dsp_page);
|
||||
outb (0x10, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_four_v2); i++) {
|
||||
outb (page_four_v2[i], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x06, dev->fx_dsp_page);
|
||||
|
||||
/* Page six v.2 is algorithmic */
|
||||
|
||||
for (i = 0x10; i <= 0x3e; i += 2) {
|
||||
outb (i, dev->fx_dsp_addr);
|
||||
outb (0x00, dev->fx_dsp_msb);
|
||||
outb (0x00, dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
outb (0x10, dev->fx_dsp_addr);
|
||||
|
||||
for (i = 0; i < sizeof (page_seven_v2); i += 2) {
|
||||
outb (page_seven_v2[i], dev->fx_dsp_msb);
|
||||
outb (page_seven_v2[i+1], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0x00; i < sizeof(mod_v2); i += 2) {
|
||||
outb (mod_v2[i], dev->fx_mod_addr);
|
||||
outb (mod_v2[i+1], dev->fx_mod_data);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof (coefficients2); i += 4) {
|
||||
outb (coefficients2[i], dev->fx_dsp_page);
|
||||
outb (coefficients2[i+1], dev->fx_dsp_addr);
|
||||
outb (coefficients2[i+2], dev->fx_dsp_msb);
|
||||
outb (coefficients2[i+3], dev->fx_dsp_lsb);
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof (coefficients3); i += 2) {
|
||||
int x;
|
||||
|
||||
outb (0x07, dev->fx_dsp_page);
|
||||
x = (i % 4) ? 0x4e : 0x4c;
|
||||
outb (x, dev->fx_dsp_addr);
|
||||
outb (coefficients3[i], dev->fx_dsp_msb);
|
||||
outb (coefficients3[i+1], dev->fx_dsp_lsb);
|
||||
}
|
||||
|
||||
outb (0x00, dev->fx_op); /* mute off */
|
||||
if (!wavefront_fx_idle (dev)) return (-1);
|
||||
|
||||
return (0);
|
||||
out:
|
||||
#ifdef FIRMWARE_IN_THE_KERNEL
|
||||
if (firmware != &yss225_registers_firmware)
|
||||
#endif
|
||||
release_firmware(firmware);
|
||||
return err;
|
||||
}
|
||||
|
|
2739
sound/isa/wavefront/yss225.c
Normal file
2739
sound/isa/wavefront/yss225.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -236,7 +236,7 @@ config SND_CS5535AUDIO
|
|||
config SND_DARLA20
|
||||
tristate "(Echoaudio) Darla20"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Darla.
|
||||
|
@ -247,7 +247,7 @@ config SND_DARLA20
|
|||
config SND_GINA20
|
||||
tristate "(Echoaudio) Gina20"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Gina.
|
||||
|
@ -258,7 +258,7 @@ config SND_GINA20
|
|||
config SND_LAYLA20
|
||||
tristate "(Echoaudio) Layla20"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
|
@ -270,7 +270,7 @@ config SND_LAYLA20
|
|||
config SND_DARLA24
|
||||
tristate "(Echoaudio) Darla24"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Darla24.
|
||||
|
@ -281,7 +281,7 @@ config SND_DARLA24
|
|||
config SND_GINA24
|
||||
tristate "(Echoaudio) Gina24"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Gina24.
|
||||
|
@ -292,7 +292,7 @@ config SND_GINA24
|
|||
config SND_LAYLA24
|
||||
tristate "(Echoaudio) Layla24"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
|
@ -304,7 +304,7 @@ config SND_LAYLA24
|
|||
config SND_MONA
|
||||
tristate "(Echoaudio) Mona"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
|
@ -316,7 +316,7 @@ config SND_MONA
|
|||
config SND_MIA
|
||||
tristate "(Echoaudio) Mia"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
|
@ -328,7 +328,7 @@ config SND_MIA
|
|||
config SND_ECHO3G
|
||||
tristate "(Echoaudio) 3G cards"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
help
|
||||
|
@ -340,7 +340,7 @@ config SND_ECHO3G
|
|||
config SND_INDIGO
|
||||
tristate "(Echoaudio) Indigo"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Indigo.
|
||||
|
@ -351,7 +351,7 @@ config SND_INDIGO
|
|||
config SND_INDIGOIO
|
||||
tristate "(Echoaudio) Indigo IO"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
|
||||
|
@ -362,7 +362,7 @@ config SND_INDIGOIO
|
|||
config SND_INDIGODJ
|
||||
tristate "(Echoaudio) Indigo DJ"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
|
||||
|
@ -373,6 +373,7 @@ config SND_INDIGODJ
|
|||
config SND_EMU10K1
|
||||
tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
|
||||
depends on SND
|
||||
select FW_LOADER
|
||||
select SND_HWDEP
|
||||
select SND_RAWMIDI
|
||||
select SND_AC97_CODEC
|
||||
|
@ -575,6 +576,7 @@ config SND_INTEL8X0M
|
|||
config SND_KORG1212
|
||||
tristate "Korg 1212 IO"
|
||||
depends on SND
|
||||
select FW_LOADER
|
||||
select SND_PCM
|
||||
help
|
||||
Say Y here to include support for Korg 1212IO soundcards.
|
||||
|
@ -585,6 +587,7 @@ config SND_KORG1212
|
|||
config SND_MAESTRO3
|
||||
tristate "ESS Allegro/Maestro3"
|
||||
depends on SND
|
||||
select FW_LOADER
|
||||
select SND_AC97_CODEC
|
||||
help
|
||||
Say Y here to include support for soundcards based on ESS Maestro 3
|
||||
|
@ -629,7 +632,7 @@ config SND_PCXHR
|
|||
config SND_RIPTIDE
|
||||
tristate "Conexant Riptide"
|
||||
depends on SND
|
||||
depends on FW_LOADER
|
||||
select FW_LOADER
|
||||
select SND_OPL3_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_AC97_CODEC
|
||||
|
@ -734,6 +737,7 @@ config SND_VX222
|
|||
config SND_YMFPCI
|
||||
tristate "Yamaha YMF724/740/744/754"
|
||||
depends on SND
|
||||
select FW_LOADER
|
||||
select SND_OPL3_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_AC97_CODEC
|
||||
|
|
|
@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
|
|||
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL },
|
||||
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL },
|
||||
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL },
|
||||
{ 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL },
|
||||
{ 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL },
|
||||
{ 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL },
|
||||
{ 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL },
|
||||
{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */
|
||||
|
@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
|
|||
|
||||
|
||||
static void update_power_regs(struct snd_ac97 *ac97);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
#define ac97_is_power_save_mode(ac97) \
|
||||
((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save)
|
||||
#else
|
||||
#define ac97_is_power_save_mode(ac97) 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* I/O routines
|
||||
|
@ -982,8 +989,8 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
|
|||
{
|
||||
if (ac97) {
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
if (ac97->power_workq)
|
||||
destroy_workqueue(ac97->power_workq);
|
||||
cancel_delayed_work(&ac97->power_work);
|
||||
flush_scheduled_work();
|
||||
#endif
|
||||
snd_ac97_proc_done(ac97);
|
||||
if (ac97->bus)
|
||||
|
@ -1184,13 +1191,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
|
|||
/*
|
||||
* set dB information
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
|
||||
static unsigned int *find_db_scale(unsigned int maxval)
|
||||
static const unsigned int *find_db_scale(unsigned int maxval)
|
||||
{
|
||||
switch (maxval) {
|
||||
case 0x0f: return db_scale_4bit;
|
||||
|
@ -1200,8 +1207,8 @@ static unsigned int *find_db_scale(unsigned int maxval)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
|
||||
{
|
||||
static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv)
|
||||
{
|
||||
kctl->tlv.p = tlv;
|
||||
if (tlv)
|
||||
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||
|
@ -1989,7 +1996,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
|
|||
mutex_init(&ac97->reg_mutex);
|
||||
mutex_init(&ac97->page_mutex);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
ac97->power_workq = create_workqueue("ac97");
|
||||
INIT_DELAYED_WORK(&ac97->power_work, do_update_power);
|
||||
#endif
|
||||
|
||||
|
@ -2275,15 +2281,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
|
|||
udelay(100);
|
||||
power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
|
||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
if (power_save) {
|
||||
if (ac97_is_power_save_mode(ac97)) {
|
||||
udelay(100);
|
||||
/* AC-link powerdown, internal Clk disable */
|
||||
/* FIXME: this may cause click noises on some boards */
|
||||
power |= AC97_PD_PR4 | AC97_PD_PR5;
|
||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -2337,14 +2341,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
|
|||
}
|
||||
}
|
||||
|
||||
if (power_save && !powerup && ac97->power_workq)
|
||||
if (ac97_is_power_save_mode(ac97) && !powerup)
|
||||
/* adjust power-down bits after two seconds delay
|
||||
* (for avoiding loud click noises for many (OSS) apps
|
||||
* that open/close frequently)
|
||||
*/
|
||||
queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
|
||||
else
|
||||
schedule_delayed_work(&ac97->power_work, HZ*2);
|
||||
else {
|
||||
cancel_delayed_work(&ac97->power_work);
|
||||
update_power_regs(ac97);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2357,19 +2363,15 @@ static void update_power_regs(struct snd_ac97 *ac97)
|
|||
unsigned int power_up, bits;
|
||||
int i;
|
||||
|
||||
power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
|
||||
power_up |= (1 << PWIDX_MIC);
|
||||
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
||||
power_up |= (1 << PWIDX_SURR);
|
||||
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
||||
power_up |= (1 << PWIDX_CLFE);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
if (power_save)
|
||||
if (ac97_is_power_save_mode(ac97))
|
||||
power_up = ac97->power_up;
|
||||
else {
|
||||
#endif
|
||||
power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
|
||||
power_up |= (1 << PWIDX_MIC);
|
||||
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
||||
power_up |= (1 << PWIDX_SURR);
|
||||
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
||||
power_up |= (1 << PWIDX_CLFE);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
}
|
||||
#endif
|
||||
if (power_up) {
|
||||
if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
|
||||
|
@ -2414,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
|
|||
return;
|
||||
if (ac97->build_ops->suspend)
|
||||
ac97->build_ops->suspend(ac97);
|
||||
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||
cancel_delayed_work(&ac97->power_work);
|
||||
flush_scheduled_work();
|
||||
#endif
|
||||
snd_ac97_powerdown(ac97);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
|
|||
|
||||
/* replace with a new TLV */
|
||||
static void reset_tlv(struct snd_ac97 *ac97, const char *name,
|
||||
unsigned int *tlv)
|
||||
const unsigned int *tlv)
|
||||
{
|
||||
struct snd_ctl_elem_id sid;
|
||||
struct snd_kcontrol *kctl;
|
||||
|
@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97)
|
|||
return ac97->channel_mode >= 2;
|
||||
}
|
||||
|
||||
static inline int is_shared_linein(struct snd_ac97 *ac97)
|
||||
/* system has shared jacks with surround out enabled */
|
||||
static inline int is_shared_surrout(struct snd_ac97 *ac97)
|
||||
{
|
||||
return ! ac97->indep_surround && is_surround_on(ac97);
|
||||
return !ac97->indep_surround && is_surround_on(ac97);
|
||||
}
|
||||
|
||||
/* system has shared jacks with center/lfe out enabled */
|
||||
static inline int is_shared_clfeout(struct snd_ac97 *ac97)
|
||||
{
|
||||
return !ac97->indep_surround && is_clfe_on(ac97);
|
||||
}
|
||||
|
||||
/* system has shared jacks with line in enabled */
|
||||
static inline int is_shared_linein(struct snd_ac97 *ac97)
|
||||
{
|
||||
return !ac97->indep_surround && !is_surround_on(ac97);
|
||||
}
|
||||
|
||||
/* system has shared jacks with mic in enabled */
|
||||
static inline int is_shared_micin(struct snd_ac97 *ac97)
|
||||
{
|
||||
return ! ac97->indep_surround && is_clfe_on(ac97);
|
||||
return !ac97->indep_surround && !is_clfe_on(ac97);
|
||||
}
|
||||
|
||||
|
||||
|
@ -941,6 +955,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97)
|
|||
{
|
||||
int err;
|
||||
|
||||
/* the register bit is writable, but the function is not implemented: */
|
||||
snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL);
|
||||
|
||||
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
|
||||
if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
|
||||
return err;
|
||||
|
@ -1552,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = {
|
|||
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
|
||||
};
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
|
||||
|
||||
static int patch_ad1885_specific(struct snd_ac97 * ac97)
|
||||
{
|
||||
|
@ -1609,19 +1626,22 @@ int patch_ad1886(struct snd_ac97 * ac97)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* MISC bits */
|
||||
/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */
|
||||
#define AC97_AD198X_MBC 0x0003 /* mic boost */
|
||||
#define AC97_AD198X_MBC_20 0x0000 /* +20dB */
|
||||
#define AC97_AD198X_MBC_10 0x0001 /* +10dB */
|
||||
#define AC97_AD198X_MBC_30 0x0002 /* +30dB */
|
||||
#define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */
|
||||
#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */
|
||||
#define AC97_AD198X_VREF_0 0x000c /* 0V */
|
||||
#define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */
|
||||
#define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */
|
||||
#define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD)
|
||||
#define AC97_AD198X_VREF_SHIFT 2
|
||||
#define AC97_AD198X_SRU 0x0010 /* sample rate unlock */
|
||||
#define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */
|
||||
#define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */
|
||||
#define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */
|
||||
#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */
|
||||
#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */
|
||||
/* 0 = 6-to-4, 1 = 6-to-2 downmix */
|
||||
#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */
|
||||
#define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */
|
||||
#define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */
|
||||
|
@ -1630,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97)
|
|||
#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */
|
||||
#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */
|
||||
|
||||
/* MISC 1 bits (AD1986 register 0x76) */
|
||||
#define AC97_AD1986_MBC 0x0003 /* mic boost */
|
||||
#define AC97_AD1986_MBC_20 0x0000 /* +20dB */
|
||||
#define AC97_AD1986_MBC_10 0x0001 /* +10dB */
|
||||
#define AC97_AD1986_MBC_30 0x0002 /* +30dB */
|
||||
#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */
|
||||
#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */
|
||||
#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)
|
||||
#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */
|
||||
#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */
|
||||
#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */
|
||||
#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */
|
||||
#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */
|
||||
#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */
|
||||
#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */
|
||||
#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */
|
||||
/* 0 = 6-to-4, 1 = 6-to-2 downmix */
|
||||
#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */
|
||||
#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */
|
||||
#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */
|
||||
#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */
|
||||
#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */
|
||||
#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */
|
||||
|
||||
/* MISC 2 bits (AD1986 register 0x70) */
|
||||
#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */
|
||||
|
||||
#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */
|
||||
#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */
|
||||
#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */
|
||||
#define AC97_AD1986_CVREF_MASK \
|
||||
(AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)
|
||||
#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */
|
||||
#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */
|
||||
#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */
|
||||
#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */
|
||||
#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */
|
||||
#define AC97_AD1986_MVREF_MASK \
|
||||
(AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)
|
||||
|
||||
/* MISC 3 bits (AD1986 register 0x7a) */
|
||||
#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */
|
||||
|
||||
#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */
|
||||
#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */
|
||||
#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */
|
||||
#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */
|
||||
#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */
|
||||
#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */
|
||||
#define AC97_AD1986_LVREF_MASK \
|
||||
(AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)
|
||||
#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */
|
||||
#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */
|
||||
#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */
|
||||
/* input select Surround DACs */
|
||||
#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */
|
||||
/* select C/LFE DACs */
|
||||
#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */
|
||||
|
||||
/* Serial Config bits (AD1986 register 0x74) (incomplete) */
|
||||
#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */
|
||||
#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */
|
||||
#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */
|
||||
#define AC97_AD1986_OMS_MASK \
|
||||
(AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)
|
||||
#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */
|
||||
#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */
|
||||
#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */
|
||||
#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */
|
||||
/* are MIC sources */
|
||||
#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */
|
||||
/* are MIC sources */
|
||||
#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */
|
||||
/* are MIC sources */
|
||||
#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */
|
||||
/* are MIC sources */
|
||||
|
||||
|
||||
static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
|
@ -1952,8 +2049,80 @@ int patch_ad1980(struct snd_ac97 * ac97)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = 4;
|
||||
if (uinfo->value.enumerated.item > 3)
|
||||
uinfo->value.enumerated.item = 3;
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
static const int reg2ctrl[4] = {2, 0, 1, 3};
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short val;
|
||||
val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK)
|
||||
>> AC97_AD198X_VREF_SHIFT;
|
||||
ucontrol->value.enumerated.item[0] = reg2ctrl[val];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
static const int ctrl2reg[4] = {1, 2, 0, 3};
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short val;
|
||||
|
||||
if (ucontrol->value.enumerated.item[0] > 3
|
||||
|| ucontrol->value.enumerated.item[0] < 0)
|
||||
return -EINVAL;
|
||||
val = ctrl2reg[ucontrol->value.enumerated.item[0]]
|
||||
<< AC97_AD198X_VREF_SHIFT;
|
||||
return snd_ac97_update_bits(ac97, AC97_AD_MISC,
|
||||
AC97_AD198X_VREF_MASK, val);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = {
|
||||
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
|
||||
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Exchange Front/Surround",
|
||||
.info = snd_ac97_ad1888_lohpsel_info,
|
||||
.get = snd_ac97_ad1888_lohpsel_get,
|
||||
.put = snd_ac97_ad1888_lohpsel_put
|
||||
},
|
||||
AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
|
||||
AC97_SINGLE("Spread Front to Surround and Center/LFE",
|
||||
AC97_AD_MISC, 7, 1, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Downmix",
|
||||
.info = snd_ac97_ad1888_downmix_info,
|
||||
.get = snd_ac97_ad1888_downmix_get,
|
||||
.put = snd_ac97_ad1888_downmix_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "V_REFOUT",
|
||||
.info = snd_ac97_ad1985_vrefout_info,
|
||||
.get = snd_ac97_ad1985_vrefout_get,
|
||||
.put = snd_ac97_ad1985_vrefout_put
|
||||
},
|
||||
AC97_SURROUND_JACK_MODE_CTL,
|
||||
AC97_CHANNEL_MODE_CTL,
|
||||
|
||||
AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
|
||||
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
|
||||
};
|
||||
|
||||
static void ad1985_update_jacks(struct snd_ac97 *ac97)
|
||||
|
@ -1967,9 +2136,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97)
|
|||
{
|
||||
int err;
|
||||
|
||||
if ((err = patch_ad1980_specific(ac97)) < 0)
|
||||
/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
|
||||
snd_ac97_rename_vol_ctl(ac97, "Master Playback",
|
||||
"Master Surround Playback");
|
||||
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
|
||||
|
||||
if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
|
||||
return err;
|
||||
return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls));
|
||||
|
||||
return patch_build_controls(ac97, snd_ac97_ad1985_controls,
|
||||
ARRAY_SIZE(snd_ac97_ad1985_controls));
|
||||
}
|
||||
|
||||
static struct snd_ac97_build_ops patch_ad1985_build_ops = {
|
||||
|
@ -1989,24 +2165,311 @@ int patch_ad1985(struct snd_ac97 * ac97)
|
|||
ac97->build_ops = &patch_ad1985_build_ops;
|
||||
misc = snd_ac97_read(ac97, AC97_AD_MISC);
|
||||
/* switch front/surround line-out/hp-out */
|
||||
/* center/LFE, mic in 3.75V mode */
|
||||
/* AD-compatible mode */
|
||||
/* Stereo mutes enabled */
|
||||
/* in accordance with ADI driver: misc | 0x5c28 */
|
||||
snd_ac97_write_cache(ac97, AC97_AD_MISC, misc |
|
||||
AC97_AD198X_VREFH |
|
||||
AC97_AD198X_LOSEL |
|
||||
AC97_AD198X_HPSEL |
|
||||
AC97_AD198X_CLDIS |
|
||||
AC97_AD198X_LODIS |
|
||||
AC97_AD198X_MSPLT |
|
||||
AC97_AD198X_AC97NC);
|
||||
ac97->flags |= AC97_STEREO_MUTES;
|
||||
|
||||
/* update current jack configuration */
|
||||
ad1985_update_jacks(ac97);
|
||||
|
||||
/* on AD1985 rev. 3, AC'97 revision bits are zero */
|
||||
ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short val;
|
||||
|
||||
val = ac97->regs[AC97_AD_MISC3];
|
||||
ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
int ret0;
|
||||
int ret1;
|
||||
int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0;
|
||||
|
||||
ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL,
|
||||
ucontrol->value.integer.value[0] != 0
|
||||
? AC97_AD1986_LOSEL : 0);
|
||||
if (ret0 < 0)
|
||||
return ret0;
|
||||
|
||||
/* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
|
||||
ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
|
||||
(ucontrol->value.integer.value[0] != 0
|
||||
|| sprd)
|
||||
? AC97_AD1986_SOSEL : 0);
|
||||
if (ret1 < 0)
|
||||
return ret1;
|
||||
|
||||
return (ret0 > 0 || ret1 > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short val;
|
||||
|
||||
val = ac97->regs[AC97_AD_MISC];
|
||||
ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
int ret0;
|
||||
int ret1;
|
||||
int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0;
|
||||
|
||||
ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD,
|
||||
ucontrol->value.integer.value[0] != 0
|
||||
? AC97_AD1986_SPRD : 0);
|
||||
if (ret0 < 0)
|
||||
return ret0;
|
||||
|
||||
/* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
|
||||
ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
|
||||
(ucontrol->value.integer.value[0] != 0
|
||||
|| sprd)
|
||||
? AC97_AD1986_SOSEL : 0);
|
||||
if (ret1 < 0)
|
||||
return ret1;
|
||||
|
||||
return (ret0 > 0 || ret1 > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned char swap = ucontrol->value.integer.value[0] != 0;
|
||||
|
||||
if (swap != ac97->spec.ad18xx.swap_mic_linein) {
|
||||
ac97->spec.ad18xx.swap_mic_linein = swap;
|
||||
if (ac97->build_ops->update_jacks)
|
||||
ac97->build_ops->update_jacks(ac97);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
/* Use MIC_1/2 V_REFOUT as the "get" value */
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short val;
|
||||
unsigned short reg = ac97->regs[AC97_AD_MISC2];
|
||||
if ((reg & AC97_AD1986_MVREF0) != 0)
|
||||
val = 2;
|
||||
else if ((reg & AC97_AD1986_MVREF1) != 0)
|
||||
val = 3;
|
||||
else if ((reg & AC97_AD1986_MVREF2) != 0)
|
||||
val = 1;
|
||||
else
|
||||
val = 0;
|
||||
ucontrol->value.enumerated.item[0] = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short cval;
|
||||
unsigned short lval;
|
||||
unsigned short mval;
|
||||
int cret;
|
||||
int lret;
|
||||
int mret;
|
||||
|
||||
switch (ucontrol->value.enumerated.item[0])
|
||||
{
|
||||
case 0: /* High-Z */
|
||||
cval = 0;
|
||||
lval = 0;
|
||||
mval = 0;
|
||||
break;
|
||||
case 1: /* 3.7 V */
|
||||
cval = AC97_AD1986_CVREF2;
|
||||
lval = AC97_AD1986_LVREF2;
|
||||
mval = AC97_AD1986_MVREF2;
|
||||
break;
|
||||
case 2: /* 2.25 V */
|
||||
cval = AC97_AD1986_CVREF0;
|
||||
lval = AC97_AD1986_LVREF0;
|
||||
mval = AC97_AD1986_MVREF0;
|
||||
break;
|
||||
case 3: /* 0 V */
|
||||
cval = AC97_AD1986_CVREF1;
|
||||
lval = AC97_AD1986_LVREF1;
|
||||
mval = AC97_AD1986_MVREF1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
|
||||
AC97_AD1986_CVREF_MASK, cval);
|
||||
if (cret < 0)
|
||||
return cret;
|
||||
lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3,
|
||||
AC97_AD1986_LVREF_MASK, lval);
|
||||
if (lret < 0)
|
||||
return lret;
|
||||
mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
|
||||
AC97_AD1986_MVREF_MASK, mval);
|
||||
if (mret < 0)
|
||||
return mret;
|
||||
|
||||
return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = {
|
||||
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Exchange Front/Surround",
|
||||
.info = snd_ac97_ad1986_bool_info,
|
||||
.get = snd_ac97_ad1986_lososel_get,
|
||||
.put = snd_ac97_ad1986_lososel_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Exchange Mic/Line In",
|
||||
.info = snd_ac97_ad1986_bool_info,
|
||||
.get = snd_ac97_ad1986_miclisel_get,
|
||||
.put = snd_ac97_ad1986_miclisel_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Spread Front to Surround and Center/LFE",
|
||||
.info = snd_ac97_ad1986_bool_info,
|
||||
.get = snd_ac97_ad1986_spread_get,
|
||||
.put = snd_ac97_ad1986_spread_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Downmix",
|
||||
.info = snd_ac97_ad1888_downmix_info,
|
||||
.get = snd_ac97_ad1888_downmix_get,
|
||||
.put = snd_ac97_ad1888_downmix_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "V_REFOUT",
|
||||
.info = snd_ac97_ad1985_vrefout_info,
|
||||
.get = snd_ac97_ad1986_vrefout_get,
|
||||
.put = snd_ac97_ad1986_vrefout_put
|
||||
},
|
||||
AC97_SURROUND_JACK_MODE_CTL,
|
||||
AC97_CHANNEL_MODE_CTL,
|
||||
|
||||
AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
|
||||
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0)
|
||||
};
|
||||
|
||||
static void ad1986_update_jacks(struct snd_ac97 *ac97)
|
||||
{
|
||||
unsigned short misc_val = 0;
|
||||
unsigned short ser_val;
|
||||
|
||||
/* disable SURROUND and CENTER/LFE if not surround mode */
|
||||
if (! is_surround_on(ac97))
|
||||
misc_val |= AC97_AD1986_SODIS;
|
||||
if (! is_clfe_on(ac97))
|
||||
misc_val |= AC97_AD1986_CLDIS;
|
||||
|
||||
/* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
|
||||
if (is_shared_linein(ac97))
|
||||
misc_val |= AC97_AD1986_LISEL_SURR;
|
||||
else if (ac97->spec.ad18xx.swap_mic_linein != 0)
|
||||
misc_val |= AC97_AD1986_LISEL_MIC;
|
||||
snd_ac97_update_bits(ac97, AC97_AD_MISC,
|
||||
AC97_AD1986_SODIS | AC97_AD1986_CLDIS |
|
||||
AC97_AD1986_LISEL_MASK,
|
||||
misc_val);
|
||||
|
||||
/* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */
|
||||
if (is_shared_micin(ac97))
|
||||
ser_val = AC97_AD1986_OMS_C;
|
||||
else if (ac97->spec.ad18xx.swap_mic_linein != 0)
|
||||
ser_val = AC97_AD1986_OMS_L;
|
||||
else
|
||||
ser_val = AC97_AD1986_OMS_M;
|
||||
snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG,
|
||||
AC97_AD1986_OMS_MASK,
|
||||
ser_val);
|
||||
}
|
||||
|
||||
static int patch_ad1986_specific(struct snd_ac97 *ac97)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
|
||||
return err;
|
||||
|
||||
return patch_build_controls(ac97, snd_ac97_ad1986_controls,
|
||||
ARRAY_SIZE(snd_ac97_ad1985_controls));
|
||||
}
|
||||
|
||||
static struct snd_ac97_build_ops patch_ad1986_build_ops = {
|
||||
.build_post_spdif = patch_ad198x_post_spdif,
|
||||
.build_specific = patch_ad1986_specific,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ad18xx_resume,
|
||||
#endif
|
||||
.update_jacks = ad1986_update_jacks,
|
||||
};
|
||||
|
||||
int patch_ad1986(struct snd_ac97 * ac97)
|
||||
{
|
||||
patch_ad1881(ac97);
|
||||
ac97->build_ops = &patch_ad1986_build_ops;
|
||||
ac97->flags |= AC97_STEREO_MUTES;
|
||||
|
||||
/* update current jack configuration */
|
||||
ad1986_update_jacks(ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* realtek ALC65x/850 codecs
|
||||
*/
|
||||
|
@ -2014,12 +2477,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)
|
|||
{
|
||||
int shared;
|
||||
|
||||
/* shared Line-In */
|
||||
shared = is_shared_linein(ac97);
|
||||
/* shared Line-In / Surround Out */
|
||||
shared = is_shared_surrout(ac97);
|
||||
snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
|
||||
shared ? (1 << 9) : 0);
|
||||
/* update shared Mic */
|
||||
shared = is_shared_micin(ac97);
|
||||
/* update shared Mic In / Center/LFE Out */
|
||||
shared = is_shared_clfeout(ac97);
|
||||
/* disable/enable vref */
|
||||
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
|
||||
shared ? (1 << 12) : 0);
|
||||
|
@ -2064,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = {
|
|||
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
|
||||
};
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
|
||||
|
||||
static int patch_alc650_specific(struct snd_ac97 * ac97)
|
||||
{
|
||||
|
@ -2149,12 +2612,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97)
|
|||
{
|
||||
int shared;
|
||||
|
||||
/* shared Line-In */
|
||||
shared = is_shared_linein(ac97);
|
||||
/* shared Line-In / Surround Out */
|
||||
shared = is_shared_surrout(ac97);
|
||||
ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
|
||||
shared ? (1 << 9) : 0, 0);
|
||||
/* update shared mic */
|
||||
shared = is_shared_micin(ac97);
|
||||
/* update shared Mic In / Center/LFE Out */
|
||||
shared = is_shared_clfeout(ac97);
|
||||
/* misc control; vrefout disable */
|
||||
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
|
||||
shared ? (1 << 12) : 0);
|
||||
|
@ -2264,7 +2727,8 @@ int patch_alc655(struct snd_ac97 * ac97)
|
|||
if (ac97->subsystem_vendor == 0x1462 &&
|
||||
(ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
|
||||
ac97->subsystem_device == 0x0161 || /* LG K1 Express */
|
||||
ac97->subsystem_device == 0x0351)) /* MSI L725 laptop */
|
||||
ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */
|
||||
ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */
|
||||
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
|
||||
else
|
||||
val |= (1 << 1); /* Pin 47 is spdif input pin */
|
||||
|
@ -2297,16 +2761,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97)
|
|||
{
|
||||
int shared;
|
||||
|
||||
/* shared Line-In */
|
||||
shared = is_shared_linein(ac97);
|
||||
/* shared Line-In / Surround Out */
|
||||
shared = is_shared_surrout(ac97);
|
||||
/* SURR 1kOhm (bit4), Amp (bit5) */
|
||||
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
|
||||
shared ? (1<<5) : (1<<4));
|
||||
/* LINE-IN = 0, SURROUND = 2 */
|
||||
snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
|
||||
shared ? (2<<12) : (0<<12));
|
||||
/* update shared mic */
|
||||
shared = is_shared_micin(ac97);
|
||||
/* update shared Mic In / Center/LFE Out */
|
||||
shared = is_shared_clfeout(ac97);
|
||||
/* Vref disable (bit12), 1kOhm (bit13) */
|
||||
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
|
||||
shared ? (1<<12) : (1<<13));
|
||||
|
@ -2379,9 +2843,9 @@ int patch_alc850(struct snd_ac97 *ac97)
|
|||
*/
|
||||
static void cm9738_update_jacks(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* shared Line-In */
|
||||
/* shared Line-In / Surround Out */
|
||||
snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
|
||||
is_shared_linein(ac97) ? (1 << 10) : 0);
|
||||
is_shared_surrout(ac97) ? (1 << 10) : 0);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = {
|
||||
|
@ -2463,12 +2927,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = {
|
|||
|
||||
static void cm9739_update_jacks(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* shared Line-In */
|
||||
/* shared Line-In / Surround Out */
|
||||
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
|
||||
is_shared_linein(ac97) ? (1 << 10) : 0);
|
||||
/* shared Mic */
|
||||
is_shared_surrout(ac97) ? (1 << 10) : 0);
|
||||
/* shared Mic In / Center/LFE Out **/
|
||||
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
|
||||
is_shared_micin(ac97) ? 0x1000 : 0x2000);
|
||||
is_shared_clfeout(ac97) ? 0x1000 : 0x2000);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = {
|
||||
|
@ -2580,8 +3044,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97)
|
|||
|
||||
val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)];
|
||||
val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)];
|
||||
val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)];
|
||||
val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)];
|
||||
val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)];
|
||||
val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)];
|
||||
|
||||
snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val);
|
||||
}
|
||||
|
@ -2821,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97)
|
|||
snd_ac97_write_cache(ac97, 0x5c, 0x20);
|
||||
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
|
||||
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
|
||||
ac97->build_ops = &patch_vt1616_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2828,12 +3293,12 @@ int patch_vt1617a(struct snd_ac97 * ac97)
|
|||
*/
|
||||
static void it2646_update_jacks(struct snd_ac97 *ac97)
|
||||
{
|
||||
/* shared Line-In */
|
||||
/* shared Line-In / Surround Out */
|
||||
snd_ac97_update_bits(ac97, 0x76, 1 << 9,
|
||||
is_shared_linein(ac97) ? (1<<9) : 0);
|
||||
/* shared Mic */
|
||||
is_shared_surrout(ac97) ? (1<<9) : 0);
|
||||
/* shared Mic / Center/LFE Out */
|
||||
snd_ac97_update_bits(ac97, 0x76, 1 << 10,
|
||||
is_shared_micin(ac97) ? (1<<10) : 0);
|
||||
is_shared_clfeout(ac97) ? (1<<10) : 0);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = {
|
||||
|
|
|
@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97);
|
|||
int patch_ad1981a(struct snd_ac97 * ac97);
|
||||
int patch_ad1981b(struct snd_ac97 * ac97);
|
||||
int patch_ad1985(struct snd_ac97 * ac97);
|
||||
int patch_ad1986(struct snd_ac97 * ac97);
|
||||
int patch_alc650(struct snd_ac97 * ac97);
|
||||
int patch_alc655(struct snd_ac97 * ac97);
|
||||
int patch_alc850(struct snd_ac97 * ac97);
|
||||
|
|
|
@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
|
|||
return change;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_ak4531_controls[] = {
|
||||
|
||||
|
|
|
@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
snd_pcm_hw_params_t * hw_params)
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
return snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
|
@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip)
|
|||
snd_als300_dbgcallleave();
|
||||
}
|
||||
|
||||
static int __devinit snd_als300_create(snd_card_t *card,
|
||||
static int __devinit snd_als300_create(struct snd_card *card,
|
||||
struct pci_dev *pci, int chip_type,
|
||||
struct snd_als300 **rchip)
|
||||
{
|
||||
|
@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card,
|
|||
void *irq_handler;
|
||||
int err;
|
||||
|
||||
static snd_device_ops_t ops = {
|
||||
static struct snd_device_ops ops = {
|
||||
.dev_free = snd_als300_dev_free,
|
||||
};
|
||||
*rchip = NULL;
|
||||
|
|
|
@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
|
|||
static int ac97_clock = 48000;
|
||||
static char *ac97_quirk;
|
||||
static int spdif_aclink = 1;
|
||||
static int ac97_codec = -1;
|
||||
|
||||
module_param(index, int, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
|
||||
|
@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444);
|
|||
MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
|
||||
module_param(ac97_quirk, charp, 0444);
|
||||
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
|
||||
module_param(ac97_codec, int, 0444);
|
||||
MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing.");
|
||||
module_param(spdif_aclink, bool, 0444);
|
||||
MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
|
||||
|
||||
|
@ -293,6 +296,10 @@ static struct pci_device_id snd_atiixp_ids[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
|
||||
|
||||
static struct snd_pci_quirk atiixp_quirks[] __devinitdata = {
|
||||
SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0),
|
||||
{ } /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* lowlevel functions
|
||||
|
@ -553,11 +560,33 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
|
|||
ATI_REG_ISR_CODEC2_NOT_READY)
|
||||
#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
|
||||
|
||||
static int ac97_probing_bugs(struct pci_dev *pci)
|
||||
{
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
q = snd_pci_quirk_lookup(pci, atiixp_quirks);
|
||||
if (q) {
|
||||
snd_printdd(KERN_INFO "Atiixp quirk for %s. "
|
||||
"Forcing codec %d\n", q->name, q->value);
|
||||
return q->value;
|
||||
}
|
||||
/* this hardware doesn't need workarounds. Probe for codec */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int snd_atiixp_codec_detect(struct atiixp *chip)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
chip->codec_not_ready_bits = 0;
|
||||
if (ac97_codec == -1)
|
||||
ac97_codec = ac97_probing_bugs(chip->pci);
|
||||
if (ac97_codec >= 0) {
|
||||
chip->codec_not_ready_bits |=
|
||||
CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10));
|
||||
return 0;
|
||||
}
|
||||
|
||||
atiixp_write(chip, IER, CODEC_CHECK_BITS);
|
||||
/* wait for the interrupts */
|
||||
timeout = 50;
|
||||
|
@ -1396,7 +1425,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
|
|||
ac97.private_data = chip;
|
||||
ac97.pci = chip->pci;
|
||||
ac97.num = i;
|
||||
ac97.scaps = AC97_SCAP_SKIP_MODEM;
|
||||
ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
|
||||
if (! chip->spdif_over_aclink)
|
||||
ac97.scaps |= AC97_SCAP_NO_SPDIF;
|
||||
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
|
||||
|
|
|
@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
|
|||
ac97.private_data = chip;
|
||||
ac97.pci = chip->pci;
|
||||
ac97.num = i;
|
||||
ac97.scaps = AC97_SCAP_SKIP_AUDIO;
|
||||
ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
|
||||
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
|
||||
chip->ac97[i] = NULL; /* to be sure */
|
||||
snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
|
||||
|
|
|
@ -1382,7 +1382,6 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
|
|||
snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
|
||||
snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
|
||||
chip->spdif_enable = 0; /* Set digital SPDIF output off */
|
||||
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
|
||||
//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
|
||||
//snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */
|
||||
|
||||
|
@ -1402,8 +1401,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
|
|||
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */
|
||||
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */
|
||||
}
|
||||
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
|
||||
chip->capture_source = 3; /* Set CAPTURE_SOURCE */
|
||||
if (chip->details->i2c_adc == 1) {
|
||||
/* Select MIC, Line in, TAD in, AUX in */
|
||||
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
|
||||
/* Default to CAPTURE_SOURCE to i2s in */
|
||||
chip->capture_source = 3;
|
||||
} else if (chip->details->ac97 == 1) {
|
||||
/* Default to AC97 in */
|
||||
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
|
||||
/* Default to CAPTURE_SOURCE to AC97 in */
|
||||
chip->capture_source = 4;
|
||||
} else {
|
||||
/* Select MIC, Line in, TAD in, AUX in */
|
||||
snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
|
||||
/* Default to Set CAPTURE_SOURCE to i2s in */
|
||||
chip->capture_source = 3;
|
||||
}
|
||||
|
||||
if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
|
||||
/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
|
||||
|
@ -1605,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
|
|||
snd_ca0106_proc_init(chip);
|
||||
#endif
|
||||
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
|
||||
if ((err = snd_card_register(card)) < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
|
|
|
@ -74,8 +74,8 @@
|
|||
|
||||
#include "ca0106.h"
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
|
||||
static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
|
||||
|
||||
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
|
@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
|
|||
.private_value = ((chid) << 8) | (reg) \
|
||||
}
|
||||
|
||||
#define I2C_VOLUME(xname,chid) \
|
||||
{ \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_ca0106_i2c_volume_info, \
|
||||
.get = snd_ca0106_i2c_volume_get, \
|
||||
.put = snd_ca0106_i2c_volume_put, \
|
||||
.tlv = { .p = snd_ca0106_db_scale2 }, \
|
||||
.private_value = chid \
|
||||
}
|
||||
|
||||
|
||||
static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
|
||||
CA_VOLUME("Analog Front Playback Volume",
|
||||
CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
|
||||
|
@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
|
|||
CA_VOLUME("CAPTURE feedback Playback Volume",
|
||||
1, CAPTURE_CONTROL),
|
||||
|
||||
I2C_VOLUME("Phone Capture Volume", 0),
|
||||
I2C_VOLUME("Mic Capture Volume", 1),
|
||||
I2C_VOLUME("Line in Capture Volume", 2),
|
||||
I2C_VOLUME("Aux Capture Volume", 3),
|
||||
|
||||
{
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
|
@ -539,14 +521,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
|
|||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Digital Capture Source",
|
||||
.name = "Digital Source Capture Enum",
|
||||
.info = snd_ca0106_capture_source_info,
|
||||
.get = snd_ca0106_capture_source_get,
|
||||
.put = snd_ca0106_capture_source_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.name = "Analog Source Capture Enum",
|
||||
.info = snd_ca0106_i2c_capture_source_info,
|
||||
.get = snd_ca0106_i2c_capture_source_get,
|
||||
.put = snd_ca0106_i2c_capture_source_put
|
||||
|
@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
|
|||
},
|
||||
};
|
||||
|
||||
#define I2C_VOLUME(xname,chid) \
|
||||
{ \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_ca0106_i2c_volume_info, \
|
||||
.get = snd_ca0106_i2c_volume_get, \
|
||||
.put = snd_ca0106_i2c_volume_put, \
|
||||
.tlv = { .p = snd_ca0106_db_scale2 }, \
|
||||
.private_value = chid \
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
|
||||
I2C_VOLUME("Phone Capture Volume", 0),
|
||||
I2C_VOLUME("Mic Capture Volume", 1),
|
||||
I2C_VOLUME("Line in Capture Volume", 2),
|
||||
I2C_VOLUME("Aux Capture Volume", 3),
|
||||
};
|
||||
|
||||
static int __devinit remove_ctl(struct snd_card *card, const char *name)
|
||||
{
|
||||
struct snd_ctl_elem_id id;
|
||||
|
@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
|
|||
return err;
|
||||
}
|
||||
if (emu->details->i2c_adc == 1) {
|
||||
for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (emu->details->gpio_type == 1)
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
|
||||
else /* gpio_type == 2 */
|
||||
|
|
|
@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
|
|||
return change;
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_cs4281_fm_vol =
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/asoundef.h>
|
||||
|
|
|
@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on);
|
|||
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
|
||||
char force);
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444);
|
|||
MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
|
||||
|
||||
static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
|
||||
|
||||
static int get_firmware(const struct firmware **fw_entry,
|
||||
const struct firmware *frm, struct echoaudio *chip)
|
||||
|
@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
|
|||
static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
|
||||
.name = "Line Playback Volume",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = snd_echo_output_gain_info,
|
||||
.get = snd_echo_output_gain_get,
|
||||
.put = snd_echo_output_gain_put,
|
||||
.tlv = {.p = db_scale_output_gain},
|
||||
};
|
||||
#else
|
||||
static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
|
||||
.name = "PCM Playback Volume",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = snd_echo_output_gain_info,
|
||||
.get = snd_echo_output_gain_get,
|
||||
.put = snd_echo_output_gain_put,
|
||||
.tlv = {.p = db_scale_output_gain},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
|
|||
return changed;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
|
||||
.name = "Line Capture Volume",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = snd_echo_input_gain_info,
|
||||
.get = snd_echo_input_gain_get,
|
||||
.put = snd_echo_input_gain_put,
|
||||
.tlv = {.p = db_scale_input_gain},
|
||||
};
|
||||
|
||||
#endif /* ECHOCARD_HAS_INPUT_GAIN */
|
||||
|
@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
|
|||
static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
|
||||
.name = "Monitor Mixer Volume",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = snd_echo_mixer_info,
|
||||
.get = snd_echo_mixer_get,
|
||||
.put = snd_echo_mixer_put,
|
||||
.tlv = {.p = db_scale_output_gain},
|
||||
};
|
||||
|
||||
#endif /* ECHOCARD_HAS_MONITOR */
|
||||
|
@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
|
|||
static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
|
||||
.name = "VMixer Volume",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = snd_echo_vmixer_info,
|
||||
.get = snd_echo_vmixer_get,
|
||||
.put = snd_echo_vmixer_put,
|
||||
.tlv = {.p = db_scale_output_gain},
|
||||
};
|
||||
|
||||
#endif /* ECHOCARD_HAS_VMIXER */
|
||||
|
@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
|
|||
static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
|
||||
.name = "VU-meters",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = snd_echo_vumeters_info,
|
||||
.get = snd_echo_vumeters_get,
|
||||
.tlv = {.p = db_scale_output_gain},
|
||||
};
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue