mirror of https://gitee.com/openkylin/linux.git
sound updates for 4.20
There have been little changes in ALSA core stuff, but ASoC core still kept rolling for the continued restructuring. The rest are lots of small driver-specific changes and some minor API updates. Here are highlights: General: - Appropriate fall-through annotations everywhere - Some code cleanup in memalloc code, handling non-cacahed pages more commonly in the helper - Deployment of SNDRV_PCM_INFO_SYNC_APPLPTR flag consistently Drivers: - More HD-audio CA0132 codec improvement for supporting other Creative boards - Plumbing legacy HD-audio codecs as ASoC BE on Intel SST; this will give move support of existing HD-audio devices with DSP - A few device-specific HD-audio quirks as usual - New quirk for RME CC devices and correction for B&W PX for USB-audio - FireWire: code refactoring including devres usages ASoC Core: - Continued componentization works; it's almost done! - A bunch of new for_each_foo macros - Cleanups and fixes in DAPM code ASoC Drivers: - MCLK support for several different devices, including CS42L51, STM32 SAI, and MAX98373 - Support for Allwinner A64 CODEC analog, Intel boards with DA7219 and MAX98927, Meson AXG PDM inputs, Nuvoton NAU8822, Renesas R8A7744 and TI PCM3060 -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAlvRbLkOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE9FMg//eGuq13WyoNn4OrgncGdxP4U+Dd3qXj7h6wmo af8ZebRSZht5jswJz5TEmYM5zR8jfKfDCN6bDKIV99Ondp9bN1vEqxBa2mUx9T/C mhY17dPJX0Fwdk951TkAANfOvIqECjqWj9qMI4QdigfVqVXaIxdPSnA4tKDtq6++ Ocr4+GtC01Nmd/jWzpC4fDh9k+mwTAG0VZjeLFCjsv61U9DKbic+UcRni7YTvRGg pUXWNNUxIa6FMYEpsHClBJkCCUi4+ZT9nQe7Dy/W4lMq0uVBrPBqDYQJKDdjwf4p VEptmlhEpMcY/bG1yW7l5YOHgYs8Cx5YYygBag+3YCE6a6KItuxNp9UbgxGqZ7GD Svh4vPn8n4+UZfMbS04IlYvJP8bTiIfHRLkUBSHgC2egco0TjDEZiH71ucxFOq9q 3cVKlSfLvcSMCAnUiDP18EfBq6ayGJmzJsFzU1RZLW/r+RcuMzPuwAbCuC83mlI4 bobNLXCyEArJlvQyrAAIXrX/j4GhFzheL26hXQ96tQ9Y/nNX9tE/cL8bWtm45i4s +EuPnWosfZbo5JtPASosEQhilVrrOK/VmqAA6xHURKxspdqwIVyOvAa6kPLRJx8T LvczeX9pK3PwvZhDU+eg+HpcPNSWH8BtPvShutsNd0lp9UGBFeBUB5gc4s0iYqLq rMnbzwg= =3LrT -----END PGP SIGNATURE----- Merge tag 'sound-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "There have been little changes in ALSA core stuff, but ASoC core still kept rolling for the continued restructuring. The rest are lots of small driver-specific changes and some minor API updates. Here are highlights: General: - Appropriate fall-through annotations everywhere - Some code cleanup in memalloc code, handling non-cacahed pages more commonly in the helper - Deployment of SNDRV_PCM_INFO_SYNC_APPLPTR flag consistently Drivers: - More HD-audio CA0132 codec improvement for supporting other Creative boards - Plumbing legacy HD-audio codecs as ASoC BE on Intel SST; this will give move support of existing HD-audio devices with DSP - A few device-specific HD-audio quirks as usual - New quirk for RME CC devices and correction for B&W PX for USB-audio - FireWire: code refactoring including devres usages ASoC Core: - Continued componentization works; it's almost done! - A bunch of new for_each_foo macros - Cleanups and fixes in DAPM code ASoC Drivers: - MCLK support for several different devices, including CS42L51, STM32 SAI, and MAX98373 - Support for Allwinner A64 CODEC analog, Intel boards with DA7219 and MAX98927, Meson AXG PDM inputs, Nuvoton NAU8822, Renesas R8A7744 and TI PCM3060" * tag 'sound-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (299 commits) ASoC: stm32: sai: fix master clock naming ASoC: stm32: add clock dependency for sai ALSA: hda/ca0132 - Actually fix microphone issue ASoC: sun4i-i2s: move code from startup/shutdown hooks into pm_runtime hooks ASoC: wm2000: Remove wm2000_read helper function ASoC: cs42l51: fix mclk support ASoC: wm_adsp: Log addresses as 8 digits in wm_adsp_buffer_populate ASoC: wm_adsp: Rename memory fields in wm_adsp_buffer ASoC: cs42l51: add mclk support ASoC: stm32: sai: set sai as mclk clock provider ASoC: dt-bindings: add mclk support to cs42l51 ASoC: dt-bindings: add mclk provider support to stm32 sai ASoC: soc-core: fix trivial checkpatch issues ASoC: dapm: Add support for hw_free on CODEC to CODEC links ASoC: Intel: kbl_da7219_max98927: minor white space clean up ALSA: i2c/cs8427: Fix int to char conversion ALSA: doc: Brush up the old writing-an-alsa-driver ASoC: rsnd: tidyup SSICR::SWSP for TDM ASoC: rsnd: enable TDM settings for SSI parent ASoC: pcm3168a: add hw constraint for capture channel ...
This commit is contained in:
commit
3acbd2de6b
|
@ -0,0 +1,54 @@
|
|||
Analog Devices ADAU1977/ADAU1978/ADAU1979
|
||||
|
||||
Datasheets:
|
||||
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf
|
||||
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf
|
||||
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf
|
||||
|
||||
This driver supports both the I2C and SPI bus.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following:
|
||||
"adi,adau1977"
|
||||
"adi,adau1978"
|
||||
"adi,adau1979"
|
||||
|
||||
- AVDD-supply: analog power supply for the device, please consult
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Optional properties:
|
||||
- reset-gpio: the reset pin for the chip, for more details consult
|
||||
Documentation/devicetree/bindings/gpio/gpio.txt
|
||||
|
||||
- DVDD-supply: supply voltage for the digital core, please consult
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
For required properties on SPI, please consult
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Required properties on I2C:
|
||||
|
||||
- reg: The i2c address. Value depends on the state of ADDR0
|
||||
and ADDR1, as wired in hardware.
|
||||
|
||||
Examples:
|
||||
|
||||
adau1977_spi: adau1977@0 {
|
||||
compatible = "adi,adau1977";
|
||||
spi-max-frequency = <600000>;
|
||||
|
||||
AVDD-supply = <®ulator>;
|
||||
DVDD-supply = <®ulator_digital>;
|
||||
|
||||
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
adau1977_i2c: adau1977@11 {
|
||||
compatible = "adi,adau1977";
|
||||
reg = <0x11>;
|
||||
|
||||
AVDD-supply = <®ulator>;
|
||||
DVDD-supply = <®ulator_digital>;
|
||||
|
||||
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
* Amlogic Audio PDM input
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-pdm'
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
- clock-names: should contain the following:
|
||||
* "pclk" : peripheral clock.
|
||||
* "dclk" : pdm digital clock
|
||||
* "sysclk" : dsp system clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Example of PDM on the A113 SoC:
|
||||
|
||||
pdm: audio-controller@ff632000 {
|
||||
compatible = "amlogic,axg-pdm";
|
||||
reg = <0x0 0xff632000 0x0 0x34>;
|
||||
#sound-dai-cells = <0>;
|
||||
clocks = <&clkc_audio AUD_CLKID_PDM>,
|
||||
<&clkc_audio AUD_CLKID_PDM_DCLK>,
|
||||
<&clkc_audio AUD_CLKID_PDM_SYSCLK>;
|
||||
clock-names = "pclk", "dclk", "sysclk";
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
CS42L51 audio CODEC
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks : a list of phandles + clock-specifiers, one for each entry in
|
||||
clock-names
|
||||
|
||||
- clock-names : must contain "MCLK"
|
||||
|
||||
Example:
|
||||
|
||||
cs42l51: cs42l51@4a {
|
||||
compatible = "cirrus,cs42l51";
|
||||
reg = <0x4a>;
|
||||
clocks = <&mclk_prov>;
|
||||
clock-names = "MCLK";
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
MAX98088 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "maxim,max98088" or "maxim,max98089".
|
||||
- reg: The I2C address of the device.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section
|
||||
"consumer" for more information.
|
||||
- clock-names: must be set to "mclk"
|
||||
|
||||
Example:
|
||||
|
||||
max98089: codec@10 {
|
||||
compatible = "maxim,max98089";
|
||||
reg = <0x10>;
|
||||
clocks = <&clks IMX6QDL_CLK_CKO2>;
|
||||
clock-names = "mclk";
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
Mikroe-PROTO audio board
|
||||
|
||||
Required properties:
|
||||
- compatible: "mikroe,mikroe-proto"
|
||||
- dai-format: Must be "i2s".
|
||||
- i2s-controller: The phandle of the I2S controller.
|
||||
- audio-codec: The phandle of the WM8731 audio codec.
|
||||
Optional properties:
|
||||
- model: The user-visible name of this sound complex.
|
||||
- bitclock-master: Indicates dai-link bit clock master; for details see simple-card.txt (1).
|
||||
- frame-master: Indicates dai-link frame master; for details see simple-card.txt (1).
|
||||
|
||||
(1) : There must be the same master for both bit and frame clocks.
|
||||
|
||||
Example:
|
||||
sound {
|
||||
compatible = "mikroe,mikroe-proto";
|
||||
model = "wm8731 @ sama5d2_xplained";
|
||||
i2s-controller = <&i2s0>;
|
||||
audio-codec = <&wm8731>;
|
||||
dai-format = "i2s";
|
||||
};
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
NAU8822 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "nuvoton,nau8822"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
codec: nau8822@1a {
|
||||
compatible = "nuvoton,nau8822";
|
||||
reg = <0x1a>;
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
PCM3060 audio CODEC
|
||||
|
||||
This driver supports both I2C and SPI.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,pcm3060"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Examples:
|
||||
|
||||
pcm3060: pcm3060@46 {
|
||||
compatible = "ti,pcm3060";
|
||||
reg = <0x46>;
|
||||
};
|
|
@ -49,7 +49,7 @@ configuration of each dai. Must contain the following properties.
|
|||
Usage: required for mi2s interface
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Must be list of serial data lines used by this dai.
|
||||
should be one or more of the 1-4 sd lines.
|
||||
should be one or more of the 0-3 sd lines.
|
||||
|
||||
- qcom,tdm-sync-mode:
|
||||
Usage: required for tdm interface
|
||||
|
@ -137,42 +137,42 @@ q6afe@4 {
|
|||
|
||||
prim-mi2s-rx@16 {
|
||||
reg = <16>;
|
||||
qcom,sd-lines = <1 3>;
|
||||
qcom,sd-lines = <0 2>;
|
||||
};
|
||||
|
||||
prim-mi2s-tx@17 {
|
||||
reg = <17>;
|
||||
qcom,sd-lines = <2>;
|
||||
qcom,sd-lines = <1>;
|
||||
};
|
||||
|
||||
sec-mi2s-rx@18 {
|
||||
reg = <18>;
|
||||
qcom,sd-lines = <1 4>;
|
||||
qcom,sd-lines = <0 3>;
|
||||
};
|
||||
|
||||
sec-mi2s-tx@19 {
|
||||
reg = <19>;
|
||||
qcom,sd-lines = <2>;
|
||||
qcom,sd-lines = <1>;
|
||||
};
|
||||
|
||||
tert-mi2s-rx@20 {
|
||||
reg = <20>;
|
||||
qcom,sd-lines = <2 4>;
|
||||
qcom,sd-lines = <1 3>;
|
||||
};
|
||||
|
||||
tert-mi2s-tx@21 {
|
||||
reg = <21>;
|
||||
qcom,sd-lines = <1>;
|
||||
qcom,sd-lines = <0>;
|
||||
};
|
||||
|
||||
quat-mi2s-rx@22 {
|
||||
reg = <22>;
|
||||
qcom,sd-lines = <1>;
|
||||
qcom,sd-lines = <0>;
|
||||
};
|
||||
|
||||
quat-mi2s-tx@23 {
|
||||
reg = <23>;
|
||||
qcom,sd-lines = <2>;
|
||||
qcom,sd-lines = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -340,10 +340,12 @@ Required properties:
|
|||
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
||||
"renesas,rcar_sound-gen1" if generation1, and
|
||||
"renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
|
||||
"renesas,rcar_sound-gen3" if generation3
|
||||
"renesas,rcar_sound-gen3" if generation3 (or RZ/G2)
|
||||
Examples with soctypes are:
|
||||
- "renesas,rcar_sound-r8a7743" (RZ/G1M)
|
||||
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
|
||||
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
|
||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||
|
@ -353,6 +355,7 @@ Required properties:
|
|||
- "renesas,rcar_sound-r8a7795" (R-Car H3)
|
||||
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
||||
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
|
||||
- "renesas,rcar_sound-r8a77990" (R-Car E3)
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
|
|
|
@ -19,6 +19,10 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- clocks, clock-names: Clock specifier for XTI input clock.
|
||||
If specified, the clock will be enabled when the codec is probed,
|
||||
and disabled when it is removed. The 'clock-names' must be set to 'xti'.
|
||||
|
||||
- st,output-conf: number, Selects the output configuration:
|
||||
0: 2-channel (full-bridge) power, 2-channel data-out
|
||||
1: 2 (half-bridge). 1 (full-bridge) on-board power
|
||||
|
@ -39,6 +43,9 @@ Optional properties:
|
|||
- st,thermal-warning-recover:
|
||||
If present, thermal warning recovery is enabled.
|
||||
|
||||
- st,fault-detect-recovery:
|
||||
If present, fault detect recovery is enabled.
|
||||
|
||||
- st,thermal-warning-adjustment:
|
||||
If present, thermal warning adjustment is enabled.
|
||||
|
||||
|
@ -76,6 +83,8 @@ Example:
|
|||
codec: sta32x@38 {
|
||||
compatible = "st,sta32x";
|
||||
reg = <0x1c>;
|
||||
clocks = <&clock>;
|
||||
clock-names = "xti";
|
||||
reset-gpios = <&gpio1 19 0>;
|
||||
power-down-gpios = <&gpio1 16 0>;
|
||||
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
|
||||
|
|
|
@ -31,7 +31,11 @@ SAI subnodes required properties:
|
|||
- reg: Base address and size of SAI sub-block register set.
|
||||
- clocks: Must contain one phandle and clock specifier pair
|
||||
for sai_ck which feeds the internal clock generator.
|
||||
If the SAI shares a master clock, with another SAI set as MCLK
|
||||
clock provider, SAI provider phandle must be specified here.
|
||||
- clock-names: Must contain "sai_ck".
|
||||
Must also contain "MCLK", if SAI shares a master clock,
|
||||
with a SAI set as MCLK clock provider.
|
||||
- dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
|
||||
- dma-names: identifier string for each DMA request line
|
||||
"tx": if sai sub-block is configured as playback DAI
|
||||
|
@ -51,6 +55,9 @@ SAI subnodes Optional properties:
|
|||
configured according to protocol defined in related DAI link node,
|
||||
such as i2s, left justified, right justified, dsp and pdm protocols.
|
||||
Note: ac97 protocol is not supported by SAI driver
|
||||
- #clock-cells: should be 0. This property must be present if the SAI device
|
||||
is a master clock provider, according to clocks bindings, described in
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt.
|
||||
|
||||
The device node should contain one 'port' child node with one child 'endpoint'
|
||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||
|
|
|
@ -10,6 +10,7 @@ Required properties:
|
|||
- "allwinner,sun6i-a31-i2s"
|
||||
- "allwinner,sun8i-a83t-i2s"
|
||||
- "allwinner,sun8i-h3-i2s"
|
||||
- "allwinner,sun50i-a64-codec-i2s"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: should contain the I2S interrupt.
|
||||
|
@ -26,6 +27,7 @@ Required properties for the following compatibles:
|
|||
- "allwinner,sun6i-a31-i2s"
|
||||
- "allwinner,sun8i-a83t-i2s"
|
||||
- "allwinner,sun8i-h3-i2s"
|
||||
- "allwinner,sun50i-a64-codec-i2s"
|
||||
- resets: phandle to the reset line for this codec
|
||||
|
||||
Example:
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
* Allwinner A64 Codec Analog Controls
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of the following compatibles:
|
||||
- "allwinner,sun50i-a64-codec-analog"
|
||||
- reg: must contain the registers location and length
|
||||
|
||||
Example:
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun50i-a64-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
};
|
|
@ -14,7 +14,7 @@ Required properties:
|
|||
|
||||
Optional properies:
|
||||
- ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7).
|
||||
Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
|
||||
Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage
|
||||
2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
|
||||
Default value is "1" (2.2V).
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
WM8782 stereo ADC
|
||||
|
||||
This device does not have any control interface or reset pins.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8782"
|
||||
- Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V)
|
||||
- Vdd-supply : phandle to a regulator for the digital power supply (2.7V - 3.6V)
|
||||
|
||||
Example:
|
||||
|
||||
wm8782: stereo-adc {
|
||||
compatible = "wlf,wm8782";
|
||||
Vdda-supply = <&vdda_supply>;
|
||||
Vdd-supply = <&vdd_supply>;
|
||||
};
|
|
@ -35,7 +35,6 @@ at,24c08 i2c serial eeprom (24cxx)
|
|||
atmel,at97sc3204t i2c trusted platform module (TPM)
|
||||
capella,cm32181 CM32181: Ambient Light Sensor
|
||||
capella,cm3232 CM3232: Ambient Light Sensor
|
||||
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
|
||||
dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
|
||||
dallas,ds1631 High-Precision Digital Thermometer
|
||||
dallas,ds1672 Dallas DS1672 Real-time Clock
|
||||
|
|
|
@ -235,6 +235,7 @@ micrel Micrel Inc.
|
|||
microchip Microchip Technology Inc.
|
||||
microcrystal Micro Crystal AG
|
||||
micron Micron Technology Inc.
|
||||
mikroe MikroElektronika d.o.o.
|
||||
minix MINIX Technology Ltd.
|
||||
miramems MiraMEMS Sensing Technology Co., Ltd.
|
||||
mitsubishi Mitsubishi Electric Corporation
|
||||
|
|
|
@ -309,6 +309,8 @@ asus-nx50
|
|||
ASUS Nx50 fixups
|
||||
asus-nx51
|
||||
ASUS Nx51 fixups
|
||||
asus-g751
|
||||
ASUS G751 fixups
|
||||
alc891-headset
|
||||
Headset mode support on ALC891
|
||||
alc891-headset-multi
|
||||
|
|
|
@ -3,8 +3,6 @@ Writing an ALSA Driver
|
|||
======================
|
||||
|
||||
:Author: Takashi Iwai <tiwai@suse.de>
|
||||
:Date: Oct 15, 2007
|
||||
:Edition: 0.3.7
|
||||
|
||||
Preface
|
||||
=======
|
||||
|
@ -21,11 +19,6 @@ explain the general topic of linux kernel coding and doesn't cover
|
|||
low-level driver implementation details. It only describes the standard
|
||||
way to write a PCI sound driver on ALSA.
|
||||
|
||||
If you are already familiar with the older ALSA ver.0.5.x API, you can
|
||||
check the drivers such as ``sound/pci/es1938.c`` or
|
||||
``sound/pci/maestro3.c`` which have also almost the same code-base in
|
||||
the ALSA 0.5.x tree, so you can compare the differences.
|
||||
|
||||
This document is still a draft version. Any feedback and corrections,
|
||||
please!!
|
||||
|
||||
|
@ -35,24 +28,7 @@ File Tree Structure
|
|||
General
|
||||
-------
|
||||
|
||||
The ALSA drivers are provided in two ways.
|
||||
|
||||
One is the trees provided as a tarball or via cvs from the ALSA's ftp
|
||||
site, and another is the 2.6 (or later) Linux kernel tree. To
|
||||
synchronize both, the ALSA driver tree is split into two different
|
||||
trees: alsa-kernel and alsa-driver. The former contains purely the
|
||||
source code for the Linux 2.6 (or later) tree. This tree is designed
|
||||
only for compilation on 2.6 or later environment. The latter,
|
||||
alsa-driver, contains many subtle files for compiling ALSA drivers
|
||||
outside of the Linux kernel tree, wrapper functions for older 2.2 and
|
||||
2.4 kernels, to adapt the latest kernel API, and additional drivers
|
||||
which are still in development or in tests. The drivers in alsa-driver
|
||||
tree will be moved to alsa-kernel (and eventually to the 2.6 kernel
|
||||
tree) when they are finished and confirmed to work fine.
|
||||
|
||||
The file tree structure of ALSA driver is depicted below. Both
|
||||
alsa-kernel and alsa-driver have almost the same file structure, except
|
||||
for “core” directory. It's named as “acore” in alsa-driver tree.
|
||||
The file tree structure of ALSA driver is depicted below.
|
||||
|
||||
::
|
||||
|
||||
|
@ -61,14 +37,11 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
|
|||
/oss
|
||||
/seq
|
||||
/oss
|
||||
/instr
|
||||
/ioctl32
|
||||
/include
|
||||
/drivers
|
||||
/mpu401
|
||||
/opl3
|
||||
/i2c
|
||||
/l3
|
||||
/synth
|
||||
/emux
|
||||
/pci
|
||||
|
@ -80,6 +53,7 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
|
|||
/sparc
|
||||
/usb
|
||||
/pcmcia /(cards)
|
||||
/soc
|
||||
/oss
|
||||
|
||||
|
||||
|
@ -99,13 +73,6 @@ directory. The rawmidi OSS emulation is included in the ALSA rawmidi
|
|||
code since it's quite small. The sequencer code is stored in
|
||||
``core/seq/oss`` directory (see `below <#core-seq-oss>`__).
|
||||
|
||||
core/ioctl32
|
||||
~~~~~~~~~~~~
|
||||
|
||||
This directory contains the 32bit-ioctl wrappers for 64bit architectures
|
||||
such like x86-64, ppc64 and sparc64. For 32bit and alpha architectures,
|
||||
these are not compiled.
|
||||
|
||||
core/seq
|
||||
~~~~~~~~
|
||||
|
||||
|
@ -119,11 +86,6 @@ core/seq/oss
|
|||
|
||||
This contains the OSS sequencer emulation codes.
|
||||
|
||||
core/seq/instr
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
This directory contains the modules for the sequencer instrument layer.
|
||||
|
||||
include directory
|
||||
-----------------
|
||||
|
||||
|
@ -161,11 +123,6 @@ Although there is a standard i2c layer on Linux, ALSA has its own i2c
|
|||
code for some cards, because the soundcard needs only a simple operation
|
||||
and the standard i2c API is too complicated for such a purpose.
|
||||
|
||||
i2c/l3
|
||||
~~~~~~
|
||||
|
||||
This is a sub-directory for ARM L3 i2c.
|
||||
|
||||
synth directory
|
||||
---------------
|
||||
|
||||
|
@ -209,11 +166,19 @@ The PCMCIA, especially PCCard drivers will go here. CardBus drivers will
|
|||
be in the pci directory, because their API is identical to that of
|
||||
standard PCI cards.
|
||||
|
||||
soc directory
|
||||
-------------
|
||||
|
||||
This directory contains the codes for ASoC (ALSA System on Chip)
|
||||
layer including ASoC core, codec and machine drivers.
|
||||
|
||||
oss directory
|
||||
-------------
|
||||
|
||||
The OSS/Lite source files are stored here in Linux 2.6 (or later) tree.
|
||||
In the ALSA driver tarball, this directory is empty, of course :)
|
||||
Here contains OSS/Lite codes.
|
||||
All codes have been deprecated except for dmasound on m68k as of
|
||||
writing this.
|
||||
|
||||
|
||||
Basic Flow for PCI Drivers
|
||||
==========================
|
||||
|
@ -352,10 +317,8 @@ to details explained in the following section.
|
|||
|
||||
/* (3) */
|
||||
err = snd_mychip_create(card, pci, &chip);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/* (4) */
|
||||
strcpy(card->driver, "My Chip");
|
||||
|
@ -368,22 +331,23 @@ to details explained in the following section.
|
|||
|
||||
/* (6) */
|
||||
err = snd_card_register(card);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/* (7) */
|
||||
pci_set_drvdata(pci, card);
|
||||
dev++;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* destructor -- see the "Destructor" sub-section */
|
||||
static void snd_mychip_remove(struct pci_dev *pci)
|
||||
{
|
||||
snd_card_free(pci_get_drvdata(pci));
|
||||
pci_set_drvdata(pci, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -445,14 +409,26 @@ In this part, the PCI resources are allocated.
|
|||
struct mychip *chip;
|
||||
....
|
||||
err = snd_mychip_create(card, pci, &chip);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
The details will be explained in the section `PCI Resource
|
||||
Management`_.
|
||||
|
||||
When something goes wrong, the probe function needs to deal with the
|
||||
error. In this example, we have a single error handling path placed
|
||||
at the end of the function.
|
||||
|
||||
::
|
||||
|
||||
error:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
|
||||
Since each component can be properly freed, the single
|
||||
:c:func:`snd_card_free()` call should suffice in most cases.
|
||||
|
||||
|
||||
4) Set the driver ID and name strings.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -486,10 +462,8 @@ too.
|
|||
::
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
Will be explained in the section `Management of Cards and
|
||||
Components`_, too.
|
||||
|
@ -513,14 +487,13 @@ The destructor, remove callback, simply releases the card instance. Then
|
|||
the ALSA middle layer will release all the attached components
|
||||
automatically.
|
||||
|
||||
It would be typically like the following:
|
||||
It would be typically just :c:func:`calling snd_card_free()`:
|
||||
|
||||
::
|
||||
|
||||
static void snd_mychip_remove(struct pci_dev *pci)
|
||||
{
|
||||
snd_card_free(pci_get_drvdata(pci));
|
||||
pci_set_drvdata(pci, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -546,7 +519,7 @@ in the source file. If the code is split into several files, the files
|
|||
without module options don't need them.
|
||||
|
||||
In addition to these headers, you'll need ``<linux/interrupt.h>`` for
|
||||
interrupt handling, and ``<asm/io.h>`` for I/O access. If you use the
|
||||
interrupt handling, and ``<linux/io.h>`` for I/O access. If you use the
|
||||
:c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need
|
||||
to include ``<linux/delay.h>`` too.
|
||||
|
||||
|
@ -720,6 +693,13 @@ function, which will call the real destructor.
|
|||
|
||||
where :c:func:`snd_mychip_free()` is the real destructor.
|
||||
|
||||
The demerit of this method is the obviously more amount of codes.
|
||||
The merit is, however, you can trigger the own callback at registering
|
||||
and disconnecting the card via setting in snd_device_ops.
|
||||
About the registering and disconnecting the card, see the subsections
|
||||
below.
|
||||
|
||||
|
||||
Registration and Release
|
||||
------------------------
|
||||
|
||||
|
@ -905,10 +885,8 @@ Resource Allocation
|
|||
-------------------
|
||||
|
||||
The allocation of I/O ports and irqs is done via standard kernel
|
||||
functions. Unlike ALSA ver.0.5.x., there are no helpers for that. And
|
||||
these resources must be released in the destructor function (see below).
|
||||
Also, on ALSA 0.9.x, you don't need to allocate (pseudo-)DMA for PCI
|
||||
like in ALSA 0.5.x.
|
||||
functions. These resources must be released in the destructor
|
||||
function (see below).
|
||||
|
||||
Now assume that the PCI device has an I/O port with 8 bytes and an
|
||||
interrupt. Then :c:type:`struct mychip <mychip>` will have the
|
||||
|
@ -1064,7 +1042,8 @@ and the allocation would be like below:
|
|||
|
||||
::
|
||||
|
||||
if ((err = pci_request_regions(pci, "My Chip")) < 0) {
|
||||
err = pci_request_regions(pci, "My Chip");
|
||||
if (err < 0) {
|
||||
kfree(chip);
|
||||
return err;
|
||||
}
|
||||
|
@ -1086,6 +1065,21 @@ and the corresponding destructor would be:
|
|||
....
|
||||
}
|
||||
|
||||
Of course, a modern way with :c:func:`pci_iomap()` will make things a
|
||||
bit easier, too.
|
||||
|
||||
::
|
||||
|
||||
err = pci_request_regions(pci, "My Chip");
|
||||
if (err < 0) {
|
||||
kfree(chip);
|
||||
return err;
|
||||
}
|
||||
chip->iobase_virt = pci_iomap(pci, 0, 0);
|
||||
|
||||
which is paired with :c:func:`pci_iounmap()` at destructor.
|
||||
|
||||
|
||||
PCI Entries
|
||||
-----------
|
||||
|
||||
|
@ -1154,13 +1148,6 @@ And at last, the module entries:
|
|||
Note that these module entries are tagged with ``__init`` and ``__exit``
|
||||
prefixes.
|
||||
|
||||
Oh, one thing was forgotten. If you have no exported symbols, you need
|
||||
to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels).
|
||||
|
||||
::
|
||||
|
||||
EXPORT_NO_SYMBOLS;
|
||||
|
||||
That's all!
|
||||
|
||||
PCM Interface
|
||||
|
@ -2113,6 +2100,16 @@ non-contiguous buffers. The mmap calls this callback to get the page
|
|||
address. Some examples will be explained in the later section `Buffer
|
||||
and Memory Management`_, too.
|
||||
|
||||
mmap calllback
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
This is another optional callback for controlling mmap behavior.
|
||||
Once when defined, PCM core calls this callback when a page is
|
||||
memory-mapped instead of dealing via the standard helper.
|
||||
If you need special handling (due to some architecture or
|
||||
device-specific issues), implement everything here as you like.
|
||||
|
||||
|
||||
PCM Interrupt Handler
|
||||
---------------------
|
||||
|
||||
|
@ -2370,6 +2367,27 @@ to define the inverse rule:
|
|||
hw_rule_format_by_channels, NULL,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||
|
||||
One typical usage of the hw constraints is to align the buffer size
|
||||
with the period size. As default, ALSA PCM core doesn't enforce the
|
||||
buffer size to be aligned with the period size. For example, it'd be
|
||||
possible to have a combination like 256 period bytes with 999 buffer
|
||||
bytes.
|
||||
|
||||
Many device chips, however, require the buffer to be a multiple of
|
||||
periods. In such a case, call
|
||||
:c:func:`snd_pcm_hw_constraint_integer()` for
|
||||
``SNDRV_PCM_HW_PARAM_PERIODS``.
|
||||
|
||||
::
|
||||
|
||||
snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
|
||||
This assures that the number of periods is integer, hence the buffer
|
||||
size is aligned with the period size.
|
||||
|
||||
The hw constraint is a very much powerful mechanism to define the
|
||||
preferred PCM configuration, and there are relevant helpers.
|
||||
I won't give more details here, rather I would like to say, “Luke, use
|
||||
the source.”
|
||||
|
||||
|
@ -3712,7 +3730,14 @@ example, for an intermediate buffer. Since the allocated pages are not
|
|||
contiguous, you need to set the ``page`` callback to obtain the physical
|
||||
address at every offset.
|
||||
|
||||
The implementation of ``page`` callback would be like this:
|
||||
The easiest way to achieve it would be to use
|
||||
:c:func:`snd_pcm_lib_alloc_vmalloc_buffer()` for allocating the buffer
|
||||
via :c:func:`vmalloc()`, and set :c:func:`snd_pcm_sgbuf_ops_page()` to
|
||||
the ``page`` callback. At release, you need to call
|
||||
:c:func:`snd_pcm_lib_free_vmalloc_buffer()`.
|
||||
|
||||
If you want to implementation the ``page`` manually, it would be like
|
||||
this:
|
||||
|
||||
::
|
||||
|
||||
|
@ -3848,7 +3873,9 @@ Power Management
|
|||
|
||||
If the chip is supposed to work with suspend/resume functions, you need
|
||||
to add power-management code to the driver. The additional code for
|
||||
power-management should be ifdef-ed with ``CONFIG_PM``.
|
||||
power-management should be ifdef-ed with ``CONFIG_PM``, or annotated
|
||||
with __maybe_unused attribute; otherwise the compiler will complain
|
||||
you.
|
||||
|
||||
If the driver *fully* supports suspend/resume that is, the device can be
|
||||
properly resumed to its state when suspend was called, you can set the
|
||||
|
@ -3879,18 +3906,16 @@ the case of PCI drivers, the callbacks look like below:
|
|||
|
||||
::
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
|
||||
static int __maybe_unused snd_my_suspend(struct device *dev)
|
||||
{
|
||||
.... /* do things for suspend */
|
||||
return 0;
|
||||
}
|
||||
static int snd_my_resume(struct pci_dev *pci)
|
||||
static int __maybe_unused snd_my_resume(struct device *dev)
|
||||
{
|
||||
.... /* do things for suspend */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
The scheme of the real suspend job is as follows.
|
||||
|
||||
|
@ -3909,18 +3934,14 @@ The scheme of the real suspend job is as follows.
|
|||
|
||||
6. Stop the hardware if necessary.
|
||||
|
||||
7. Disable the PCI device by calling
|
||||
:c:func:`pci_disable_device()`. Then, call
|
||||
:c:func:`pci_save_state()` at last.
|
||||
|
||||
A typical code would be like:
|
||||
|
||||
::
|
||||
|
||||
static int mychip_suspend(struct pci_dev *pci, pm_message_t state)
|
||||
static int __maybe_unused mychip_suspend(struct device *dev)
|
||||
{
|
||||
/* (1) */
|
||||
struct snd_card *card = pci_get_drvdata(pci);
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct mychip *chip = card->private_data;
|
||||
/* (2) */
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
|
@ -3932,9 +3953,6 @@ A typical code would be like:
|
|||
snd_mychip_save_registers(chip);
|
||||
/* (6) */
|
||||
snd_mychip_stop_hardware(chip);
|
||||
/* (7) */
|
||||
pci_disable_device(pci);
|
||||
pci_save_state(pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3943,44 +3961,35 @@ The scheme of the real resume job is as follows.
|
|||
|
||||
1. Retrieve the card and the chip data.
|
||||
|
||||
2. Set up PCI. First, call :c:func:`pci_restore_state()`. Then
|
||||
enable the pci device again by calling
|
||||
:c:func:`pci_enable_device()`. Call
|
||||
:c:func:`pci_set_master()` if necessary, too.
|
||||
2. Re-initialize the chip.
|
||||
|
||||
3. Re-initialize the chip.
|
||||
3. Restore the saved registers if necessary.
|
||||
|
||||
4. Restore the saved registers if necessary.
|
||||
4. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`.
|
||||
|
||||
5. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`.
|
||||
5. Restart the hardware (if any).
|
||||
|
||||
6. Restart the hardware (if any).
|
||||
|
||||
7. Call :c:func:`snd_power_change_state()` with
|
||||
6. Call :c:func:`snd_power_change_state()` with
|
||||
``SNDRV_CTL_POWER_D0`` to notify the processes.
|
||||
|
||||
A typical code would be like:
|
||||
|
||||
::
|
||||
|
||||
static int mychip_resume(struct pci_dev *pci)
|
||||
static int __maybe_unused mychip_resume(struct pci_dev *pci)
|
||||
{
|
||||
/* (1) */
|
||||
struct snd_card *card = pci_get_drvdata(pci);
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct mychip *chip = card->private_data;
|
||||
/* (2) */
|
||||
pci_restore_state(pci);
|
||||
pci_enable_device(pci);
|
||||
pci_set_master(pci);
|
||||
/* (3) */
|
||||
snd_mychip_reinit_chip(chip);
|
||||
/* (4) */
|
||||
/* (3) */
|
||||
snd_mychip_restore_registers(chip);
|
||||
/* (5) */
|
||||
/* (4) */
|
||||
snd_ac97_resume(chip->ac97);
|
||||
/* (6) */
|
||||
/* (5) */
|
||||
snd_mychip_restart_chip(chip);
|
||||
/* (7) */
|
||||
/* (6) */
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4046,15 +4055,14 @@ And next, set suspend/resume callbacks to the pci_driver.
|
|||
|
||||
::
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_my_ids,
|
||||
.probe = snd_my_probe,
|
||||
.remove = snd_my_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_my_suspend,
|
||||
.resume = snd_my_resume,
|
||||
#endif
|
||||
.driver.pm = &snd_my_pm_ops,
|
||||
};
|
||||
|
||||
Module Parameters
|
||||
|
@ -4078,7 +4086,7 @@ variables, instead. ``enable`` option is not always necessary in this
|
|||
case, but it would be better to have a dummy option for compatibility.
|
||||
|
||||
The module parameters must be declared with the standard
|
||||
``module_param()()``, ``module_param_array()()`` and
|
||||
``module_param()``, ``module_param_array()`` and
|
||||
:c:func:`MODULE_PARM_DESC()` macros.
|
||||
|
||||
The typical coding would be like below:
|
||||
|
@ -4094,15 +4102,14 @@ The typical coding would be like below:
|
|||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
|
||||
|
||||
Also, don't forget to define the module description, classes, license
|
||||
and devices. Especially, the recent modprobe requires to define the
|
||||
Also, don't forget to define the module description and the license.
|
||||
Especially, the recent modprobe requires to define the
|
||||
module license as GPL, etc., otherwise the system is shown as “tainted”.
|
||||
|
||||
::
|
||||
|
||||
MODULE_DESCRIPTION("My Chip");
|
||||
MODULE_DESCRIPTION("Sound driver for My Chip");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("{{Vendor,My Chip Name}}");
|
||||
|
||||
|
||||
How To Put Your Driver Into ALSA Tree
|
||||
|
@ -4117,21 +4124,17 @@ a question now: how to put my own driver into the ALSA driver tree? Here
|
|||
|
||||
Suppose that you create a new PCI driver for the card “xyz”. The card
|
||||
module name would be snd-xyz. The new driver is usually put into the
|
||||
alsa-driver tree, ``alsa-driver/pci`` directory in the case of PCI
|
||||
cards. Then the driver is evaluated, audited and tested by developers
|
||||
and users. After a certain time, the driver will go to the alsa-kernel
|
||||
tree (to the corresponding directory, such as ``alsa-kernel/pci``) and
|
||||
eventually will be integrated into the Linux 2.6 tree (the directory
|
||||
would be ``linux/sound/pci``).
|
||||
alsa-driver tree, ``sound/pci`` directory in the case of PCI
|
||||
cards.
|
||||
|
||||
In the following sections, the driver code is supposed to be put into
|
||||
alsa-driver tree. The two cases are covered: a driver consisting of a
|
||||
Linux kernel tree. The two cases are covered: a driver consisting of a
|
||||
single source file and one consisting of several source files.
|
||||
|
||||
Driver with A Single Source File
|
||||
--------------------------------
|
||||
|
||||
1. Modify alsa-driver/pci/Makefile
|
||||
1. Modify sound/pci/Makefile
|
||||
|
||||
Suppose you have a file xyz.c. Add the following two lines
|
||||
|
||||
|
@ -4160,52 +4163,43 @@ Driver with A Single Source File
|
|||
|
||||
For the details of Kconfig script, refer to the kbuild documentation.
|
||||
|
||||
3. Run cvscompile script to re-generate the configure script and build
|
||||
the whole stuff again.
|
||||
|
||||
Drivers with Several Source Files
|
||||
---------------------------------
|
||||
|
||||
Suppose that the driver snd-xyz have several source files. They are
|
||||
located in the new subdirectory, pci/xyz.
|
||||
located in the new subdirectory, sound/pci/xyz.
|
||||
|
||||
1. Add a new directory (``xyz``) in ``alsa-driver/pci/Makefile`` as
|
||||
below
|
||||
1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile``
|
||||
as below
|
||||
|
||||
::
|
||||
|
||||
obj-$(CONFIG_SND) += xyz/
|
||||
obj-$(CONFIG_SND) += sound/pci/xyz/
|
||||
|
||||
|
||||
2. Under the directory ``xyz``, create a Makefile
|
||||
2. Under the directory ``sound/pci/xyz``, create a Makefile
|
||||
|
||||
::
|
||||
|
||||
ifndef SND_TOPDIR
|
||||
SND_TOPDIR=../..
|
||||
endif
|
||||
|
||||
include $(SND_TOPDIR)/toplevel.config
|
||||
include $(SND_TOPDIR)/Makefile.conf
|
||||
|
||||
snd-xyz-objs := xyz.o abc.o def.o
|
||||
|
||||
obj-$(CONFIG_SND_XYZ) += snd-xyz.o
|
||||
|
||||
include $(SND_TOPDIR)/Rules.make
|
||||
|
||||
3. Create the Kconfig entry
|
||||
|
||||
This procedure is as same as in the last section.
|
||||
|
||||
4. Run cvscompile script to re-generate the configure script and build
|
||||
the whole stuff again.
|
||||
|
||||
Useful Functions
|
||||
================
|
||||
|
||||
:c:func:`snd_printk()` and friends
|
||||
---------------------------------------
|
||||
----------------------------------
|
||||
|
||||
.. note:: This subsection describes a few helper functions for
|
||||
decorating a bit more on the standard :c:func:`printk()` & co.
|
||||
However, in general, the use of such helpers is no longer recommended.
|
||||
If possible, try to stick with the standard functions like
|
||||
:c:func:`dev_err()` or :c:func:`pr_err()`.
|
||||
|
||||
ALSA provides a verbose version of the :c:func:`printk()` function.
|
||||
If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function
|
||||
|
@ -4221,13 +4215,10 @@ just like :c:func:`snd_printk()`. If the ALSA is compiled without
|
|||
the debugging flag, it's ignored.
|
||||
|
||||
:c:func:`snd_printdd()` is compiled in only when
|
||||
``CONFIG_SND_DEBUG_VERBOSE`` is set. Please note that
|
||||
``CONFIG_SND_DEBUG_VERBOSE`` is not set as default even if you configure
|
||||
the alsa-driver with ``--with-debug=full`` option. You need to give
|
||||
explicitly ``--with-debug=detect`` option instead.
|
||||
``CONFIG_SND_DEBUG_VERBOSE`` is set.
|
||||
|
||||
:c:func:`snd_BUG()`
|
||||
------------------------
|
||||
-------------------
|
||||
|
||||
It shows the ``BUG?`` message and stack trace as well as
|
||||
:c:func:`snd_BUG_ON()` at the point. It's useful to show that a
|
||||
|
@ -4236,7 +4227,7 @@ fatal error happens there.
|
|||
When no debug flag is set, this macro is ignored.
|
||||
|
||||
:c:func:`snd_BUG_ON()`
|
||||
----------------------------
|
||||
----------------------
|
||||
|
||||
:c:func:`snd_BUG_ON()` macro is similar with
|
||||
:c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or
|
||||
|
|
|
@ -14759,6 +14759,13 @@ L: netdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/net/ethernet/ti/netcp*
|
||||
|
||||
TI PCM3060 ASoC CODEC DRIVER
|
||||
M: Kirill Marinushkin <kmarinushkin@birdec.tech>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/pcm3060.txt
|
||||
F: sound/soc/codecs/pcm3060*
|
||||
|
||||
TI TAS571X FAMILY ASoC CODEC DRIVER
|
||||
M: Kevin Cernekee <cernekee@chromium.org>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
|
|
|
@ -47,10 +47,13 @@ struct snd_dma_device {
|
|||
#define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */
|
||||
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
|
||||
#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */
|
||||
#define SNDRV_DMA_TYPE_DEV_UC 5 /* continuous non-cahced */
|
||||
#ifdef CONFIG_SND_DMA_SGBUF
|
||||
#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */
|
||||
#define SNDRV_DMA_TYPE_DEV_UC_SG 6 /* SG non-cached */
|
||||
#else
|
||||
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */
|
||||
#define SNDRV_DMA_TYPE_DEV_UC_SG SNDRV_DMA_TYPE_DEV_UC
|
||||
#endif
|
||||
#ifdef CONFIG_GENERIC_ALLOCATOR
|
||||
#define SNDRV_DMA_TYPE_DEV_IRAM 4 /* generic device iram-buffer */
|
||||
|
|
|
@ -171,6 +171,7 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
|
|||
unsigned char *buffer, int count);
|
||||
int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
|
||||
int count);
|
||||
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
|
||||
|
||||
/* main midi functions */
|
||||
|
||||
|
|
|
@ -51,29 +51,35 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
|||
|
||||
#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
|
||||
dai_link->cpu_dai_name)
|
||||
dai_link->cpu_dai_name, NULL)
|
||||
#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
|
||||
dai_link->codec_dai_name)
|
||||
dai_link->codec_dai_name, dai_link->codecs)
|
||||
int asoc_simple_card_parse_clk(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct device_node *dai_of_node,
|
||||
struct asoc_simple_dai *simple_dai,
|
||||
const char *name);
|
||||
const char *dai_name,
|
||||
struct snd_soc_dai_link_component *dlc);
|
||||
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
|
||||
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
|
||||
|
||||
#define asoc_simple_card_parse_cpu(node, dai_link, \
|
||||
list_name, cells_name, is_single_link) \
|
||||
asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node, \
|
||||
asoc_simple_card_parse_dai(node, NULL, \
|
||||
&dai_link->cpu_of_node, \
|
||||
&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
|
||||
#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \
|
||||
asoc_simple_card_parse_dai(node, &dai_link->codec_of_node, \
|
||||
&dai_link->codec_dai_name, list_name, cells_name, NULL)
|
||||
asoc_simple_card_parse_dai(node, dai_link->codecs, \
|
||||
&dai_link->codec_of_node, \
|
||||
&dai_link->codec_dai_name, \
|
||||
list_name, cells_name, NULL)
|
||||
#define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \
|
||||
asoc_simple_card_parse_dai(node, &dai_link->platform_of_node, \
|
||||
asoc_simple_card_parse_dai(node, dai_link->platform, \
|
||||
&dai_link->platform_of_node, \
|
||||
NULL, list_name, cells_name, NULL)
|
||||
int asoc_simple_card_parse_dai(struct device_node *node,
|
||||
struct snd_soc_dai_link_component *dlc,
|
||||
struct device_node **endpoint_np,
|
||||
const char **dai_name,
|
||||
const char *list_name,
|
||||
|
@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node,
|
|||
int *is_single_links);
|
||||
|
||||
#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
|
||||
asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \
|
||||
asoc_simple_card_parse_graph_dai(ep, NULL, \
|
||||
&dai_link->cpu_of_node, \
|
||||
&dai_link->cpu_dai_name)
|
||||
#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
|
||||
asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \
|
||||
asoc_simple_card_parse_graph_dai(ep, dai_link->codecs, \
|
||||
&dai_link->codec_of_node, \
|
||||
&dai_link->codec_dai_name)
|
||||
int asoc_simple_card_parse_graph_dai(struct device_node *ep,
|
||||
struct snd_soc_dai_link_component *dlc,
|
||||
struct device_node **endpoint_np,
|
||||
const char **dai_name);
|
||||
|
||||
|
|
|
@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
|
|||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
|
||||
|
||||
/*
|
||||
* generic table used for HDA codec-based platforms, possibly with
|
||||
* additional ACPI-enumerated codecs
|
||||
*/
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
|
|||
struct snd_soc_dai *dai);
|
||||
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
|
||||
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
|
||||
int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
const struct snd_soc_pcm_stream *params,
|
||||
unsigned int num_params,
|
||||
struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink);
|
||||
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
|
||||
|
@ -590,9 +584,6 @@ struct snd_soc_dapm_widget {
|
|||
void *priv; /* widget specific data */
|
||||
struct regulator *regulator; /* attached regulator */
|
||||
struct pinctrl *pinctrl; /* attached pinctrl */
|
||||
const struct snd_soc_pcm_stream *params; /* params for dai links */
|
||||
unsigned int num_params; /* number of params for dai links */
|
||||
unsigned int params_select; /* currently selected param for dai link */
|
||||
|
||||
/* dapm control */
|
||||
int reg; /* negative reg = no direct dapm */
|
||||
|
|
|
@ -103,6 +103,16 @@ struct snd_soc_dpcm_runtime {
|
|||
int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
|
||||
};
|
||||
|
||||
#define for_each_dpcm_fe(be, stream, dpcm) \
|
||||
list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe)
|
||||
|
||||
#define for_each_dpcm_be(fe, stream, dpcm) \
|
||||
list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
|
||||
#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \
|
||||
list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be)
|
||||
#define for_each_dpcm_be_rollback(fe, stream, dpcm) \
|
||||
list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
|
||||
|
||||
/* can this BE stop and free */
|
||||
int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
|
||||
struct snd_soc_pcm_runtime *be, int stream);
|
||||
|
|
|
@ -372,6 +372,11 @@
|
|||
#define SND_SOC_COMP_ORDER_LATE 1
|
||||
#define SND_SOC_COMP_ORDER_LAST 2
|
||||
|
||||
#define for_each_comp_order(order) \
|
||||
for (order = SND_SOC_COMP_ORDER_FIRST; \
|
||||
order <= SND_SOC_COMP_ORDER_LAST; \
|
||||
order++)
|
||||
|
||||
/*
|
||||
* Bias levels
|
||||
*
|
||||
|
@ -859,6 +864,11 @@ struct snd_soc_component {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define for_each_component_dais(component, dai)\
|
||||
list_for_each_entry(dai, &(component)->dai_list, list)
|
||||
#define for_each_component_dais_safe(component, dai, _dai)\
|
||||
list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list)
|
||||
|
||||
struct snd_soc_rtdcom_list {
|
||||
struct snd_soc_component *component;
|
||||
struct list_head list; /* rtd::component_list */
|
||||
|
@ -915,6 +925,8 @@ struct snd_soc_dai_link {
|
|||
*/
|
||||
const char *platform_name;
|
||||
struct device_node *platform_of_node;
|
||||
struct snd_soc_dai_link_component *platform;
|
||||
|
||||
int id; /* optional ID for machine driver link identification */
|
||||
|
||||
const struct snd_soc_pcm_stream *params;
|
||||
|
@ -976,6 +988,10 @@ struct snd_soc_dai_link {
|
|||
struct list_head list; /* DAI link list of the soc card */
|
||||
struct snd_soc_dobj dobj; /* For topology */
|
||||
};
|
||||
#define for_each_link_codecs(link, i, codec) \
|
||||
for ((i) = 0; \
|
||||
((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \
|
||||
(i)++)
|
||||
|
||||
struct snd_soc_codec_conf {
|
||||
/*
|
||||
|
@ -1054,7 +1070,6 @@ struct snd_soc_card {
|
|||
struct snd_soc_dai_link *dai_link; /* predefined links only */
|
||||
int num_links; /* predefined links only */
|
||||
struct list_head dai_link_list; /* all links */
|
||||
int num_dai_links;
|
||||
|
||||
struct list_head rtd_list;
|
||||
int num_rtd;
|
||||
|
@ -1092,6 +1107,7 @@ struct snd_soc_card {
|
|||
|
||||
/* lists of probed devices belonging to this card */
|
||||
struct list_head component_dev_list;
|
||||
struct list_head list;
|
||||
|
||||
struct list_head widgets;
|
||||
struct list_head paths;
|
||||
|
@ -1114,6 +1130,23 @@ struct snd_soc_card {
|
|||
|
||||
void *drvdata;
|
||||
};
|
||||
#define for_each_card_prelinks(card, i, link) \
|
||||
for ((i) = 0; \
|
||||
((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \
|
||||
(i)++)
|
||||
|
||||
#define for_each_card_links(card, link) \
|
||||
list_for_each_entry(dai_link, &(card)->dai_link_list, list)
|
||||
#define for_each_card_links_safe(card, link, _link) \
|
||||
list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list)
|
||||
|
||||
#define for_each_card_rtds(card, rtd) \
|
||||
list_for_each_entry(rtd, &(card)->rtd_list, list)
|
||||
#define for_each_card_rtds_safe(card, rtd, _rtd) \
|
||||
list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list)
|
||||
|
||||
#define for_each_card_components(card, component) \
|
||||
list_for_each_entry(component, &(card)->component_dev_list, card_list)
|
||||
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
struct snd_soc_pcm_runtime {
|
||||
|
@ -1124,6 +1157,8 @@ struct snd_soc_pcm_runtime {
|
|||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
struct snd_pcm_ops ops;
|
||||
|
||||
unsigned int params_select; /* currently selected param for dai link */
|
||||
|
||||
/* Dynamic PCM BE runtime data */
|
||||
struct snd_soc_dpcm_runtime dpcm[2];
|
||||
int fe_compr;
|
||||
|
@ -1152,6 +1187,13 @@ struct snd_soc_pcm_runtime {
|
|||
unsigned int dev_registered:1;
|
||||
unsigned int pop_wait:1;
|
||||
};
|
||||
#define for_each_rtd_codec_dai(rtd, i, dai)\
|
||||
for ((i) = 0; \
|
||||
((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
|
||||
(i)++)
|
||||
#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \
|
||||
for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);)
|
||||
|
||||
|
||||
/* mixer control */
|
||||
struct soc_mixer_control {
|
||||
|
@ -1359,6 +1401,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
|
|||
INIT_LIST_HEAD(&card->dapm_list);
|
||||
INIT_LIST_HEAD(&card->aux_comp_list);
|
||||
INIT_LIST_HEAD(&card->component_dev_list);
|
||||
INIT_LIST_HEAD(&card->list);
|
||||
}
|
||||
|
||||
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
|
||||
|
|
|
@ -752,7 +752,7 @@ struct snd_timer_info {
|
|||
#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */
|
||||
|
||||
struct snd_timer_params {
|
||||
unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */
|
||||
unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */
|
||||
unsigned int ticks; /* requested resolution in ticks */
|
||||
unsigned int queue_size; /* total size of queue (32-1024) */
|
||||
unsigned int reserved0; /* reserved, was: failure locations */
|
||||
|
|
|
@ -157,18 +157,19 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
|||
struct device_node *child = NULL, *sound = NULL;
|
||||
struct resource *r;
|
||||
int i, layout = 0, rlen, ok = force;
|
||||
static const char *rnames[] = { "i2sbus: %s (control)",
|
||||
"i2sbus: %s (tx)",
|
||||
"i2sbus: %s (rx)" };
|
||||
char node_name[6];
|
||||
static const char *rnames[] = { "i2sbus: %pOFn (control)",
|
||||
"i2sbus: %pOFn (tx)",
|
||||
"i2sbus: %pOFn (rx)" };
|
||||
static irq_handler_t ints[] = {
|
||||
i2sbus_bus_intr,
|
||||
i2sbus_tx_intr,
|
||||
i2sbus_rx_intr
|
||||
};
|
||||
|
||||
if (strlen(np->name) != 5)
|
||||
if (snprintf(node_name, sizeof(node_name), "%pOFn", np) != 5)
|
||||
return 0;
|
||||
if (strncmp(np->name, "i2s-", 4))
|
||||
if (strncmp(node_name, "i2s-", 4))
|
||||
return 0;
|
||||
|
||||
dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
|
||||
|
@ -228,13 +229,13 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
|||
dev->sound.pcmid = -1;
|
||||
dev->macio = macio;
|
||||
dev->control = control;
|
||||
dev->bus_number = np->name[4] - 'a';
|
||||
dev->bus_number = node_name[4] - 'a';
|
||||
INIT_LIST_HEAD(&dev->sound.codec_list);
|
||||
|
||||
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
|
||||
dev->interrupts[i] = -1;
|
||||
snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
|
||||
rnames[i], np->name);
|
||||
rnames[i], np);
|
||||
}
|
||||
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
|
||||
int irq = irq_of_parse_and_map(np, i);
|
||||
|
|
|
@ -31,7 +31,6 @@ endif # SND_ARM
|
|||
|
||||
config SND_PXA2XX_LIB
|
||||
tristate
|
||||
select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
|
||||
select SND_DMAENGINE_PCM
|
||||
|
||||
config SND_PXA2XX_LIB_AC97
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/genalloc.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/set_memory.h>
|
||||
#endif
|
||||
#include <sound/memalloc.h>
|
||||
|
||||
/*
|
||||
|
@ -82,31 +85,32 @@ EXPORT_SYMBOL(snd_free_pages);
|
|||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
/* allocate the coherent DMA pages */
|
||||
static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
|
||||
static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size)
|
||||
{
|
||||
int pg;
|
||||
gfp_t gfp_flags;
|
||||
|
||||
if (WARN_ON(!dma))
|
||||
return NULL;
|
||||
pg = get_order(size);
|
||||
gfp_flags = GFP_KERNEL
|
||||
| __GFP_COMP /* compound page lets parts be mapped */
|
||||
| __GFP_NORETRY /* don't trigger OOM-killer */
|
||||
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
|
||||
return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
|
||||
dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
|
||||
gfp_flags);
|
||||
#ifdef CONFIG_X86
|
||||
if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
|
||||
set_memory_wc((unsigned long)dmab->area,
|
||||
PAGE_ALIGN(size) >> PAGE_SHIFT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* free the coherent DMA pages */
|
||||
static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
|
||||
dma_addr_t dma)
|
||||
static void snd_free_dev_pages(struct snd_dma_buffer *dmab)
|
||||
{
|
||||
int pg;
|
||||
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
pg = get_order(size);
|
||||
dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
|
||||
#ifdef CONFIG_X86
|
||||
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
|
||||
set_memory_wb((unsigned long)dmab->area,
|
||||
PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
|
||||
#endif
|
||||
dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_ALLOCATOR
|
||||
|
@ -199,12 +203,15 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
|
|||
*/
|
||||
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
||||
/* fall through */
|
||||
case SNDRV_DMA_TYPE_DEV:
|
||||
dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
|
||||
case SNDRV_DMA_TYPE_DEV_UC:
|
||||
snd_malloc_dev_pages(dmab, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SND_DMA_SGBUF
|
||||
case SNDRV_DMA_TYPE_DEV_SG:
|
||||
case SNDRV_DMA_TYPE_DEV_UC_SG:
|
||||
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
|
||||
break;
|
||||
#endif
|
||||
|
@ -275,11 +282,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
|
|||
break;
|
||||
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
||||
case SNDRV_DMA_TYPE_DEV:
|
||||
snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
|
||||
case SNDRV_DMA_TYPE_DEV_UC:
|
||||
snd_free_dev_pages(dmab);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SND_DMA_SGBUF
|
||||
case SNDRV_DMA_TYPE_DEV_SG:
|
||||
case SNDRV_DMA_TYPE_DEV_UC_SG:
|
||||
snd_free_sgbuf_pages(dmab);
|
||||
break;
|
||||
#endif
|
||||
|
|
|
@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
|
|||
while (plugin->next) {
|
||||
if (plugin->dst_frames)
|
||||
frames = plugin->dst_frames(plugin, frames);
|
||||
if (snd_BUG_ON(frames <= 0))
|
||||
if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
|
||||
return -ENXIO;
|
||||
plugin = plugin->next;
|
||||
err = snd_pcm_plugin_alloc(plugin, frames);
|
||||
|
@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
|
|||
while (plugin->prev) {
|
||||
if (plugin->src_frames)
|
||||
frames = plugin->src_frames(plugin, frames);
|
||||
if (snd_BUG_ON(frames <= 0))
|
||||
if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
|
||||
return -ENXIO;
|
||||
plugin = plugin->prev;
|
||||
err = snd_pcm_plugin_alloc(plugin, frames);
|
||||
|
|
|
@ -2172,18 +2172,25 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
|
|||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
|
||||
if (!is_playback &&
|
||||
runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
|
||||
size >= runtime->start_threshold) {
|
||||
err = snd_pcm_start(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
}
|
||||
|
||||
runtime->twake = runtime->control->avail_min ? : 1;
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
||||
snd_pcm_update_hw_ptr(substream);
|
||||
|
||||
if (!is_playback &&
|
||||
runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
|
||||
if (size >= runtime->start_threshold) {
|
||||
err = snd_pcm_start(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
} else {
|
||||
/* nothing to do */
|
||||
err = 0;
|
||||
goto _end_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
avail = snd_pcm_avail(substream);
|
||||
|
||||
while (size > 0) {
|
||||
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
|
||||
snd_pcm_uframes_t cont;
|
||||
|
|
|
@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
|
|||
}
|
||||
EXPORT_SYMBOL(snd_rawmidi_transmit);
|
||||
|
||||
/**
|
||||
* snd_rawmidi_proceed - Discard the all pending bytes and proceed
|
||||
* @substream: rawmidi substream
|
||||
*
|
||||
* Return: the number of discarded bytes
|
||||
*/
|
||||
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct snd_rawmidi_runtime *runtime = substream->runtime;
|
||||
unsigned long flags;
|
||||
int count = 0;
|
||||
|
||||
spin_lock_irqsave(&runtime->lock, flags);
|
||||
if (runtime->avail < runtime->buffer_size) {
|
||||
count = runtime->buffer_size - runtime->avail;
|
||||
__snd_rawmidi_transmit_ack(substream, count);
|
||||
}
|
||||
spin_unlock_irqrestore(&runtime->lock, flags);
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_rawmidi_proceed);
|
||||
|
||||
static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
|
||||
const unsigned char __user *userbuf,
|
||||
const unsigned char *kernelbuf,
|
||||
|
|
|
@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
|
|||
case TMR_WAIT_REL:
|
||||
parm += rec->cur_tick;
|
||||
rec->realtime = 0;
|
||||
/* fall through and continue to next */
|
||||
/* fall through */
|
||||
case TMR_WAIT_ABS:
|
||||
if (parm == 0) {
|
||||
rec->realtime = 1;
|
||||
|
|
|
@ -123,6 +123,7 @@ int __init snd_seq_system_client_init(void)
|
|||
{
|
||||
struct snd_seq_port_callback pcallbacks;
|
||||
struct snd_seq_port_info *port;
|
||||
int err;
|
||||
|
||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
if (!port)
|
||||
|
@ -134,6 +135,10 @@ int __init snd_seq_system_client_init(void)
|
|||
|
||||
/* register client */
|
||||
sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
|
||||
if (sysclient < 0) {
|
||||
kfree(port);
|
||||
return sysclient;
|
||||
}
|
||||
|
||||
/* register timer */
|
||||
strcpy(port->name, "Timer");
|
||||
|
@ -144,7 +149,10 @@ int __init snd_seq_system_client_init(void)
|
|||
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
|
||||
port->addr.client = sysclient;
|
||||
port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
|
||||
snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
|
||||
err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
|
||||
port);
|
||||
if (err < 0)
|
||||
goto error_port;
|
||||
|
||||
/* register announcement port */
|
||||
strcpy(port->name, "Announce");
|
||||
|
@ -154,16 +162,24 @@ int __init snd_seq_system_client_init(void)
|
|||
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
|
||||
port->addr.client = sysclient;
|
||||
port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
|
||||
snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
|
||||
err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
|
||||
port);
|
||||
if (err < 0)
|
||||
goto error_port;
|
||||
announce_port = port->addr.port;
|
||||
|
||||
kfree(port);
|
||||
return 0;
|
||||
|
||||
error_port:
|
||||
snd_seq_system_client_done();
|
||||
kfree(port);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* unregister our internal client */
|
||||
void __exit snd_seq_system_client_done(void)
|
||||
void snd_seq_system_client_done(void)
|
||||
{
|
||||
int oldsysclient = sysclient;
|
||||
|
||||
|
|
|
@ -149,9 +149,7 @@ static void snd_vmidi_output_work(struct work_struct *work)
|
|||
/* discard the outputs in dispatch mode unless subscribed */
|
||||
if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
|
||||
!(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
|
||||
char buf[32];
|
||||
while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0)
|
||||
; /* ignored */
|
||||
snd_rawmidi_proceed(substream);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <sound/memalloc.h>
|
||||
|
||||
|
||||
|
@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
|
|||
dmab->area = NULL;
|
||||
|
||||
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG)
|
||||
tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC;
|
||||
tmpb.dev.dev = sgbuf->dev;
|
||||
for (i = 0; i < sgbuf->pages; i++) {
|
||||
if (!(sgbuf->table[i].addr & ~PAGE_MASK))
|
||||
|
@ -72,12 +75,20 @@ void *snd_malloc_sgbuf_pages(struct device *device,
|
|||
struct snd_dma_buffer tmpb;
|
||||
struct snd_sg_page *table;
|
||||
struct page **pgtable;
|
||||
int type = SNDRV_DMA_TYPE_DEV;
|
||||
pgprot_t prot = PAGE_KERNEL;
|
||||
|
||||
dmab->area = NULL;
|
||||
dmab->addr = 0;
|
||||
dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
|
||||
if (! sgbuf)
|
||||
return NULL;
|
||||
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
|
||||
type = SNDRV_DMA_TYPE_DEV_UC;
|
||||
#ifdef pgprot_noncached
|
||||
prot = pgprot_noncached(PAGE_KERNEL);
|
||||
#endif
|
||||
}
|
||||
sgbuf->dev = device;
|
||||
pages = snd_sgbuf_aligned_pages(size);
|
||||
sgbuf->tblsize = sgbuf_align_table(pages);
|
||||
|
@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
|
|||
if (chunk > maxpages)
|
||||
chunk = maxpages;
|
||||
chunk <<= PAGE_SHIFT;
|
||||
if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
|
||||
if (snd_dma_alloc_pages_fallback(type, device,
|
||||
chunk, &tmpb) < 0) {
|
||||
if (!sgbuf->pages)
|
||||
goto _failed;
|
||||
|
@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
|
|||
}
|
||||
|
||||
sgbuf->size = size;
|
||||
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
|
||||
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
|
||||
if (! dmab->area)
|
||||
goto _failed;
|
||||
if (res_size)
|
||||
|
|
|
@ -147,7 +147,9 @@ config SND_FIREWIRE_MOTU
|
|||
help
|
||||
Say Y here to enable support for FireWire devices which MOTU produced:
|
||||
* 828mk2
|
||||
* Traveler
|
||||
* 828mk3
|
||||
* Audio Express
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-firewire-motu.
|
||||
|
|
|
@ -140,6 +140,59 @@ const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = {
|
|||
};
|
||||
EXPORT_SYMBOL(amdtp_rate_table);
|
||||
|
||||
static int apply_constraint_to_size(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_interval *s = hw_param_interval(params, rule->var);
|
||||
const struct snd_interval *r =
|
||||
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval t = {
|
||||
.min = s->min, .max = s->max, .integer = 1,
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CIP_SFC_COUNT; ++i) {
|
||||
unsigned int rate = amdtp_rate_table[i];
|
||||
unsigned int step = amdtp_syt_intervals[i];
|
||||
|
||||
if (!snd_interval_test(r, rate))
|
||||
continue;
|
||||
|
||||
t.min = roundup(t.min, step);
|
||||
t.max = rounddown(t.max, step);
|
||||
}
|
||||
|
||||
if (snd_interval_checkempty(&t))
|
||||
return -EINVAL;
|
||||
|
||||
return snd_interval_refine(s, &t);
|
||||
}
|
||||
|
||||
static int apply_constraint_to_rate(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_interval *r =
|
||||
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||
const struct snd_interval *s = hw_param_interval_c(params, rule->deps[0]);
|
||||
struct snd_interval t = {
|
||||
.min = UINT_MAX, .max = 0, .integer = 1,
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CIP_SFC_COUNT; ++i) {
|
||||
unsigned int step = amdtp_syt_intervals[i];
|
||||
unsigned int rate = amdtp_rate_table[i];
|
||||
|
||||
if (s->min % step || s->max % step)
|
||||
continue;
|
||||
|
||||
t.min = min(t.min, rate);
|
||||
t.max = max(t.max, rate);
|
||||
}
|
||||
|
||||
return snd_interval_refine(r, &t);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
|
||||
* @s: the AMDTP stream, which must be initialized.
|
||||
|
@ -194,16 +247,27 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
|
|||
* number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
|
||||
* depending on its sampling rate. For accurate period interrupt, it's
|
||||
* preferrable to align period/buffer sizes to current SYT_INTERVAL.
|
||||
*
|
||||
* TODO: These constraints can be improved with proper rules.
|
||||
* Currently apply LCM of SYT_INTERVALs.
|
||||
*/
|
||||
err = snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
|
||||
apply_constraint_to_size, NULL,
|
||||
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
apply_constraint_to_rate, NULL,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
|
||||
apply_constraint_to_size, NULL,
|
||||
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
apply_constraint_to_rate, NULL,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
err = snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
|
||||
end:
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -126,23 +126,6 @@ name_device(struct snd_bebob *bebob)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void bebob_free(struct snd_bebob *bebob)
|
||||
{
|
||||
snd_bebob_stream_destroy_duplex(bebob);
|
||||
fw_unit_put(bebob->unit);
|
||||
|
||||
kfree(bebob->maudio_special_quirk);
|
||||
|
||||
mutex_destroy(&bebob->mutex);
|
||||
kfree(bebob);
|
||||
}
|
||||
|
||||
/*
|
||||
* This module releases the FireWire unit data after all ALSA character devices
|
||||
* are released by applications. This is for releasing stream data or finishing
|
||||
* transactions safely. Thus at returning from .remove(), this module still keep
|
||||
* references for the unit.
|
||||
*/
|
||||
static void
|
||||
bebob_card_free(struct snd_card *card)
|
||||
{
|
||||
|
@ -152,7 +135,7 @@ bebob_card_free(struct snd_card *card)
|
|||
clear_bit(bebob->card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
||||
bebob_free(card->private_data);
|
||||
snd_bebob_stream_destroy_duplex(bebob);
|
||||
}
|
||||
|
||||
static const struct snd_bebob_spec *
|
||||
|
@ -192,7 +175,6 @@ do_registration(struct work_struct *work)
|
|||
return;
|
||||
|
||||
mutex_lock(&devices_mutex);
|
||||
|
||||
for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
|
||||
if (!test_bit(card_index, devices_used) && enable[card_index])
|
||||
break;
|
||||
|
@ -208,6 +190,11 @@ do_registration(struct work_struct *work)
|
|||
mutex_unlock(&devices_mutex);
|
||||
return;
|
||||
}
|
||||
set_bit(card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
||||
bebob->card->private_free = bebob_card_free;
|
||||
bebob->card->private_data = bebob;
|
||||
|
||||
err = name_device(bebob);
|
||||
if (err < 0)
|
||||
|
@ -248,23 +235,10 @@ do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
set_bit(card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
||||
/*
|
||||
* After registered, bebob instance can be released corresponding to
|
||||
* releasing the sound card instance.
|
||||
*/
|
||||
bebob->card->private_free = bebob_card_free;
|
||||
bebob->card->private_data = bebob;
|
||||
bebob->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
mutex_unlock(&devices_mutex);
|
||||
snd_bebob_stream_destroy_duplex(bebob);
|
||||
kfree(bebob->maudio_special_quirk);
|
||||
bebob->maudio_special_quirk = NULL;
|
||||
snd_card_free(bebob->card);
|
||||
dev_info(&bebob->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
|
@ -295,15 +269,15 @@ bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
|
|||
}
|
||||
|
||||
/* Allocate this independent of sound card instance. */
|
||||
bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL);
|
||||
if (bebob == NULL)
|
||||
bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob),
|
||||
GFP_KERNEL);
|
||||
if (!bebob)
|
||||
return -ENOMEM;
|
||||
|
||||
bebob->unit = fw_unit_get(unit);
|
||||
bebob->entry = entry;
|
||||
bebob->spec = spec;
|
||||
dev_set_drvdata(&unit->device, bebob);
|
||||
|
||||
bebob->entry = entry;
|
||||
bebob->spec = spec;
|
||||
mutex_init(&bebob->mutex);
|
||||
spin_lock_init(&bebob->lock);
|
||||
init_waitqueue_head(&bebob->hwdep_wait);
|
||||
|
@ -379,12 +353,12 @@ static void bebob_remove(struct fw_unit *unit)
|
|||
cancel_delayed_work_sync(&bebob->dwork);
|
||||
|
||||
if (bebob->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(bebob->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
bebob_free(bebob);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(bebob->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&bebob->mutex);
|
||||
fw_unit_put(bebob->unit);
|
||||
}
|
||||
|
||||
static const struct snd_bebob_rate_spec normal_rate_spec = {
|
||||
|
|
|
@ -261,8 +261,9 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
|
|||
struct special_params *params;
|
||||
int err;
|
||||
|
||||
params = kzalloc(sizeof(struct special_params), GFP_KERNEL);
|
||||
if (params == NULL)
|
||||
params = devm_kzalloc(&bebob->card->card_dev,
|
||||
sizeof(struct special_params), GFP_KERNEL);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bebob->mutex);
|
||||
|
|
|
@ -122,25 +122,12 @@ static void dice_card_strings(struct snd_dice *dice)
|
|||
strcpy(card->mixername, "DICE");
|
||||
}
|
||||
|
||||
static void dice_free(struct snd_dice *dice)
|
||||
{
|
||||
snd_dice_stream_destroy_duplex(dice);
|
||||
snd_dice_transaction_destroy(dice);
|
||||
fw_unit_put(dice->unit);
|
||||
|
||||
mutex_destroy(&dice->mutex);
|
||||
kfree(dice);
|
||||
}
|
||||
|
||||
/*
|
||||
* This module releases the FireWire unit data after all ALSA character devices
|
||||
* are released by applications. This is for releasing stream data or finishing
|
||||
* transactions safely. Thus at returning from .remove(), this module still keep
|
||||
* references for the unit.
|
||||
*/
|
||||
static void dice_card_free(struct snd_card *card)
|
||||
{
|
||||
dice_free(card->private_data);
|
||||
struct snd_dice *dice = card->private_data;
|
||||
|
||||
snd_dice_stream_destroy_duplex(dice);
|
||||
snd_dice_transaction_destroy(dice);
|
||||
}
|
||||
|
||||
static void do_registration(struct work_struct *work)
|
||||
|
@ -155,6 +142,8 @@ static void do_registration(struct work_struct *work)
|
|||
&dice->card);
|
||||
if (err < 0)
|
||||
return;
|
||||
dice->card->private_free = dice_card_free;
|
||||
dice->card->private_data = dice;
|
||||
|
||||
err = snd_dice_transaction_init(dice);
|
||||
if (err < 0)
|
||||
|
@ -192,19 +181,10 @@ static void do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* After registered, dice instance can be released corresponding to
|
||||
* releasing the sound card instance.
|
||||
*/
|
||||
dice->card->private_free = dice_card_free;
|
||||
dice->card->private_data = dice;
|
||||
dice->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
snd_dice_stream_destroy_duplex(dice);
|
||||
snd_dice_transaction_destroy(dice);
|
||||
snd_dice_stream_destroy_duplex(dice);
|
||||
snd_card_free(dice->card);
|
||||
dev_info(&dice->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
|
@ -223,10 +203,9 @@ static int dice_probe(struct fw_unit *unit,
|
|||
}
|
||||
|
||||
/* Allocate this independent of sound card instance. */
|
||||
dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
|
||||
if (dice == NULL)
|
||||
dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL);
|
||||
if (!dice)
|
||||
return -ENOMEM;
|
||||
|
||||
dice->unit = fw_unit_get(unit);
|
||||
dev_set_drvdata(&unit->device, dice);
|
||||
|
||||
|
@ -263,10 +242,10 @@ static void dice_remove(struct fw_unit *unit)
|
|||
if (dice->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(dice->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
dice_free(dice);
|
||||
}
|
||||
|
||||
mutex_destroy(&dice->mutex);
|
||||
fw_unit_put(dice->unit);
|
||||
}
|
||||
|
||||
static void dice_bus_reset(struct fw_unit *unit)
|
||||
|
|
|
@ -41,20 +41,12 @@ static int name_card(struct snd_dg00x *dg00x)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dg00x_free(struct snd_dg00x *dg00x)
|
||||
{
|
||||
snd_dg00x_stream_destroy_duplex(dg00x);
|
||||
snd_dg00x_transaction_unregister(dg00x);
|
||||
|
||||
fw_unit_put(dg00x->unit);
|
||||
|
||||
mutex_destroy(&dg00x->mutex);
|
||||
kfree(dg00x);
|
||||
}
|
||||
|
||||
static void dg00x_card_free(struct snd_card *card)
|
||||
{
|
||||
dg00x_free(card->private_data);
|
||||
struct snd_dg00x *dg00x = card->private_data;
|
||||
|
||||
snd_dg00x_stream_destroy_duplex(dg00x);
|
||||
snd_dg00x_transaction_unregister(dg00x);
|
||||
}
|
||||
|
||||
static void do_registration(struct work_struct *work)
|
||||
|
@ -70,6 +62,8 @@ static void do_registration(struct work_struct *work)
|
|||
&dg00x->card);
|
||||
if (err < 0)
|
||||
return;
|
||||
dg00x->card->private_free = dg00x_card_free;
|
||||
dg00x->card->private_data = dg00x;
|
||||
|
||||
err = name_card(dg00x);
|
||||
if (err < 0)
|
||||
|
@ -101,14 +95,10 @@ static void do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
dg00x->card->private_free = dg00x_card_free;
|
||||
dg00x->card->private_data = dg00x;
|
||||
dg00x->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
snd_dg00x_transaction_unregister(dg00x);
|
||||
snd_dg00x_stream_destroy_duplex(dg00x);
|
||||
snd_card_free(dg00x->card);
|
||||
dev_info(&dg00x->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
|
@ -120,8 +110,9 @@ static int snd_dg00x_probe(struct fw_unit *unit,
|
|||
struct snd_dg00x *dg00x;
|
||||
|
||||
/* Allocate this independent of sound card instance. */
|
||||
dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL);
|
||||
if (dg00x == NULL)
|
||||
dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x),
|
||||
GFP_KERNEL);
|
||||
if (!dg00x)
|
||||
return -ENOMEM;
|
||||
|
||||
dg00x->unit = fw_unit_get(unit);
|
||||
|
@ -173,12 +164,12 @@ static void snd_dg00x_remove(struct fw_unit *unit)
|
|||
cancel_delayed_work_sync(&dg00x->dwork);
|
||||
|
||||
if (dg00x->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(dg00x->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
dg00x_free(dg00x);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(dg00x->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&dg00x->mutex);
|
||||
fw_unit_put(dg00x->unit);
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id snd_dg00x_id_table[] = {
|
||||
|
|
|
@ -27,20 +27,12 @@ static void name_card(struct snd_ff *ff)
|
|||
dev_name(&ff->unit->device), 100 << fw_dev->max_speed);
|
||||
}
|
||||
|
||||
static void ff_free(struct snd_ff *ff)
|
||||
{
|
||||
snd_ff_stream_destroy_duplex(ff);
|
||||
snd_ff_transaction_unregister(ff);
|
||||
|
||||
fw_unit_put(ff->unit);
|
||||
|
||||
mutex_destroy(&ff->mutex);
|
||||
kfree(ff);
|
||||
}
|
||||
|
||||
static void ff_card_free(struct snd_card *card)
|
||||
{
|
||||
ff_free(card->private_data);
|
||||
struct snd_ff *ff = card->private_data;
|
||||
|
||||
snd_ff_stream_destroy_duplex(ff);
|
||||
snd_ff_transaction_unregister(ff);
|
||||
}
|
||||
|
||||
static void do_registration(struct work_struct *work)
|
||||
|
@ -55,6 +47,8 @@ static void do_registration(struct work_struct *work)
|
|||
&ff->card);
|
||||
if (err < 0)
|
||||
return;
|
||||
ff->card->private_free = ff_card_free;
|
||||
ff->card->private_data = ff;
|
||||
|
||||
err = snd_ff_transaction_register(ff);
|
||||
if (err < 0)
|
||||
|
@ -84,14 +78,10 @@ static void do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
ff->card->private_free = ff_card_free;
|
||||
ff->card->private_data = ff;
|
||||
ff->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
snd_ff_transaction_unregister(ff);
|
||||
snd_ff_stream_destroy_duplex(ff);
|
||||
snd_card_free(ff->card);
|
||||
dev_info(&ff->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
|
@ -102,11 +92,9 @@ static int snd_ff_probe(struct fw_unit *unit,
|
|||
{
|
||||
struct snd_ff *ff;
|
||||
|
||||
ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL);
|
||||
if (ff == NULL)
|
||||
ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL);
|
||||
if (!ff)
|
||||
return -ENOMEM;
|
||||
|
||||
/* initialize myself */
|
||||
ff->unit = fw_unit_get(unit);
|
||||
dev_set_drvdata(&unit->device, ff);
|
||||
|
||||
|
@ -149,12 +137,12 @@ static void snd_ff_remove(struct fw_unit *unit)
|
|||
cancel_work_sync(&ff->dwork.work);
|
||||
|
||||
if (ff->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(ff->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
ff_free(ff);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(ff->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&ff->mutex);
|
||||
fw_unit_put(ff->unit);
|
||||
}
|
||||
|
||||
static const struct snd_ff_spec spec_ff400 = {
|
||||
|
|
|
@ -184,36 +184,17 @@ get_hardware_info(struct snd_efw *efw)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void efw_free(struct snd_efw *efw)
|
||||
{
|
||||
snd_efw_stream_destroy_duplex(efw);
|
||||
snd_efw_transaction_remove_instance(efw);
|
||||
fw_unit_put(efw->unit);
|
||||
|
||||
kfree(efw->resp_buf);
|
||||
|
||||
mutex_destroy(&efw->mutex);
|
||||
kfree(efw);
|
||||
}
|
||||
|
||||
/*
|
||||
* This module releases the FireWire unit data after all ALSA character devices
|
||||
* are released by applications. This is for releasing stream data or finishing
|
||||
* transactions safely. Thus at returning from .remove(), this module still keep
|
||||
* references for the unit.
|
||||
*/
|
||||
static void
|
||||
efw_card_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_efw *efw = card->private_data;
|
||||
|
||||
if (efw->card_index >= 0) {
|
||||
mutex_lock(&devices_mutex);
|
||||
clear_bit(efw->card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
}
|
||||
mutex_lock(&devices_mutex);
|
||||
clear_bit(efw->card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
||||
efw_free(card->private_data);
|
||||
snd_efw_stream_destroy_duplex(efw);
|
||||
snd_efw_transaction_remove_instance(efw);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -226,9 +207,8 @@ do_registration(struct work_struct *work)
|
|||
if (efw->registered)
|
||||
return;
|
||||
|
||||
mutex_lock(&devices_mutex);
|
||||
|
||||
/* check registered cards */
|
||||
mutex_lock(&devices_mutex);
|
||||
for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
|
||||
if (!test_bit(card_index, devices_used) && enable[card_index])
|
||||
break;
|
||||
|
@ -244,12 +224,18 @@ do_registration(struct work_struct *work)
|
|||
mutex_unlock(&devices_mutex);
|
||||
return;
|
||||
}
|
||||
set_bit(card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
||||
efw->card->private_free = efw_card_free;
|
||||
efw->card->private_data = efw;
|
||||
|
||||
/* prepare response buffer */
|
||||
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
|
||||
SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
|
||||
efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL);
|
||||
if (efw->resp_buf == NULL) {
|
||||
efw->resp_buf = devm_kzalloc(&efw->card->card_dev,
|
||||
snd_efw_resp_buf_size, GFP_KERNEL);
|
||||
if (!efw->resp_buf) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
@ -284,25 +270,11 @@ do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
set_bit(card_index, devices_used);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
||||
/*
|
||||
* After registered, efw instance can be released corresponding to
|
||||
* releasing the sound card instance.
|
||||
*/
|
||||
efw->card->private_free = efw_card_free;
|
||||
efw->card->private_data = efw;
|
||||
efw->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
mutex_unlock(&devices_mutex);
|
||||
snd_efw_transaction_remove_instance(efw);
|
||||
snd_efw_stream_destroy_duplex(efw);
|
||||
snd_card_free(efw->card);
|
||||
kfree(efw->resp_buf);
|
||||
efw->resp_buf = NULL;
|
||||
dev_info(&efw->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
}
|
||||
|
@ -312,10 +284,9 @@ efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
|
|||
{
|
||||
struct snd_efw *efw;
|
||||
|
||||
efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL);
|
||||
efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL);
|
||||
if (efw == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
efw->unit = fw_unit_get(unit);
|
||||
dev_set_drvdata(&unit->device, efw);
|
||||
|
||||
|
@ -363,12 +334,12 @@ static void efw_remove(struct fw_unit *unit)
|
|||
cancel_delayed_work_sync(&efw->dwork);
|
||||
|
||||
if (efw->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(efw->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
efw_free(efw);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(efw->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&efw->mutex);
|
||||
fw_unit_put(efw->unit);
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id efw_id_table[] = {
|
||||
|
|
|
@ -602,8 +602,6 @@ static void isight_card_free(struct snd_card *card)
|
|||
struct isight *isight = card->private_data;
|
||||
|
||||
fw_iso_resources_destroy(&isight->resources);
|
||||
fw_unit_put(isight->unit);
|
||||
mutex_destroy(&isight->mutex);
|
||||
}
|
||||
|
||||
static u64 get_unit_base(struct fw_unit *unit)
|
||||
|
@ -640,7 +638,7 @@ static int isight_probe(struct fw_unit *unit,
|
|||
if (!isight->audio_base) {
|
||||
dev_err(&unit->device, "audio unit base not found\n");
|
||||
err = -ENXIO;
|
||||
goto err_unit;
|
||||
goto error;
|
||||
}
|
||||
fw_iso_resources_init(&isight->resources, unit);
|
||||
|
||||
|
@ -669,12 +667,12 @@ static int isight_probe(struct fw_unit *unit,
|
|||
dev_set_drvdata(&unit->device, isight);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unit:
|
||||
fw_unit_put(isight->unit);
|
||||
mutex_destroy(&isight->mutex);
|
||||
error:
|
||||
snd_card_free(card);
|
||||
|
||||
mutex_destroy(&isight->mutex);
|
||||
fw_unit_put(isight->unit);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -703,7 +701,11 @@ static void isight_remove(struct fw_unit *unit)
|
|||
isight_stop_streaming(isight);
|
||||
mutex_unlock(&isight->mutex);
|
||||
|
||||
snd_card_free_when_closed(isight->card);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(isight->card);
|
||||
|
||||
mutex_destroy(&isight->mutex);
|
||||
fw_unit_put(isight->unit);
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id isight_id_table[] = {
|
||||
|
|
|
@ -52,26 +52,12 @@ static void name_card(struct snd_motu *motu)
|
|||
dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
|
||||
}
|
||||
|
||||
static void motu_free(struct snd_motu *motu)
|
||||
{
|
||||
snd_motu_transaction_unregister(motu);
|
||||
|
||||
snd_motu_stream_destroy_duplex(motu);
|
||||
fw_unit_put(motu->unit);
|
||||
|
||||
mutex_destroy(&motu->mutex);
|
||||
kfree(motu);
|
||||
}
|
||||
|
||||
/*
|
||||
* This module releases the FireWire unit data after all ALSA character devices
|
||||
* are released by applications. This is for releasing stream data or finishing
|
||||
* transactions safely. Thus at returning from .remove(), this module still keep
|
||||
* references for the unit.
|
||||
*/
|
||||
static void motu_card_free(struct snd_card *card)
|
||||
{
|
||||
motu_free(card->private_data);
|
||||
struct snd_motu *motu = card->private_data;
|
||||
|
||||
snd_motu_transaction_unregister(motu);
|
||||
snd_motu_stream_destroy_duplex(motu);
|
||||
}
|
||||
|
||||
static void do_registration(struct work_struct *work)
|
||||
|
@ -86,6 +72,8 @@ static void do_registration(struct work_struct *work)
|
|||
&motu->card);
|
||||
if (err < 0)
|
||||
return;
|
||||
motu->card->private_free = motu_card_free;
|
||||
motu->card->private_data = motu;
|
||||
|
||||
name_card(motu);
|
||||
|
||||
|
@ -120,18 +108,10 @@ static void do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* After registered, motu instance can be released corresponding to
|
||||
* releasing the sound card instance.
|
||||
*/
|
||||
motu->card->private_free = motu_card_free;
|
||||
motu->card->private_data = motu;
|
||||
motu->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
snd_motu_transaction_unregister(motu);
|
||||
snd_motu_stream_destroy_duplex(motu);
|
||||
snd_card_free(motu->card);
|
||||
dev_info(&motu->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
|
@ -143,14 +123,13 @@ static int motu_probe(struct fw_unit *unit,
|
|||
struct snd_motu *motu;
|
||||
|
||||
/* Allocate this independently of sound card instance. */
|
||||
motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
|
||||
if (motu == NULL)
|
||||
motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL);
|
||||
if (!motu)
|
||||
return -ENOMEM;
|
||||
|
||||
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
|
||||
motu->unit = fw_unit_get(unit);
|
||||
dev_set_drvdata(&unit->device, motu);
|
||||
|
||||
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
|
||||
mutex_init(&motu->mutex);
|
||||
spin_lock_init(&motu->lock);
|
||||
init_waitqueue_head(&motu->hwdep_wait);
|
||||
|
@ -174,12 +153,12 @@ static void motu_remove(struct fw_unit *unit)
|
|||
cancel_delayed_work_sync(&motu->dwork);
|
||||
|
||||
if (motu->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(motu->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
motu_free(motu);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(motu->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&motu->mutex);
|
||||
fw_unit_put(motu->unit);
|
||||
}
|
||||
|
||||
static void motu_bus_update(struct fw_unit *unit)
|
||||
|
|
|
@ -372,8 +372,9 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
|
|||
struct fw_scs1x *scs;
|
||||
int err;
|
||||
|
||||
scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL);
|
||||
if (scs == NULL)
|
||||
scs = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_scs1x),
|
||||
GFP_KERNEL);
|
||||
if (!scs)
|
||||
return -ENOMEM;
|
||||
scs->fw_dev = fw_parent_device(oxfw->unit);
|
||||
oxfw->spec = scs;
|
||||
|
|
|
@ -270,8 +270,9 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
|
|||
unsigned int i, first_ch;
|
||||
int err;
|
||||
|
||||
spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL);
|
||||
if (spkr == NULL)
|
||||
spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr),
|
||||
GFP_KERNEL);
|
||||
if (!spkr)
|
||||
return -ENOMEM;
|
||||
oxfw->spec = spkr;
|
||||
|
||||
|
|
|
@ -517,8 +517,9 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
|
|||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
|
||||
if (formats[eid] == NULL) {
|
||||
formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
|
||||
GFP_KERNEL);
|
||||
if (!formats[eid]) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
@ -535,7 +536,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
|
|||
continue;
|
||||
|
||||
eid++;
|
||||
formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
|
||||
formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
|
||||
GFP_KERNEL);
|
||||
if (formats[eid] == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
|
@ -597,8 +599,9 @@ static int fill_stream_formats(struct snd_oxfw *oxfw,
|
|||
if (err < 0)
|
||||
break;
|
||||
|
||||
formats[eid] = kmemdup(buf, len, GFP_KERNEL);
|
||||
if (formats[eid] == NULL) {
|
||||
formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
|
||||
GFP_KERNEL);
|
||||
if (!formats[eid]) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -113,35 +113,13 @@ static int name_card(struct snd_oxfw *oxfw)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void oxfw_free(struct snd_oxfw *oxfw)
|
||||
static void oxfw_card_free(struct snd_card *card)
|
||||
{
|
||||
unsigned int i;
|
||||
struct snd_oxfw *oxfw = card->private_data;
|
||||
|
||||
snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
|
||||
if (oxfw->has_output)
|
||||
snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
|
||||
|
||||
fw_unit_put(oxfw->unit);
|
||||
|
||||
for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
|
||||
kfree(oxfw->tx_stream_formats[i]);
|
||||
kfree(oxfw->rx_stream_formats[i]);
|
||||
}
|
||||
|
||||
kfree(oxfw->spec);
|
||||
mutex_destroy(&oxfw->mutex);
|
||||
kfree(oxfw);
|
||||
}
|
||||
|
||||
/*
|
||||
* This module releases the FireWire unit data after all ALSA character devices
|
||||
* are released by applications. This is for releasing stream data or finishing
|
||||
* transactions safely. Thus at returning from .remove(), this module still keep
|
||||
* references for the unit.
|
||||
*/
|
||||
static void oxfw_card_free(struct snd_card *card)
|
||||
{
|
||||
oxfw_free(card->private_data);
|
||||
}
|
||||
|
||||
static int detect_quirks(struct snd_oxfw *oxfw)
|
||||
|
@ -208,7 +186,6 @@ static int detect_quirks(struct snd_oxfw *oxfw)
|
|||
static void do_registration(struct work_struct *work)
|
||||
{
|
||||
struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
|
||||
int i;
|
||||
int err;
|
||||
|
||||
if (oxfw->registered)
|
||||
|
@ -218,6 +195,8 @@ static void do_registration(struct work_struct *work)
|
|||
&oxfw->card);
|
||||
if (err < 0)
|
||||
return;
|
||||
oxfw->card->private_free = oxfw_card_free;
|
||||
oxfw->card->private_data = oxfw;
|
||||
|
||||
err = name_card(oxfw);
|
||||
if (err < 0)
|
||||
|
@ -258,28 +237,11 @@ static void do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* After registered, oxfw instance can be released corresponding to
|
||||
* releasing the sound card instance.
|
||||
*/
|
||||
oxfw->card->private_free = oxfw_card_free;
|
||||
oxfw->card->private_data = oxfw;
|
||||
oxfw->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
|
||||
if (oxfw->has_output)
|
||||
snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
|
||||
for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; ++i) {
|
||||
kfree(oxfw->tx_stream_formats[i]);
|
||||
oxfw->tx_stream_formats[i] = NULL;
|
||||
kfree(oxfw->rx_stream_formats[i]);
|
||||
oxfw->rx_stream_formats[i] = NULL;
|
||||
}
|
||||
snd_card_free(oxfw->card);
|
||||
kfree(oxfw->spec);
|
||||
oxfw->spec = NULL;
|
||||
dev_info(&oxfw->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
}
|
||||
|
@ -293,14 +255,13 @@ static int oxfw_probe(struct fw_unit *unit,
|
|||
return -ENODEV;
|
||||
|
||||
/* Allocate this independent of sound card instance. */
|
||||
oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL);
|
||||
if (oxfw == NULL)
|
||||
oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL);
|
||||
if (!oxfw)
|
||||
return -ENOMEM;
|
||||
|
||||
oxfw->entry = entry;
|
||||
oxfw->unit = fw_unit_get(unit);
|
||||
dev_set_drvdata(&unit->device, oxfw);
|
||||
|
||||
oxfw->entry = entry;
|
||||
mutex_init(&oxfw->mutex);
|
||||
spin_lock_init(&oxfw->lock);
|
||||
init_waitqueue_head(&oxfw->hwdep_wait);
|
||||
|
@ -347,12 +308,12 @@ static void oxfw_remove(struct fw_unit *unit)
|
|||
cancel_delayed_work_sync(&oxfw->dwork);
|
||||
|
||||
if (oxfw->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(oxfw->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
oxfw_free(oxfw);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(oxfw->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&oxfw->mutex);
|
||||
fw_unit_put(oxfw->unit);
|
||||
}
|
||||
|
||||
static const struct compat_info griffin_firewave = {
|
||||
|
|
|
@ -85,20 +85,12 @@ static int identify_model(struct snd_tscm *tscm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tscm_free(struct snd_tscm *tscm)
|
||||
{
|
||||
snd_tscm_transaction_unregister(tscm);
|
||||
snd_tscm_stream_destroy_duplex(tscm);
|
||||
|
||||
fw_unit_put(tscm->unit);
|
||||
|
||||
mutex_destroy(&tscm->mutex);
|
||||
kfree(tscm);
|
||||
}
|
||||
|
||||
static void tscm_card_free(struct snd_card *card)
|
||||
{
|
||||
tscm_free(card->private_data);
|
||||
struct snd_tscm *tscm = card->private_data;
|
||||
|
||||
snd_tscm_transaction_unregister(tscm);
|
||||
snd_tscm_stream_destroy_duplex(tscm);
|
||||
}
|
||||
|
||||
static void do_registration(struct work_struct *work)
|
||||
|
@ -110,6 +102,8 @@ static void do_registration(struct work_struct *work)
|
|||
&tscm->card);
|
||||
if (err < 0)
|
||||
return;
|
||||
tscm->card->private_free = tscm_card_free;
|
||||
tscm->card->private_data = tscm;
|
||||
|
||||
err = identify_model(tscm);
|
||||
if (err < 0)
|
||||
|
@ -141,18 +135,10 @@ static void do_registration(struct work_struct *work)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* After registered, tscm instance can be released corresponding to
|
||||
* releasing the sound card instance.
|
||||
*/
|
||||
tscm->card->private_free = tscm_card_free;
|
||||
tscm->card->private_data = tscm;
|
||||
tscm->registered = true;
|
||||
|
||||
return;
|
||||
error:
|
||||
snd_tscm_transaction_unregister(tscm);
|
||||
snd_tscm_stream_destroy_duplex(tscm);
|
||||
snd_card_free(tscm->card);
|
||||
dev_info(&tscm->unit->device,
|
||||
"Sound card registration failed: %d\n", err);
|
||||
|
@ -164,11 +150,9 @@ static int snd_tscm_probe(struct fw_unit *unit,
|
|||
struct snd_tscm *tscm;
|
||||
|
||||
/* Allocate this independent of sound card instance. */
|
||||
tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL);
|
||||
if (tscm == NULL)
|
||||
tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL);
|
||||
if (!tscm)
|
||||
return -ENOMEM;
|
||||
|
||||
/* initialize myself */
|
||||
tscm->unit = fw_unit_get(unit);
|
||||
dev_set_drvdata(&unit->device, tscm);
|
||||
|
||||
|
@ -216,12 +200,12 @@ static void snd_tscm_remove(struct fw_unit *unit)
|
|||
cancel_delayed_work_sync(&tscm->dwork);
|
||||
|
||||
if (tscm->registered) {
|
||||
/* No need to wait for releasing card object in this context. */
|
||||
snd_card_free_when_closed(tscm->card);
|
||||
} else {
|
||||
/* Don't forget this case. */
|
||||
tscm_free(tscm);
|
||||
// Block till all of ALSA character devices are released.
|
||||
snd_card_free(tscm->card);
|
||||
}
|
||||
|
||||
mutex_destroy(&tscm->mutex);
|
||||
fw_unit_put(tscm->unit);
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id snd_tscm_id_table[] = {
|
||||
|
|
|
@ -48,9 +48,11 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
|
|||
}
|
||||
|
||||
if (enable)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
|
||||
AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN);
|
||||
else
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
|
||||
AZX_PPCTL_GPROCEN, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
|
||||
|
||||
|
@ -68,9 +70,11 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
|
|||
}
|
||||
|
||||
if (enable)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
|
||||
AZX_PPCTL_PIE, AZX_PPCTL_PIE);
|
||||
else
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
|
||||
AZX_PPCTL_PIE, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
|
||||
|
||||
|
@ -194,7 +198,8 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
|
|||
*/
|
||||
int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
|
||||
{
|
||||
snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
|
||||
snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
|
||||
AZX_MLCTL_SPA, AZX_MLCTL_SPA);
|
||||
|
||||
return check_hdac_link_power_active(link, true);
|
||||
}
|
||||
|
@ -222,8 +227,8 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
|
|||
int ret;
|
||||
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||
snd_hdac_updatel(hlink->ml_addr,
|
||||
AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
|
||||
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
|
||||
AZX_MLCTL_SPA, AZX_MLCTL_SPA);
|
||||
ret = check_hdac_link_power_active(hlink, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
|
|||
int ret;
|
||||
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
|
||||
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
|
||||
AZX_MLCTL_SPA, 0);
|
||||
ret = check_hdac_link_power_active(hlink, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
@ -118,7 +118,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
|
|||
struct cs8427 *chip = device->private_data;
|
||||
char *hw_data = udata ?
|
||||
chip->playback.hw_udata : chip->playback.hw_status;
|
||||
char data[32];
|
||||
unsigned char data[32];
|
||||
int err, idx;
|
||||
|
||||
if (!memcmp(hw_data, ndata, count))
|
||||
|
|
|
@ -389,7 +389,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
|
|||
case OPTi9XX_HW_82C931:
|
||||
/* disable 3D sound (set GPIO1 as output, low) */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
|
||||
case OPTi9XX_HW_82C933: /* FALL THROUGH */
|
||||
/* fall through */
|
||||
case OPTi9XX_HW_82C933:
|
||||
/*
|
||||
* The BTC 1817DW has QS1000 wavetable which is connected
|
||||
* to the serial digital input of the OPTI931.
|
||||
|
@ -400,7 +401,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
|
|||
* or digital input signal.
|
||||
*/
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
|
||||
case OPTi9XX_HW_82C930: /* FALL THROUGH */
|
||||
/* fall through */
|
||||
case OPTi9XX_HW_82C930:
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
|
||||
|
|
|
@ -130,13 +130,13 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
|
|||
chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
|
||||
break;
|
||||
}
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SB_HW_201:
|
||||
if (rate > 23000) {
|
||||
chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
|
||||
break;
|
||||
}
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SB_HW_20:
|
||||
chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
|
||||
break;
|
||||
|
@ -287,7 +287,7 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
|
|||
chip->capture_format = SB_DSP_HI_INPUT_AUTO;
|
||||
break;
|
||||
}
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SB_HW_20:
|
||||
chip->capture_format = SB_DSP_LO_INPUT_AUTO;
|
||||
break;
|
||||
|
@ -387,7 +387,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
|
|||
case SB_MODE_PLAYBACK_16: /* ok.. playback is active */
|
||||
if (chip->hardware != SB_HW_JAZZ16)
|
||||
break;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SB_MODE_PLAYBACK_8:
|
||||
substream = chip->playback_substream;
|
||||
if (chip->playback_format == SB_DSP_OUTPUT)
|
||||
|
@ -397,7 +397,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
|
|||
case SB_MODE_CAPTURE_16:
|
||||
if (chip->hardware != SB_HW_JAZZ16)
|
||||
break;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SB_MODE_CAPTURE_8:
|
||||
substream = chip->capture_substream;
|
||||
if (chip->capture_format == SB_DSP_INPUT)
|
||||
|
|
|
@ -500,7 +500,8 @@ static const struct snd_pcm_hardware hal2_pcm_hw = {
|
|||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER),
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_BE,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.rate_min = 8000,
|
||||
|
@ -563,6 +564,8 @@ static int hal2_playback_prepare(struct snd_pcm_substream *substream)
|
|||
dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
|
||||
memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
|
||||
dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
|
||||
dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
|
||||
dac->pcm_indirect.hw_io = dac->buffer_dma;
|
||||
dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
|
||||
dac->substream = substream;
|
||||
hal2_setup_dac(hal2);
|
||||
|
@ -575,9 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma;
|
||||
hal2->dac.pcm_indirect.hw_data = 0;
|
||||
substream->ops->ack(substream);
|
||||
hal2_start_dac(hal2);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
|
@ -615,7 +615,6 @@ static int hal2_playback_ack(struct snd_pcm_substream *substream)
|
|||
struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
|
||||
struct hal2_codec *dac = &hal2->dac;
|
||||
|
||||
dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
|
||||
return snd_pcm_indirect_playback_transfer(substream,
|
||||
&dac->pcm_indirect,
|
||||
hal2_playback_transfer);
|
||||
|
@ -655,6 +654,7 @@ static int hal2_capture_prepare(struct snd_pcm_substream *substream)
|
|||
memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
|
||||
adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
|
||||
adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
|
||||
adc->pcm_indirect.hw_io = adc->buffer_dma;
|
||||
adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
|
||||
adc->substream = substream;
|
||||
hal2_setup_adc(hal2);
|
||||
|
@ -667,9 +667,6 @@ static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma;
|
||||
hal2->adc.pcm_indirect.hw_data = 0;
|
||||
printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma);
|
||||
hal2_start_adc(hal2);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
|
|
|
@ -49,7 +49,7 @@ u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
|
|||
/*?? any benefit in using managed dmam_alloc_coherent? */
|
||||
p_mem_area->vaddr =
|
||||
dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
|
||||
GFP_DMA32 | GFP_KERNEL);
|
||||
GFP_KERNEL);
|
||||
|
||||
if (p_mem_area->vaddr) {
|
||||
HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",
|
||||
|
|
|
@ -903,15 +903,15 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
|
|||
case 8:
|
||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
|
||||
ATI_REG_OUT_DMA_SLOT_BIT(11);
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case 6:
|
||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
|
||||
ATI_REG_OUT_DMA_SLOT_BIT(8);
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case 4:
|
||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
|
||||
ATI_REG_OUT_DMA_SLOT_BIT(9);
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
default:
|
||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
|
||||
ATI_REG_OUT_DMA_SLOT_BIT(4);
|
||||
|
|
|
@ -1115,6 +1115,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
|
|||
hwwrite(vortex->mmio,
|
||||
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
|
||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
|
||||
/* fall through */
|
||||
/* 3 pages */
|
||||
case 3:
|
||||
dma->cfg0 |= 0x12000000;
|
||||
|
@ -1122,12 +1123,14 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
|
|||
hwwrite(vortex->mmio,
|
||||
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
|
||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
|
||||
/* fall through */
|
||||
/* 2 pages */
|
||||
case 2:
|
||||
dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
|
||||
hwwrite(vortex->mmio,
|
||||
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
|
||||
snd_pcm_sgbuf_get_addr(dma->substream, psize));
|
||||
/* fall through */
|
||||
/* 1 page */
|
||||
case 1:
|
||||
dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
|
||||
|
@ -1390,17 +1393,20 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
|
|||
dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
|
||||
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
|
||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
|
||||
/* fall through */
|
||||
/* 3 pages */
|
||||
case 3:
|
||||
dma->cfg0 |= 0x12000000;
|
||||
dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
|
||||
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x8,
|
||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
|
||||
/* fall through */
|
||||
/* 2 pages */
|
||||
case 2:
|
||||
dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
|
||||
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
|
||||
snd_pcm_sgbuf_get_addr(dma->substream, psize));
|
||||
/* fall through */
|
||||
/* 1 page */
|
||||
case 1:
|
||||
dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
|
||||
|
|
|
@ -1443,7 +1443,8 @@ static const struct snd_pcm_hardware snd_cs46xx_playback =
|
|||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
|
||||
/*SNDRV_PCM_INFO_RESUME*/),
|
||||
/*SNDRV_PCM_INFO_RESUME*/ |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
|
||||
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
|
||||
|
@ -1465,7 +1466,8 @@ static const struct snd_pcm_hardware snd_cs46xx_capture =
|
|||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
|
||||
/*SNDRV_PCM_INFO_RESUME*/),
|
||||
/*SNDRV_PCM_INFO_RESUME*/ |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
|
||||
.rate_min = 5500,
|
||||
|
|
|
@ -1753,7 +1753,8 @@ static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
|
|||
{
|
||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
/* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE),
|
||||
/* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/sort.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef __SOUND_HDA_BEEP_H
|
||||
#define __SOUND_HDA_BEEP_H
|
||||
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
|
||||
#define HDA_BEEP_MODE_OFF 0
|
||||
#define HDA_BEEP_MODE_ON 1
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
/*
|
||||
|
@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
|
|||
hda_codec_patch_t patch;
|
||||
int err;
|
||||
|
||||
if (codec->bus->core.ext_ops) {
|
||||
if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
|
||||
return -EINVAL;
|
||||
return codec->bus->core.ext_ops->hdev_attach(&codec->core);
|
||||
}
|
||||
|
||||
if (WARN_ON(!codec->preset))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
|
|||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
|
||||
if (codec->bus->core.ext_ops) {
|
||||
if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
|
||||
return -EINVAL;
|
||||
return codec->bus->core.ext_ops->hdev_detach(&codec->core);
|
||||
}
|
||||
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/initval.h>
|
||||
|
|
|
@ -130,8 +130,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
azx_dev->core.bufsize = 0;
|
||||
azx_dev->core.period_bytes = 0;
|
||||
azx_dev->core.format_val = 0;
|
||||
ret = chip->ops->substream_alloc_pages(chip, substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
ret = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
|
||||
unlock:
|
||||
dsp_unlock(azx_dev);
|
||||
return ret;
|
||||
|
@ -141,7 +142,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
{
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
struct azx *chip = apcm->chip;
|
||||
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
|
||||
int err;
|
||||
|
||||
|
@ -152,7 +152,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
|
||||
snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
|
||||
|
||||
err = chip->ops->substream_free_pages(chip, substream);
|
||||
err = snd_pcm_lib_free_pages(substream);
|
||||
azx_stream(azx_dev)->prepared = 0;
|
||||
dsp_unlock(azx_dev);
|
||||
return err;
|
||||
|
@ -732,6 +732,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
|
|||
int pcm_dev = cpcm->device;
|
||||
unsigned int size;
|
||||
int s, err;
|
||||
int type = SNDRV_DMA_TYPE_DEV_SG;
|
||||
|
||||
list_for_each_entry(apcm, &chip->pcm_list, list) {
|
||||
if (apcm->pcm->device == pcm_dev) {
|
||||
|
@ -770,7 +771,9 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
|
|||
size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
|
||||
if (size > MAX_PREALLOC_SIZE)
|
||||
size = MAX_PREALLOC_SIZE;
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
|
||||
if (chip->uc_buffer)
|
||||
type = SNDRV_DMA_TYPE_DEV_UC_SG;
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, type,
|
||||
chip->card->dev,
|
||||
size, MAX_PREALLOC_SIZE);
|
||||
return 0;
|
||||
|
@ -1220,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus)
|
|||
bus->in_reset = 0;
|
||||
}
|
||||
|
||||
static int get_jackpoll_interval(struct azx *chip)
|
||||
{
|
||||
int i;
|
||||
unsigned int j;
|
||||
|
||||
if (!chip->jackpoll_ms)
|
||||
return 0;
|
||||
|
||||
i = chip->jackpoll_ms[chip->dev_index];
|
||||
if (i == 0)
|
||||
return 0;
|
||||
if (i < 50 || i > 60000)
|
||||
j = 0;
|
||||
else
|
||||
j = msecs_to_jiffies(i);
|
||||
if (j == 0)
|
||||
dev_warn(chip->card->dev,
|
||||
"jackpoll_ms value out of range: %d\n", i);
|
||||
return j;
|
||||
}
|
||||
|
||||
/* HD-audio bus initialization */
|
||||
int azx_bus_init(struct azx *chip, const char *model,
|
||||
const struct hdac_io_ops *io_ops)
|
||||
|
@ -1323,7 +1305,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
|
|||
err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
|
||||
if (err < 0)
|
||||
continue;
|
||||
codec->jackpoll_interval = get_jackpoll_interval(chip);
|
||||
codec->jackpoll_interval = chip->jackpoll_interval;
|
||||
codec->beep_mode = chip->beep_mode;
|
||||
codecs++;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include <sound/hda_register.h>
|
||||
|
||||
#define AZX_MAX_CODECS HDA_MAX_CODECS
|
||||
|
@ -76,7 +76,6 @@ struct azx_dev {
|
|||
* when link position is not greater than FIFO size
|
||||
*/
|
||||
unsigned int insufficient:1;
|
||||
unsigned int wc_marked:1;
|
||||
};
|
||||
|
||||
#define azx_stream(dev) (&(dev)->core)
|
||||
|
@ -88,11 +87,6 @@ struct azx;
|
|||
struct hda_controller_ops {
|
||||
/* Disable msi if supported, PCI only */
|
||||
int (*disable_msi_reset_irq)(struct azx *);
|
||||
int (*substream_alloc_pages)(struct azx *chip,
|
||||
struct snd_pcm_substream *substream,
|
||||
size_t size);
|
||||
int (*substream_free_pages)(struct azx *chip,
|
||||
struct snd_pcm_substream *substream);
|
||||
void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area);
|
||||
/* Check if current position is acceptable */
|
||||
|
@ -127,7 +121,7 @@ struct azx {
|
|||
int capture_streams;
|
||||
int capture_index_offset;
|
||||
int num_streams;
|
||||
const int *jackpoll_ms; /* per-card jack poll interval */
|
||||
int jackpoll_interval; /* jack poll interval in jiffies */
|
||||
|
||||
/* Register interaction. */
|
||||
const struct hda_controller_ops *ops;
|
||||
|
@ -160,6 +154,7 @@ struct azx {
|
|||
unsigned int msi:1;
|
||||
unsigned int probing:1; /* codec probing phase */
|
||||
unsigned int snoop:1;
|
||||
unsigned int uc_buffer:1; /* non-cached pages for stream buffers */
|
||||
unsigned int align_buffer_size:1;
|
||||
unsigned int region_requested:1;
|
||||
unsigned int disabled:1; /* disabled by vga_switcheroo */
|
||||
|
@ -175,11 +170,10 @@ struct azx {
|
|||
#define azx_bus(chip) (&(chip)->bus.core)
|
||||
#define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core)
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#define azx_snoop(chip) ((chip)->snoop)
|
||||
#else
|
||||
#define azx_snoop(chip) true
|
||||
#endif
|
||||
static inline bool azx_snoop(struct azx *chip)
|
||||
{
|
||||
return !IS_ENABLED(CONFIG_X86) || chip->snoop;
|
||||
}
|
||||
|
||||
/*
|
||||
* macros for easy use
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <sound/hda_chmap.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
enum eld_versions {
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/compat.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/minors.h>
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
#include <linux/vgaarb.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_controller.h"
|
||||
#include "hda_intel.h"
|
||||
|
||||
|
@ -399,61 +399,6 @@ static char *driver_short_names[] = {
|
|||
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
|
||||
{
|
||||
int pages;
|
||||
|
||||
if (azx_snoop(chip))
|
||||
return;
|
||||
if (!dmab || !dmab->area || !dmab->bytes)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_SND_DMA_SGBUF
|
||||
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
|
||||
struct snd_sg_buf *sgbuf = dmab->private_data;
|
||||
if (chip->driver_type == AZX_DRIVER_CMEDIA)
|
||||
return; /* deal with only CORB/RIRB buffers */
|
||||
if (on)
|
||||
set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
|
||||
else
|
||||
set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
if (on)
|
||||
set_memory_wc((unsigned long)dmab->area, pages);
|
||||
else
|
||||
set_memory_wb((unsigned long)dmab->area, pages);
|
||||
}
|
||||
|
||||
static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
|
||||
bool on)
|
||||
{
|
||||
__mark_pages_wc(chip, buf, on);
|
||||
}
|
||||
static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
|
||||
struct snd_pcm_substream *substream, bool on)
|
||||
{
|
||||
if (azx_dev->wc_marked != on) {
|
||||
__mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on);
|
||||
azx_dev->wc_marked = on;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* NOP for other archs */
|
||||
static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
|
||||
bool on)
|
||||
{
|
||||
}
|
||||
static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
|
||||
struct snd_pcm_substream *substream, bool on)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
|
||||
static void set_default_power_save(struct azx *chip);
|
||||
|
||||
|
@ -1678,6 +1623,7 @@ static void azx_check_snoop_available(struct azx *chip)
|
|||
dev_info(chip->card->dev, "Force to %s mode by module option\n",
|
||||
snoop ? "snoop" : "non-snoop");
|
||||
chip->snoop = snoop;
|
||||
chip->uc_buffer = !snoop;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1698,8 +1644,12 @@ static void azx_check_snoop_available(struct azx *chip)
|
|||
snoop = false;
|
||||
|
||||
chip->snoop = snoop;
|
||||
if (!snoop)
|
||||
if (!snoop) {
|
||||
dev_info(chip->card->dev, "Force to non-snoop mode\n");
|
||||
/* C-Media requires non-cached pages only for CORB/RIRB */
|
||||
if (chip->driver_type != AZX_DRIVER_CMEDIA)
|
||||
chip->uc_buffer = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void azx_probe_work(struct work_struct *work)
|
||||
|
@ -1767,7 +1717,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
|
|||
chip->driver_type = driver_caps & 0xff;
|
||||
check_msi(chip);
|
||||
chip->dev_index = dev;
|
||||
chip->jackpoll_ms = jackpoll_ms;
|
||||
if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
|
||||
chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
|
||||
INIT_LIST_HEAD(&chip->pcm_list);
|
||||
INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
|
||||
INIT_LIST_HEAD(&hda->list);
|
||||
|
@ -2090,55 +2041,24 @@ static int dma_alloc_pages(struct hdac_bus *bus,
|
|||
struct snd_dma_buffer *buf)
|
||||
{
|
||||
struct azx *chip = bus_to_azx(bus);
|
||||
int err;
|
||||
|
||||
err = snd_dma_alloc_pages(type,
|
||||
bus->dev,
|
||||
size, buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mark_pages_wc(chip, buf, true);
|
||||
return 0;
|
||||
if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV)
|
||||
type = SNDRV_DMA_TYPE_DEV_UC;
|
||||
return snd_dma_alloc_pages(type, bus->dev, size, buf);
|
||||
}
|
||||
|
||||
static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
|
||||
{
|
||||
struct azx *chip = bus_to_azx(bus);
|
||||
|
||||
mark_pages_wc(chip, buf, false);
|
||||
snd_dma_free_pages(buf);
|
||||
}
|
||||
|
||||
static int substream_alloc_pages(struct azx *chip,
|
||||
struct snd_pcm_substream *substream,
|
||||
size_t size)
|
||||
{
|
||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
int ret;
|
||||
|
||||
mark_runtime_wc(chip, azx_dev, substream, false);
|
||||
ret = snd_pcm_lib_malloc_pages(substream, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
mark_runtime_wc(chip, azx_dev, substream, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int substream_free_pages(struct azx *chip,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
mark_runtime_wc(chip, azx_dev, substream, false);
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct azx *chip = apcm->chip;
|
||||
if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA)
|
||||
if (chip->uc_buffer)
|
||||
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
|
||||
#endif
|
||||
}
|
||||
|
@ -2156,8 +2076,6 @@ static const struct hdac_io_ops pci_hda_io_ops = {
|
|||
|
||||
static const struct hda_controller_ops pci_hda_ops = {
|
||||
.disable_msi_reset_irq = disable_msi_reset_irq,
|
||||
.substream_alloc_pages = substream_alloc_pages,
|
||||
.substream_free_pages = substream_free_pages,
|
||||
.pcm_mmap_prepare = pcm_mmap_prepare,
|
||||
.position_check = azx_position_check,
|
||||
.link_power = azx_intel_link_power,
|
||||
|
@ -2257,8 +2175,12 @@ static struct snd_pci_quirk power_save_blacklist[] = {
|
|||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
|
||||
SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
|
||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
|
||||
SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
|
||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
|
||||
/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
|
||||
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
|
||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
|
||||
SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0),
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
|
||||
SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
|
||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <linux/module.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
static int dump_coef = -1;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/export.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/minors.h>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_controller.h"
|
||||
|
||||
/* Defines for Nvidia Tegra HDA support */
|
||||
|
@ -99,19 +99,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
|
|||
snd_dma_free_pages(buf);
|
||||
}
|
||||
|
||||
static int substream_alloc_pages(struct azx *chip,
|
||||
struct snd_pcm_substream *substream,
|
||||
size_t size)
|
||||
{
|
||||
return snd_pcm_lib_malloc_pages(substream, size);
|
||||
}
|
||||
|
||||
static int substream_free_pages(struct azx *chip,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register access ops. Tegra HDA register access is DWORD only.
|
||||
*/
|
||||
|
@ -180,10 +167,7 @@ static const struct hdac_io_ops hda_tegra_io_ops = {
|
|||
.dma_free_pages = dma_free_pages,
|
||||
};
|
||||
|
||||
static const struct hda_controller_ops hda_tegra_ops = {
|
||||
.substream_alloc_pages = substream_alloc_pages,
|
||||
.substream_free_pages = substream_free_pages,
|
||||
};
|
||||
static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
|
||||
|
||||
static void hda_tegra_init(struct hda_tegra *hda)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/module.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
|
@ -943,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include <sound/hdaudio.h>
|
||||
#include <sound/hda_i915.h>
|
||||
#include <sound/hda_chmap.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -6841,6 +6841,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
|
|||
{0x1a, 0x02a11040},
|
||||
{0x1b, 0x01014020},
|
||||
{0x21, 0x0221101f}),
|
||||
SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
|
||||
{0x14, 0x90170110},
|
||||
{0x19, 0x02a11030},
|
||||
{0x1a, 0x02a11040},
|
||||
{0x1b, 0x01011020},
|
||||
{0x21, 0x0221101f}),
|
||||
SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
|
||||
{0x14, 0x90170110},
|
||||
{0x19, 0x02a11020},
|
||||
|
@ -7738,6 +7744,8 @@ enum {
|
|||
ALC662_FIXUP_ASUS_Nx50,
|
||||
ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
|
||||
ALC668_FIXUP_ASUS_Nx51,
|
||||
ALC668_FIXUP_MIC_COEF,
|
||||
ALC668_FIXUP_ASUS_G751,
|
||||
ALC891_FIXUP_HEADSET_MODE,
|
||||
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
|
||||
ALC662_FIXUP_ACER_VERITON,
|
||||
|
@ -8007,6 +8015,23 @@ static const struct hda_fixup alc662_fixups[] = {
|
|||
.chained = true,
|
||||
.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
|
||||
},
|
||||
[ALC668_FIXUP_MIC_COEF] = {
|
||||
.type = HDA_FIXUP_VERBS,
|
||||
.v.verbs = (const struct hda_verb[]) {
|
||||
{ 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
|
||||
{ 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
|
||||
{}
|
||||
},
|
||||
},
|
||||
[ALC668_FIXUP_ASUS_G751] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
{ 0x16, 0x0421101f }, /* HP */
|
||||
{}
|
||||
},
|
||||
.chained = true,
|
||||
.chain_id = ALC668_FIXUP_MIC_COEF
|
||||
},
|
||||
[ALC891_FIXUP_HEADSET_MODE] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_headset_mode,
|
||||
|
@ -8080,6 +8105,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
|
||||
SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
|
||||
SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
|
||||
SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
|
||||
SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
|
||||
SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
|
||||
SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
|
||||
|
@ -8184,6 +8210,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
|
|||
{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
|
||||
{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
|
||||
{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
|
||||
{.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
|
||||
{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
|
||||
{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
|
||||
{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
/* si3054 verbs */
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
|
@ -77,6 +77,7 @@ enum {
|
|||
STAC_DELL_M6_BOTH,
|
||||
STAC_DELL_EQ,
|
||||
STAC_ALIENWARE_M17X,
|
||||
STAC_ELO_VUPOINT_15MX,
|
||||
STAC_92HD89XX_HP_FRONT_JACK,
|
||||
STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
|
||||
STAC_92HD73XX_ASUS_MOBO,
|
||||
|
@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
|
|||
codec->no_jack_detect = 1;
|
||||
}
|
||||
|
||||
|
||||
static void stac92hd73xx_disable_automute(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
if (action != HDA_FIXUP_ACT_PRE_PROBE)
|
||||
return;
|
||||
|
||||
spec->gen.suppress_auto_mute = 1;
|
||||
}
|
||||
|
||||
static const struct hda_fixup stac92hd73xx_fixups[] = {
|
||||
[STAC_92HD73XX_REF] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
|
@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = stac92hd73xx_fixup_alienware_m17x,
|
||||
},
|
||||
[STAC_ELO_VUPOINT_15MX] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = stac92hd73xx_disable_automute,
|
||||
},
|
||||
[STAC_92HD73XX_INTEL] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = intel_dg45id_pin_configs,
|
||||
|
@ -1942,6 +1959,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
|
|||
{ .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
|
||||
{ .id = STAC_DELL_EQ, .name = "dell-eq" },
|
||||
{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
|
||||
{ .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
|
||||
{ .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
|
||||
{}
|
||||
};
|
||||
|
@ -1991,6 +2009,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
|
|||
"Alienware M17x", STAC_ALIENWARE_M17X),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
|
||||
"Alienware M17x R3", STAC_DELL_EQ),
|
||||
SND_PCI_QUIRK(0x1059, 0x1011,
|
||||
"ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
|
||||
"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
|
|
@ -38,11 +38,6 @@
|
|||
#include <sound/ac97_codec.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/initval.h>
|
||||
/* for 440MX workaround */
|
||||
#include <asm/pgtable.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/set_memory.h>
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
|
||||
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
|
||||
|
@ -374,7 +369,6 @@ struct ichdev {
|
|||
unsigned int ali_slot; /* ALI DMA slot */
|
||||
struct ac97_pcm *pcm;
|
||||
int pcm_open_flag;
|
||||
unsigned int page_attr_changed: 1;
|
||||
unsigned int suspended: 1;
|
||||
};
|
||||
|
||||
|
@ -724,25 +718,6 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
|
|||
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
/*
|
||||
* Intel 82443MX running a 100MHz processor system bus has a hardware bug,
|
||||
* which aborts PCI busmaster for audio transfer. A workaround is to set
|
||||
* the pages as non-cached. For details, see the errata in
|
||||
* http://download.intel.com/design/chipsets/specupdt/24505108.pdf
|
||||
*/
|
||||
static void fill_nocache(void *buf, int size, int nocache)
|
||||
{
|
||||
size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
if (nocache)
|
||||
set_pages_uc(virt_to_page(buf), size);
|
||||
else
|
||||
set_pages_wb(virt_to_page(buf), size);
|
||||
}
|
||||
#else
|
||||
#define fill_nocache(buf, size, nocache) do { ; } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt handler
|
||||
*/
|
||||
|
@ -850,7 +825,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
|
|||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
ichdev->suspended = 0;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
val = ICH_IOCE | ICH_STARTBM;
|
||||
|
@ -858,7 +833,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
|
|||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
ichdev->suspended = 1;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
val = 0;
|
||||
break;
|
||||
|
@ -892,7 +867,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
|
|||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
ichdev->suspended = 0;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
|
@ -909,7 +884,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
|
|||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
ichdev->suspended = 1;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
/* pause */
|
||||
|
@ -938,23 +913,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
|
||||
struct ichdev *ichdev = get_ichdev(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int dbl = params_rate(hw_params) > 48000;
|
||||
int err;
|
||||
|
||||
if (chip->fix_nocache && ichdev->page_attr_changed) {
|
||||
fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */
|
||||
ichdev->page_attr_changed = 0;
|
||||
}
|
||||
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (chip->fix_nocache) {
|
||||
if (runtime->dma_area && ! ichdev->page_attr_changed) {
|
||||
fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
|
||||
ichdev->page_attr_changed = 1;
|
||||
}
|
||||
}
|
||||
if (ichdev->pcm_open_flag) {
|
||||
snd_ac97_pcm_close(ichdev->pcm);
|
||||
ichdev->pcm_open_flag = 0;
|
||||
|
@ -974,17 +938,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
|
||||
struct ichdev *ichdev = get_ichdev(substream);
|
||||
|
||||
if (ichdev->pcm_open_flag) {
|
||||
snd_ac97_pcm_close(ichdev->pcm);
|
||||
ichdev->pcm_open_flag = 0;
|
||||
}
|
||||
if (chip->fix_nocache && ichdev->page_attr_changed) {
|
||||
fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0);
|
||||
ichdev->page_attr_changed = 0;
|
||||
}
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
|
@ -1510,6 +1469,9 @@ struct ich_pcm_table {
|
|||
int ac97_idx;
|
||||
};
|
||||
|
||||
#define intel8x0_dma_type(chip) \
|
||||
((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV)
|
||||
|
||||
static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
|
||||
struct ich_pcm_table *rec)
|
||||
{
|
||||
|
@ -1540,7 +1502,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
|
|||
strcpy(pcm->name, chip->card->shortname);
|
||||
chip->pcm[device] = pcm;
|
||||
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip),
|
||||
snd_dma_pci_data(chip->pci),
|
||||
rec->prealloc_size, rec->prealloc_max_size);
|
||||
|
||||
|
@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
|
|||
__hw_end:
|
||||
if (chip->irq >= 0)
|
||||
free_irq(chip->irq, chip);
|
||||
if (chip->bdbars.area) {
|
||||
if (chip->fix_nocache)
|
||||
fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
|
||||
if (chip->bdbars.area)
|
||||
snd_dma_free_pages(&chip->bdbars);
|
||||
}
|
||||
if (chip->addr)
|
||||
pci_iounmap(chip->pci, chip->addr);
|
||||
if (chip->bmaddr)
|
||||
|
@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev)
|
|||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
for (i = 0; i < chip->pcm_devs; i++)
|
||||
snd_pcm_suspend_all(chip->pcm[i]);
|
||||
/* clear nocache */
|
||||
if (chip->fix_nocache) {
|
||||
for (i = 0; i < chip->bdbars_count; i++) {
|
||||
struct ichdev *ichdev = &chip->ichd[i];
|
||||
if (ichdev->substream && ichdev->page_attr_changed) {
|
||||
struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
|
||||
if (runtime->dma_area)
|
||||
fill_nocache(runtime->dma_area, runtime->dma_bytes, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < chip->ncodecs; i++)
|
||||
snd_ac97_suspend(chip->ac97[i]);
|
||||
if (chip->device_type == DEVICE_INTEL_ICH4)
|
||||
|
@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev)
|
|||
ICH_PCM_SPDIF_1011);
|
||||
}
|
||||
|
||||
/* refill nocache */
|
||||
if (chip->fix_nocache)
|
||||
fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
|
||||
|
||||
for (i = 0; i < chip->ncodecs; i++)
|
||||
snd_ac97_resume(chip->ac97[i]);
|
||||
|
||||
/* refill nocache */
|
||||
if (chip->fix_nocache) {
|
||||
for (i = 0; i < chip->bdbars_count; i++) {
|
||||
struct ichdev *ichdev = &chip->ichd[i];
|
||||
if (ichdev->substream && ichdev->page_attr_changed) {
|
||||
struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
|
||||
if (runtime->dma_area)
|
||||
fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* resume status */
|
||||
for (i = 0; i < chip->bdbars_count; i++) {
|
||||
struct ichdev *ichdev = &chip->ichd[i];
|
||||
|
@ -3057,6 +2989,12 @@ static int snd_intel8x0_create(struct snd_card *card,
|
|||
|
||||
chip->inside_vm = snd_intel8x0_inside_vm(pci);
|
||||
|
||||
/*
|
||||
* Intel 82443MX running a 100MHz processor system bus has a hardware
|
||||
* bug, which aborts PCI busmaster for audio transfer. A workaround
|
||||
* is to set the pages as non-cached. For details, see the errata in
|
||||
* http://download.intel.com/design/chipsets/specupdt/24505108.pdf
|
||||
*/
|
||||
if (pci->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
pci->device == PCI_DEVICE_ID_INTEL_440MX)
|
||||
chip->fix_nocache = 1; /* enable workaround */
|
||||
|
@ -3128,7 +3066,7 @@ static int snd_intel8x0_create(struct snd_card *card,
|
|||
|
||||
/* allocate buffer descriptor lists */
|
||||
/* the start of each lists must be aligned to 8 bytes */
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci),
|
||||
chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
|
||||
&chip->bdbars) < 0) {
|
||||
snd_intel8x0_free(chip);
|
||||
|
@ -3137,9 +3075,6 @@ static int snd_intel8x0_create(struct snd_card *card,
|
|||
}
|
||||
/* tables must be aligned to 8 bytes here, but the kernel pages
|
||||
are much bigger, so we don't care (on i386) */
|
||||
/* workaround for 440MX */
|
||||
if (chip->fix_nocache)
|
||||
fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
|
||||
int_sta_masks = 0;
|
||||
for (i = 0; i < chip->bdbars_count; i++) {
|
||||
ichdev = &chip->ichd[i];
|
||||
|
|
|
@ -1171,16 +1171,6 @@ static int snd_intel8x0m_create(struct snd_card *card,
|
|||
}
|
||||
|
||||
port_inited:
|
||||
if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, chip)) {
|
||||
dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_intel8x0m_free(chip);
|
||||
return -EBUSY;
|
||||
}
|
||||
chip->irq = pci->irq;
|
||||
pci_set_master(pci);
|
||||
synchronize_irq(chip->irq);
|
||||
|
||||
/* initialize offsets */
|
||||
chip->bdbars_count = 2;
|
||||
tbl = intel_regs;
|
||||
|
@ -1224,11 +1214,21 @@ static int snd_intel8x0m_create(struct snd_card *card,
|
|||
chip->int_sta_reg = ICH_REG_GLOB_STA;
|
||||
chip->int_sta_mask = int_sta_masks;
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
|
||||
snd_intel8x0m_free(chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, chip)) {
|
||||
dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_intel8x0m_free(chip);
|
||||
return -EBUSY;
|
||||
}
|
||||
chip->irq = pci->irq;
|
||||
|
||||
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
|
||||
snd_intel8x0m_free(chip);
|
||||
return err;
|
||||
|
|
|
@ -319,7 +319,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_info = {
|
|||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE),
|
||||
.rates = (SNDRV_PCM_RATE_32000 |
|
||||
|
@ -346,7 +347,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_info =
|
|||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats= SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = (SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000),
|
||||
|
@ -370,7 +372,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_fd_info = {
|
|||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE),
|
||||
.rates = (SNDRV_PCM_RATE_32000 |
|
||||
|
@ -397,7 +400,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_fd_info =
|
|||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||
.formats= SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = (SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000),
|
||||
|
@ -1104,16 +1108,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
snd_pcm_trigger_done(s, substream);
|
||||
}
|
||||
|
||||
/* prefill playback buffer */
|
||||
if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) {
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s == rme32->playback_substream) {
|
||||
s->ops->ack(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (rme32->running && ! RME32_ISWORKING(rme32))
|
||||
|
|
|
@ -6534,7 +6534,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
|
|||
dev_dbg(card->dev, "Update mixer controls...\n");
|
||||
hdspm_update_simple_mixer_controls(hdspm);
|
||||
|
||||
dev_dbg(card->dev, "Initializeing complete ???\n");
|
||||
dev_dbg(card->dev, "Initializing complete?\n");
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0) {
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#include "../codecs/da7219.h"
|
||||
#include "../codecs/da7219-aad.h"
|
||||
|
||||
#define CZ_PLAT_CLK 25000000
|
||||
#define CZ_PLAT_CLK 48000000
|
||||
#define DUAL_CHANNEL 2
|
||||
|
||||
static struct snd_soc_jack cz_jack;
|
||||
|
@ -75,7 +75,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
|
|||
da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
|
||||
|
||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
||||
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
|
||||
SND_JACK_HEADSET | SND_JACK_LINEOUT |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
||||
&cz_jack, NULL, 0);
|
||||
|
@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
|
|||
.mask = 0,
|
||||
};
|
||||
|
||||
static int cz_da7219_startup(struct snd_pcm_substream *substream)
|
||||
static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
|
|||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->play_i2s_instance = I2S_SP_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->cap_i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->capture_channel = CAP_CHANNEL1;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
@ -162,11 +183,22 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
|
|||
|
||||
static int cz_max_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->play_i2s_instance = I2S_BT_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
|
@ -177,21 +209,43 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
|
|||
|
||||
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->cap_i2s_instance = I2S_BT_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->cap_i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->capture_channel = CAP_CHANNEL0;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
@ -201,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
|
|||
da7219_clk_disable();
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops cz_da7219_play_ops = {
|
||||
.startup = cz_da7219_play_startup,
|
||||
.shutdown = cz_da7219_shutdown,
|
||||
};
|
||||
|
||||
static const struct snd_soc_ops cz_da7219_cap_ops = {
|
||||
.startup = cz_da7219_startup,
|
||||
.startup = cz_da7219_cap_startup,
|
||||
.shutdown = cz_da7219_shutdown,
|
||||
};
|
||||
|
||||
|
@ -233,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
|||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.init = cz_da7219_init,
|
||||
.dpcm_playback = 1,
|
||||
.ops = &cz_da7219_cap_ops,
|
||||
.ops = &cz_da7219_play_ops,
|
||||
},
|
||||
{
|
||||
.name = "amd-da7219-cap",
|
||||
|
|
|
@ -867,8 +867,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
return -EINVAL;
|
||||
|
||||
if (pinfo) {
|
||||
rtd->i2s_instance = pinfo->i2s_instance;
|
||||
rtd->capture_channel = pinfo->capture_channel;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
rtd->i2s_instance = pinfo->play_i2s_instance;
|
||||
} else {
|
||||
rtd->i2s_instance = pinfo->cap_i2s_instance;
|
||||
rtd->capture_channel = pinfo->capture_channel;
|
||||
}
|
||||
}
|
||||
if (adata->asic_type == CHIP_STONEY) {
|
||||
val = acp_reg_read(adata->acp_mmio,
|
||||
|
@ -1036,16 +1040,22 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
|||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
period_bytes = frames_to_bytes(runtime, runtime->period_size);
|
||||
dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
|
||||
if (dscr == rtd->dma_dscr_idx_1)
|
||||
pos = period_bytes;
|
||||
else
|
||||
pos = 0;
|
||||
bytescount = acp_get_byte_count(rtd);
|
||||
if (bytescount > rtd->bytescount)
|
||||
if (bytescount >= rtd->bytescount)
|
||||
bytescount -= rtd->bytescount;
|
||||
delay = do_div(bytescount, period_bytes);
|
||||
runtime->delay = bytes_to_frames(runtime, delay);
|
||||
if (bytescount < period_bytes) {
|
||||
pos = 0;
|
||||
} else {
|
||||
dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
|
||||
if (dscr == rtd->dma_dscr_idx_1)
|
||||
pos = period_bytes;
|
||||
else
|
||||
pos = 0;
|
||||
}
|
||||
if (bytescount > 0) {
|
||||
delay = do_div(bytescount, period_bytes);
|
||||
runtime->delay = bytes_to_frames(runtime, delay);
|
||||
}
|
||||
} else {
|
||||
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
||||
bytescount = acp_get_byte_count(rtd);
|
||||
|
|
|
@ -158,7 +158,8 @@ struct audio_drv_data {
|
|||
* and dma driver
|
||||
*/
|
||||
struct acp_platform_info {
|
||||
u16 i2s_instance;
|
||||
u16 play_i2s_instance;
|
||||
u16 cap_i2s_instance;
|
||||
u16 capture_channel;
|
||||
};
|
||||
|
||||
|
|
|
@ -97,4 +97,16 @@ config SND_ATMEL_SOC_I2S
|
|||
help
|
||||
Say Y or M if you want to add support for Atmel ASoc driver for boards
|
||||
using I2S.
|
||||
|
||||
config SND_SOC_MIKROE_PROTO
|
||||
tristate "Support for Mikroe-PROTO board"
|
||||
depends on OF
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8731
|
||||
help
|
||||
Say Y or M if you want to add support for MikroElektronika PROTO Audio
|
||||
Board. This board contains the WM8731 codec, which can be configured
|
||||
using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins.
|
||||
Both playback and capture are supported.
|
||||
|
||||
endif
|
||||
|
|
|
@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
|
|||
snd-atmel-soc-classd-objs := atmel-classd.o
|
||||
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
|
||||
snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
|
||||
snd-soc-mikroe-proto-objs := mikroe-proto.o
|
||||
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
|
||||
|
@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
|
|||
obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
|
||||
obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o
|
||||
|
|
|
@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev)
|
|||
struct ssc_device *ssc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_register_component(dev, &atmel_ssc_component,
|
||||
ret = devm_snd_soc_register_component(dev, &atmel_ssc_component,
|
||||
&atmel_ssc_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register DAI: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ssc->pdata->use_dma)
|
||||
|
@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev)
|
|||
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register PCM: %d\n", ret);
|
||||
goto err_unregister_dai;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_dai:
|
||||
snd_soc_unregister_component(dev);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asoc_ssc_exit(struct device *dev)
|
||||
|
@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev)
|
|||
atmel_pcm_dma_platform_unregister(dev);
|
||||
else
|
||||
atmel_pcm_pdc_platform_unregister(dev);
|
||||
|
||||
snd_soc_unregister_component(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* ASoC driver for PROTO AudioCODEC (with a WM8731)
|
||||
*
|
||||
* Author: Florian Meier, <koalo@koalo.de>
|
||||
* Copyright 2013
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
#include "../codecs/wm8731.h"
|
||||
|
||||
#define XTAL_RATE 12288000 /* This is fixed on this board */
|
||||
|
||||
static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
|
||||
/* Set proto sysclk */
|
||||
int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
XTAL_RATE, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget snd_proto_widget[] = {
|
||||
SND_SOC_DAPM_MIC("Microphone Jack", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route snd_proto_route[] = {
|
||||
/* speaker connected to LHPOUT/RHPOUT */
|
||||
{"Headphone Jack", NULL, "LHPOUT"},
|
||||
{"Headphone Jack", NULL, "RHPOUT"},
|
||||
|
||||
/* mic is connected to Mic Jack, with WM8731 Mic Bias */
|
||||
{"MICIN", NULL, "Mic Bias"},
|
||||
{"Mic Bias", NULL, "Microphone Jack"},
|
||||
};
|
||||
|
||||
/* audio machine driver */
|
||||
static struct snd_soc_card snd_proto = {
|
||||
.name = "snd_mikroe_proto",
|
||||
.owner = THIS_MODULE,
|
||||
.dapm_widgets = snd_proto_widget,
|
||||
.num_dapm_widgets = ARRAY_SIZE(snd_proto_widget),
|
||||
.dapm_routes = snd_proto_route,
|
||||
.num_dapm_routes = ARRAY_SIZE(snd_proto_route),
|
||||
};
|
||||
|
||||
static int snd_proto_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_dai_link *dai;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *codec_np, *cpu_np;
|
||||
struct device_node *bitclkmaster = NULL;
|
||||
struct device_node *framemaster = NULL;
|
||||
unsigned int dai_fmt;
|
||||
int ret = 0;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "No device node supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_proto.dev = &pdev->dev;
|
||||
ret = snd_soc_of_parse_card_name(&snd_proto, "model");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
|
||||
if (!dai)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_proto.dai_link = dai;
|
||||
snd_proto.num_links = 1;
|
||||
|
||||
dai->name = "WM8731";
|
||||
dai->stream_name = "WM8731 HiFi";
|
||||
dai->codec_dai_name = "wm8731-hifi";
|
||||
dai->init = &snd_proto_init;
|
||||
|
||||
codec_np = of_parse_phandle(np, "audio-codec", 0);
|
||||
if (!codec_np) {
|
||||
dev_err(&pdev->dev, "audio-codec node missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dai->codec_of_node = codec_np;
|
||||
|
||||
cpu_np = of_parse_phandle(np, "i2s-controller", 0);
|
||||
if (!cpu_np) {
|
||||
dev_err(&pdev->dev, "i2s-controller missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dai->cpu_of_node = cpu_np;
|
||||
dai->platform_of_node = cpu_np;
|
||||
|
||||
dai_fmt = snd_soc_of_parse_daifmt(np, NULL,
|
||||
&bitclkmaster, &framemaster);
|
||||
if (bitclkmaster != framemaster) {
|
||||
dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bitclkmaster) {
|
||||
dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
|
||||
if (codec_np == bitclkmaster)
|
||||
dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
|
||||
else
|
||||
dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
|
||||
}
|
||||
of_node_put(bitclkmaster);
|
||||
of_node_put(framemaster);
|
||||
dai->dai_fmt = dai_fmt;
|
||||
|
||||
of_node_put(codec_np);
|
||||
of_node_put(cpu_np);
|
||||
|
||||
ret = snd_soc_register_card(&snd_proto);
|
||||
if (ret && ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"snd_soc_register_card() failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int snd_proto_remove(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_unregister_card(&snd_proto);
|
||||
}
|
||||
|
||||
static const struct of_device_id snd_proto_of_match[] = {
|
||||
{ .compatible = "mikroe,mikroe-proto", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, snd_proto_of_match);
|
||||
|
||||
static struct platform_driver snd_proto_driver = {
|
||||
.driver = {
|
||||
.name = "snd-mikroe-proto",
|
||||
.of_match_table = snd_proto_of_match,
|
||||
},
|
||||
.probe = snd_proto_probe,
|
||||
.remove = snd_proto_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(snd_proto_driver);
|
||||
|
||||
MODULE_AUTHOR("Florian Meier");
|
||||
MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
|
||||
MODULE_LICENSE("GPL");
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue