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:
Коммит
502012534d
|
@ -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):
|
||||
|
|
|
@ -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
|
|
@ -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->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;
|
||||
....
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
~~~~~~~~
|
||||
|
|
|
@ -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
|
||||
-----------------------------------
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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) { \
|
||||
|
|
|
@ -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)
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@
|
|||
/*
|
||||
* R231 (0xE7) - Jack Status
|
||||
*/
|
||||
#define WM8350_JACK_L_LVL 0x0800
|
||||
#define WM8350_JACK_R_LVL 0x0400
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -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 ""
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -60,6 +60,8 @@ source "sound/aoa/Kconfig"
|
|||
|
||||
source "sound/arm/Kconfig"
|
||||
|
||||
source "sound/atmel/Kconfig"
|
||||
|
||||
source "sound/spi/Kconfig"
|
||||
|
||||
source "sound/mips/Kconfig"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -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
|
|
@ -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
|
|
@ -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>");
|
|
@ -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>");
|
|
@ -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 */
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(®ister_mutex);
|
||||
rmidi = snd_rawmidi_search(card, device);
|
||||
mutex_unlock(®ister_mutex);
|
||||
if (rmidi == NULL) {
|
||||
err = -ENODEV;
|
||||
goto __error1;
|
||||
mutex_unlock(®ister_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!try_module_get(rmidi->card->module)) {
|
||||
err = -EFAULT;
|
||||
goto __error1;
|
||||
mutex_unlock(®ister_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(®ister_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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)");
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#
|
||||
# Makefile for ALSA
|
||||
#
|
||||
|
||||
snd-uda1341-objs := uda1341.o
|
||||
|
||||
# Module Dependency
|
||||
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-uda1341.o
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче