Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (430 commits)
  ALSA: hda - Add quirk for Acer Ferrari 5000
  ALSA: hda - Use cached calls to get widget caps and pin caps
  ALSA: hda - Don't create empty/single-item input source
  ALSA: hda - Fix the wrong pin-cap check in patch_realtek.c
  ALSA: hda - Cache pin-cap values
  ALSA: hda - Avoid output amp manipulation to digital mic pins
  ALSA: hda - Add function id to proc output
  ALSA: pcm - Safer boundary checks
  ALSA: hda - Detect digital-mic inputs on ALC663 / ALC272
  ALSA: sound/ali5451: typo: s/resouces/resources/
  ALSA: hda - Don't show the current connection for power widgets
  ALSA: Fix wrong pointer to dev_err() in arm/pxa2xx-ac97-lib.c
  ASoC: Declare Headset as Mic and Headphone widgets for SDP3430
  ASoC: OMAP: N810: Add more jack functions
  ASoC: OMAP: N810: Mark not connected input pins
  ASoC: Add FLL support for WM8400
  ALSA: hda - Don't reset stream at each prepare callback
  ALSA: hda - Don't reset BDL unnecessarily
  ALSA: pcm - Fix delta calculation at boundary overlap
  ALSA: pcm - Reset invalid position even without debug option
  ...
This commit is contained in:
Linus Torvalds 2009-03-26 11:05:17 -07:00
commit 502012534d
415 changed files with 20505 additions and 9798 deletions

View File

@ -12,7 +12,8 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
mac80211.xml debugobjects.xml sh.xml regulator.xml
mac80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml
###
# The build process is as follows (targets):

View File

@ -1,11 +1,11 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<book>
<?dbhtml filename="index.html">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<!-- ****************************************************** -->
<!-- Header -->
<!-- ****************************************************** -->
<book id="ALSA-Driver-API">
<bookinfo>
<title>The ALSA Driver API</title>
@ -35,6 +35,8 @@
</bookinfo>
<toc></toc>
<chapter><title>Management of Cards and Devices</title>
<sect1><title>Card Management</title>
!Esound/core/init.c
@ -71,6 +73,10 @@
!Esound/pci/ac97/ac97_codec.c
!Esound/pci/ac97/ac97_pcm.c
</sect1>
<sect1><title>Virtual Master Control API</title>
!Esound/core/vmaster.c
!Iinclude/sound/control.h
</sect1>
</chapter>
<chapter><title>MIDI API</title>
<sect1><title>Raw MIDI API</title>
@ -88,6 +94,9 @@
<chapter><title>Miscellaneous Functions</title>
<sect1><title>Hardware-Dependent Devices API</title>
!Esound/core/hwdep.c
</sect1>
<sect1><title>Jack Abstraction Layer API</title>
!Esound/core/jack.c
</sect1>
<sect1><title>ISA DMA Helpers</title>
!Esound/core/isadma.c

View File

@ -1,11 +1,11 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<book>
<?dbhtml filename="index.html">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<!-- ****************************************************** -->
<!-- Header -->
<!-- ****************************************************** -->
<book id="Writing-an-ALSA-Driver">
<bookinfo>
<title>Writing an ALSA Driver</title>
<author>
@ -492,9 +492,9 @@
}
/* (2) */
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
return err;
/* (3) */
err = snd_mychip_create(card, pci, &chip);
@ -590,8 +590,9 @@
<programlisting>
<![CDATA[
struct snd_card *card;
int err;
....
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
]]>
</programlisting>
</informalexample>
@ -809,26 +810,28 @@
<para>
As mentioned above, to create a card instance, call
<function>snd_card_new()</function>.
<function>snd_card_create()</function>.
<informalexample>
<programlisting>
<![CDATA[
struct snd_card *card;
card = snd_card_new(index, id, module, extra_size);
int err;
err = snd_card_create(index, id, module, extra_size, &card);
]]>
</programlisting>
</informalexample>
</para>
<para>
The function takes four arguments, the card-index number, the
The function takes five arguments, the card-index number, the
id string, the module pointer (usually
<constant>THIS_MODULE</constant>),
and the size of extra-data space. The last argument is used to
the size of extra-data space, and the pointer to return the
card instance. The extra_size argument is used to
allocate card-&gt;private_data for the
chip-specific data. Note that these data
are allocated by <function>snd_card_new()</function>.
are allocated by <function>snd_card_create()</function>.
</para>
</section>
@ -915,15 +918,16 @@
</para>
<section id="card-management-chip-specific-snd-card-new">
<title>1. Allocating via <function>snd_card_new()</function>.</title>
<title>1. Allocating via <function>snd_card_create()</function>.</title>
<para>
As mentioned above, you can pass the extra-data-length
to the 4th argument of <function>snd_card_new()</function>, i.e.
to the 4th argument of <function>snd_card_create()</function>, i.e.
<informalexample>
<programlisting>
<![CDATA[
card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct mychip));
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct mychip), &card);
]]>
</programlisting>
</informalexample>
@ -952,8 +956,8 @@
<para>
After allocating a card instance via
<function>snd_card_new()</function> (with
<constant>NULL</constant> on the 4th arg), call
<function>snd_card_create()</function> (with
<constant>0</constant> on the 4th arg), call
<function>kzalloc()</function>.
<informalexample>
@ -961,7 +965,7 @@
<![CDATA[
struct snd_card *card;
struct mychip *chip;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
.....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
]]>
@ -5750,8 +5754,9 @@ struct _snd_pcm_runtime {
....
struct snd_card *card;
struct mychip *chip;
int err;
....
card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
....
@ -5763,7 +5768,7 @@ struct _snd_pcm_runtime {
</informalexample>
When you created the chip data with
<function>snd_card_new()</function>, it's anyway accessible
<function>snd_card_create()</function>, it's anyway accessible
via <structfield>private_data</structfield> field.
<informalexample>
@ -5775,9 +5780,10 @@ struct _snd_pcm_runtime {
....
struct snd_card *card;
struct mychip *chip;
int err;
....
card = snd_card_new(index[dev], id[dev], THIS_MODULE,
sizeof(struct mychip));
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct mychip), &card);
....
chip = card->private_data;
....

View File

@ -346,6 +346,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
sbirq - IRQ # for CMI8330 chip (SB16)
sbdma8 - 8bit DMA # for CMI8330 chip (SB16)
sbdma16 - 16bit DMA # for CMI8330 chip (SB16)
fmport - (optional) OPL3 I/O port
mpuport - (optional) MPU401 I/O port
mpuirq - (optional) MPU401 irq #
This module supports multiple cards and autoprobe.
@ -388,34 +391,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
Module snd-cs4232
-----------------
Module for sound cards based on CS4232/CS4232A ISA chips.
isapnp - ISA PnP detection - 0 = disable, 1 = enable (default)
with isapnp=0, the following options are available:
port - port # for CS4232 chip (PnP setup - 0x534)
cport - control port # for CS4232 chip (PnP setup - 0x120,0x210,0xf00)
mpu_port - port # for MPU-401 UART (PnP setup - 0x300), -1 = disable
fm_port - FM port # for CS4232 chip (PnP setup - 0x388), -1 = disable
irq - IRQ # for CS4232 chip (5,7,9,11,12,15)
mpu_irq - IRQ # for MPU-401 UART (9,11,12,15)
dma1 - first DMA # for CS4232 chip (0,1,3)
dma2 - second DMA # for Yamaha CS4232 chip (0,1,3), -1 = disable
This module supports multiple cards. This module does not support autoprobe
(if ISA PnP is not used) thus main port must be specified!!! Other ports are
optional.
The power-management is supported.
Module snd-cs4236
-----------------
Module for sound cards based on CS4235/CS4236/CS4236B/CS4237B/
Module for sound cards based on CS4232/CS4232A,
CS4235/CS4236/CS4236B/CS4237B/
CS4238B/CS4239 ISA chips.
isapnp - ISA PnP detection - 0 = disable, 1 = enable (default)
@ -437,6 +417,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
This module is aliased as snd-cs4232 since it provides the old
snd-cs4232 functionality, too.
Module snd-cs4281
-----------------
@ -606,6 +589,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for ESS AudioDrive ES-1688 and ES-688 sound cards.
port - port # for ES-1688 chip (0x220,0x240,0x260)
fm_port - port # for OPL3 (option; share the same port as default)
mpu_port - port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
irq - IRQ # for ES-1688 chip (5,7,9,10)
mpu_irq - IRQ # for MPU-401 port (5,7,9,10)
@ -757,6 +741,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
model - force the model name
position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
probe_mask - Bitmask to probe codecs (default = -1, meaning all slots)
When the bit 8 (0x100) is set, the lower 8 bits are used
as the "fixed" codec slots; i.e. the driver probes the
slots regardless what hardware reports back
probe_only - Only probing and no codec initialization (default=off);
Useful to check the initial codec status for debugging
bdl_pos_adj - Specifies the DMA IRQ timing delay in samples.
@ -1185,6 +1172,54 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple devices and PnP.
Module snd-msnd-classic
-----------------------
Module for Turtle Beach MultiSound Classic, Tahiti or Monterey
soundcards.
io - Port # for msnd-classic card
irq - IRQ # for msnd-classic card
mem - Memory address (0xb0000, 0xc8000, 0xd0000, 0xd8000,
0xe0000 or 0xe8000)
write_ndelay - enable write ndelay (default = 1)
calibrate_signal - calibrate signal (default = 0)
isapnp - ISA PnP detection - 0 = disable, 1 = enable (default)
digital - Digital daughterboard present (default = 0)
cfg - Config port (0x250, 0x260 or 0x270) default = PnP
reset - Reset all devices
mpu_io - MPU401 I/O port
mpu_irq - MPU401 irq#
ide_io0 - IDE port #0
ide_io1 - IDE port #1
ide_irq - IDE irq#
joystick_io - Joystick I/O port
The driver requires firmware files "turtlebeach/msndinit.bin" and
"turtlebeach/msndperm.bin" in the proper firmware directory.
See Documentation/sound/oss/MultiSound for important information
about this driver. Note that it has been discontinued, but the
Voyetra Turtle Beach knowledge base entry for it is still available
at
http://www.turtlebeach.com/site/kb_ftp/790.asp
Module snd-msnd-pinnacle
------------------------
Module for Turtle Beach MultiSound Pinnacle/Fiji soundcards.
io - Port # for pinnacle/fiji card
irq - IRQ # for pinnalce/fiji card
mem - Memory address (0xb0000, 0xc8000, 0xd0000, 0xd8000,
0xe0000 or 0xe8000)
write_ndelay - enable write ndelay (default = 1)
calibrate_signal - calibrate signal (default = 0)
isapnp - ISA PnP detection - 0 = disable, 1 = enable (default)
The driver requires firmware files "turtlebeach/pndspini.bin" and
"turtlebeach/pndsperm.bin" in the proper firmware directory.
Module snd-mtpav
----------------
@ -1824,7 +1859,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
-------------------
Module for sound cards based on the Asus AV100/AV200 chips,
i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe).
i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX.
This module supports autoprobe and multiple cards.

View File

@ -56,6 +56,7 @@ ALC262
sony-assamd Sony ASSAMD
toshiba-s06 Toshiba S06
toshiba-rx1 Toshiba RX1
tyan Tyan Thunder n6650W (S2915-E)
ultra Samsung Q1 Ultra Vista model
lenovo-3000 Lenovo 3000 y410
nec NEC Versa S9100
@ -261,6 +262,8 @@ Conexant 5051
=============
laptop Basic Laptop config (default)
hp HP Spartan laptop
hp-dv6736 HP dv6736
lenovo-x200 Lenovo X200 laptop
STAC9200
========
@ -278,6 +281,7 @@ STAC9200
gateway-m4 Gateway laptops with EAPD control
gateway-m4-2 Gateway laptops with EAPD control
panasonic Panasonic CF-74
auto BIOS setup (default)
STAC9205/9254
=============
@ -285,6 +289,8 @@ STAC9205/9254
dell-m42 Dell (unknown)
dell-m43 Dell Precision
dell-m44 Dell Inspiron
eapd Keep EAPD on (e.g. Gateway T1616)
auto BIOS setup (default)
STAC9220/9221
=============
@ -308,6 +314,7 @@ STAC9220/9221
dell-d82 Dell (unknown)
dell-m81 Dell (unknown)
dell-m82 Dell XPS M1210
auto BIOS setup (default)
STAC9202/9250/9251
==================
@ -319,6 +326,7 @@ STAC9202/9250/9251
m3 Some Gateway MX series laptops
m5 Some Gateway MX series laptops (MP6954)
m6 Some Gateway NX series laptops
auto BIOS setup (default)
STAC9227/9228/9229/927x
=======================
@ -328,6 +336,7 @@ STAC9227/9228/9229/927x
5stack D965 5stack + SPDIF
dell-3stack Dell Dimension E520
dell-bios Fixes with Dell BIOS setup
auto BIOS setup (default)
STAC92HD71B*
============
@ -335,7 +344,10 @@ STAC92HD71B*
dell-m4-1 Dell desktops
dell-m4-2 Dell desktops
dell-m4-3 Dell desktops
hp-m4 HP dv laptops
hp-m4 HP mini 1000
hp-dv5 HP dv series
hp-hdx HP HDX series
auto BIOS setup (default)
STAC92HD73*
===========
@ -345,13 +357,16 @@ STAC92HD73*
dell-m6-dmic Dell desktops/laptops with digital mics
dell-m6 Dell desktops/laptops with both type of mics
dell-eq Dell desktops/laptops
auto BIOS setup (default)
STAC92HD83*
===========
ref Reference board
mic-ref Reference board with power managment for ports
dell-s14 Dell laptop
auto BIOS setup (default)
STAC9872
========
vaio Setup for VAIO FE550G/SZ110
vaio-ar Setup for VAIO AR
vaio VAIO laptop without SPDIF
auto BIOS setup (default)

View File

@ -109,6 +109,13 @@ slot, pass `probe_mask=1`. For the first and the third slots, pass
Since 2.6.29 kernel, the driver has a more robust probing method, so
this error might happen rarely, though.
On a machine with a broken BIOS, sometimes you need to force the
driver to probe the codec slots the hardware doesn't report for use.
In such a case, turn the bit 8 (0x100) of `probe_mask` option on.
Then the rest 8 bits are passed as the codec slots to probe
unconditionally. For example, `probe_mask=0x103` will force to probe
the codec slots 0 and 1 no matter what the hardware reports.
Interrupt Handling
~~~~~~~~~~~~~~~~~~
@ -358,10 +365,26 @@ modelname::
to this file.
init_verbs::
The extra verbs to execute at initialization. You can add a verb by
writing to this file. Pass tree numbers, nid, verb and parameter.
writing to this file. Pass three numbers: nid, verb and parameter
(separated with a space).
hints::
Shows hint strings for codec parsers for any use. Right now it's
not used.
Shows / stores hint strings for codec parsers for any use.
Its format is `key = value`. For example, passing `hp_detect = yes`
to IDT/STAC codec parser will result in the disablement of the
headphone detection.
init_pin_configs::
Shows the initial pin default config values set by BIOS.
driver_pin_configs::
Shows the pin default values set by the codec parser explicitly.
This doesn't show all pin values but only the changed values by
the parser. That is, if the parser doesn't change the pin default
config values by itself, this will contain nothing.
user_pin_configs::
Shows the pin default config values to override the BIOS setup.
Writing this (with two numbers, NID and value) appends the new
value. The given will be used instead of the initial BIOS value at
the next reconfiguration time. Note that this config will override
even the driver pin configs, too.
reconfig::
Triggers the codec re-configuration. When any value is written to
this file, the driver re-initialize and parses the codec tree
@ -371,6 +394,14 @@ clear::
Resets the codec, removes the mixer elements and PCM stuff of the
specified codec, and clear all init verbs and hints.
For example, when you want to change the pin default configuration
value of the pin widget 0x14 to 0x9993013f, and let the driver
re-configure based on that state, run like below:
------------------------------------------------------------------------
# echo 0x14 0x9993013f > /sys/class/sound/hwC0D0/user_pin_configs
# echo 1 > /sys/class/sound/hwC0D0/reconfig
------------------------------------------------------------------------
Power-Saving
~~~~~~~~~~~~
@ -461,6 +492,16 @@ run with `--no-upload` option, and attach the generated file.
There are some other useful options. See `--help` option output for
details.
When a probe error occurs or when the driver obviously assigns a
mismatched model, it'd be helpful to load the driver with
`probe_only=1` option (at best after the cold reboot) and run
alsa-info at this state. With this option, the driver won't configure
the mixer and PCM but just tries to probe the codec slot. After
probing, the proc file is available, so you can get the raw codec
information before modified by the driver. Of course, the driver
isn't usable with `probe_only=1`. But you can continue the
configuration via hwdep sysfs file if hda-reconfig option is enabled.
hda-verb
~~~~~~~~

View File

@ -116,6 +116,9 @@ 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)),
If you dont want the mixer elements prefixed with the name of the mixer widget,
you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same
as for SND_SOC_DAPM_MIXER.
2.3 Platform/Machine domain Widgets
-----------------------------------

View File

@ -1,23 +0,0 @@
To configure the Crystal CS423x sound chip and activate its DSP functions,
modules may be loaded in this order:
modprobe sound
insmod ad1848
insmod uart401
insmod cs4232 io=* irq=* dma=* dma2=*
This is the meaning of the parameters:
io--I/O address of the Windows Sound System (normally 0x534)
irq--IRQ of this device
dma and dma2--DMA channels (DMA2 may be 0)
On some cards, the board attempts to do non-PnP setup, and fails. If you
have problems, use Linux' PnP facilities.
To get MIDI facilities add
insmod opl3 io=*
where "io" is the I/O address of the OPL3 synthesizer. This will be shown
in /proc/sys/pnp and is normally 0x388.

View File

@ -80,7 +80,7 @@ Notes:
additional features.
2. The commercial OSS driver may be obtained from the site:
http://www/opensound.com. This may be used for cards that
http://www.opensound.com. This may be used for cards that
are unsupported by the kernel driver, or may be used
by other operating systems.

View File

@ -135,6 +135,11 @@ static unsigned long e740_pin_config[] __initdata = {
/* IrDA */
GPIO38_GPIO | MFP_LPM_DRIVE_HIGH,
/* Audio power control */
GPIO16_GPIO, /* AC97 codec AVDD2 supply (analogue power) */
GPIO40_GPIO, /* Mic amp power */
GPIO41_GPIO, /* Headphone amp power */
/* PC Card */
GPIO8_GPIO, /* CD0 */
GPIO44_GPIO, /* CD1 */

View File

@ -133,6 +133,11 @@ static unsigned long e750_pin_config[] __initdata = {
/* IrDA */
GPIO38_GPIO | MFP_LPM_DRIVE_HIGH,
/* Audio power control */
GPIO4_GPIO, /* Headphone amp power */
GPIO7_GPIO, /* Speaker amp power */
GPIO37_GPIO, /* Headphone detect */
/* PC Card */
GPIO8_GPIO, /* CD0 */
GPIO44_GPIO, /* CD1 */

View File

@ -153,6 +153,13 @@ static unsigned long h5000_pin_config[] __initdata = {
GPIO23_SSP1_SCLK,
GPIO25_SSP1_TXD,
GPIO26_SSP1_RXD,
/* I2S */
GPIO28_I2S_BITCLK_OUT,
GPIO29_I2S_SDATA_IN,
GPIO30_I2S_SDATA_OUT,
GPIO31_I2S_SYNC,
GPIO32_I2S_SYSCLK,
};
/*

View File

@ -45,6 +45,21 @@
/* e7xx IrDA power control */
#define GPIO_E7XX_IR_OFF 38
/* e740 audio control GPIOs */
#define GPIO_E740_WM9705_nAVDD2 16
#define GPIO_E740_MIC_ON 40
#define GPIO_E740_AMP_ON 41
/* e750 audio control GPIOs */
#define GPIO_E750_HP_AMP_OFF 4
#define GPIO_E750_SPK_AMP_OFF 7
#define GPIO_E750_HP_DETECT 37
/* e800 audio control GPIOs */
#define GPIO_E800_HP_DETECT 81
#define GPIO_E800_HP_AMP_OFF 82
#define GPIO_E800_SPK_AMP_ON 83
/* ASIC related GPIOs */
#define GPIO_ESERIES_TMIO_IRQ 5
#define GPIO_ESERIES_TMIO_PCLR 19

View File

@ -50,7 +50,7 @@
#define SSCR0_TUM (1 << 23) /* Transmit FIFO underrun interrupt mask */
#define SSCR0_FRDC (0x07000000) /* Frame rate divider control (mask) */
#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per frame [1..8] */
#define SSCR0_ADC (1 << 30) /* Audio clock select */
#define SSCR0_ACS (1 << 30) /* Audio clock select */
#define SSCR0_MOD (1 << 31) /* Mode (normal or network) */
#endif
@ -109,6 +109,11 @@
#define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */
#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
#if defined(CONFIG_PXA3xx)
#define SSPSP_EDMYSTOP(x) ((x) << 28) /* Extended Dummy Stop */
#define SSPSP_EDMYSTRT(x) ((x) << 26) /* Extended Dummy Start */
#endif
#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */
#define SSPSP_SFRMWDTH(x) ((x) << 16) /* Serial Frame Width */

View File

@ -105,6 +105,12 @@ static unsigned long spitz_pin_config[] __initdata = {
GPIO57_nIOIS16,
GPIO104_PSKTSEL,
/* I2S */
GPIO28_I2S_BITCLK_OUT,
GPIO29_I2S_SDATA_IN,
GPIO30_I2S_SDATA_OUT,
GPIO31_I2S_SYNC,
/* MMC */
GPIO32_MMC_CLK,
GPIO112_MMC_CMD,

View File

@ -28,7 +28,7 @@
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <asm/plat-s3c24xx/regs-iis.h>
#include <plat/regs-iis.h>
#include <plat/regs-spi.h>
static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {

View File

@ -29,8 +29,8 @@
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
#include <asm/plat-s3c24xx/regs-iis.h>
#include <plat/regs-s3c2412-iis.h>
#include <plat/regs-iis.h>
#include <plat/regs-spi.h>
#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }

View File

@ -28,7 +28,7 @@
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <asm/plat-s3c24xx/regs-iis.h>
#include <plat/regs-iis.h>
#include <plat/regs-spi.h>
static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {

View File

@ -29,7 +29,7 @@
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <asm/plat-s3c24xx/regs-iis.h>
#include <plat/regs-iis.h>
#include <plat/regs-spi.h>
#define MAP(x) { \

View File

@ -33,6 +33,9 @@
#define S3C2412_IISCON_RXDMA_ACTIVE (1 << 1)
#define S3C2412_IISCON_IIS_ACTIVE (1 << 0)
#define S3C64XX_IISMOD_IMS_PCLK (0 << 10)
#define S3C64XX_IISMOD_IMS_SYSMUX (1 << 10)
#define S3C2412_IISMOD_MASTER_INTERNAL (0 << 10)
#define S3C2412_IISMOD_MASTER_EXTERNAL (1 << 10)
#define S3C2412_IISMOD_SLAVE (2 << 10)
@ -44,8 +47,8 @@
#define S3C2412_IISMOD_LR_LLOW (0 << 7)
#define S3C2412_IISMOD_LR_RLOW (1 << 7)
#define S3C2412_IISMOD_SDF_IIS (0 << 5)
#define S3C2412_IISMOD_SDF_MSB (0 << 5)
#define S3C2412_IISMOD_SDF_LSB (0 << 5)
#define S3C2412_IISMOD_SDF_MSB (1 << 5)
#define S3C2412_IISMOD_SDF_LSB (2 << 5)
#define S3C2412_IISMOD_SDF_MASK (3 << 5)
#define S3C2412_IISMOD_RCLK_256FS (0 << 3)
#define S3C2412_IISMOD_RCLK_512FS (1 << 3)

View File

@ -803,9 +803,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
return (-ENOENT);
}
card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t));
if (!card)
return (-ENOMEM);
err = snd_card_create(index[devno], id[devno], THIS_MODULE,
sizeof(snd_cx88_card_t), &card);
if (err < 0)
return err;
card->private_free = snd_cx88_dev_free;

View File

@ -448,9 +448,10 @@ static int em28xx_audio_init(struct em28xx *dev)
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
"Rechberger\n");
card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
&card);
if (err < 0)
return err;
spin_lock_init(&adev->slock);
err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);

View File

@ -990,10 +990,10 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
if (!enable[devnum])
return -ENODEV;
card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t));
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
sizeof(snd_card_saa7134_t), &card);
if (err < 0)
return err;
strcpy(card->driver, "SAA7134");

View File

@ -248,10 +248,11 @@ int go7007_snd_init(struct go7007 *go)
spin_lock_init(&gosnd->lock);
gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
gosnd->capturing = 0;
gosnd->card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (gosnd->card == NULL) {
ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0,
&gosnd->card);
if (ret < 0) {
kfree(gosnd);
return -ENOMEM;
return ret;
}
ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go,
&go7007_snd_device_ops);

View File

@ -1099,10 +1099,9 @@ static int gmidi_register_card(struct gmidi_device *dev)
.dev_free = gmidi_snd_free,
};
card = snd_card_new(index, id, THIS_MODULE, 0);
if (!card) {
ERROR(dev, "snd_card_new failed\n");
err = -ENOMEM;
err = snd_card_create(index, id, THIS_MODULE, 0, &card);
if (err < 0) {
ERROR(dev, "snd_card_create failed\n");
goto fail;
}
dev->card = card;

View File

@ -661,6 +661,7 @@ struct input_absinfo {
#define SW_DOCK 0x05 /* set = plugged into dock */
#define SW_LINEOUT_INSERT 0x06 /* set = inserted */
#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */
#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */
#define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1)

View File

@ -490,6 +490,7 @@
/*
* R231 (0xE7) - Jack Status
*/
#define WM8350_JACK_L_LVL 0x0800
#define WM8350_JACK_R_LVL 0x0400
/*

View File

@ -1181,6 +1181,7 @@
#define WM8400_FLL_OUTDIV_SHIFT 0 /* FLL_OUTDIV - [2:0] */
#define WM8400_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [2:0] */
struct wm8400;
void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400);
#endif

View File

@ -2112,6 +2112,8 @@
#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
#define PCI_VENDOR_ID_DFI 0x15bd
#define PCI_VENDOR_ID_QUICKNET 0x15e2
#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500

View File

@ -169,5 +169,7 @@ extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,
extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
struct snd_timer **rtimer);
#endif /* __SOUND_AD1816A_H */

View File

@ -126,12 +126,10 @@ struct snd_hwdep_dsp_image {
unsigned long driver_data; /* W: driver-specific data */
};
enum {
SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int),
SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct snd_hwdep_info),
SNDRV_HWDEP_IOCTL_DSP_STATUS = _IOR('H', 0x02, struct snd_hwdep_dsp_status),
SNDRV_HWDEP_IOCTL_DSP_LOAD = _IOW('H', 0x03, struct snd_hwdep_dsp_image)
};
#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int)
#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info)
#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status)
#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image)
/*****************************************************************************
* *
@ -451,40 +449,35 @@ enum {
SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
};
enum {
SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct snd_pcm_info),
SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int),
SNDRV_PCM_IOCTL_TTSTAMP = _IOW('A', 0x03, int),
SNDRV_PCM_IOCTL_HW_REFINE = _IOWR('A', 0x10, struct snd_pcm_hw_params),
SNDRV_PCM_IOCTL_HW_PARAMS = _IOWR('A', 0x11, struct snd_pcm_hw_params),
SNDRV_PCM_IOCTL_HW_FREE = _IO('A', 0x12),
SNDRV_PCM_IOCTL_SW_PARAMS = _IOWR('A', 0x13, struct snd_pcm_sw_params),
SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct snd_pcm_status),
SNDRV_PCM_IOCTL_DELAY = _IOR('A', 0x21, snd_pcm_sframes_t),
SNDRV_PCM_IOCTL_HWSYNC = _IO('A', 0x22),
SNDRV_PCM_IOCTL_SYNC_PTR = _IOWR('A', 0x23, struct snd_pcm_sync_ptr),
SNDRV_PCM_IOCTL_CHANNEL_INFO = _IOR('A', 0x32, struct snd_pcm_channel_info),
SNDRV_PCM_IOCTL_PREPARE = _IO('A', 0x40),
SNDRV_PCM_IOCTL_RESET = _IO('A', 0x41),
SNDRV_PCM_IOCTL_START = _IO('A', 0x42),
SNDRV_PCM_IOCTL_DROP = _IO('A', 0x43),
SNDRV_PCM_IOCTL_DRAIN = _IO('A', 0x44),
SNDRV_PCM_IOCTL_PAUSE = _IOW('A', 0x45, int),
SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, snd_pcm_uframes_t),
SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47),
SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48),
SNDRV_PCM_IOCTL_FORWARD = _IOW('A', 0x49, snd_pcm_uframes_t),
SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct snd_xferi),
SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct snd_xferi),
SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct snd_xfern),
SNDRV_PCM_IOCTL_READN_FRAMES = _IOR('A', 0x53, struct snd_xfern),
SNDRV_PCM_IOCTL_LINK = _IOW('A', 0x60, int),
SNDRV_PCM_IOCTL_UNLINK = _IO('A', 0x61),
};
/* Trick to make alsa-lib/acinclude.m4 happy */
#define SNDRV_PCM_IOCTL_REWIND SNDRV_PCM_IOCTL_REWIND
#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int)
#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params)
#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params)
#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12)
#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params)
#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
#define SNDRV_PCM_IOCTL_START _IO('A', 0x42)
#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43)
#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44)
#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int)
#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t)
#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47)
#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48)
#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t)
#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi)
#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi)
#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern)
#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern)
#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int)
#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61)
/*****************************************************************************
* *
@ -538,14 +531,12 @@ struct snd_rawmidi_status {
unsigned char reserved[16]; /* reserved for future use */
};
enum {
SNDRV_RAWMIDI_IOCTL_PVERSION = _IOR('W', 0x00, int),
SNDRV_RAWMIDI_IOCTL_INFO = _IOR('W', 0x01, struct snd_rawmidi_info),
SNDRV_RAWMIDI_IOCTL_PARAMS = _IOWR('W', 0x10, struct snd_rawmidi_params),
SNDRV_RAWMIDI_IOCTL_STATUS = _IOWR('W', 0x20, struct snd_rawmidi_status),
SNDRV_RAWMIDI_IOCTL_DROP = _IOW('W', 0x30, int),
SNDRV_RAWMIDI_IOCTL_DRAIN = _IOW('W', 0x31, int),
};
#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params)
#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
/*
* Timer section - /dev/snd/timer
@ -654,23 +645,21 @@ struct snd_timer_status {
unsigned char reserved[64]; /* reserved */
};
enum {
SNDRV_TIMER_IOCTL_PVERSION = _IOR('T', 0x00, int),
SNDRV_TIMER_IOCTL_NEXT_DEVICE = _IOWR('T', 0x01, struct snd_timer_id),
SNDRV_TIMER_IOCTL_TREAD = _IOW('T', 0x02, int),
SNDRV_TIMER_IOCTL_GINFO = _IOWR('T', 0x03, struct snd_timer_ginfo),
SNDRV_TIMER_IOCTL_GPARAMS = _IOW('T', 0x04, struct snd_timer_gparams),
SNDRV_TIMER_IOCTL_GSTATUS = _IOWR('T', 0x05, struct snd_timer_gstatus),
SNDRV_TIMER_IOCTL_SELECT = _IOW('T', 0x10, struct snd_timer_select),
SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct snd_timer_info),
SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct snd_timer_params),
SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct snd_timer_status),
/* The following four ioctls are changed since 1.0.9 due to confliction */
SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0),
SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1),
SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2),
SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3),
};
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int)
#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select)
#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info)
#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params)
#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status)
/* The following four ioctls are changed since 1.0.9 due to confliction */
#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0)
#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
struct snd_timer_read {
unsigned int resolution;
@ -847,33 +836,31 @@ struct snd_ctl_tlv {
unsigned int tlv[0]; /* first TLV */
};
enum {
SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
SNDRV_CTL_IOCTL_ELEM_LIST = _IOWR('U', 0x10, struct snd_ctl_elem_list),
SNDRV_CTL_IOCTL_ELEM_INFO = _IOWR('U', 0x11, struct snd_ctl_elem_info),
SNDRV_CTL_IOCTL_ELEM_READ = _IOWR('U', 0x12, struct snd_ctl_elem_value),
SNDRV_CTL_IOCTL_ELEM_WRITE = _IOWR('U', 0x13, struct snd_ctl_elem_value),
SNDRV_CTL_IOCTL_ELEM_LOCK = _IOW('U', 0x14, struct snd_ctl_elem_id),
SNDRV_CTL_IOCTL_ELEM_UNLOCK = _IOW('U', 0x15, struct snd_ctl_elem_id),
SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS = _IOWR('U', 0x16, int),
SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct snd_ctl_tlv),
SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
SNDRV_CTL_IOCTL_PCM_INFO = _IOWR('U', 0x31, struct snd_pcm_info),
SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE = _IOW('U', 0x32, int),
SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE = _IOWR('U', 0x40, int),
SNDRV_CTL_IOCTL_RAWMIDI_INFO = _IOWR('U', 0x41, struct snd_rawmidi_info),
SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE = _IOW('U', 0x42, int),
SNDRV_CTL_IOCTL_POWER = _IOWR('U', 0xd0, int),
SNDRV_CTL_IOCTL_POWER_STATE = _IOR('U', 0xd1, int),
};
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info)
#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int)
#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info)
#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)
/*
* Read interface.
@ -919,18 +906,4 @@ struct snd_ctl_event {
#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream"
#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
/*
*
*/
struct snd_xferv {
const struct iovec *vector;
unsigned long count;
};
enum {
SNDRV_IOCTL_READV = _IOW('K', 0x00, struct snd_xferv),
SNDRV_IOCTL_WRITEV = _IOW('K', 0x01, struct snd_xferv),
};
#endif /* __SOUND_ASOUND_H */

View File

@ -0,0 +1,23 @@
/*
* Driver for the Atmel Audio Bitstream DAC (ABDAC)
*
* Copyright (C) 2009 Atmel Corporation
*
* 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 __INCLUDE_SOUND_ATMEL_ABDAC_H
#define __INCLUDE_SOUND_ATMEL_ABDAC_H
#include <linux/dw_dmac.h>
/**
* struct atmel_abdac_pdata - board specific ABDAC configuration
* @dws: DMA slave interface to use for sound playback.
*/
struct atmel_abdac_pdata {
struct dw_dma_slave dws;
};
#endif /* __INCLUDE_SOUND_ATMEL_ABDAC_H */

View File

@ -0,0 +1,40 @@
/*
* Driver for the Atmel AC97C controller
*
* Copyright (C) 2005-2009 Atmel Corporation
*
* 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 __INCLUDE_SOUND_ATMEL_AC97C_H
#define __INCLUDE_SOUND_ATMEL_AC97C_H
#include <linux/dw_dmac.h>
#define AC97C_CAPTURE 0x01
#define AC97C_PLAYBACK 0x02
#define AC97C_BOTH (AC97C_CAPTURE | AC97C_PLAYBACK)
/**
* struct atmel_ac97c_pdata - board specific AC97C configuration
* @rx_dws: DMA slave interface to use for sound capture.
* @tx_dws: DMA slave interface to use for sound playback.
* @reset_pin: GPIO pin wired to the reset input on the external AC97 codec,
* optional to use, set to -ENODEV if not in use. AC97 layer will
* try to do a software reset of the external codec anyway.
* @flags: Flags for which directions should be enabled.
*
* If the user do not want to use a DMA channel for playback or capture, i.e.
* only one feature is required on the board. The slave for playback or capture
* can be set to NULL. The AC97C driver will take use of this when setting up
* the sound streams.
*/
struct ac97c_platform_data {
struct dw_dma_slave rx_dws;
struct dw_dma_slave tx_dws;
unsigned int flags;
int reset_pin;
};
#endif /* __INCLUDE_SOUND_ATMEL_AC97C_H */

View File

@ -171,6 +171,54 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
*/
struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
const unsigned int *tlv);
int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave);
int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
unsigned int flags);
/* optional flags for slave */
#define SND_CTL_SLAVE_NEED_UPDATE (1 << 0)
/**
* snd_ctl_add_slave - Add a virtual slave control
* @master: vmaster element
* @slave: slave element to add
*
* Add a virtual slave control to the given master element created via
* snd_ctl_create_virtual_master() beforehand.
* Returns zero if successful or a negative error code.
*
* All slaves must be the same type (returning the same information
* via info callback). The fucntion doesn't check it, so it's your
* responsibility.
*
* Also, some additional limitations:
* at most two channels,
* logarithmic volume control (dB level) thus no linear volume,
* master can only attenuate the volume without gain
*/
static inline int
snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
{
return _snd_ctl_add_slave(master, slave, 0);
}
/**
* snd_ctl_add_slave_uncached - Add a virtual slave control
* @master: vmaster element
* @slave: slave element to add
*
* Add a virtual slave control to the given master.
* Unlike snd_ctl_add_slave(), the element added via this function
* is supposed to have volatile values, and get callback is called
* at each time quried from the master.
*
* When the control peeks the hardware values directly and the value
* can be changed by other means than the put callback of the element,
* this function should be used to keep the value always up-to-date.
*/
static inline int
snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
struct snd_kcontrol *slave)
{
return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE);
}
#endif /* __SOUND_CONTROL_H */

View File

@ -97,9 +97,9 @@ struct snd_device {
struct snd_monitor_file {
struct file *file;
struct snd_monitor_file *next;
const struct file_operations *disconnected_f_op;
struct list_head shutdown_list;
struct list_head shutdown_list; /* still need to shutdown */
struct list_head list; /* link of monitor files */
};
/* main structure for soundcard */
@ -134,7 +134,7 @@ struct snd_card {
struct snd_info_entry *proc_id; /* the card id */
struct proc_dir_entry *proc_root_link; /* number link to real id */
struct snd_monitor_file *files; /* all files associated to this card */
struct list_head files_list; /* all files associated to this card */
struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown
state */
spinlock_t files_lock; /* lock the files for this card */
@ -296,8 +296,20 @@ int snd_card_locked(int card);
extern int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int cmd);
#endif
int snd_card_create(int idx, const char *id,
struct module *module, int extra_size,
struct snd_card **card_ret);
static inline __deprecated
struct snd_card *snd_card_new(int idx, const char *id,
struct module *module, int extra_size);
struct module *module, int extra_size)
{
struct snd_card *card;
if (snd_card_create(idx, id, module, extra_size, &card) < 0)
return NULL;
return card;
}
int snd_card_disconnect(struct snd_card *card);
int snd_card_free(struct snd_card *card);
int snd_card_free_when_closed(struct snd_card *card);
@ -446,21 +458,33 @@ static inline int __snd_bug_on(int cond)
struct snd_pci_quirk {
unsigned short subvendor; /* PCI subvendor ID */
unsigned short subdevice; /* PCI subdevice ID */
unsigned short subdevice_mask; /* bitmask to match */
int value; /* value */
#ifdef CONFIG_SND_DEBUG_VERBOSE
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_MASK(vend, mask, dev) \
.subvendor = (vend), .subdevice = (dev), .subdevice_mask = (mask)
#define _SND_PCI_QUIRK_ID(vend, dev) \
_SND_PCI_QUIRK_ID_MASK(vend, 0xffff, dev)
#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
#ifdef CONFIG_SND_DEBUG_VERBOSE
#define SND_PCI_QUIRK(vend,dev,xname,val) \
{_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
#define SND_PCI_QUIRK_VENDOR(vend, xname, val) \
{_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val), .name = (xname)}
#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val) \
{_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), \
.value = (val), .name = (xname)}
#else
#define SND_PCI_QUIRK(vend,dev,xname,val) \
{_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val) \
{_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), .value = (val)}
#define SND_PCI_QUIRK_VENDOR(vend, xname, val) \
{_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val)}
#endif
const struct snd_pci_quirk *

View File

@ -27,18 +27,28 @@
struct snd_hwdep;
/* hwdep file ops; all ops can be NULL */
struct snd_hwdep_ops {
long long (*llseek) (struct snd_hwdep *hw, struct file * file, long long offset, int orig);
long (*read) (struct snd_hwdep *hw, char __user *buf, long count, loff_t *offset);
long (*write) (struct snd_hwdep *hw, const char __user *buf, long count, loff_t *offset);
int (*open) (struct snd_hwdep * hw, struct file * file);
int (*release) (struct snd_hwdep *hw, struct file * file);
unsigned int (*poll) (struct snd_hwdep *hw, struct file * file, poll_table * wait);
int (*ioctl) (struct snd_hwdep *hw, struct file * file, unsigned int cmd, unsigned long arg);
int (*ioctl_compat) (struct snd_hwdep *hw, struct file * file, unsigned int cmd, unsigned long arg);
int (*mmap) (struct snd_hwdep *hw, struct file * file, struct vm_area_struct * vma);
int (*dsp_status) (struct snd_hwdep *hw, struct snd_hwdep_dsp_status *status);
int (*dsp_load) (struct snd_hwdep *hw, struct snd_hwdep_dsp_image *image);
long long (*llseek)(struct snd_hwdep *hw, struct file *file,
long long offset, int orig);
long (*read)(struct snd_hwdep *hw, char __user *buf,
long count, loff_t *offset);
long (*write)(struct snd_hwdep *hw, const char __user *buf,
long count, loff_t *offset);
int (*open)(struct snd_hwdep *hw, struct file * file);
int (*release)(struct snd_hwdep *hw, struct file * file);
unsigned int (*poll)(struct snd_hwdep *hw, struct file *file,
poll_table *wait);
int (*ioctl)(struct snd_hwdep *hw, struct file *file,
unsigned int cmd, unsigned long arg);
int (*ioctl_compat)(struct snd_hwdep *hw, struct file *file,
unsigned int cmd, unsigned long arg);
int (*mmap)(struct snd_hwdep *hw, struct file *file,
struct vm_area_struct *vma);
int (*dsp_status)(struct snd_hwdep *hw,
struct snd_hwdep_dsp_status *status);
int (*dsp_load)(struct snd_hwdep *hw,
struct snd_hwdep_dsp_image *image);
};
struct snd_hwdep {
@ -61,9 +71,9 @@ struct snd_hwdep {
void (*private_free) (struct snd_hwdep *hwdep);
struct mutex open_mutex;
int used;
unsigned int dsp_loaded;
unsigned int exclusive: 1;
int used; /* reference counter */
unsigned int dsp_loaded; /* bit fields of loaded dsp indices */
unsigned int exclusive:1; /* exclusive access mode */
};
extern int snd_hwdep_new(struct snd_card *card, char *id, int device,

View File

@ -30,6 +30,9 @@ struct input_dev;
/**
* Jack types which can be reported. These values are used as a
* bitmask.
*
* Note that this must be kept in sync with the lookup table in
* sound/core/jack.c.
*/
enum snd_jack_types {
SND_JACK_HEADPHONE = 0x0001,
@ -37,6 +40,8 @@ enum snd_jack_types {
SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
SND_JACK_LINEOUT = 0x0004,
SND_JACK_MECHANICAL = 0x0008, /* If detected separately */
SND_JACK_VIDEOOUT = 0x0010,
SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
};
struct snd_jack {

View File

@ -364,7 +364,6 @@ struct snd_pcm_substream {
/* -- timer section -- */
struct snd_timer *timer; /* timer */
unsigned timer_running: 1; /* time is running */
spinlock_t timer_lock;
/* -- next substream -- */
struct snd_pcm_substream *next;
/* -- linked substreams -- */
@ -451,7 +450,7 @@ struct snd_pcm_notify {
extern const struct file_operations snd_pcm_f_ops[2];
int snd_pcm_new(struct snd_card *card, char *id, int device,
int snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count,
struct snd_pcm **rpcm);
int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count);

View File

@ -42,4 +42,19 @@ extern int pxa2xx_ac97_hw_resume(void);
extern int pxa2xx_ac97_hw_probe(struct platform_device *dev);
extern void pxa2xx_ac97_hw_remove(struct platform_device *dev);
/* AC97 platform_data */
/**
* struct pxa2xx_ac97_platform_data - pxa ac97 platform data
* @reset_gpio: AC97 reset gpio (normally gpio113 or gpio95)
* a -1 value means no gpio will be used for reset
*
* Platform data should only be specified for pxa27x CPUs where a silicon bug
* prevents correct operation of the reset line. If not specified, the default
* behaviour is to consider gpio 113 as the AC97 reset line, which is the
* default on most boards.
*/
struct pxa2xx_ac97_platform_data {
int reset_gpio;
};
#endif

View File

@ -42,7 +42,6 @@
#define SNDRV_RAWMIDI_LFLG_INPUT (1<<1)
#define SNDRV_RAWMIDI_LFLG_OPEN (3<<0)
#define SNDRV_RAWMIDI_LFLG_APPEND (1<<2)
#define SNDRV_RAWMIDI_LFLG_NOOPENLOCK (1<<3)
struct snd_rawmidi;
struct snd_rawmidi_substream;

View File

@ -249,6 +249,7 @@ struct snd_sb {
#define SB_ALS4000_3D_AUTO_MUTE 0x52
#define SB_ALS4000_ANALOG_BLOCK_CTRL 0x53
#define SB_ALS4000_3D_DELAYLINE_PATTERN 0x54
#define SB_ALS4000_CR3_CONFIGURATION 0xc3 /* bit 7 is Digital Loop Enable */
#define SB_ALS4000_QSOUND 0xdb
/* IRQ setting bitmap */
@ -330,7 +331,8 @@ enum {
SB_MIX_DOUBLE,
SB_MIX_INPUT_SW,
SB_MIX_CAPTURE_PRO,
SB_MIX_CAPTURE_DT019X
SB_MIX_CAPTURE_DT019X,
SB_MIX_MONO_CAPTURE_ALS4K
};
#define SB_MIXVAL_DOUBLE(left_reg, right_reg, left_shift, right_shift, mask) \

View File

@ -202,13 +202,11 @@ struct snd_emux_misc_mode {
int value2; /* reserved */
};
enum {
SNDRV_EMUX_IOCTL_VERSION = _IOR('H', 0x80, unsigned int),
SNDRV_EMUX_IOCTL_LOAD_PATCH = _IOWR('H', 0x81, struct soundfont_patch_info),
SNDRV_EMUX_IOCTL_RESET_SAMPLES = _IO('H', 0x82),
SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES = _IO('H', 0x83),
SNDRV_EMUX_IOCTL_MEM_AVAIL = _IOW('H', 0x84, int),
SNDRV_EMUX_IOCTL_MISC_MODE = _IOWR('H', 0x84, struct snd_emux_misc_mode),
};
#define SNDRV_EMUX_IOCTL_VERSION _IOR('H', 0x80, unsigned int)
#define SNDRV_EMUX_IOCTL_LOAD_PATCH _IOWR('H', 0x81, struct soundfont_patch_info)
#define SNDRV_EMUX_IOCTL_RESET_SAMPLES _IO('H', 0x82)
#define SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES _IO('H', 0x83)
#define SNDRV_EMUX_IOCTL_MEM_AVAIL _IOW('H', 0x84, int)
#define SNDRV_EMUX_IOCTL_MISC_MODE _IOWR('H', 0x84, struct snd_emux_misc_mode)
#endif /* __SOUND_SFNT_INFO_H */

View File

@ -203,7 +203,7 @@ struct snd_soc_dai {
int (*resume)(struct snd_soc_dai *dai);
/* ops */
struct snd_soc_dai_ops ops;
struct snd_soc_dai_ops *ops;
/* DAI capabilities */
struct snd_soc_pcm_stream capture;

View File

@ -76,6 +76,11 @@
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer_named_ctl, .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}
@ -101,6 +106,11 @@
{ .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_MIXER_NAMED_CTL_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, \
@ -182,6 +192,12 @@
.get = snd_soc_dapm_get_value_enum_double, \
.put = snd_soc_dapm_put_value_enum_double, \
.private_value = (unsigned long)&xenum }
#define SOC_DAPM_PIN_SWITCH(xname) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \
.info = snd_soc_dapm_info_pin_switch, \
.get = snd_soc_dapm_get_pin_switch, \
.put = snd_soc_dapm_put_pin_switch, \
.private_value = (unsigned long)xname }
/* dapm stream operations */
#define SND_SOC_DAPM_STREAM_NOP 0x0
@ -228,6 +244,12 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uncontrol);
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uncontrol);
int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
const struct snd_soc_dapm_widget *widget);
int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
@ -250,10 +272,10 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
int snd_soc_dapm_sys_add(struct device *dev);
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_sync(struct snd_soc_codec *codec);
/* dapm widget types */
@ -263,6 +285,7 @@ enum snd_soc_dapm_type {
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_mixer, /* mixes several analog signals together */
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
snd_soc_dapm_adc, /* analog to digital converter */
snd_soc_dapm_dac, /* digital to analog converter */

View File

@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/control.h>
@ -154,6 +156,8 @@ enum snd_soc_bias_level {
SND_SOC_BIAS_OFF,
};
struct snd_jack;
struct snd_soc_card;
struct snd_soc_device;
struct snd_soc_pcm_stream;
struct snd_soc_ops;
@ -164,6 +168,11 @@ struct snd_soc_platform;
struct snd_soc_codec;
struct soc_enum;
struct snd_soc_ac97_ops;
struct snd_soc_jack;
struct snd_soc_jack_pin;
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio;
#endif
typedef int (*hw_write_t)(void *,const char* ,int);
typedef int (*hw_read_t)(void *,char* ,int);
@ -184,6 +193,19 @@ int snd_soc_init_card(struct snd_soc_device *socdev);
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw);
/* Jack reporting */
int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
struct snd_soc_jack *jack);
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_pin *pins);
#ifdef CONFIG_GPIOLIB
int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios);
void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios);
#endif
/* codec IO */
#define snd_soc_read(codec, reg) codec->read(codec, reg)
#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
@ -203,6 +225,8 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
*/
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
void *data, char *long_name);
int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls);
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,
@ -237,6 +261,48 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
/**
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
*
* @pin: name of the pin to update
* @mask: bits to check for in reported jack status
* @invert: if non-zero then pin is enabled when status is not reported
*/
struct snd_soc_jack_pin {
struct list_head list;
const char *pin;
int mask;
bool invert;
};
/**
* struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
*
* @gpio: gpio number
* @name: gpio name
* @report: value to report when jack detected
* @invert: report presence in low state
* @debouce_time: debouce time in ms
*/
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio {
unsigned int gpio;
const char *name;
int report;
int invert;
int debounce_time;
struct snd_soc_jack *jack;
struct work_struct work;
};
#endif
struct snd_soc_jack {
struct snd_jack *jack;
struct snd_soc_card *card;
struct list_head pins;
int status;
};
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
char *stream_name;
@ -384,6 +450,8 @@ struct snd_soc_card {
struct snd_soc_device *socdev;
struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
struct delayed_work delayed_work;
struct work_struct deferred_resume_work;
@ -393,7 +461,6 @@ struct snd_soc_card {
struct snd_soc_device {
struct device *dev;
struct snd_soc_card *card;
struct snd_soc_codec *codec;
struct snd_soc_codec_device *codec_dev;
void *codec_data;
};

View File

@ -1,126 +0,0 @@
/*
* linux/include/linux/l3/uda1341.h
*
* Philips UDA1341 mixer device driver for ALSA
*
* Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*
* History:
*
* 2002-03-13 Tomas Kasparek Initial release - based on uda1341.h from OSS
* 2002-03-30 Tomas Kasparek Proc filesystem support, complete mixer and DSP
* features support
*/
#define UDA1341_ALSA_NAME "snd-uda1341"
/*
* Default rate set after inicialization
*/
#define AUDIO_RATE_DEFAULT 44100
/*
* UDA1341 L3 address and command types
*/
#define UDA1341_L3ADDR 5
#define UDA1341_DATA0 (UDA1341_L3ADDR << 2 | 0)
#define UDA1341_DATA1 (UDA1341_L3ADDR << 2 | 1)
#define UDA1341_STATUS (UDA1341_L3ADDR << 2 | 2)
enum uda1341_onoff {
OFF=0,
ON,
};
enum uda1341_format {
I2S=0,
LSB16,
LSB18,
LSB20,
MSB,
LSB16MSB,
LSB18MSB,
LSB20MSB,
};
enum uda1341_fs {
F512=0,
F384,
F256,
Funused,
};
enum uda1341_peak {
BEFORE=0,
AFTER,
};
enum uda1341_filter {
FLAT=0,
MIN,
MIN2,
MAX,
};
enum uda1341_mixer {
DOUBLE,
LINE,
MIC,
MIXER,
};
enum uda1341_deemp {
NONE,
D32,
D44,
D48,
};
enum uda1341_config {
CMD_READ_REG = 0,
CMD_RESET,
CMD_FS,
CMD_FORMAT,
CMD_OGAIN,
CMD_IGAIN,
CMD_DAC,
CMD_ADC,
CMD_VOLUME,
CMD_BASS,
CMD_TREBBLE,
CMD_PEAK,
CMD_DEEMP,
CMD_MUTE,
CMD_FILTER,
CMD_CH1,
CMD_CH2,
CMD_MIC,
CMD_MIXER,
CMD_AGC,
CMD_IG,
CMD_AGC_TIME,
CMD_AGC_LEVEL,
#ifdef CONFIG_PM
CMD_SUSPEND,
CMD_RESUME,
#endif
CMD_LAST,
};
enum write_through {
//used in update_bits (write_cfg) to avoid l3_write - just update local copy of regs.
REGS_ONLY=0,
//update local regs and write value to uda1341 - do l3_write
FLUSH,
};
int __init snd_chip_uda1341_mixer_new(struct snd_card *card, struct l3_client **clnt);
/*
* Local variables:
* indent-tabs-mode: t
* End:
*/

View File

@ -1,3 +1,3 @@
/* include/version.h */
#define CONFIG_SND_VERSION "1.0.18a"
#define CONFIG_SND_VERSION "1.0.19"
#define CONFIG_SND_DATE ""

View File

@ -154,6 +154,7 @@ int snd_wss_create(struct snd_card *card,
unsigned short hardware,
unsigned short hwshare,
struct snd_wss **rchip);
int snd_wss_free(struct snd_wss *chip);
int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
int snd_wss_mixer(struct snd_wss *chip);

View File

@ -60,6 +60,8 @@ source "sound/aoa/Kconfig"
source "sound/arm/Kconfig"
source "sound/atmel/Kconfig"
source "sound/spi/Kconfig"
source "sound/mips/Kconfig"

View File

@ -6,7 +6,7 @@ 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/ sh/ synth/ usb/ \
sparc/ spi/ parisc/ pcmcia/ mips/ soc/
sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out

View File

@ -34,10 +34,12 @@ struct gpio_methods {
void (*set_headphone)(struct gpio_runtime *rt, int on);
void (*set_speakers)(struct gpio_runtime *rt, int on);
void (*set_lineout)(struct gpio_runtime *rt, int on);
void (*set_master)(struct gpio_runtime *rt, int on);
int (*get_headphone)(struct gpio_runtime *rt);
int (*get_speakers)(struct gpio_runtime *rt);
int (*get_lineout)(struct gpio_runtime *rt);
int (*get_master)(struct gpio_runtime *rt);
void (*set_hw_reset)(struct gpio_runtime *rt, int on);

View File

@ -23,9 +23,10 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
/* cannot be EEXIST due to usage in aoa_fabric_register */
return -EBUSY;
alsa_card = snd_card_new(index, name, mod, sizeof(struct aoa_card));
if (!alsa_card)
return -ENOMEM;
err = snd_card_create(index, name, mod, sizeof(struct aoa_card),
&alsa_card);
if (err < 0)
return err;
aoa_card = alsa_card->private_data;
aoa_card->alsa_card = alsa_card;
alsa_card->dev = dev;

View File

@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include "../aoa.h"
/* TODO: these are 20 global variables
/* TODO: these are lots of global variables
* that aren't used on most machines...
* Move them into a dynamically allocated
* structure and use that.
@ -23,6 +23,7 @@
/* these are the GPIO numbers (register addresses as offsets into
* the GPIO space) */
static int headphone_mute_gpio;
static int master_mute_gpio;
static int amp_mute_gpio;
static int lineout_mute_gpio;
static int hw_reset_gpio;
@ -32,6 +33,7 @@ static int linein_detect_gpio;
/* see the SWITCH_GPIO macro */
static int headphone_mute_gpio_activestate;
static int master_mute_gpio_activestate;
static int amp_mute_gpio_activestate;
static int lineout_mute_gpio_activestate;
static int hw_reset_gpio_activestate;
@ -156,6 +158,7 @@ static int ftr_gpio_get_##name(struct gpio_runtime *rt) \
FTR_GPIO(headphone, 0);
FTR_GPIO(amp, 1);
FTR_GPIO(lineout, 2);
FTR_GPIO(master, 3);
static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
{
@ -172,6 +175,8 @@ static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
hw_reset_gpio, v);
}
static struct gpio_methods methods;
static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
{
int saved;
@ -181,6 +186,8 @@ static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
ftr_gpio_set_headphone(rt, 0);
ftr_gpio_set_amp(rt, 0);
ftr_gpio_set_lineout(rt, 0);
if (methods.set_master)
ftr_gpio_set_master(rt, 0);
rt->implementation_private = saved;
}
@ -193,6 +200,8 @@ static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
ftr_gpio_set_headphone(rt, (s>>0)&1);
ftr_gpio_set_amp(rt, (s>>1)&1);
ftr_gpio_set_lineout(rt, (s>>2)&1);
if (methods.set_master)
ftr_gpio_set_master(rt, (s>>3)&1);
}
static void ftr_handle_notify(struct work_struct *work)
@ -231,6 +240,12 @@ static void ftr_gpio_init(struct gpio_runtime *rt)
get_gpio("hw-reset", "audio-hw-reset",
&hw_reset_gpio,
&hw_reset_gpio_activestate);
if (get_gpio("master-mute", NULL,
&master_mute_gpio,
&master_mute_gpio_activestate)) {
methods.set_master = ftr_gpio_set_master;
methods.get_master = ftr_gpio_get_master;
}
headphone_detect_node = get_gpio("headphone-detect", NULL,
&headphone_detect_gpio,

View File

@ -1,16 +1,14 @@
/*
* Apple Onboard Audio driver -- layout fabric
* Apple Onboard Audio driver -- layout/machine id fabric
*
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
*
* GPL v2, can be found in COPYING.
*
*
* This fabric module looks for sound codecs
* based on the layout-id property in the device tree.
*
* This fabric module looks for sound codecs based on the
* layout-id or device-id property in the device tree.
*/
#include <asm/prom.h>
#include <linux/list.h>
#include <linux/module.h>
@ -63,7 +61,7 @@ struct codec_connect_info {
#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
struct layout {
unsigned int layout_id;
unsigned int layout_id, device_id;
struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
int flags;
@ -111,6 +109,10 @@ MODULE_ALIAS("sound-layout-96");
MODULE_ALIAS("sound-layout-98");
MODULE_ALIAS("sound-layout-100");
MODULE_ALIAS("aoa-device-id-14");
MODULE_ALIAS("aoa-device-id-22");
MODULE_ALIAS("aoa-device-id-35");
/* onyx with all but microphone connected */
static struct codec_connection onyx_connections_nomic[] = {
{
@ -518,6 +520,27 @@ static struct layout layouts[] = {
.connections = onyx_connections_noheadphones,
},
},
/* PowerMac3,4 */
{ .device_id = 14,
.codecs[0] = {
.name = "tas",
.connections = tas_connections_noline,
},
},
/* PowerMac3,6 */
{ .device_id = 22,
.codecs[0] = {
.name = "tas",
.connections = tas_connections_all,
},
},
/* PowerBook5,2 */
{ .device_id = 35,
.codecs[0] = {
.name = "tas",
.connections = tas_connections_all,
},
},
{}
};
@ -526,7 +549,7 @@ static struct layout *find_layout_by_id(unsigned int id)
struct layout *l;
l = layouts;
while (l->layout_id) {
while (l->codecs[0].name) {
if (l->layout_id == id)
return l;
l++;
@ -534,6 +557,19 @@ static struct layout *find_layout_by_id(unsigned int id)
return NULL;
}
static struct layout *find_layout_by_device(unsigned int id)
{
struct layout *l;
l = layouts;
while (l->codecs[0].name) {
if (l->device_id == id)
return l;
l++;
}
return NULL;
}
static void use_layout(struct layout *l)
{
int i;
@ -564,6 +600,7 @@ struct layout_dev {
struct snd_kcontrol *headphone_ctrl;
struct snd_kcontrol *lineout_ctrl;
struct snd_kcontrol *speaker_ctrl;
struct snd_kcontrol *master_ctrl;
struct snd_kcontrol *headphone_detected_ctrl;
struct snd_kcontrol *lineout_detected_ctrl;
@ -615,6 +652,7 @@ static struct snd_kcontrol_new n##_ctl = { \
AMP_CONTROL(headphone, "Headphone Switch");
AMP_CONTROL(speakers, "Speakers Switch");
AMP_CONTROL(lineout, "Line-Out Switch");
AMP_CONTROL(master, "Master Switch");
static int detect_choice_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@ -855,6 +893,11 @@ static void layout_attached_codec(struct aoa_codec *codec)
lineout = codec->gpio->methods->get_detect(codec->gpio,
AOA_NOTIFY_LINE_OUT);
if (codec->gpio->methods->set_master) {
ctl = snd_ctl_new1(&master_ctl, codec->gpio);
ldev->master_ctrl = ctl;
aoa_snd_ctl_add(ctl);
}
while (cc->connected) {
if (cc->connected & CC_SPEAKERS) {
if (headphones <= 0 && lineout <= 0)
@ -938,8 +981,8 @@ static struct aoa_fabric layout_fabric = {
static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
{
struct device_node *sound = NULL;
const unsigned int *layout_id;
struct layout *layout;
const unsigned int *id;
struct layout *layout = NULL;
struct layout_dev *ldev = NULL;
int err;
@ -952,15 +995,18 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
break;
}
if (!sound) return -ENODEV;
if (!sound)
return -ENODEV;
layout_id = of_get_property(sound, "layout-id", NULL);
if (!layout_id)
goto outnodev;
printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
*layout_id);
id = of_get_property(sound, "layout-id", NULL);
if (id) {
layout = find_layout_by_id(*id);
} else {
id = of_get_property(sound, "device-id", NULL);
if (id)
layout = find_layout_by_device(*id);
}
layout = find_layout_by_id(*layout_id);
if (!layout) {
printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
goto outnodev;
@ -976,6 +1022,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
ldev->layout = layout;
ldev->gpio.node = sound->parent;
switch (layout->layout_id) {
case 0: /* anything with device_id, not layout_id */
case 41: /* that unknown machine no one seems to have */
case 51: /* PowerBook5,4 */
case 58: /* Mac Mini */

View File

@ -1,7 +1,7 @@
/*
* i2sbus driver
*
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
*
* GPL v2, can be found in COPYING.
*/
@ -186,13 +186,25 @@ static int i2sbus_add_dev(struct macio_dev *macio,
}
}
if (i == 1) {
const u32 *layout_id =
of_get_property(sound, "layout-id", NULL);
if (layout_id) {
layout = *layout_id;
const u32 *id = of_get_property(sound, "layout-id", NULL);
if (id) {
layout = *id;
snprintf(dev->sound.modalias, 32,
"sound-layout-%d", layout);
ok = 1;
} else {
id = of_get_property(sound, "device-id", NULL);
/*
* We probably cannot handle all device-id machines,
* so restrict to those we do handle for now.
*/
if (id && (*id == 22 || *id == 14 || *id == 35)) {
snprintf(dev->sound.modalias, 32,
"aoa-device-id-%d", *id);
ok = 1;
layout = -1;
}
}
}
/* for the time being, until we can handle non-layout-id

View File

@ -11,17 +11,6 @@ menuconfig SND_ARM
if SND_ARM
config SND_SA11XX_UDA1341
tristate "SA11xx UDA1341TS driver (iPaq H3600)"
depends on ARCH_SA1100 && L3
select SND_PCM
help
Say Y here if you have a Compaq iPaq H3x00 handheld computer
and want to use its Philips UDA 1341 audio chip.
To compile this driver as a module, choose M here: the module
will be called snd-sa11xx-uda1341.
config SND_ARMAACI
tristate "ARM PrimeCell PL041 AC Link support"
depends on ARM_AMBA

View File

@ -2,9 +2,6 @@
# Makefile for ALSA
#
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o
snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
snd-aaci-objs := aaci.o devdma.o

View File

@ -995,10 +995,11 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
{
struct aaci *aaci;
struct snd_card *card;
int err;
card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct aaci));
if (card == NULL)
err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct aaci), &card);
if (err < 0)
return NULL;
card->private_free = aaci_free_card;

View File

@ -31,6 +31,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
static volatile long gsr_bits;
static struct clk *ac97_clk;
static struct clk *ac97conf_clk;
static int reset_gpio;
/*
* Beware PXA27x bugs:
@ -42,6 +43,45 @@ static struct clk *ac97conf_clk;
* 1 jiffy timeout if interrupt never comes).
*/
enum {
RESETGPIO_FORCE_HIGH,
RESETGPIO_FORCE_LOW,
RESETGPIO_NORMAL_ALTFUNC
};
/**
* set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA
* @mode: chosen action
*
* As the PXA27x CPUs suffer from a AC97 bug, a manual control of the reset line
* must be done to insure proper work of AC97 reset line. This function
* computes the correct gpio_mode for further use by reset functions, and
* applied the change through pxa_gpio_mode.
*/
static void set_resetgpio_mode(int resetgpio_action)
{
int mode = 0;
if (reset_gpio)
switch (resetgpio_action) {
case RESETGPIO_NORMAL_ALTFUNC:
if (reset_gpio == 113)
mode = 113 | GPIO_OUT | GPIO_DFLT_LOW;
if (reset_gpio == 95)
mode = 95 | GPIO_ALT_FN_1_OUT;
break;
case RESETGPIO_FORCE_LOW:
mode = reset_gpio | GPIO_OUT | GPIO_DFLT_LOW;
break;
case RESETGPIO_FORCE_HIGH:
mode = reset_gpio | GPIO_OUT | GPIO_DFLT_HIGH;
break;
};
if (mode)
pxa_gpio_mode(mode);
}
unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
unsigned short val = -1;
@ -137,10 +177,10 @@ static inline void pxa_ac97_warm_pxa27x(void)
/* warm reset broken on Bulverde,
so manually keep AC97 reset high */
pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
set_resetgpio_mode(RESETGPIO_FORCE_HIGH);
udelay(10);
GCR |= GCR_WARM_RST;
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
udelay(500);
}
@ -308,8 +348,8 @@ int pxa2xx_ac97_hw_resume(void)
pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
}
if (cpu_is_pxa27x()) {
/* Use GPIO 113 as AC97 Reset on Bulverde */
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
/* Use GPIO 113 or 95 as AC97 Reset on Bulverde */
set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
}
clk_enable(ac97_clk);
return 0;
@ -320,6 +360,27 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
{
int ret;
struct pxa2xx_ac97_platform_data *pdata = dev->dev.platform_data;
if (pdata) {
switch (pdata->reset_gpio) {
case 95:
case 113:
reset_gpio = pdata->reset_gpio;
break;
case 0:
reset_gpio = 113;
break;
case -1:
break;
default:
dev_err(&dev->dev, "Invalid reset GPIO %d\n",
pdata->reset_gpio);
}
} else {
if (cpu_is_pxa27x())
reset_gpio = 113;
}
if (cpu_is_pxa25x() || cpu_is_pxa27x()) {
pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
@ -330,7 +391,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
if (cpu_is_pxa27x()) {
/* Use GPIO 113 as AC97 Reset on Bulverde */
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
if (IS_ERR(ac97conf_clk)) {
ret = PTR_ERR(ac97conf_clk);

View File

@ -173,10 +173,9 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
struct snd_ac97_template ac97_template;
int ret;
ret = -ENOMEM;
card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, 0);
if (!card)
ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, 0, &card);
if (ret < 0)
goto err;
card->dev = &dev->dev;

View File

@ -1,983 +0,0 @@
/*
* Driver for Philips UDA1341TS on Compaq iPAQ H3600 soundcard
* Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License.
*
* History:
*
* 2002-03-13 Tomas Kasparek initial release - based on h3600-uda1341.c from OSS
* 2002-03-20 Tomas Kasparek playback over ALSA is working
* 2002-03-28 Tomas Kasparek playback over OSS emulation is working
* 2002-03-29 Tomas Kasparek basic capture is working (native ALSA)
* 2002-03-29 Tomas Kasparek capture is working (OSS emulation)
* 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates)
* 2003-02-14 Brian Avery fixed full duplex mode, other updates
* 2003-02-20 Tomas Kasparek merged updates by Brian (except HAL)
* 2003-04-19 Jaroslav Kysela recoded DMA stuff to follow 2.4.18rmk3-hh24 kernel
* working suspend and resume
* 2003-04-28 Tomas Kasparek updated work by Jaroslav to compile it under 2.5.x again
* merged HAL layer (patches from Brian)
*/
/***************************************************************************************************
*
* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
* available in the Alsa doc section on the website
*
* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.
* We are using SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated
* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.
* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the
* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which
* is a mem loc that always decodes to 0's w/ no off chip access.
*
* Some alsa terminology:
* frame => num_channels * sample_size e.g stereo 16 bit is 2 * 16 = 32 bytes
* period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte
* buffer and 4 periods in the runtime structure this means we'll get an int every 256
* bytes or 4 times per buffer.
* A number of the sizes are in frames rather than bytes, use frames_to_bytes and
* bytes_to_frames to convert. The easiest way to tell the units is to look at the
* type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t
*
* Notes about the pointer fxn:
* The pointer fxn needs to return the offset into the dma buffer in frames.
* Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.
*
* Notes about pause/resume
* Implementing this would be complicated so it's skipped. The problem case is:
* A full duplex connection is going, then play is paused. At this point you need to start xmitting
* 0's to keep the record active which means you cant just freeze the dma and resume it later you'd
* need to save off the dma info, and restore it properly on a resume. Yeach!
*
* Notes about transfer methods:
* The async write calls fail. I probably need to implement something else to support them?
*
***************************************************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/slab.h>
#ifdef CONFIG_PM
#include <linux/pm.h>
#endif
#include <mach/hardware.h>
#include <mach/h3600.h>
#include <asm/mach-types.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <linux/l3/l3.h>
#undef DEBUG_MODE
#undef DEBUG_FUNCTION_NAMES
#include <sound/uda1341.h>
/*
* FIXME: Is this enough as autodetection of 2.4.X-rmkY-hhZ kernels?
* We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this
* module for Familiar 0.6.1
*/
/* {{{ Type definitions */
MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");
MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");
static char *id; /* ID for this card */
module_param(id, charp, 0444);
MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
struct audio_stream {
char *id; /* identification string */
int stream_id; /* numeric identification */
dma_device_t dma_dev; /* device identifier for DMA */
#ifdef HH_VERSION
dmach_t dmach; /* dma channel identification */
#else
dma_regs_t *dma_regs; /* points to our DMA registers */
#endif
unsigned int active:1; /* we are using this stream for transfer now */
int period; /* current transfer period */
int periods; /* current count of periods registerd in the DMA engine */
int tx_spin; /* are we recoding - flag used to do DMA trans. for sync */
unsigned int old_offset;
spinlock_t dma_lock; /* for locking in DMA operations (see dma-sa1100.c in the kernel) */
struct snd_pcm_substream *stream;
};
struct sa11xx_uda1341 {
struct snd_card *card;
struct l3_client *uda1341;
struct snd_pcm *pcm;
long samplerate;
struct audio_stream s[2]; /* playback & capture */
};
static unsigned int rates[] = {
8000, 10666, 10985, 14647,
16000, 21970, 22050, 24000,
29400, 32000, 44100, 48000,
};
static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static struct platform_device *device;
/* }}} */
/* {{{ Clock and sample rate stuff */
/*
* Stop-gap solution until rest of hh.org HAL stuff is merged.
*/
#define GPIO_H3600_CLK_SET0 GPIO_GPIO (12)
#define GPIO_H3600_CLK_SET1 GPIO_GPIO (13)
#ifdef CONFIG_SA1100_H3XXX
#define clr_sa11xx_uda1341_egpio(x) clr_h3600_egpio(x)
#define set_sa11xx_uda1341_egpio(x) set_h3600_egpio(x)
#else
#error This driver could serve H3x00 handhelds only!
#endif
static void sa11xx_uda1341_set_audio_clock(long val)
{
switch (val) {
case 24000: case 32000: case 48000: /* 00: 12.288 MHz */
GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
break;
case 22050: case 29400: case 44100: /* 01: 11.2896 MHz */
GPSR = GPIO_H3600_CLK_SET0;
GPCR = GPIO_H3600_CLK_SET1;
break;
case 8000: case 10666: case 16000: /* 10: 4.096 MHz */
GPCR = GPIO_H3600_CLK_SET0;
GPSR = GPIO_H3600_CLK_SET1;
break;
case 10985: case 14647: case 21970: /* 11: 5.6245 MHz */
GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
break;
}
}
static void sa11xx_uda1341_set_samplerate(struct sa11xx_uda1341 *sa11xx_uda1341, long rate)
{
int clk_div = 0;
int clk=0;
/* We don't want to mess with clocks when frames are in flight */
Ser4SSCR0 &= ~SSCR0_SSE;
/* wait for any frame to complete */
udelay(125);
/*
* We have the following clock sources:
* 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz
* Those can be divided either by 256, 384 or 512.
* This makes up 12 combinations for the following samplerates...
*/
if (rate >= 48000)
rate = 48000;
else if (rate >= 44100)
rate = 44100;
else if (rate >= 32000)
rate = 32000;
else if (rate >= 29400)
rate = 29400;
else if (rate >= 24000)
rate = 24000;
else if (rate >= 22050)
rate = 22050;
else if (rate >= 21970)
rate = 21970;
else if (rate >= 16000)
rate = 16000;
else if (rate >= 14647)
rate = 14647;
else if (rate >= 10985)
rate = 10985;
else if (rate >= 10666)
rate = 10666;
else
rate = 8000;
/* Set the external clock generator */
sa11xx_uda1341_set_audio_clock(rate);
/* Select the clock divisor */
switch (rate) {
case 8000:
case 10985:
case 22050:
case 24000:
clk = F512;
clk_div = SSCR0_SerClkDiv(16);
break;
case 16000:
case 21970:
case 44100:
case 48000:
clk = F256;
clk_div = SSCR0_SerClkDiv(8);
break;
case 10666:
case 14647:
case 29400:
case 32000:
clk = F384;
clk_div = SSCR0_SerClkDiv(12);
break;
}
/* FMT setting should be moved away when other FMTs are added (FIXME) */
l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);
l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);
Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
sa11xx_uda1341->samplerate = rate;
}
/* }}} */
/* {{{ HW init and shutdown */
static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341)
{
unsigned long flags;
/* Setup DMA stuff */
sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].id = "UDA1341 out";
sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;
sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = DMA_Ser4SSPWr;
sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].id = "UDA1341 in";
sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;
sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = DMA_Ser4SSPRd;
/* Initialize the UDA1341 internal state */
/* Setup the uarts */
local_irq_save(flags);
GAFR |= (GPIO_SSP_CLK);
GPDR &= ~(GPIO_SSP_CLK);
Ser4SSCR0 = 0;
Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
Ser4SSCR0 |= SSCR0_SSE;
local_irq_restore(flags);
/* Enable the audio power */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
/* Wait for the UDA1341 to wake up */
mdelay(1); //FIXME - was removed by Perex - Why?
/* Initialize the UDA1341 internal state */
l3_open(sa11xx_uda1341->uda1341);
/* external clock configuration (after l3_open - regs must be initialized */
sa11xx_uda1341_set_samplerate(sa11xx_uda1341, sa11xx_uda1341->samplerate);
/* Wait for the UDA1341 to wake up */
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
mdelay(1);
/* make the left and right channels unswapped (flip the WS latch) */
Ser4SSDR = 0;
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
}
static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341)
{
/* mute on */
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
/* disable the audio power and all signals leading to the audio chip */
l3_close(sa11xx_uda1341->uda1341);
Ser4SSCR0 = 0;
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
/* power off and mute off */
/* FIXME - is muting off necesary??? */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
}
/* }}} */
/* {{{ DMA staff */
/*
* these are the address and sizes used to fill the xmit buffer
* so we can get a clock in record only mode
*/
#define FORCE_CLOCK_ADDR (dma_addr_t)FLUSH_BASE_PHYS
#define FORCE_CLOCK_SIZE 4096 // was 2048
// FIXME Why this value exactly - wrote comment
#define DMA_BUF_SIZE 8176 /* <= MAX_DMA_SIZE from asm/arch-sa1100/dma.h */
#ifdef HH_VERSION
static int audio_dma_request(struct audio_stream *s, void (*callback)(void *, int))
{
int ret;
ret = sa1100_request_dma(&s->dmach, s->id, s->dma_dev);
if (ret < 0) {
printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
return ret;
}
sa1100_dma_set_callback(s->dmach, callback);
return 0;
}
static inline void audio_dma_free(struct audio_stream *s)
{
sa1100_free_dma(s->dmach);
s->dmach = -1;
}
#else
static int audio_dma_request(struct audio_stream *s, void (*callback)(void *))
{
int ret;
ret = sa1100_request_dma(s->dma_dev, s->id, callback, s, &s->dma_regs);
if (ret < 0)
printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
return ret;
}
static void audio_dma_free(struct audio_stream *s)
{
sa1100_free_dma(s->dma_regs);
s->dma_regs = 0;
}
#endif
static u_int audio_get_dma_pos(struct audio_stream *s)
{
struct snd_pcm_substream *substream = s->stream;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int offset;
unsigned long flags;
dma_addr_t addr;
// this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
spin_lock_irqsave(&s->dma_lock, flags);
#ifdef HH_VERSION
sa1100_dma_get_current(s->dmach, NULL, &addr);
#else
addr = sa1100_get_dma_pos((s)->dma_regs);
#endif
offset = addr - runtime->dma_addr;
spin_unlock_irqrestore(&s->dma_lock, flags);
offset = bytes_to_frames(runtime,offset);
if (offset >= runtime->buffer_size)
offset = 0;
return offset;
}
/*
* this stops the dma and clears the dma ptrs
*/
static void audio_stop_dma(struct audio_stream *s)
{
unsigned long flags;
spin_lock_irqsave(&s->dma_lock, flags);
s->active = 0;
s->period = 0;
/* this stops the dma channel and clears the buffer ptrs */
#ifdef HH_VERSION
sa1100_dma_flush_all(s->dmach);
#else
sa1100_clear_dma(s->dma_regs);
#endif
spin_unlock_irqrestore(&s->dma_lock, flags);
}
static void audio_process_dma(struct audio_stream *s)
{
struct snd_pcm_substream *substream = s->stream;
struct snd_pcm_runtime *runtime;
unsigned int dma_size;
unsigned int offset;
int ret;
/* we are requested to process synchronization DMA transfer */
if (s->tx_spin) {
if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK))
return;
/* fill the xmit dma buffers and return */
#ifdef HH_VERSION
sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
#else
while (1) {
ret = sa1100_start_dma(s->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
if (ret)
return;
}
#endif
return;
}
/* must be set here - only valid for running streams, not for forced_clock dma fills */
runtime = substream->runtime;
while (s->active && s->periods < runtime->periods) {
dma_size = frames_to_bytes(runtime, runtime->period_size);
if (s->old_offset) {
/* a little trick, we need resume from old position */
offset = frames_to_bytes(runtime, s->old_offset - 1);
s->old_offset = 0;
s->periods = 0;
s->period = offset / dma_size;
offset %= dma_size;
dma_size = dma_size - offset;
if (!dma_size)
continue; /* special case */
} else {
offset = dma_size * s->period;
snd_BUG_ON(dma_size > DMA_BUF_SIZE);
}
#ifdef HH_VERSION
ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);
if (ret)
return; //FIXME
#else
ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);
if (ret) {
printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);
return;
}
#endif
s->period++;
s->period %= runtime->periods;
s->periods++;
}
}
#ifdef HH_VERSION
static void audio_dma_callback(void *data, int size)
#else
static void audio_dma_callback(void *data)
#endif
{
struct audio_stream *s = data;
/*
* If we are getting a callback for an active stream then we inform
* the PCM middle layer we've finished a period
*/
if (s->active)
snd_pcm_period_elapsed(s->stream);
spin_lock(&s->dma_lock);
if (!s->tx_spin && s->periods > 0)
s->periods--;
audio_process_dma(s);
spin_unlock(&s->dma_lock);
}
/* }}} */
/* {{{ PCM setting */
/* {{{ trigger & timer */
static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
int stream_id = substream->pstr->stream;
struct audio_stream *s = &chip->s[stream_id];
struct audio_stream *s1 = &chip->s[stream_id ^ 1];
int err = 0;
/* note local interrupts are already disabled in the midlevel code */
spin_lock(&s->dma_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* now we need to make sure a record only stream has a clock */
if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
/* we need to force fill the xmit DMA with zeros */
s1->tx_spin = 1;
audio_process_dma(s1);
}
/* this case is when you were recording then you turn on a
* playback stream so we stop (also clears it) the dma first,
* clear the sync flag and then we let it turned on
*/
else {
s->tx_spin = 0;
}
/* requested stream startup */
s->active = 1;
audio_process_dma(s);
break;
case SNDRV_PCM_TRIGGER_STOP:
/* requested stream shutdown */
audio_stop_dma(s);
/*
* now we need to make sure a record only stream has a clock
* so if we're stopping a playback with an active capture
* we need to turn the 0 fill dma on for the xmit side
*/
if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) {
/* we need to force fill the xmit DMA with zeros */
s->tx_spin = 1;
audio_process_dma(s);
}
/*
* we killed a capture only stream, so we should also kill
* the zero fill transmit
*/
else {
if (s1->tx_spin) {
s1->tx_spin = 0;
audio_stop_dma(s1);
}
}
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
s->active = 0;
#ifdef HH_VERSION
sa1100_dma_stop(s->dmach);
#else
//FIXME - DMA API
#endif
s->old_offset = audio_get_dma_pos(s) + 1;
#ifdef HH_VERSION
sa1100_dma_flush_all(s->dmach);
#else
//FIXME - DMA API
#endif
s->periods = 0;
break;
case SNDRV_PCM_TRIGGER_RESUME:
s->active = 1;
s->tx_spin = 0;
audio_process_dma(s);
if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
s1->tx_spin = 1;
audio_process_dma(s1);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
#ifdef HH_VERSION
sa1100_dma_stop(s->dmach);
#else
//FIXME - DMA API
#endif
s->active = 0;
if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
if (s1->active) {
s->tx_spin = 1;
s->old_offset = audio_get_dma_pos(s) + 1;
#ifdef HH_VERSION
sa1100_dma_flush_all(s->dmach);
#else
//FIXME - DMA API
#endif
audio_process_dma(s);
}
} else {
if (s1->tx_spin) {
s1->tx_spin = 0;
#ifdef HH_VERSION
sa1100_dma_flush_all(s1->dmach);
#else
//FIXME - DMA API
#endif
}
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
s->active = 1;
if (s->old_offset) {
s->tx_spin = 0;
audio_process_dma(s);
break;
}
if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
s1->tx_spin = 1;
audio_process_dma(s1);
}
#ifdef HH_VERSION
sa1100_dma_resume(s->dmach);
#else
//FIXME - DMA API
#endif
break;
default:
err = -EINVAL;
break;
}
spin_unlock(&s->dma_lock);
return err;
}
static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream)
{
struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_stream *s = &chip->s[substream->pstr->stream];
/* set requested samplerate */
sa11xx_uda1341_set_samplerate(chip, runtime->rate);
/* set requestd format when available */
/* set FMT here !!! FIXME */
s->period = 0;
s->periods = 0;
return 0;
}
static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream)
{
struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
}
/* }}} */
static struct snd_pcm_hardware snd_sa11xx_uda1341_capture =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_KNOT),
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 64*1024,
.period_bytes_min = 64,
.period_bytes_max = DMA_BUF_SIZE,
.periods_min = 2,
.periods_max = 255,
.fifo_size = 0,
};
static struct snd_pcm_hardware snd_sa11xx_uda1341_playback =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_KNOT),
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 64*1024,
.period_bytes_min = 64,
.period_bytes_max = DMA_BUF_SIZE,
.periods_min = 2,
.periods_max = 255,
.fifo_size = 0,
};
static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream)
{
struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int stream_id = substream->pstr->stream;
int err;
chip->s[stream_id].stream = substream;
if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
runtime->hw = snd_sa11xx_uda1341_playback;
else
runtime->hw = snd_sa11xx_uda1341_capture;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)
return err;
return 0;
}
static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream)
{
struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
chip->s[substream->pstr->stream].stream = NULL;
return 0;
}
/* {{{ HW params & free */
static int snd_sa11xx_uda1341_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
static int snd_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_pages(substream);
}
/* }}} */
static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = {
.open = snd_card_sa11xx_uda1341_open,
.close = snd_card_sa11xx_uda1341_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_sa11xx_uda1341_hw_params,
.hw_free = snd_sa11xx_uda1341_hw_free,
.prepare = snd_sa11xx_uda1341_prepare,
.trigger = snd_sa11xx_uda1341_trigger,
.pointer = snd_sa11xx_uda1341_pointer,
};
static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = {
.open = snd_card_sa11xx_uda1341_open,
.close = snd_card_sa11xx_uda1341_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_sa11xx_uda1341_hw_params,
.hw_free = snd_sa11xx_uda1341_hw_free,
.prepare = snd_sa11xx_uda1341_prepare,
.trigger = snd_sa11xx_uda1341_trigger,
.pointer = snd_sa11xx_uda1341_pointer,
};
static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device)
{
struct snd_pcm *pcm;
int err;
if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)
return err;
/*
* this sets up our initial buffers and sets the dma_type to isa.
* isa works but I'm not sure why (or if) it's the right choice
* this may be too large, trying it for now
*/
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
64*1024, 64*1024);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
pcm->private_data = sa11xx_uda1341;
pcm->info_flags = 0;
strcpy(pcm->name, "UDA1341 PCM");
sa11xx_uda1341_audio_init(sa11xx_uda1341);
/* setup DMA controller */
audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);
audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);
sa11xx_uda1341->pcm = pcm;
return 0;
}
/* }}} */
/* {{{ module init & exit */
#ifdef CONFIG_PM
static int snd_sa11xx_uda1341_suspend(struct platform_device *devptr,
pm_message_t state)
{
struct snd_card *card = platform_get_drvdata(devptr);
struct sa11xx_uda1341 *chip = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
#ifdef HH_VERSION
sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
#else
//FIXME
#endif
l3_command(chip->uda1341, CMD_SUSPEND, NULL);
sa11xx_uda1341_audio_shutdown(chip);
return 0;
}
static int snd_sa11xx_uda1341_resume(struct platform_device *devptr)
{
struct snd_card *card = platform_get_drvdata(devptr);
struct sa11xx_uda1341 *chip = card->private_data;
sa11xx_uda1341_audio_init(chip);
l3_command(chip->uda1341, CMD_RESUME, NULL);
#ifdef HH_VERSION
sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
#else
//FIXME
#endif
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif /* COMFIG_PM */
void snd_sa11xx_uda1341_free(struct snd_card *card)
{
struct sa11xx_uda1341 *chip = card->private_data;
audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
}
static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr)
{
int err;
struct snd_card *card;
struct sa11xx_uda1341 *chip;
/* register the soundcard */
card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341));
if (card == NULL)
return -ENOMEM;
chip = card->private_data;
spin_lock_init(&chip->s[0].dma_lock);
spin_lock_init(&chip->s[1].dma_lock);
card->private_free = snd_sa11xx_uda1341_free;
chip->card = card;
chip->samplerate = AUDIO_RATE_DEFAULT;
// mixer
if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))
goto nodev;
// PCM
if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)
goto nodev;
strcpy(card->driver, "UDA1341");
strcpy(card->shortname, "H3600 UDA1341TS");
sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");
snd_card_set_dev(card, &devptr->dev);
if ((err = snd_card_register(card)) == 0) {
printk( KERN_INFO "iPAQ audio support initialized\n" );
platform_set_drvdata(devptr, card);
return 0;
}
nodev:
snd_card_free(card);
return err;
}
static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr)
{
snd_card_free(platform_get_drvdata(devptr));
platform_set_drvdata(devptr, NULL);
return 0;
}
#define SA11XX_UDA1341_DRIVER "sa11xx_uda1341"
static struct platform_driver sa11xx_uda1341_driver = {
.probe = sa11xx_uda1341_probe,
.remove = __devexit_p(sa11xx_uda1341_remove),
#ifdef CONFIG_PM
.suspend = snd_sa11xx_uda1341_suspend,
.resume = snd_sa11xx_uda1341_resume,
#endif
.driver = {
.name = SA11XX_UDA1341_DRIVER,
},
};
static int __init sa11xx_uda1341_init(void)
{
int err;
if (!machine_is_h3xxx())
return -ENODEV;
if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)
return err;
device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);
if (!IS_ERR(device)) {
if (platform_get_drvdata(device))
return 0;
platform_device_unregister(device);
err = -ENODEV;
} else
err = PTR_ERR(device);
platform_driver_unregister(&sa11xx_uda1341_driver);
return err;
}
static void __exit sa11xx_uda1341_exit(void)
{
platform_device_unregister(device);
platform_driver_unregister(&sa11xx_uda1341_driver);
}
module_init(sa11xx_uda1341_init);
module_exit(sa11xx_uda1341_exit);
/* }}} */
/*
* Local variables:
* indent-tabs-mode: t
* End:
*/

19
sound/atmel/Kconfig Normal file
View File

@ -0,0 +1,19 @@
menu "Atmel devices (AVR32 and AT91)"
depends on AVR32 || ARCH_AT91
config SND_ATMEL_ABDAC
tristate "Atmel Audio Bitstream DAC (ABDAC) driver"
select SND_PCM
depends on DW_DMAC && AVR32
help
ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC).
config SND_ATMEL_AC97C
tristate "Atmel AC97 Controller (AC97C) driver"
select SND_PCM
select SND_AC97_CODEC
depends on DW_DMAC && AVR32
help
ALSA sound driver for the Atmel AC97 controller.
endmenu

5
sound/atmel/Makefile Normal file
View File

@ -0,0 +1,5 @@
snd-atmel-abdac-objs := abdac.o
snd-atmel-ac97c-objs := ac97c.o
obj-$(CONFIG_SND_ATMEL_ABDAC) += snd-atmel-abdac.o
obj-$(CONFIG_SND_ATMEL_AC97C) += snd-atmel-ac97c.o

602
sound/atmel/abdac.c Normal file
View File

@ -0,0 +1,602 @@
/*
* Driver for the Atmel on-chip Audio Bitstream DAC (ABDAC)
*
* Copyright (C) 2006-2009 Atmel Corporation
*
* 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.
*/
#include <linux/clk.h>
#include <linux/bitmap.h>
#include <linux/dw_dmac.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/atmel-abdac.h>
/* DAC register offsets */
#define DAC_DATA 0x0000
#define DAC_CTRL 0x0008
#define DAC_INT_MASK 0x000c
#define DAC_INT_EN 0x0010
#define DAC_INT_DIS 0x0014
#define DAC_INT_CLR 0x0018
#define DAC_INT_STATUS 0x001c
/* Bitfields in CTRL */
#define DAC_SWAP_OFFSET 30
#define DAC_SWAP_SIZE 1
#define DAC_EN_OFFSET 31
#define DAC_EN_SIZE 1
/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */
#define DAC_UNDERRUN_OFFSET 28
#define DAC_UNDERRUN_SIZE 1
#define DAC_TX_READY_OFFSET 29
#define DAC_TX_READY_SIZE 1
/* Bit manipulation macros */
#define DAC_BIT(name) \
(1 << DAC_##name##_OFFSET)
#define DAC_BF(name, value) \
(((value) & ((1 << DAC_##name##_SIZE) - 1)) \
<< DAC_##name##_OFFSET)
#define DAC_BFEXT(name, value) \
(((value) >> DAC_##name##_OFFSET) \
& ((1 << DAC_##name##_SIZE) - 1))
#define DAC_BFINS(name, value, old) \
(((old) & ~(((1 << DAC_##name##_SIZE) - 1) \
<< DAC_##name##_OFFSET)) \
| DAC_BF(name, value))
/* Register access macros */
#define dac_readl(port, reg) \
__raw_readl((port)->regs + DAC_##reg)
#define dac_writel(port, reg, value) \
__raw_writel((value), (port)->regs + DAC_##reg)
/*
* ABDAC supports a maximum of 6 different rates from a generic clock. The
* generic clock has a power of two divider, which gives 6 steps from 192 kHz
* to 5112 Hz.
*/
#define MAX_NUM_RATES 6
/* ALSA seems to use rates between 192000 Hz and 5112 Hz. */
#define RATE_MAX 192000
#define RATE_MIN 5112
enum {
DMA_READY = 0,
};
struct atmel_abdac_dma {
struct dma_chan *chan;
struct dw_cyclic_desc *cdesc;
};
struct atmel_abdac {
struct clk *pclk;
struct clk *sample_clk;
struct platform_device *pdev;
struct atmel_abdac_dma dma;
struct snd_pcm_hw_constraint_list constraints_rates;
struct snd_pcm_substream *substream;
struct snd_card *card;
struct snd_pcm *pcm;
void __iomem *regs;
unsigned long flags;
unsigned int rates[MAX_NUM_RATES];
unsigned int rates_num;
int irq;
};
#define get_dac(card) ((struct atmel_abdac *)(card)->private_data)
/* This function is called by the DMA driver. */
static void atmel_abdac_dma_period_done(void *arg)
{
struct atmel_abdac *dac = arg;
snd_pcm_period_elapsed(dac->substream);
}
static int atmel_abdac_prepare_dma(struct atmel_abdac *dac,
struct snd_pcm_substream *substream,
enum dma_data_direction direction)
{
struct dma_chan *chan = dac->dma.chan;
struct dw_cyclic_desc *cdesc;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long buffer_len, period_len;
/*
* We don't do DMA on "complex" transfers, i.e. with
* non-halfword-aligned buffers or lengths.
*/
if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
dev_dbg(&dac->pdev->dev, "too complex transfer\n");
return -EINVAL;
}
buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
period_len = frames_to_bytes(runtime, runtime->period_size);
cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
period_len, DMA_TO_DEVICE);
if (IS_ERR(cdesc)) {
dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n");
return PTR_ERR(cdesc);
}
cdesc->period_callback = atmel_abdac_dma_period_done;
cdesc->period_callback_param = dac;
dac->dma.cdesc = cdesc;
set_bit(DMA_READY, &dac->flags);
return 0;
}
static struct snd_pcm_hardware atmel_abdac_hw = {
.info = (SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
| SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BLOCK_TRANSFER
| SNDRV_PCM_INFO_RESUME
| SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_BE),
.rates = (SNDRV_PCM_RATE_KNOT),
.rate_min = RATE_MIN,
.rate_max = RATE_MAX,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 64 * 4096,
.period_bytes_min = 4096,
.period_bytes_max = 4096,
.periods_min = 4,
.periods_max = 64,
};
static int atmel_abdac_open(struct snd_pcm_substream *substream)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
dac->substream = substream;
atmel_abdac_hw.rate_max = dac->rates[dac->rates_num - 1];
atmel_abdac_hw.rate_min = dac->rates[0];
substream->runtime->hw = atmel_abdac_hw;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &dac->constraints_rates);
}
static int atmel_abdac_close(struct snd_pcm_substream *substream)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
dac->substream = NULL;
return 0;
}
static int atmel_abdac_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
int retval;
retval = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_READY, &dac->flags))
dw_dma_cyclic_free(dac->dma.chan);
return retval;
}
static int atmel_abdac_hw_free(struct snd_pcm_substream *substream)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
if (test_and_clear_bit(DMA_READY, &dac->flags))
dw_dma_cyclic_free(dac->dma.chan);
return snd_pcm_lib_free_pages(substream);
}
static int atmel_abdac_prepare(struct snd_pcm_substream *substream)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
int retval;
retval = clk_set_rate(dac->sample_clk, 256 * substream->runtime->rate);
if (retval)
return retval;
if (!test_bit(DMA_READY, &dac->flags))
retval = atmel_abdac_prepare_dma(dac, substream, DMA_TO_DEVICE);
return retval;
}
static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
int retval = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
clk_enable(dac->sample_clk);
retval = dw_dma_cyclic_start(dac->dma.chan);
if (retval)
goto out;
dac_writel(dac, CTRL, DAC_BIT(EN));
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
dw_dma_cyclic_stop(dac->dma.chan);
dac_writel(dac, DATA, 0);
dac_writel(dac, CTRL, 0);
clk_disable(dac->sample_clk);
break;
default:
retval = -EINVAL;
break;
}
out:
return retval;
}
static snd_pcm_uframes_t
atmel_abdac_pointer(struct snd_pcm_substream *substream)
{
struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t frames;
unsigned long bytes;
bytes = dw_dma_get_src_addr(dac->dma.chan);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
if (frames >= runtime->buffer_size)
frames -= runtime->buffer_size;
return frames;
}
static irqreturn_t abdac_interrupt(int irq, void *dev_id)
{
struct atmel_abdac *dac = dev_id;
u32 status;
status = dac_readl(dac, INT_STATUS);
if (status & DAC_BIT(UNDERRUN)) {
dev_err(&dac->pdev->dev, "underrun detected\n");
dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN));
} else {
dev_err(&dac->pdev->dev, "spurious interrupt (status=0x%x)\n",
status);
dac_writel(dac, INT_CLR, status);
}
return IRQ_HANDLED;
}
static struct snd_pcm_ops atmel_abdac_ops = {
.open = atmel_abdac_open,
.close = atmel_abdac_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = atmel_abdac_hw_params,
.hw_free = atmel_abdac_hw_free,
.prepare = atmel_abdac_prepare,
.trigger = atmel_abdac_trigger,
.pointer = atmel_abdac_pointer,
};
static int __devinit atmel_abdac_pcm_new(struct atmel_abdac *dac)
{
struct snd_pcm_hardware hw = atmel_abdac_hw;
struct snd_pcm *pcm;
int retval;
retval = snd_pcm_new(dac->card, dac->card->shortname,
dac->pdev->id, 1, 0, &pcm);
if (retval)
return retval;
strcpy(pcm->name, dac->card->shortname);
pcm->private_data = dac;
pcm->info_flags = 0;
dac->pcm = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_abdac_ops);
retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
&dac->pdev->dev, hw.periods_min * hw.period_bytes_min,
hw.buffer_bytes_max);
return retval;
}
static bool filter(struct dma_chan *chan, void *slave)
{
struct dw_dma_slave *dws = slave;
if (dws->dma_dev == chan->device->dev) {
chan->private = dws;
return true;
} else
return false;
}
static int set_sample_rates(struct atmel_abdac *dac)
{
long new_rate = RATE_MAX;
int retval = -EINVAL;
int index = 0;
/* we start at 192 kHz and work our way down to 5112 Hz */
while (new_rate >= RATE_MIN && index < (MAX_NUM_RATES + 1)) {
new_rate = clk_round_rate(dac->sample_clk, 256 * new_rate);
if (new_rate < 0)
break;
/* make sure we are below the ABDAC clock */
if (new_rate <= clk_get_rate(dac->pclk)) {
dac->rates[index] = new_rate / 256;
index++;
}
/* divide by 256 and then by two to get next rate */
new_rate /= 256 * 2;
}
if (index) {
int i;
/* reverse array, smallest go first */
for (i = 0; i < (index / 2); i++) {
unsigned int tmp = dac->rates[index - 1 - i];
dac->rates[index - 1 - i] = dac->rates[i];
dac->rates[i] = tmp;
}
dac->constraints_rates.count = index;
dac->constraints_rates.list = dac->rates;
dac->constraints_rates.mask = 0;
dac->rates_num = index;
retval = 0;
}
return retval;
}
static int __devinit atmel_abdac_probe(struct platform_device *pdev)
{
struct snd_card *card;
struct atmel_abdac *dac;
struct resource *regs;
struct atmel_abdac_pdata *pdata;
struct clk *pclk;
struct clk *sample_clk;
int retval;
int irq;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_dbg(&pdev->dev, "no memory resource\n");
return -ENXIO;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_dbg(&pdev->dev, "could not get IRQ number\n");
return irq;
}
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_dbg(&pdev->dev, "no platform data\n");
return -ENXIO;
}
pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
sample_clk = clk_get(&pdev->dev, "sample_clk");
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no sample clock\n");
retval = PTR_ERR(pclk);
goto out_put_pclk;
}
clk_enable(pclk);
retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct atmel_abdac), &card);
if (retval) {
dev_dbg(&pdev->dev, "could not create sound card device\n");
goto out_put_sample_clk;
}
dac = get_dac(card);
dac->irq = irq;
dac->card = card;
dac->pclk = pclk;
dac->sample_clk = sample_clk;
dac->pdev = pdev;
retval = set_sample_rates(dac);
if (retval < 0) {
dev_dbg(&pdev->dev, "could not set supported rates\n");
goto out_free_card;
}
dac->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!dac->regs) {
dev_dbg(&pdev->dev, "could not remap register memory\n");
goto out_free_card;
}
/* make sure the DAC is silent and disabled */
dac_writel(dac, DATA, 0);
dac_writel(dac, CTRL, 0);
retval = request_irq(irq, abdac_interrupt, 0, "abdac", dac);
if (retval) {
dev_dbg(&pdev->dev, "could not request irq\n");
goto out_unmap_regs;
}
snd_card_set_dev(card, &pdev->dev);
if (pdata->dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->dws;
dma_cap_mask_t mask;
dws->tx_reg = regs->start + DAC_DATA;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dac->dma.chan = dma_request_channel(mask, filter, dws);
}
if (!pdata->dws.dma_dev || !dac->dma.chan) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
goto out_unset_card_dev;
}
strcpy(card->driver, "Atmel ABDAC");
strcpy(card->shortname, "Atmel ABDAC");
sprintf(card->longname, "Atmel Audio Bitstream DAC");
retval = atmel_abdac_pcm_new(dac);
if (retval) {
dev_dbg(&pdev->dev, "could not register ABDAC pcm device\n");
goto out_release_dma;
}
retval = snd_card_register(card);
if (retval) {
dev_dbg(&pdev->dev, "could not register sound card\n");
goto out_release_dma;
}
platform_set_drvdata(pdev, card);
dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
dac->regs, dac->dma.chan->dev->device.bus_id);
return retval;
out_release_dma:
dma_release_channel(dac->dma.chan);
dac->dma.chan = NULL;
out_unset_card_dev:
snd_card_set_dev(card, NULL);
free_irq(irq, dac);
out_unmap_regs:
iounmap(dac->regs);
out_free_card:
snd_card_free(card);
out_put_sample_clk:
clk_put(sample_clk);
clk_disable(pclk);
out_put_pclk:
clk_put(pclk);
return retval;
}
#ifdef CONFIG_PM
static int atmel_abdac_suspend(struct platform_device *pdev, pm_message_t msg)
{
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_abdac *dac = card->private_data;
dw_dma_cyclic_stop(dac->dma.chan);
clk_disable(dac->sample_clk);
clk_disable(dac->pclk);
return 0;
}
static int atmel_abdac_resume(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_abdac *dac = card->private_data;
clk_enable(dac->pclk);
clk_enable(dac->sample_clk);
if (test_bit(DMA_READY, &dac->flags))
dw_dma_cyclic_start(dac->dma.chan);
return 0;
}
#else
#define atmel_abdac_suspend NULL
#define atmel_abdac_resume NULL
#endif
static int __devexit atmel_abdac_remove(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_abdac *dac = get_dac(card);
clk_put(dac->sample_clk);
clk_disable(dac->pclk);
clk_put(dac->pclk);
dma_release_channel(dac->dma.chan);
dac->dma.chan = NULL;
snd_card_set_dev(card, NULL);
iounmap(dac->regs);
free_irq(dac->irq, dac);
snd_card_free(card);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver atmel_abdac_driver = {
.remove = __devexit_p(atmel_abdac_remove),
.driver = {
.name = "atmel_abdac",
},
.suspend = atmel_abdac_suspend,
.resume = atmel_abdac_resume,
};
static int __init atmel_abdac_init(void)
{
return platform_driver_probe(&atmel_abdac_driver,
atmel_abdac_probe);
}
module_init(atmel_abdac_init);
static void __exit atmel_abdac_exit(void)
{
platform_driver_unregister(&atmel_abdac_driver);
}
module_exit(atmel_abdac_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Driver for Atmel Audio Bitstream DAC (ABDAC)");
MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");

932
sound/atmel/ac97c.c Normal file
View File

@ -0,0 +1,932 @@
/*
* Driver for the Atmel AC97C controller
*
* Copyright (C) 2005-2009 Atmel Corporation
*
* 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.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/bitmap.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/ac97_codec.h>
#include <sound/atmel-ac97c.h>
#include <sound/memalloc.h>
#include <linux/dw_dmac.h>
#include "ac97c.h"
enum {
DMA_TX_READY = 0,
DMA_RX_READY,
DMA_TX_CHAN_PRESENT,
DMA_RX_CHAN_PRESENT,
};
/* Serialize access to opened variable */
static DEFINE_MUTEX(opened_mutex);
struct atmel_ac97c_dma {
struct dma_chan *rx_chan;
struct dma_chan *tx_chan;
};
struct atmel_ac97c {
struct clk *pclk;
struct platform_device *pdev;
struct atmel_ac97c_dma dma;
struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream;
struct snd_card *card;
struct snd_pcm *pcm;
struct snd_ac97 *ac97;
struct snd_ac97_bus *ac97_bus;
u64 cur_format;
unsigned int cur_rate;
unsigned long flags;
/* Serialize access to opened variable */
spinlock_t lock;
void __iomem *regs;
int opened;
int reset_pin;
};
#define get_chip(card) ((struct atmel_ac97c *)(card)->private_data)
#define ac97c_writel(chip, reg, val) \
__raw_writel((val), (chip)->regs + AC97C_##reg)
#define ac97c_readl(chip, reg) \
__raw_readl((chip)->regs + AC97C_##reg)
/* This function is called by the DMA driver. */
static void atmel_ac97c_dma_playback_period_done(void *arg)
{
struct atmel_ac97c *chip = arg;
snd_pcm_period_elapsed(chip->playback_substream);
}
static void atmel_ac97c_dma_capture_period_done(void *arg)
{
struct atmel_ac97c *chip = arg;
snd_pcm_period_elapsed(chip->capture_substream);
}
static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
struct snd_pcm_substream *substream,
enum dma_data_direction direction)
{
struct dma_chan *chan;
struct dw_cyclic_desc *cdesc;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long buffer_len, period_len;
/*
* We don't do DMA on "complex" transfers, i.e. with
* non-halfword-aligned buffers or lengths.
*/
if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
dev_dbg(&chip->pdev->dev, "too complex transfer\n");
return -EINVAL;
}
if (direction == DMA_TO_DEVICE)
chan = chip->dma.tx_chan;
else
chan = chip->dma.rx_chan;
buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
period_len = frames_to_bytes(runtime, runtime->period_size);
cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
period_len, direction);
if (IS_ERR(cdesc)) {
dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
return PTR_ERR(cdesc);
}
if (direction == DMA_TO_DEVICE) {
cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
set_bit(DMA_TX_READY, &chip->flags);
} else {
cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
set_bit(DMA_RX_READY, &chip->flags);
}
cdesc->period_callback_param = chip;
return 0;
}
static struct snd_pcm_hardware atmel_ac97c_hw = {
.info = (SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
| SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BLOCK_TRANSFER
| SNDRV_PCM_INFO_JOINT_DUPLEX
| SNDRV_PCM_INFO_RESUME
| SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_BE
| SNDRV_PCM_FMTBIT_S16_LE),
.rates = (SNDRV_PCM_RATE_CONTINUOUS),
.rate_min = 4000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 64 * 4096,
.period_bytes_min = 4096,
.period_bytes_max = 4096,
.periods_min = 4,
.periods_max = 64,
};
static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
mutex_lock(&opened_mutex);
chip->opened++;
runtime->hw = atmel_ac97c_hw;
if (chip->cur_rate) {
runtime->hw.rate_min = chip->cur_rate;
runtime->hw.rate_max = chip->cur_rate;
}
if (chip->cur_format)
runtime->hw.formats = (1ULL << chip->cur_format);
mutex_unlock(&opened_mutex);
chip->playback_substream = substream;
return 0;
}
static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
mutex_lock(&opened_mutex);
chip->opened++;
runtime->hw = atmel_ac97c_hw;
if (chip->cur_rate) {
runtime->hw.rate_min = chip->cur_rate;
runtime->hw.rate_max = chip->cur_rate;
}
if (chip->cur_format)
runtime->hw.formats = (1ULL << chip->cur_format);
mutex_unlock(&opened_mutex);
chip->capture_substream = substream;
return 0;
}
static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
mutex_lock(&opened_mutex);
chip->opened--;
if (!chip->opened) {
chip->cur_rate = 0;
chip->cur_format = 0;
}
mutex_unlock(&opened_mutex);
chip->playback_substream = NULL;
return 0;
}
static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
mutex_lock(&opened_mutex);
chip->opened--;
if (!chip->opened) {
chip->cur_rate = 0;
chip->cur_format = 0;
}
mutex_unlock(&opened_mutex);
chip->capture_substream = NULL;
return 0;
}
static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
int retval;
retval = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
/* Set restrictions to params. */
mutex_lock(&opened_mutex);
chip->cur_rate = params_rate(hw_params);
chip->cur_format = params_format(hw_params);
mutex_unlock(&opened_mutex);
return retval;
}
static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
int retval;
retval = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
/* Set restrictions to params. */
mutex_lock(&opened_mutex);
chip->cur_rate = params_rate(hw_params);
chip->cur_format = params_format(hw_params);
mutex_unlock(&opened_mutex);
return retval;
}
static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
return snd_pcm_lib_free_pages(substream);
}
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
return snd_pcm_lib_free_pages(substream);
}
static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long word = 0;
int retval;
/* assign channels to AC97C channel A */
switch (runtime->channels) {
case 1:
word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
break;
case 2:
word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
| AC97C_CH_ASSIGN(PCM_RIGHT, A);
break;
default:
/* TODO: support more than two channels */
return -EINVAL;
break;
}
ac97c_writel(chip, OCA, word);
/* configure sample format and size */
word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
word |= AC97C_CMR_CEM_LITTLE;
break;
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
default:
word &= ~(AC97C_CMR_CEM_LITTLE);
break;
}
ac97c_writel(chip, CAMR, word);
/* set variable rate if needed */
if (runtime->rate != 48000) {
word = ac97c_readl(chip, MR);
word |= AC97C_MR_VRA;
ac97c_writel(chip, MR, word);
} else {
word = ac97c_readl(chip, MR);
word &= ~(AC97C_MR_VRA);
ac97c_writel(chip, MR, word);
}
retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
runtime->rate);
if (retval)
dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
runtime->rate);
if (!test_bit(DMA_TX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_TO_DEVICE);
return retval;
}
static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long word = 0;
int retval;
/* assign channels to AC97C channel A */
switch (runtime->channels) {
case 1:
word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
break;
case 2:
word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
| AC97C_CH_ASSIGN(PCM_RIGHT, A);
break;
default:
/* TODO: support more than two channels */
return -EINVAL;
break;
}
ac97c_writel(chip, ICA, word);
/* configure sample format and size */
word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
word |= AC97C_CMR_CEM_LITTLE;
break;
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
default:
word &= ~(AC97C_CMR_CEM_LITTLE);
break;
}
ac97c_writel(chip, CAMR, word);
/* set variable rate if needed */
if (runtime->rate != 48000) {
word = ac97c_readl(chip, MR);
word |= AC97C_MR_VRA;
ac97c_writel(chip, MR, word);
} else {
word = ac97c_readl(chip, MR);
word &= ~(AC97C_MR_VRA);
ac97c_writel(chip, MR, word);
}
retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE,
runtime->rate);
if (retval)
dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
runtime->rate);
if (!test_bit(DMA_RX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_FROM_DEVICE);
return retval;
}
static int
atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
unsigned long camr;
int retval = 0;
camr = ac97c_readl(chip, CAMR);
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.tx_chan);
if (retval)
goto out;
camr |= AC97C_CMR_CENA;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
dw_dma_cyclic_stop(chip->dma.tx_chan);
if (chip->opened <= 1)
camr &= ~AC97C_CMR_CENA;
break;
default:
retval = -EINVAL;
goto out;
}
ac97c_writel(chip, CAMR, camr);
out:
return retval;
}
static int
atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
unsigned long camr;
int retval = 0;
camr = ac97c_readl(chip, CAMR);
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
camr |= AC97C_CMR_CENA;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
dw_dma_cyclic_stop(chip->dma.rx_chan);
if (chip->opened <= 1)
camr &= ~AC97C_CMR_CENA;
break;
default:
retval = -EINVAL;
break;
}
ac97c_writel(chip, CAMR, camr);
out:
return retval;
}
static snd_pcm_uframes_t
atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t frames;
unsigned long bytes;
bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
if (frames >= runtime->buffer_size)
frames -= runtime->buffer_size;
return frames;
}
static snd_pcm_uframes_t
atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t frames;
unsigned long bytes;
bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
if (frames >= runtime->buffer_size)
frames -= runtime->buffer_size;
return frames;
}
static struct snd_pcm_ops atmel_ac97_playback_ops = {
.open = atmel_ac97c_playback_open,
.close = atmel_ac97c_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = atmel_ac97c_playback_hw_params,
.hw_free = atmel_ac97c_playback_hw_free,
.prepare = atmel_ac97c_playback_prepare,
.trigger = atmel_ac97c_playback_trigger,
.pointer = atmel_ac97c_playback_pointer,
};
static struct snd_pcm_ops atmel_ac97_capture_ops = {
.open = atmel_ac97c_capture_open,
.close = atmel_ac97c_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = atmel_ac97c_capture_hw_params,
.hw_free = atmel_ac97c_capture_hw_free,
.prepare = atmel_ac97c_capture_prepare,
.trigger = atmel_ac97c_capture_trigger,
.pointer = atmel_ac97c_capture_pointer,
};
static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
{
struct snd_pcm *pcm;
struct snd_pcm_hardware hw = atmel_ac97c_hw;
int capture, playback, retval;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
retval = snd_pcm_new(chip->card, chip->card->shortname,
chip->pdev->id, playback, capture, &pcm);
if (retval)
return retval;
if (capture)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&atmel_ac97_capture_ops);
if (playback)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&atmel_ac97_playback_ops);
retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
hw.buffer_bytes_max);
if (retval)
return retval;
pcm->private_data = chip;
pcm->info_flags = 0;
strcpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
return 0;
}
static int atmel_ac97c_mixer_new(struct atmel_ac97c *chip)
{
struct snd_ac97_template template;
memset(&template, 0, sizeof(template));
template.private_data = chip;
return snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
}
static void atmel_ac97c_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
struct atmel_ac97c *chip = get_chip(ac97);
unsigned long word;
int timeout = 40;
word = (reg & 0x7f) << 16 | val;
do {
if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
ac97c_writel(chip, COTHR, word);
return;
}
udelay(1);
} while (--timeout);
dev_dbg(&chip->pdev->dev, "codec write timeout\n");
}
static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
unsigned short reg)
{
struct atmel_ac97c *chip = get_chip(ac97);
unsigned long word;
int timeout = 40;
int write = 10;
word = (0x80 | (reg & 0x7f)) << 16;
if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
ac97c_readl(chip, CORHR);
retry_write:
timeout = 40;
do {
if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
ac97c_writel(chip, COTHR, word);
goto read_reg;
}
udelay(10);
} while (--timeout);
if (!--write)
goto timed_out;
goto retry_write;
read_reg:
do {
if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
unsigned short val = ac97c_readl(chip, CORHR);
return val;
}
udelay(10);
} while (--timeout);
if (!--write)
goto timed_out;
goto retry_write;
timed_out:
dev_dbg(&chip->pdev->dev, "codec read timeout\n");
return 0xffff;
}
static bool filter(struct dma_chan *chan, void *slave)
{
struct dw_dma_slave *dws = slave;
if (dws->dma_dev == chan->device->dev) {
chan->private = dws;
return true;
} else
return false;
}
static void atmel_ac97c_reset(struct atmel_ac97c *chip)
{
ac97c_writel(chip, MR, AC97C_MR_WRST);
if (gpio_is_valid(chip->reset_pin)) {
gpio_set_value(chip->reset_pin, 0);
/* AC97 v2.2 specifications says minimum 1 us. */
udelay(10);
gpio_set_value(chip->reset_pin, 1);
}
udelay(1);
ac97c_writel(chip, MR, AC97C_MR_ENA);
}
static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
{
struct snd_card *card;
struct atmel_ac97c *chip;
struct resource *regs;
struct ac97c_platform_data *pdata;
struct clk *pclk;
static struct snd_ac97_bus_ops ops = {
.write = atmel_ac97c_write,
.read = atmel_ac97c_read,
};
int retval;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_dbg(&pdev->dev, "no memory resource\n");
return -ENXIO;
}
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_dbg(&pdev->dev, "no platform data\n");
return -ENXIO;
}
pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
clk_enable(pclk);
retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct atmel_ac97c), &card);
if (retval) {
dev_dbg(&pdev->dev, "could not create sound card device\n");
goto err_snd_card_new;
}
chip = get_chip(card);
spin_lock_init(&chip->lock);
strcpy(card->driver, "Atmel AC97C");
strcpy(card->shortname, "Atmel AC97C");
sprintf(card->longname, "Atmel AC97 controller");
chip->card = card;
chip->pclk = pclk;
chip->pdev = pdev;
chip->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!chip->regs) {
dev_dbg(&pdev->dev, "could not remap register memory\n");
goto err_ioremap;
}
if (gpio_is_valid(pdata->reset_pin)) {
if (gpio_request(pdata->reset_pin, "reset_pin")) {
dev_dbg(&pdev->dev, "reset pin not available\n");
chip->reset_pin = -ENODEV;
} else {
gpio_direction_output(pdata->reset_pin, 1);
chip->reset_pin = pdata->reset_pin;
}
}
snd_card_set_dev(card, &pdev->dev);
retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
if (retval) {
dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
goto err_ac97_bus;
}
atmel_ac97c_reset(chip);
retval = atmel_ac97c_mixer_new(chip);
if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
goto err_ac97_bus;
}
if (pdata->rx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->rx_dws;
dma_cap_mask_t mask;
dws->rx_reg = regs->start + AC97C_CARHR + 2;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
chip->dma.rx_chan->dev->device.bus_id);
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
}
if (pdata->tx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->tx_dws;
dma_cap_mask_t mask;
dws->tx_reg = regs->start + AC97C_CATHR + 2;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
chip->dma.tx_chan->dev->device.bus_id);
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
}
if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
goto err_dma;
}
retval = atmel_ac97c_pcm_new(chip);
if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
goto err_dma;
}
retval = snd_card_register(card);
if (retval) {
dev_dbg(&pdev->dev, "could not register sound card\n");
goto err_ac97_bus;
}
platform_set_drvdata(pdev, card);
dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
chip->regs);
return 0;
err_dma:
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
chip->dma.rx_chan = NULL;
chip->dma.tx_chan = NULL;
err_ac97_bus:
snd_card_set_dev(card, NULL);
if (gpio_is_valid(chip->reset_pin))
gpio_free(chip->reset_pin);
iounmap(chip->regs);
err_ioremap:
snd_card_free(card);
err_snd_card_new:
clk_disable(pclk);
clk_put(pclk);
return retval;
}
#ifdef CONFIG_PM
static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg)
{
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_ac97c *chip = card->private_data;
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.rx_chan);
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
clk_disable(chip->pclk);
return 0;
}
static int atmel_ac97c_resume(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk);
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.tx_chan);
return 0;
}
#else
#define atmel_ac97c_suspend NULL
#define atmel_ac97c_resume NULL
#endif
static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_ac97c *chip = get_chip(card);
if (gpio_is_valid(chip->reset_pin))
gpio_free(chip->reset_pin);
clk_disable(chip->pclk);
clk_put(chip->pclk);
iounmap(chip->regs);
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
chip->dma.rx_chan = NULL;
chip->dma.tx_chan = NULL;
snd_card_set_dev(card, NULL);
snd_card_free(card);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver atmel_ac97c_driver = {
.remove = __devexit_p(atmel_ac97c_remove),
.driver = {
.name = "atmel_ac97c",
},
.suspend = atmel_ac97c_suspend,
.resume = atmel_ac97c_resume,
};
static int __init atmel_ac97c_init(void)
{
return platform_driver_probe(&atmel_ac97c_driver,
atmel_ac97c_probe);
}
module_init(atmel_ac97c_init);
static void __exit atmel_ac97c_exit(void)
{
platform_driver_unregister(&atmel_ac97c_driver);
}
module_exit(atmel_ac97c_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");

71
sound/atmel/ac97c.h Normal file
View File

@ -0,0 +1,71 @@
/*
* Register definitions for the Atmel AC97C controller
*
* Copyright (C) 2005-2009 Atmel Corporation
*
* 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 __SOUND_ATMEL_AC97C_H
#define __SOUND_ATMEL_AC97C_H
#define AC97C_MR 0x08
#define AC97C_ICA 0x10
#define AC97C_OCA 0x14
#define AC97C_CARHR 0x20
#define AC97C_CATHR 0x24
#define AC97C_CASR 0x28
#define AC97C_CAMR 0x2c
#define AC97C_CBRHR 0x30
#define AC97C_CBTHR 0x34
#define AC97C_CBSR 0x38
#define AC97C_CBMR 0x3c
#define AC97C_CORHR 0x40
#define AC97C_COTHR 0x44
#define AC97C_COSR 0x48
#define AC97C_COMR 0x4c
#define AC97C_SR 0x50
#define AC97C_IER 0x54
#define AC97C_IDR 0x58
#define AC97C_IMR 0x5c
#define AC97C_VERSION 0xfc
#define AC97C_CATPR PDC_TPR
#define AC97C_CATCR PDC_TCR
#define AC97C_CATNPR PDC_TNPR
#define AC97C_CATNCR PDC_TNCR
#define AC97C_CARPR PDC_RPR
#define AC97C_CARCR PDC_RCR
#define AC97C_CARNPR PDC_RNPR
#define AC97C_CARNCR PDC_RNCR
#define AC97C_PTCR PDC_PTCR
#define AC97C_MR_ENA (1 << 0)
#define AC97C_MR_WRST (1 << 1)
#define AC97C_MR_VRA (1 << 2)
#define AC97C_CSR_TXRDY (1 << 0)
#define AC97C_CSR_UNRUN (1 << 2)
#define AC97C_CSR_RXRDY (1 << 4)
#define AC97C_CSR_ENDTX (1 << 10)
#define AC97C_CSR_ENDRX (1 << 14)
#define AC97C_CMR_SIZE_20 (0 << 16)
#define AC97C_CMR_SIZE_18 (1 << 16)
#define AC97C_CMR_SIZE_16 (2 << 16)
#define AC97C_CMR_SIZE_10 (3 << 16)
#define AC97C_CMR_CEM_LITTLE (1 << 18)
#define AC97C_CMR_CEM_BIG (0 << 18)
#define AC97C_CMR_CENA (1 << 21)
#define AC97C_CMR_DMAEN (1 << 22)
#define AC97C_SR_CAEVT (1 << 3)
#define AC97C_CH_ASSIGN(slot, channel) \
(AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
#define AC97C_CHANNEL_NONE 0x0
#define AC97C_CHANNEL_A 0x1
#define AC97C_CHANNEL_B 0x2
#endif /* __SOUND_ATMEL_AC97C_H */

View File

@ -99,9 +99,6 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
if (hw == NULL)
return -ENODEV;
if (!hw->ops.open)
return -ENXIO;
if (!try_module_get(hw->card->module))
return -EFAULT;
@ -113,6 +110,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
err = -EBUSY;
break;
}
if (!hw->ops.open) {
err = 0;
break;
}
err = hw->ops.open(hw, file);
if (err >= 0)
break;
@ -151,7 +152,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
static int snd_hwdep_release(struct inode *inode, struct file * file)
{
int err = -ENXIO;
int err = 0;
struct snd_hwdep *hw = file->private_data;
struct module *mod = hw->card->module;

View File

@ -121,31 +121,44 @@ static inline int init_info_for_card(struct snd_card *card)
#endif
/**
* snd_card_new - create and initialize a soundcard structure
* snd_card_create - create and initialize a soundcard structure
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
* @extra_size: allocate this extra size after the main soundcard structure
* @card_ret: the pointer to store the created card instance
*
* Creates and initializes a soundcard structure.
*
* Returns kmallocated snd_card structure. Creates the ALSA control interface
* (which is blocked until snd_card_register function is called).
* The function allocates snd_card instance via kzalloc with the given
* space for the driver to use freely. The allocated struct is stored
* in the given card_ret pointer.
*
* Returns zero if successful or a negative error code.
*/
struct snd_card *snd_card_new(int idx, const char *xid,
struct module *module, int extra_size)
int snd_card_create(int idx, const char *xid,
struct module *module, int extra_size,
struct snd_card **card_ret)
{
struct snd_card *card;
int err, idx2;
if (snd_BUG_ON(!card_ret))
return -EINVAL;
*card_ret = NULL;
if (extra_size < 0)
extra_size = 0;
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
if (card == NULL)
return NULL;
if (!card)
return -ENOMEM;
if (xid) {
if (!snd_info_check_reserved_words(xid))
if (!snd_info_check_reserved_words(xid)) {
snd_printk(KERN_ERR
"given id string '%s' is reserved.\n", xid);
err = -EBUSY;
goto __error;
}
strlcpy(card->id, xid, sizeof(card->id));
}
err = 0;
@ -195,6 +208,7 @@ struct snd_card *snd_card_new(int idx, const char *xid,
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
init_waitqueue_head(&card->shutdown_sleep);
#ifdef CONFIG_PM
mutex_init(&card->power_lock);
@ -202,26 +216,28 @@ struct snd_card *snd_card_new(int idx, const char *xid,
#endif
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
if ((err = snd_ctl_create(card)) < 0) {
snd_printd("unable to register control minors\n");
err = snd_ctl_create(card);
if (err < 0) {
snd_printk(KERN_ERR "unable to register control minors\n");
goto __error;
}
if ((err = snd_info_card_create(card)) < 0) {
snd_printd("unable to create card info\n");
err = snd_info_card_create(card);
if (err < 0) {
snd_printk(KERN_ERR "unable to create card info\n");
goto __error_ctl;
}
if (extra_size > 0)
card->private_data = (char *)card + sizeof(struct snd_card);
return card;
*card_ret = card;
return 0;
__error_ctl:
snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
__error:
kfree(card);
return NULL;
return err;
}
EXPORT_SYMBOL(snd_card_new);
EXPORT_SYMBOL(snd_card_create);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
@ -259,6 +275,7 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
list_for_each_entry(_df, &shutdown_files, shutdown_list) {
if (_df->file == file) {
df = _df;
list_del_init(&df->shutdown_list);
break;
}
}
@ -347,8 +364,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 2: replace file->f_op with special dummy operations */
spin_lock(&card->files_lock);
mfile = card->files;
while (mfile) {
list_for_each_entry(mfile, &card->files_list, list) {
file = mfile->file;
/* it's critical part, use endless loop */
@ -361,8 +377,6 @@ int snd_card_disconnect(struct snd_card *card)
mfile->file->f_op = &snd_shutdown_f_ops;
fops_get(mfile->file->f_op);
mfile = mfile->next;
}
spin_unlock(&card->files_lock);
@ -442,7 +456,7 @@ int snd_card_free_when_closed(struct snd_card *card)
return ret;
spin_lock(&card->files_lock);
if (card->files == NULL)
if (list_empty(&card->files_list))
free_now = 1;
else
card->free_on_last_close = 1;
@ -462,7 +476,7 @@ int snd_card_free(struct snd_card *card)
return ret;
/* wait, until all devices are ready for the free operation */
wait_event(card->shutdown_sleep, card->files == NULL);
wait_event(card->shutdown_sleep, list_empty(&card->files_list));
snd_card_do_free(card);
return 0;
}
@ -809,15 +823,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
return -ENOMEM;
mfile->file = file;
mfile->disconnected_f_op = NULL;
mfile->next = NULL;
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
mfile->next = card->files;
card->files = mfile;
list_add(&mfile->list, &card->files_list);
spin_unlock(&card->files_lock);
return 0;
}
@ -839,29 +851,20 @@ EXPORT_SYMBOL(snd_card_file_add);
*/
int snd_card_file_remove(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile, *pfile = NULL;
struct snd_monitor_file *mfile, *found = NULL;
int last_close = 0;
spin_lock(&card->files_lock);
mfile = card->files;
while (mfile) {
list_for_each_entry(mfile, &card->files_list, list) {
if (mfile->file == file) {
if (pfile)
pfile->next = mfile->next;
else
card->files = mfile->next;
list_del(&mfile->list);
if (mfile->disconnected_f_op)
fops_put(mfile->disconnected_f_op);
found = mfile;
break;
}
pfile = mfile;
mfile = mfile->next;
}
if (mfile && mfile->disconnected_f_op) {
fops_put(mfile->disconnected_f_op);
spin_lock(&shutdown_lock);
list_del(&mfile->shutdown_list);
spin_unlock(&shutdown_lock);
}
if (card->files == NULL)
if (list_empty(&card->files_list))
last_close = 1;
spin_unlock(&card->files_lock);
if (last_close) {
@ -869,11 +872,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
if (card->free_on_last_close)
snd_card_do_free(card);
}
if (!mfile) {
if (!found) {
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
return -ENOENT;
}
kfree(mfile);
kfree(found);
return 0;
}

View File

@ -23,6 +23,14 @@
#include <sound/jack.h>
#include <sound/core.h>
static int jack_types[] = {
SW_HEADPHONE_INSERT,
SW_MICROPHONE_INSERT,
SW_LINEOUT_INSERT,
SW_JACK_PHYSICAL_INSERT,
SW_VIDEOOUT_INSERT,
};
static int snd_jack_dev_free(struct snd_device *device)
{
struct snd_jack *jack = device->device_data;
@ -79,6 +87,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
{
struct snd_jack *jack;
int err;
int i;
static struct snd_device_ops ops = {
.dev_free = snd_jack_dev_free,
.dev_register = snd_jack_dev_register,
@ -100,18 +109,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
jack->type = type;
if (type & SND_JACK_HEADPHONE)
input_set_capability(jack->input_dev, EV_SW,
SW_HEADPHONE_INSERT);
if (type & SND_JACK_LINEOUT)
input_set_capability(jack->input_dev, EV_SW,
SW_LINEOUT_INSERT);
if (type & SND_JACK_MICROPHONE)
input_set_capability(jack->input_dev, EV_SW,
SW_MICROPHONE_INSERT);
if (type & SND_JACK_MECHANICAL)
input_set_capability(jack->input_dev, EV_SW,
SW_JACK_PHYSICAL_INSERT);
for (i = 0; i < ARRAY_SIZE(jack_types); i++)
if (type & (1 << i))
input_set_capability(jack->input_dev, EV_SW,
jack_types[i]);
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
if (err < 0)
@ -154,21 +155,17 @@ EXPORT_SYMBOL(snd_jack_set_parent);
*/
void snd_jack_report(struct snd_jack *jack, int status)
{
int i;
if (!jack)
return;
if (jack->type & SND_JACK_HEADPHONE)
input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
status & SND_JACK_HEADPHONE);
if (jack->type & SND_JACK_LINEOUT)
input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
status & SND_JACK_LINEOUT);
if (jack->type & SND_JACK_MICROPHONE)
input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
status & SND_JACK_MICROPHONE);
if (jack->type & SND_JACK_MECHANICAL)
input_report_switch(jack->input_dev, SW_JACK_PHYSICAL_INSERT,
status & SND_JACK_MECHANICAL);
for (i = 0; i < ARRAY_SIZE(jack_types); i++) {
int testbit = 1 << i;
if (jack->type & testbit)
input_report_switch(jack->input_dev, jack_types[i],
status & testbit);
}
input_sync(jack->input_dev);
}

View File

@ -95,12 +95,14 @@ 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))
for (q = list; q->subvendor; q++) {
if (q->subvendor != pci->subsystem_vendor)
continue;
if (!q->subdevice ||
(pci->subsystem_device & q->subdevice_mask) == q->subdevice)
return q;
}
return NULL;
}
EXPORT_SYMBOL(snd_pci_quirk_lookup);
#endif

View File

@ -1160,9 +1160,11 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
printk("pcm_oss: write: recovering from XRUN\n");
printk(KERN_DEBUG "pcm_oss: write: "
"recovering from XRUN\n");
else
printk("pcm_oss: write: recovering from SUSPEND\n");
printk(KERN_DEBUG "pcm_oss: write: "
"recovering from SUSPEND\n");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@ -1196,9 +1198,11 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
printk("pcm_oss: read: recovering from XRUN\n");
printk(KERN_DEBUG "pcm_oss: read: "
"recovering from XRUN\n");
else
printk("pcm_oss: read: recovering from SUSPEND\n");
printk(KERN_DEBUG "pcm_oss: read: "
"recovering from SUSPEND\n");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@ -1242,9 +1246,11 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
printk("pcm_oss: writev: recovering from XRUN\n");
printk(KERN_DEBUG "pcm_oss: writev: "
"recovering from XRUN\n");
else
printk("pcm_oss: writev: recovering from SUSPEND\n");
printk(KERN_DEBUG "pcm_oss: writev: "
"recovering from SUSPEND\n");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@ -1278,9 +1284,11 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
printk("pcm_oss: readv: recovering from XRUN\n");
printk(KERN_DEBUG "pcm_oss: readv: "
"recovering from XRUN\n");
else
printk("pcm_oss: readv: recovering from SUSPEND\n");
printk(KERN_DEBUG "pcm_oss: readv: "
"recovering from SUSPEND\n");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@ -1533,7 +1541,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
#ifdef OSS_DEBUG
printk("sync1: size = %li\n", size);
printk(KERN_DEBUG "sync1: size = %li\n", size);
#endif
while (1) {
result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
@ -1590,7 +1598,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
mutex_lock(&runtime->oss.params_lock);
if (runtime->oss.buffer_used > 0) {
#ifdef OSS_DEBUG
printk("sync: buffer_used\n");
printk(KERN_DEBUG "sync: buffer_used\n");
#endif
size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
snd_pcm_format_set_silence(format,
@ -1603,7 +1611,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
}
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
printk("sync: period_ptr\n");
printk(KERN_DEBUG "sync: period_ptr\n");
#endif
size = runtime->oss.period_bytes - runtime->oss.period_ptr;
snd_pcm_format_set_silence(format,
@ -1952,7 +1960,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
int err, cmd;
#ifdef OSS_DEBUG
printk("pcm_oss: trigger = 0x%x\n", trigger);
printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger);
#endif
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@ -2170,7 +2178,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
}
#ifdef OSS_DEBUG
printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, "
"fragstotal = %i, fragsize = %i\n",
info.bytes, info.fragments, info.fragstotal, info.fragsize);
#endif
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@ -2473,7 +2483,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (((cmd >> 8) & 0xff) != 'P')
return -EINVAL;
#ifdef OSS_DEBUG
printk("pcm_oss: ioctl = 0x%x\n", cmd);
printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd);
#endif
switch (cmd) {
case SNDCTL_DSP_RESET:
@ -2627,7 +2637,8 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
#else
{
ssize_t res = snd_pcm_oss_read1(substream, buf, count);
printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
printk(KERN_DEBUG "pcm_oss: read %li bytes "
"(returned %li bytes)\n", (long)count, (long)res);
return res;
}
#endif
@ -2646,7 +2657,8 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
substream->f_flags = file->f_flags & O_NONBLOCK;
result = snd_pcm_oss_write1(substream, buf, count);
#ifdef OSS_DEBUG
printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n",
(long)count, (long)result);
#endif
return result;
}
@ -2720,7 +2732,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
int err;
#ifdef OSS_DEBUG
printk("pcm_oss: mmap begin\n");
printk(KERN_DEBUG "pcm_oss: mmap begin\n");
#endif
pcm_oss_file = file->private_data;
switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
@ -2770,7 +2782,8 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
runtime->silence_threshold = 0;
runtime->silence_size = 0;
#ifdef OSS_DEBUG
printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n",
runtime->oss.mmap_bytes);
#endif
/* In mmap mode we never stop */
runtime->stop_threshold = runtime->boundary;

View File

@ -176,9 +176,9 @@ static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_
#endif
#ifdef PLUGIN_DEBUG
#define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
#else
#define pdprintf( fmt, args... )
#define pdprintf(fmt, args...)
#endif
#endif /* __PCM_PLUGIN_H */

View File

@ -667,7 +667,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
spin_lock_init(&substream->self_group.lock);
INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams);
spin_lock_init(&substream->timer_lock);
atomic_set(&substream->mmap_count, 0);
prev = substream;
}
@ -692,7 +691,7 @@ EXPORT_SYMBOL(snd_pcm_new_stream);
*
* Returns zero if successful, or a negative error code on failure.
*/
int snd_pcm_new(struct snd_card *card, char *id, int device,
int snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count,
struct snd_pcm ** rpcm)
{

View File

@ -125,23 +125,32 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
}
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
#define xrun_debug(substream) ((substream)->pstr->xrun_debug)
#else
#define xrun_debug(substream) 0
#endif
#define dump_stack_on_xrun(substream) do { \
if (xrun_debug(substream) > 1) \
dump_stack(); \
} while (0)
static void xrun(struct snd_pcm_substream *substream)
{
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
if (substream->pstr->xrun_debug) {
if (xrun_debug(substream)) {
snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
substream->pcm->card->number,
substream->pcm->device,
substream->stream ? 'c' : 'p');
if (substream->pstr->xrun_debug > 1)
dump_stack();
dump_stack_on_xrun(substream);
}
#endif
}
static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
static snd_pcm_uframes_t
snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t pos;
@ -150,17 +159,21 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre
pos = substream->ops->pointer(substream);
if (pos == SNDRV_PCM_POS_XRUN)
return pos; /* XRUN */
#ifdef CONFIG_SND_DEBUG
if (pos >= runtime->buffer_size) {
snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
if (printk_ratelimit()) {
snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, "
"buffer size = 0x%lx, period size = 0x%lx\n",
substream->stream, pos, runtime->buffer_size,
runtime->period_size);
}
pos = 0;
}
#endif
pos -= pos % runtime->min_align;
return pos;
}
static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t avail;
@ -182,11 +195,21 @@ static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream
return 0;
}
static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
#define hw_ptr_error(substream, fmt, args...) \
do { \
if (xrun_debug(substream)) { \
if (printk_ratelimit()) { \
snd_printd("PCM: " fmt, ##args); \
} \
dump_stack_on_xrun(substream); \
} \
} while (0)
static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
snd_pcm_sframes_t delta;
pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@ -194,36 +217,53 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs
xrun(substream);
return -EPIPE;
}
if (runtime->period_size == runtime->buffer_size)
goto __next_buf;
new_hw_ptr = runtime->hw_ptr_base + pos;
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
delta = hw_ptr_interrupt - new_hw_ptr;
if (delta > 0) {
if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
if (runtime->periods > 1 && substream->pstr->xrun_debug) {
snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
if (substream->pstr->xrun_debug > 1)
dump_stack();
}
#endif
return 0;
}
__next_buf:
runtime->hw_ptr_base += runtime->buffer_size;
if (runtime->hw_ptr_base == runtime->boundary)
runtime->hw_ptr_base = 0;
new_hw_ptr = runtime->hw_ptr_base + pos;
delta = new_hw_ptr - hw_ptr_interrupt;
if (hw_ptr_interrupt >= runtime->boundary) {
hw_ptr_interrupt -= runtime->boundary;
if (hw_base < runtime->boundary / 2)
/* hw_base was already lapped; recalc delta */
delta = new_hw_ptr - hw_ptr_interrupt;
}
if (delta < 0) {
delta += runtime->buffer_size;
if (delta < 0) {
hw_ptr_error(substream,
"Unexpected hw_pointer value "
"(stream=%i, pos=%ld, intr_ptr=%ld)\n",
substream->stream, (long)pos,
(long)hw_ptr_interrupt);
/* rebase to interrupt position */
hw_base = new_hw_ptr = hw_ptr_interrupt;
/* align hw_base to buffer_size */
hw_base -= hw_base % runtime->buffer_size;
delta = 0;
} else {
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary)
hw_base = 0;
new_hw_ptr = hw_base + pos;
}
}
if (delta > runtime->period_size) {
hw_ptr_error(substream,
"Lost interrupts? "
"(stream=%i, delta=%ld, intr_ptr=%ld)\n",
substream->stream, (long)delta,
(long)hw_ptr_interrupt);
/* rebase hw_ptr_interrupt */
hw_ptr_interrupt =
new_hw_ptr - new_hw_ptr % runtime->period_size;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
runtime->hw_ptr_interrupt = hw_ptr_interrupt;
return snd_pcm_update_hw_ptr_post(substream, runtime);
}
@ -233,7 +273,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
snd_pcm_sframes_t delta;
old_hw_ptr = runtime->status->hw_ptr;
@ -242,29 +282,38 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
xrun(substream);
return -EPIPE;
}
new_hw_ptr = runtime->hw_ptr_base + pos;
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
delta = old_hw_ptr - new_hw_ptr;
if (delta > 0) {
if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
if (runtime->periods > 2 && substream->pstr->xrun_debug) {
snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
if (substream->pstr->xrun_debug > 1)
dump_stack();
}
#endif
delta = new_hw_ptr - old_hw_ptr;
if (delta < 0) {
delta += runtime->buffer_size;
if (delta < 0) {
hw_ptr_error(substream,
"Unexpected hw_pointer value [2] "
"(stream=%i, pos=%ld, old_ptr=%ld)\n",
substream->stream, (long)pos,
(long)old_hw_ptr);
return 0;
}
runtime->hw_ptr_base += runtime->buffer_size;
if (runtime->hw_ptr_base == runtime->boundary)
runtime->hw_ptr_base = 0;
new_hw_ptr = runtime->hw_ptr_base + pos;
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary)
hw_base = 0;
new_hw_ptr = hw_base + pos;
}
if (delta > runtime->period_size && runtime->periods > 1) {
hw_ptr_error(substream,
"hw_ptr skipping! "
"(pos=%ld, delta=%ld, period=%ld)\n",
(long)pos, (long)delta,
(long)runtime->period_size);
return 0;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
return snd_pcm_update_hw_ptr_post(substream, runtime);

View File

@ -186,7 +186,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
printk("%s = ", snd_pcm_hw_param_names[k]);
printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
changed = snd_mask_refine(m, constrs_mask(constrs, k));
@ -206,7 +206,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
printk("%s = ", snd_pcm_hw_param_names[k]);
printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
if (i->empty)
printk("empty");
else
@ -251,7 +251,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!doit)
continue;
#ifdef RULES_DEBUG
printk("Rule %d [%p]: ", k, r->func);
printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
if (r->var >= 0) {
printk("%s = ", snd_pcm_hw_param_names[r->var]);
if (hw_is_mask(r->var)) {

View File

@ -85,25 +85,19 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
static int snd_pcm_timer_start(struct snd_timer * timer)
{
unsigned long flags;
struct snd_pcm_substream *substream;
substream = snd_timer_chip(timer);
spin_lock_irqsave(&substream->timer_lock, flags);
substream->timer_running = 1;
spin_unlock_irqrestore(&substream->timer_lock, flags);
return 0;
}
static int snd_pcm_timer_stop(struct snd_timer * timer)
{
unsigned long flags;
struct snd_pcm_substream *substream;
substream = snd_timer_chip(timer);
spin_lock_irqsave(&substream->timer_lock, flags);
substream->timer_running = 0;
spin_unlock_irqrestore(&substream->timer_lock, flags);
return 0;
}

View File

@ -224,156 +224,143 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
return 0;
}
/* look for an available substream for the given stream direction;
* if a specific subdevice is given, try to assign it
*/
static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
int stream, int mode,
struct snd_rawmidi_substream **sub_ret)
{
struct snd_rawmidi_substream *substream;
struct snd_rawmidi_str *s = &rmidi->streams[stream];
static unsigned int info_flags[2] = {
[SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT,
[SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT,
};
if (!(rmidi->info_flags & info_flags[stream]))
return -ENXIO;
if (subdevice >= 0 && subdevice >= s->substream_count)
return -ENODEV;
if (s->substream_opened >= s->substream_count)
return -EAGAIN;
list_for_each_entry(substream, &s->substreams, list) {
if (substream->opened) {
if (stream == SNDRV_RAWMIDI_STREAM_INPUT ||
!(mode & SNDRV_RAWMIDI_LFLG_APPEND))
continue;
}
if (subdevice < 0 || subdevice == substream->number) {
*sub_ret = substream;
return 0;
}
}
return -EAGAIN;
}
/* open and do ref-counting for the given substream */
static int open_substream(struct snd_rawmidi *rmidi,
struct snd_rawmidi_substream *substream,
int mode)
{
int err;
err = snd_rawmidi_runtime_create(substream);
if (err < 0)
return err;
err = substream->ops->open(substream);
if (err < 0)
return err;
substream->opened = 1;
if (substream->use_count++ == 0)
substream->active_sensing = 1;
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
substream->append = 1;
rmidi->streams[substream->stream].substream_opened++;
return 0;
}
static void close_substream(struct snd_rawmidi *rmidi,
struct snd_rawmidi_substream *substream,
int cleanup);
static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
struct snd_rawmidi_file *rfile)
{
struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL;
int err;
rfile->input = rfile->output = NULL;
if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
err = assign_substream(rmidi, subdevice,
SNDRV_RAWMIDI_STREAM_INPUT,
mode, &sinput);
if (err < 0)
goto __error;
}
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
err = assign_substream(rmidi, subdevice,
SNDRV_RAWMIDI_STREAM_OUTPUT,
mode, &soutput);
if (err < 0)
goto __error;
}
if (sinput) {
err = open_substream(rmidi, sinput, mode);
if (err < 0)
goto __error;
}
if (soutput) {
err = open_substream(rmidi, soutput, mode);
if (err < 0) {
if (sinput)
close_substream(rmidi, sinput, 0);
goto __error;
}
}
rfile->rmidi = rmidi;
rfile->input = sinput;
rfile->output = soutput;
return 0;
__error:
if (sinput && sinput->runtime)
snd_rawmidi_runtime_free(sinput);
if (soutput && soutput->runtime)
snd_rawmidi_runtime_free(soutput);
return err;
}
/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
int mode, struct snd_rawmidi_file * rfile)
{
struct snd_rawmidi *rmidi;
struct list_head *list1, *list2;
struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL;
struct snd_rawmidi_runtime *input = NULL, *output = NULL;
int err;
if (rfile)
rfile->input = rfile->output = NULL;
if (snd_BUG_ON(!rfile))
return -EINVAL;
mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, device);
mutex_unlock(&register_mutex);
if (rmidi == NULL) {
err = -ENODEV;
goto __error1;
mutex_unlock(&register_mutex);
return -ENODEV;
}
if (!try_module_get(rmidi->card->module)) {
err = -EFAULT;
goto __error1;
mutex_unlock(&register_mutex);
return -ENXIO;
}
if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
mutex_lock(&rmidi->open_mutex);
if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
err = -ENXIO;
goto __error;
}
if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
err = -ENODEV;
goto __error;
}
if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >=
rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
err = -EAGAIN;
goto __error;
}
}
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) {
err = -ENXIO;
goto __error;
}
if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
err = -ENODEV;
goto __error;
}
if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >=
rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
err = -EAGAIN;
goto __error;
}
}
list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next;
while (1) {
if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
sinput = NULL;
if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
err = -EAGAIN;
goto __error;
}
break;
}
sinput = list_entry(list1, struct snd_rawmidi_substream, list);
if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened)
goto __nexti;
if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number))
break;
__nexti:
list1 = list1->next;
}
list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next;
while (1) {
if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
soutput = NULL;
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
err = -EAGAIN;
goto __error;
}
break;
}
soutput = list_entry(list2, struct snd_rawmidi_substream, list);
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
if (mode & SNDRV_RAWMIDI_LFLG_APPEND) {
if (soutput->opened && !soutput->append)
goto __nexto;
} else {
if (soutput->opened)
goto __nexto;
}
}
if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number))
break;
__nexto:
list2 = list2->next;
}
if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
if ((err = snd_rawmidi_runtime_create(sinput)) < 0)
goto __error;
input = sinput->runtime;
if ((err = sinput->ops->open(sinput)) < 0)
goto __error;
sinput->opened = 1;
rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++;
} else {
sinput = NULL;
}
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
if (soutput->opened)
goto __skip_output;
if ((err = snd_rawmidi_runtime_create(soutput)) < 0) {
if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
sinput->ops->close(sinput);
goto __error;
}
output = soutput->runtime;
if ((err = soutput->ops->open(soutput)) < 0) {
if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
sinput->ops->close(sinput);
goto __error;
}
__skip_output:
soutput->opened = 1;
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
soutput->append = 1;
if (soutput->use_count++ == 0)
soutput->active_sensing = 1;
rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++;
} else {
soutput = NULL;
}
if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
mutex_unlock(&rmidi->open_mutex);
if (rfile) {
rfile->rmidi = rmidi;
rfile->input = sinput;
rfile->output = soutput;
}
return 0;
mutex_unlock(&register_mutex);
__error:
if (input != NULL)
snd_rawmidi_runtime_free(sinput);
if (output != NULL)
snd_rawmidi_runtime_free(soutput);
module_put(rmidi->card->module);
if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
mutex_unlock(&rmidi->open_mutex);
__error1:
mutex_lock(&rmidi->open_mutex);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
mutex_unlock(&rmidi->open_mutex);
if (err < 0)
module_put(rmidi->card->module);
return err;
}
@ -385,10 +372,13 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
unsigned short fflags;
int err;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_file *rawmidi_file;
struct snd_rawmidi_file *rawmidi_file = NULL;
wait_queue_t wait;
struct snd_ctl_file *kctl;
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
if (maj == snd_major) {
rmidi = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_RAWMIDI);
@ -402,24 +392,25 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if (rmidi == NULL)
return -ENODEV;
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
if (!try_module_get(rmidi->card->module))
return -ENXIO;
mutex_lock(&rmidi->open_mutex);
card = rmidi->card;
err = snd_card_file_add(card, file);
if (err < 0)
return -ENODEV;
goto __error_card;
fflags = snd_rawmidi_file_flags(file);
if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */
fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
if (rawmidi_file == NULL) {
snd_card_file_remove(card, file);
return -ENOMEM;
err = -ENOMEM;
goto __error;
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&rmidi->open_wait, &wait);
mutex_lock(&rmidi->open_mutex);
while (1) {
subdevice = -1;
read_lock(&card->ctl_files_rwlock);
@ -431,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
}
}
read_unlock(&card->ctl_files_rwlock);
err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device,
subdevice, fflags, rawmidi_file);
err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
if (err >= 0)
break;
if (err == -EAGAIN) {
@ -451,67 +441,89 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
break;
}
}
remove_wait_queue(&rmidi->open_wait, &wait);
if (err < 0) {
kfree(rawmidi_file);
goto __error;
}
#ifdef CONFIG_SND_OSSEMUL
if (rawmidi_file->input && rawmidi_file->input->runtime)
rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);
if (rawmidi_file->output && rawmidi_file->output->runtime)
rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
#endif
remove_wait_queue(&rmidi->open_wait, &wait);
if (err >= 0) {
file->private_data = rawmidi_file;
} else {
snd_card_file_remove(card, file);
kfree(rawmidi_file);
}
file->private_data = rawmidi_file;
mutex_unlock(&rmidi->open_mutex);
return 0;
__error:
snd_card_file_remove(card, file);
__error_card:
mutex_unlock(&rmidi->open_mutex);
module_put(rmidi->card->module);
return err;
}
int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile)
static void close_substream(struct snd_rawmidi *rmidi,
struct snd_rawmidi_substream *substream,
int cleanup)
{
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *substream;
struct snd_rawmidi_runtime *runtime;
rmidi->streams[substream->stream].substream_opened--;
if (--substream->use_count)
return;
if (snd_BUG_ON(!rfile))
return -ENXIO;
rmidi = rfile->rmidi;
mutex_lock(&rmidi->open_mutex);
if (rfile->input != NULL) {
substream = rfile->input;
rfile->input = NULL;
runtime = substream->runtime;
snd_rawmidi_input_trigger(substream, 0);
substream->ops->close(substream);
if (runtime->private_free != NULL)
runtime->private_free(substream);
snd_rawmidi_runtime_free(substream);
substream->opened = 0;
rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;
}
if (rfile->output != NULL) {
substream = rfile->output;
rfile->output = NULL;
if (--substream->use_count == 0) {
runtime = substream->runtime;
if (cleanup) {
if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
snd_rawmidi_input_trigger(substream, 0);
else {
if (substream->active_sensing) {
unsigned char buf = 0xfe;
/* sending single active sensing message to shut the device up */
/* sending single active sensing message
* to shut the device up
*/
snd_rawmidi_kernel_write(substream, &buf, 1);
}
if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
snd_rawmidi_output_trigger(substream, 0);
substream->ops->close(substream);
if (runtime->private_free != NULL)
runtime->private_free(substream);
snd_rawmidi_runtime_free(substream);
substream->opened = 0;
substream->append = 0;
}
rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
}
substream->ops->close(substream);
if (substream->runtime->private_free)
substream->runtime->private_free(substream);
snd_rawmidi_runtime_free(substream);
substream->opened = 0;
substream->append = 0;
}
static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
{
struct snd_rawmidi *rmidi;
rmidi = rfile->rmidi;
mutex_lock(&rmidi->open_mutex);
if (rfile->input) {
close_substream(rmidi, rfile->input, 1);
rfile->input = NULL;
}
if (rfile->output) {
close_substream(rmidi, rfile->output, 1);
rfile->output = NULL;
}
rfile->rmidi = NULL;
mutex_unlock(&rmidi->open_mutex);
wake_up(&rmidi->open_wait);
}
/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
{
struct snd_rawmidi *rmidi;
if (snd_BUG_ON(!rfile))
return -ENXIO;
rmidi = rfile->rmidi;
rawmidi_release_priv(rfile);
module_put(rmidi->card->module);
return 0;
}
@ -520,15 +532,14 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file)
{
struct snd_rawmidi_file *rfile;
struct snd_rawmidi *rmidi;
int err;
rfile = file->private_data;
err = snd_rawmidi_kernel_release(rfile);
rmidi = rfile->rmidi;
wake_up(&rmidi->open_wait);
rawmidi_release_priv(rfile);
kfree(rfile);
snd_card_file_remove(rmidi->card, file);
return err;
module_put(rmidi->card->module);
return 0;
}
static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,

View File

@ -181,7 +181,7 @@ char *enabled_str(int bool);
/* for debug */
#ifdef SNDRV_SEQ_OSS_DEBUG
extern int seq_oss_debug;
#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printk x; } while (0)
#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printd x; } while (0)
#else
#define debug_printk(x) /**/
#endif

View File

@ -321,7 +321,8 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
freeprev = cell;
} else {
#if 0
printk("type = %i, source = %i, dest = %i, client = %i\n",
printk(KERN_DEBUG "type = %i, source = %i, dest = %i, "
"client = %i\n",
cell->event.type,
cell->event.source.client,
cell->event.dest.client,

View File

@ -50,18 +50,38 @@ struct link_slave {
struct link_master *master;
struct link_ctl_info info;
int vals[2]; /* current values */
unsigned int flags;
struct snd_kcontrol slave; /* the copy of original control entry */
};
static int slave_update(struct link_slave *slave)
{
struct snd_ctl_elem_value *uctl;
int err, ch;
uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
if (!uctl)
return -ENOMEM;
uctl->id = slave->slave.id;
err = slave->slave.get(&slave->slave, uctl);
for (ch = 0; ch < slave->info.count; ch++)
slave->vals[ch] = uctl->value.integer.value[ch];
kfree(uctl);
return 0;
}
/* get the slave ctl info and save the initial values */
static int slave_init(struct link_slave *slave)
{
struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl;
int err, ch;
int err;
if (slave->info.count)
return 0; /* already initialized */
if (slave->info.count) {
/* already initialized */
if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
return slave_update(slave);
return 0;
}
uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
if (!uinfo)
@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave)
slave->info.max_val = uinfo->value.integer.max;
kfree(uinfo);
uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
if (!uctl)
return -ENOMEM;
uctl->id = slave->slave.id;
err = slave->slave.get(&slave->slave, uctl);
for (ch = 0; ch < slave->info.count; ch++)
slave->vals[ch] = uctl->value.integer.value[ch];
kfree(uctl);
return 0;
return slave_update(slave);
}
/* initialize master volume */
@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol)
* - logarithmic volume control (dB level), no linear volume
* - master can only attenuate the volume, no gain
*/
int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
unsigned int flags)
{
struct link_master *master_link = snd_kcontrol_chip(master);
struct link_slave *srec;
@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
srec->slave = *slave;
memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
srec->master = master_link;
srec->flags = flags;
/* override callbacks */
slave->info = slave_info;
@ -254,8 +268,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
list_add_tail(&srec->list, &master_link->slaves);
return 0;
}
EXPORT_SYMBOL(snd_ctl_add_slave);
EXPORT_SYMBOL(_snd_ctl_add_slave);
/*
* ctl callbacks for master controls
@ -327,8 +340,20 @@ static void master_free(struct snd_kcontrol *kcontrol)
}
/*
* Create a virtual master control with the given name
/**
* snd_ctl_make_virtual_master - Create a virtual master control
* @name: name string of the control element to create
* @tlv: optional TLV int array for dB information
*
* Creates a virtual matster control with the given name string.
* Returns the created control element, or NULL for errors (ENOMEM).
*
* After creating a vmaster element, you can add the slave controls
* via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
*
* The optional argument @tlv can be used to specify the TLV information
* for dB scale of the master control. It should be a single element
* with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB.
*/
struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
const unsigned int *tlv)
@ -367,5 +392,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
return kctl;
}
EXPORT_SYMBOL(snd_ctl_make_virtual_master);

View File

@ -588,10 +588,10 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
card = snd_card_new(index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_dummy));
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_dummy), &card);
if (err < 0)
return err;
dummy = card->private_data;
dummy->card = card;
for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {

View File

@ -1279,9 +1279,9 @@ static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev)
if (!enable[dev])
return -ENOENT;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
if (err < 0) {
PDEBUG(INIT_FAILURE, "probe(): create failed!\n");

View File

@ -73,9 +73,9 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard)
snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
*rcard = NULL;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
return err;
strcpy(card->driver, "MPU-401 UART");
strcpy(card->shortname, card->driver);
sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);

View File

@ -303,8 +303,10 @@ static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
snd_mtpav_send_byte(mtp_card, 0xf5);
snd_mtpav_send_byte(mtp_card, portp->hwport);
//snd_printk("new outport: 0x%x\n", (unsigned int) portp->hwport);
/*
snd_printk(KERN_DEBUG "new outport: 0x%x\n",
(unsigned int) portp->hwport);
*/
if (!(outbyte & 0x80) && portp->running_status)
snd_mtpav_send_byte(mtp_card, portp->running_status);
}
@ -540,7 +542,7 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd)
u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
//printk("snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt);
/* printk(KERN_DEBUG "snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt); */
if (!(sbyt & SIGS_BYTE))
return;
@ -585,12 +587,12 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard)
{
if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) {
snd_printk("MTVAP port 0x%lx is busy\n", port);
snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
return -EBUSY;
}
mcard->port = port;
if (request_irq(irq, snd_mtpav_irqh, IRQF_DISABLED, "MOTU MTPAV", mcard)) {
snd_printk("MTVAP IRQ %d busy\n", irq);
snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
return -EBUSY;
}
mcard->irq = irq;
@ -696,9 +698,9 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
int err;
struct mtpav *mtp_card;
card = snd_card_new(index, id, THIS_MODULE, sizeof(*mtp_card));
if (! card)
return -ENOMEM;
err = snd_card_create(index, id, THIS_MODULE, sizeof(*mtp_card), &card);
if (err < 0)
return err;
mtp_card = card->private_data;
spin_lock_init(&mtp_card->spinlock);

View File

@ -957,10 +957,10 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
if ((err = snd_mts64_probe_port(p)) < 0)
return err;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL) {
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0) {
snd_printd("Cannot create card\n");
return -ENOMEM;
return err;
}
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, "ESI " CARD_NAME);
@ -1015,7 +1015,7 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
goto __err;
}
snd_printk("ESI Miditerminal 4140 on 0x%lx\n", p->base);
snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n", p->base);
return 0;
__err:

View File

@ -302,7 +302,7 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
opl3 = hw->private_data;
status = inb(opl3->l_port);
#if 0
snd_printk("AdLib IRQ status = 0x%x\n", status);
snd_printk(KERN_DEBUG "AdLib IRQ status = 0x%x\n", status);
#endif
if (!(status & 0x80))
return;

View File

@ -125,7 +125,7 @@ static void debug_alloc(struct snd_opl3 *opl3, char *s, int voice) {
int i;
char *str = "x.24";
printk("time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
printk(KERN_DEBUG "time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
for (i = 0; i < opl3->max_voices; i++)
printk("%c", *(str + opl3->voices[i].state + 1));
printk("\n");
@ -218,7 +218,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
for (i = 0; i < END; i++) {
if (best[i].voice >= 0) {
#ifdef DEBUG_ALLOC
printk("%s %iop allocation on voice %i\n",
printk(KERN_DEBUG "%s %iop allocation on voice %i\n",
alloc_type[i], instr_4op ? 4 : 2,
best[i].voice);
#endif
@ -317,7 +317,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
snd_printk(KERN_DEBUG "Note on, ch %i, inst %i, note %i, vel %i\n",
chan->number, chan->midi_program, note, vel);
#endif
@ -372,7 +372,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
return;
}
#ifdef DEBUG_MIDI
snd_printk(" --> OPL%i instrument: %s\n",
snd_printk(KERN_DEBUG " --> OPL%i instrument: %s\n",
instr_4op ? 3 : 2, patch->name);
#endif
/* in SYNTH mode, application takes care of voices */
@ -431,7 +431,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
}
#ifdef DEBUG_MIDI
snd_printk(" --> setting OPL3 connection: 0x%x\n",
snd_printk(KERN_DEBUG " --> setting OPL3 connection: 0x%x\n",
opl3->connection_reg);
#endif
/*
@ -466,7 +466,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
/* Program the FM voice characteristics */
for (i = 0; i < (instr_4op ? 4 : 2); i++) {
#ifdef DEBUG_MIDI
snd_printk(" --> programming operator %i\n", i);
snd_printk(KERN_DEBUG " --> programming operator %i\n", i);
#endif
op_offset = snd_opl3_regmap[voice_offset][i];
@ -546,7 +546,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
blocknum |= OPL3_KEYON_BIT;
#ifdef DEBUG_MIDI
snd_printk(" --> trigger voice %i\n", voice);
snd_printk(KERN_DEBUG " --> trigger voice %i\n", voice);
#endif
/* Set OPL3 KEYON_BLOCK register of requested voice */
opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
@ -602,7 +602,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
prg = extra_prg - 1;
}
#ifdef DEBUG_MIDI
snd_printk(" *** allocating extra program\n");
snd_printk(KERN_DEBUG " *** allocating extra program\n");
#endif
goto __extra_prg;
}
@ -633,7 +633,7 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
/* kill voice */
#ifdef DEBUG_MIDI
snd_printk(" --> kill voice %i\n", voice);
snd_printk(KERN_DEBUG " --> kill voice %i\n", voice);
#endif
opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
/* clear Key ON bit */
@ -670,7 +670,7 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("Note off, ch %i, inst %i, note %i\n",
snd_printk(KERN_DEBUG "Note off, ch %i, inst %i, note %i\n",
chan->number, chan->midi_program, note);
#endif
@ -709,7 +709,7 @@ void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *cha
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("Key pressure, ch#: %i, inst#: %i\n",
snd_printk(KERN_DEBUG "Key pressure, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
#endif
}
@ -723,7 +723,7 @@ void snd_opl3_terminate_note(void *p, int note, struct snd_midi_channel *chan)
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("Terminate note, ch#: %i, inst#: %i\n",
snd_printk(KERN_DEBUG "Terminate note, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
#endif
}
@ -812,7 +812,7 @@ void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan)
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n",
snd_printk(KERN_DEBUG "Controller, TYPE = %i, ch#: %i, inst#: %i\n",
type, chan->number, chan->midi_program);
#endif
@ -849,7 +849,7 @@ void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("NRPN, ch#: %i, inst#: %i\n",
snd_printk(KERN_DEBUG "NRPN, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
#endif
}
@ -864,6 +864,6 @@ void snd_opl3_sysex(void *p, unsigned char *buf, int len,
opl3 = p;
#ifdef DEBUG_MIDI
snd_printk("SYSEX\n");
snd_printk(KERN_DEBUG "SYSEX\n");
#endif
}

View File

@ -220,14 +220,14 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
return -EINVAL;
if (count < (int)sizeof(sbi)) {
snd_printk("FM Error: Patch record too short\n");
snd_printk(KERN_ERR "FM Error: Patch record too short\n");
return -EINVAL;
}
if (copy_from_user(&sbi, buf, sizeof(sbi)))
return -EFAULT;
if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
snd_printk("FM Error: Invalid instrument number %d\n",
snd_printk(KERN_ERR "FM Error: Invalid instrument number %d\n",
sbi.channel);
return -EINVAL;
}
@ -254,7 +254,9 @@ static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
opl3 = arg->private_data;
switch (cmd) {
case SNDCTL_FM_LOAD_INSTR:
snd_printk("OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
snd_printk(KERN_ERR "OPL3: "
"Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. "
"Fix the program.\n");
return -EINVAL;
case SNDCTL_SYNTH_MEMAVL:

View File

@ -168,7 +168,7 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
#ifdef CONFIG_SND_DEBUG
default:
snd_printk("unknown IOCTL: 0x%x\n", cmd);
snd_printk(KERN_WARNING "unknown IOCTL: 0x%x\n", cmd);
#endif
}
return -ENOTTY;

View File

@ -57,7 +57,7 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
else
min_div = MAX_DIV;
#if PCSP_DEBUG
printk("PCSP: lpj=%li, min_div=%i, res=%li\n",
printk(KERN_DEBUG "PCSP: lpj=%li, min_div=%i, res=%li\n",
loops_per_jiffy, min_div, tp.tv_nsec);
#endif
@ -98,9 +98,9 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pcsp_chip.timer.function = pcsp_do_timer;
card = snd_card_new(index, id, THIS_MODULE, 0);
if (!card)
return -ENOMEM;
err = snd_card_create(index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcsp_create(card);
if (err < 0) {

View File

@ -746,10 +746,10 @@ static int __devinit snd_portman_probe(struct platform_device *pdev)
if ((err = snd_portman_probe_port(p)) < 0)
return err;
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL) {
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0) {
snd_printd("Cannot create card\n");
return -ENOMEM;
return err;
}
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, CARD_NAME);

View File

@ -241,7 +241,8 @@ static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
if (status & UART_LSR_OE)
snd_printk("%s: Overrun on device at 0x%lx\n",
snd_printk(KERN_WARNING
"%s: Overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
}
@ -636,7 +637,8 @@ static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
}
} else {
if (!snd_uart16550_write_buffer(uart, midi_byte)) {
snd_printk("%s: Buffer overrun on device at 0x%lx\n",
snd_printk(KERN_WARNING
"%s: Buffer overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
return 0;
}
@ -815,7 +817,8 @@ static int __devinit 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", uart)) {
snd_printk("irq %d busy. Using Polling.\n", irq);
snd_printk(KERN_WARNING
"irq %d busy. Using Polling.\n", irq);
} else {
uart->irq = irq;
}
@ -919,26 +922,29 @@ static int __devinit snd_serial_probe(struct platform_device *devptr)
case SNDRV_SERIAL_GENERIC:
break;
default:
snd_printk("Adaptor type is out of range 0-%d (%d)\n",
snd_printk(KERN_ERR
"Adaptor type is out of range 0-%d (%d)\n",
SNDRV_SERIAL_MAX_ADAPTOR, adaptor[dev]);
return -ENODEV;
}
if (outs[dev] < 1 || outs[dev] > SNDRV_SERIAL_MAX_OUTS) {
snd_printk("Count of outputs is out of range 1-%d (%d)\n",
snd_printk(KERN_ERR
"Count of outputs is out of range 1-%d (%d)\n",
SNDRV_SERIAL_MAX_OUTS, outs[dev]);
return -ENODEV;
}
if (ins[dev] < 1 || ins[dev] > SNDRV_SERIAL_MAX_INS) {
snd_printk("Count of inputs is out of range 1-%d (%d)\n",
snd_printk(KERN_ERR
"Count of inputs is out of range 1-%d (%d)\n",
SNDRV_SERIAL_MAX_INS, ins[dev]);
return -ENODEV;
}
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
return err;
strcpy(card->driver, "Serial");
strcpy(card->shortname, "Serial MIDI (UART16550A)");

View File

@ -90,15 +90,17 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
card = snd_card_new(index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_card_virmidi));
if (card == NULL)
return -ENOMEM;
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_card_virmidi), &card);
if (err < 0)
return err;
vmidi = (struct snd_card_virmidi *)card->private_data;
vmidi->card = card;
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
snd_printk("too much midi devices for virmidi %d: force to use %d\n", dev, MAX_MIDI_DEVICES);
snd_printk(KERN_WARNING
"too much midi devices for virmidi %d: "
"force to use %d\n", dev, MAX_MIDI_DEVICES);
midi_devs[dev] = MAX_MIDI_DEVICES;
}
for (idx = 0; idx < midi_devs[dev]; idx++) {

View File

@ -688,7 +688,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
image = dsp->data + i;
/* Wait DSP ready for a new read */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
printk("dsp loading error at position %d\n", i);
printk(KERN_ERR
"dsp loading error at position %d\n", i);
return err;
}
cptr = image;

View File

@ -119,16 +119,6 @@ void snd_vx_free_firmware(struct vx_core *chip)
#else /* old style firmware loading */
static int vx_hwdep_open(struct snd_hwdep *hw, struct file *file)
{
return 0;
}
static int vx_hwdep_release(struct snd_hwdep *hw, struct file *file)
{
return 0;
}
static int vx_hwdep_dsp_status(struct snd_hwdep *hw,
struct snd_hwdep_dsp_status *info)
{
@ -243,8 +233,6 @@ int snd_vx_setup_firmware(struct vx_core *chip)
hw->iface = SNDRV_HWDEP_IFACE_VX;
hw->private_data = chip;
hw->ops.open = vx_hwdep_open;
hw->ops.release = vx_hwdep_release;
hw->ops.dsp_status = vx_hwdep_dsp_status;
hw->ops.dsp_load = vx_hwdep_dsp_load;
hw->exclusive = 1;

View File

@ -103,7 +103,7 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
* returns the frequency of UER, or 0 if not sync,
* or a negative error code.
*/
static int vx_read_uer_status(struct vx_core *chip, int *mode)
static int vx_read_uer_status(struct vx_core *chip, unsigned int *mode)
{
int val, freq;

View File

@ -7,8 +7,6 @@ snd-i2c-objs := i2c.o
snd-cs8427-objs := cs8427.o
snd-tea6330t-objs := tea6330t.o
obj-$(CONFIG_L3) += l3/
obj-$(CONFIG_SND) += other/
# Toplevel Module Dependency

View File

@ -1,8 +0,0 @@
#
# Makefile for ALSA
#
snd-uda1341-objs := uda1341.o
# Module Dependency
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-uda1341.o

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