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
|
Usage: required for mi2s interface
|
||||||
Value type: <prop-encoded-array>
|
Value type: <prop-encoded-array>
|
||||||
Definition: Must be list of serial data lines used by this dai.
|
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:
|
- qcom,tdm-sync-mode:
|
||||||
Usage: required for tdm interface
|
Usage: required for tdm interface
|
||||||
|
@ -137,42 +137,42 @@ q6afe@4 {
|
||||||
|
|
||||||
prim-mi2s-rx@16 {
|
prim-mi2s-rx@16 {
|
||||||
reg = <16>;
|
reg = <16>;
|
||||||
qcom,sd-lines = <1 3>;
|
qcom,sd-lines = <0 2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
prim-mi2s-tx@17 {
|
prim-mi2s-tx@17 {
|
||||||
reg = <17>;
|
reg = <17>;
|
||||||
qcom,sd-lines = <2>;
|
qcom,sd-lines = <1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
sec-mi2s-rx@18 {
|
sec-mi2s-rx@18 {
|
||||||
reg = <18>;
|
reg = <18>;
|
||||||
qcom,sd-lines = <1 4>;
|
qcom,sd-lines = <0 3>;
|
||||||
};
|
};
|
||||||
|
|
||||||
sec-mi2s-tx@19 {
|
sec-mi2s-tx@19 {
|
||||||
reg = <19>;
|
reg = <19>;
|
||||||
qcom,sd-lines = <2>;
|
qcom,sd-lines = <1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tert-mi2s-rx@20 {
|
tert-mi2s-rx@20 {
|
||||||
reg = <20>;
|
reg = <20>;
|
||||||
qcom,sd-lines = <2 4>;
|
qcom,sd-lines = <1 3>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tert-mi2s-tx@21 {
|
tert-mi2s-tx@21 {
|
||||||
reg = <21>;
|
reg = <21>;
|
||||||
qcom,sd-lines = <1>;
|
qcom,sd-lines = <0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
quat-mi2s-rx@22 {
|
quat-mi2s-rx@22 {
|
||||||
reg = <22>;
|
reg = <22>;
|
||||||
qcom,sd-lines = <1>;
|
qcom,sd-lines = <0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
quat-mi2s-tx@23 {
|
quat-mi2s-tx@23 {
|
||||||
reg = <23>;
|
reg = <23>;
|
||||||
qcom,sd-lines = <2>;
|
qcom,sd-lines = <1>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -340,10 +340,12 @@ Required properties:
|
||||||
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
||||||
"renesas,rcar_sound-gen1" if generation1, and
|
"renesas,rcar_sound-gen1" if generation1, and
|
||||||
"renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
|
"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:
|
Examples with soctypes are:
|
||||||
- "renesas,rcar_sound-r8a7743" (RZ/G1M)
|
- "renesas,rcar_sound-r8a7743" (RZ/G1M)
|
||||||
|
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
|
||||||
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||||
|
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
|
||||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||||
|
@ -353,6 +355,7 @@ Required properties:
|
||||||
- "renesas,rcar_sound-r8a7795" (R-Car H3)
|
- "renesas,rcar_sound-r8a7795" (R-Car H3)
|
||||||
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
||||||
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
|
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
|
||||||
|
- "renesas,rcar_sound-r8a77990" (R-Car E3)
|
||||||
- reg : Should contain the register physical address.
|
- reg : Should contain the register physical address.
|
||||||
required register is
|
required register is
|
||||||
SRU/ADG/SSI if generation1
|
SRU/ADG/SSI if generation1
|
||||||
|
|
|
@ -19,6 +19,10 @@ Required properties:
|
||||||
|
|
||||||
Optional 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:
|
- st,output-conf: number, Selects the output configuration:
|
||||||
0: 2-channel (full-bridge) power, 2-channel data-out
|
0: 2-channel (full-bridge) power, 2-channel data-out
|
||||||
1: 2 (half-bridge). 1 (full-bridge) on-board power
|
1: 2 (half-bridge). 1 (full-bridge) on-board power
|
||||||
|
@ -39,6 +43,9 @@ Optional properties:
|
||||||
- st,thermal-warning-recover:
|
- st,thermal-warning-recover:
|
||||||
If present, thermal warning recovery is enabled.
|
If present, thermal warning recovery is enabled.
|
||||||
|
|
||||||
|
- st,fault-detect-recovery:
|
||||||
|
If present, fault detect recovery is enabled.
|
||||||
|
|
||||||
- st,thermal-warning-adjustment:
|
- st,thermal-warning-adjustment:
|
||||||
If present, thermal warning adjustment is enabled.
|
If present, thermal warning adjustment is enabled.
|
||||||
|
|
||||||
|
@ -76,6 +83,8 @@ Example:
|
||||||
codec: sta32x@38 {
|
codec: sta32x@38 {
|
||||||
compatible = "st,sta32x";
|
compatible = "st,sta32x";
|
||||||
reg = <0x1c>;
|
reg = <0x1c>;
|
||||||
|
clocks = <&clock>;
|
||||||
|
clock-names = "xti";
|
||||||
reset-gpios = <&gpio1 19 0>;
|
reset-gpios = <&gpio1 19 0>;
|
||||||
power-down-gpios = <&gpio1 16 0>;
|
power-down-gpios = <&gpio1 16 0>;
|
||||||
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
|
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.
|
- reg: Base address and size of SAI sub-block register set.
|
||||||
- clocks: Must contain one phandle and clock specifier pair
|
- clocks: Must contain one phandle and clock specifier pair
|
||||||
for sai_ck which feeds the internal clock generator.
|
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".
|
- 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
|
- dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
|
||||||
- dma-names: identifier string for each DMA request line
|
- dma-names: identifier string for each DMA request line
|
||||||
"tx": if sai sub-block is configured as playback DAI
|
"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,
|
configured according to protocol defined in related DAI link node,
|
||||||
such as i2s, left justified, right justified, dsp and pdm protocols.
|
such as i2s, left justified, right justified, dsp and pdm protocols.
|
||||||
Note: ac97 protocol is not supported by SAI driver
|
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'
|
The device node should contain one 'port' child node with one child 'endpoint'
|
||||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||||
|
|
|
@ -10,6 +10,7 @@ Required properties:
|
||||||
- "allwinner,sun6i-a31-i2s"
|
- "allwinner,sun6i-a31-i2s"
|
||||||
- "allwinner,sun8i-a83t-i2s"
|
- "allwinner,sun8i-a83t-i2s"
|
||||||
- "allwinner,sun8i-h3-i2s"
|
- "allwinner,sun8i-h3-i2s"
|
||||||
|
- "allwinner,sun50i-a64-codec-i2s"
|
||||||
- reg: physical base address of the controller and length of memory mapped
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
- interrupts: should contain the I2S interrupt.
|
- interrupts: should contain the I2S interrupt.
|
||||||
|
@ -26,6 +27,7 @@ Required properties for the following compatibles:
|
||||||
- "allwinner,sun6i-a31-i2s"
|
- "allwinner,sun6i-a31-i2s"
|
||||||
- "allwinner,sun8i-a83t-i2s"
|
- "allwinner,sun8i-a83t-i2s"
|
||||||
- "allwinner,sun8i-h3-i2s"
|
- "allwinner,sun8i-h3-i2s"
|
||||||
|
- "allwinner,sun50i-a64-codec-i2s"
|
||||||
- resets: phandle to the reset line for this codec
|
- resets: phandle to the reset line for this codec
|
||||||
|
|
||||||
Example:
|
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:
|
Optional properies:
|
||||||
- ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7).
|
- 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
|
2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
|
||||||
Default value is "1" (2.2V).
|
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)
|
atmel,at97sc3204t i2c trusted platform module (TPM)
|
||||||
capella,cm32181 CM32181: Ambient Light Sensor
|
capella,cm32181 CM32181: Ambient Light Sensor
|
||||||
capella,cm3232 CM3232: 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,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
|
||||||
dallas,ds1631 High-Precision Digital Thermometer
|
dallas,ds1631 High-Precision Digital Thermometer
|
||||||
dallas,ds1672 Dallas DS1672 Real-time Clock
|
dallas,ds1672 Dallas DS1672 Real-time Clock
|
||||||
|
|
|
@ -235,6 +235,7 @@ micrel Micrel Inc.
|
||||||
microchip Microchip Technology Inc.
|
microchip Microchip Technology Inc.
|
||||||
microcrystal Micro Crystal AG
|
microcrystal Micro Crystal AG
|
||||||
micron Micron Technology Inc.
|
micron Micron Technology Inc.
|
||||||
|
mikroe MikroElektronika d.o.o.
|
||||||
minix MINIX Technology Ltd.
|
minix MINIX Technology Ltd.
|
||||||
miramems MiraMEMS Sensing Technology Co., Ltd.
|
miramems MiraMEMS Sensing Technology Co., Ltd.
|
||||||
mitsubishi Mitsubishi Electric Corporation
|
mitsubishi Mitsubishi Electric Corporation
|
||||||
|
|
|
@ -309,6 +309,8 @@ asus-nx50
|
||||||
ASUS Nx50 fixups
|
ASUS Nx50 fixups
|
||||||
asus-nx51
|
asus-nx51
|
||||||
ASUS Nx51 fixups
|
ASUS Nx51 fixups
|
||||||
|
asus-g751
|
||||||
|
ASUS G751 fixups
|
||||||
alc891-headset
|
alc891-headset
|
||||||
Headset mode support on ALC891
|
Headset mode support on ALC891
|
||||||
alc891-headset-multi
|
alc891-headset-multi
|
||||||
|
|
|
@ -3,8 +3,6 @@ Writing an ALSA Driver
|
||||||
======================
|
======================
|
||||||
|
|
||||||
:Author: Takashi Iwai <tiwai@suse.de>
|
:Author: Takashi Iwai <tiwai@suse.de>
|
||||||
:Date: Oct 15, 2007
|
|
||||||
:Edition: 0.3.7
|
|
||||||
|
|
||||||
Preface
|
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
|
low-level driver implementation details. It only describes the standard
|
||||||
way to write a PCI sound driver on ALSA.
|
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,
|
This document is still a draft version. Any feedback and corrections,
|
||||||
please!!
|
please!!
|
||||||
|
|
||||||
|
@ -35,24 +28,7 @@ File Tree Structure
|
||||||
General
|
General
|
||||||
-------
|
-------
|
||||||
|
|
||||||
The ALSA drivers are provided in two ways.
|
The file tree structure of ALSA driver is depicted below.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
@ -61,14 +37,11 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
|
||||||
/oss
|
/oss
|
||||||
/seq
|
/seq
|
||||||
/oss
|
/oss
|
||||||
/instr
|
|
||||||
/ioctl32
|
|
||||||
/include
|
/include
|
||||||
/drivers
|
/drivers
|
||||||
/mpu401
|
/mpu401
|
||||||
/opl3
|
/opl3
|
||||||
/i2c
|
/i2c
|
||||||
/l3
|
|
||||||
/synth
|
/synth
|
||||||
/emux
|
/emux
|
||||||
/pci
|
/pci
|
||||||
|
@ -80,6 +53,7 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
|
||||||
/sparc
|
/sparc
|
||||||
/usb
|
/usb
|
||||||
/pcmcia /(cards)
|
/pcmcia /(cards)
|
||||||
|
/soc
|
||||||
/oss
|
/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
|
code since it's quite small. The sequencer code is stored in
|
||||||
``core/seq/oss`` directory (see `below <#core-seq-oss>`__).
|
``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
|
core/seq
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
@ -119,11 +86,6 @@ core/seq/oss
|
||||||
|
|
||||||
This contains the OSS sequencer emulation codes.
|
This contains the OSS sequencer emulation codes.
|
||||||
|
|
||||||
core/seq/instr
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
This directory contains the modules for the sequencer instrument layer.
|
|
||||||
|
|
||||||
include directory
|
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
|
code for some cards, because the soundcard needs only a simple operation
|
||||||
and the standard i2c API is too complicated for such a purpose.
|
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
|
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
|
be in the pci directory, because their API is identical to that of
|
||||||
standard PCI cards.
|
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
|
oss directory
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The OSS/Lite source files are stored here in Linux 2.6 (or later) tree.
|
Here contains OSS/Lite codes.
|
||||||
In the ALSA driver tarball, this directory is empty, of course :)
|
All codes have been deprecated except for dmasound on m68k as of
|
||||||
|
writing this.
|
||||||
|
|
||||||
|
|
||||||
Basic Flow for PCI Drivers
|
Basic Flow for PCI Drivers
|
||||||
==========================
|
==========================
|
||||||
|
@ -352,10 +317,8 @@ to details explained in the following section.
|
||||||
|
|
||||||
/* (3) */
|
/* (3) */
|
||||||
err = snd_mychip_create(card, pci, &chip);
|
err = snd_mychip_create(card, pci, &chip);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_card_free(card);
|
goto error;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (4) */
|
/* (4) */
|
||||||
strcpy(card->driver, "My Chip");
|
strcpy(card->driver, "My Chip");
|
||||||
|
@ -368,22 +331,23 @@ to details explained in the following section.
|
||||||
|
|
||||||
/* (6) */
|
/* (6) */
|
||||||
err = snd_card_register(card);
|
err = snd_card_register(card);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_card_free(card);
|
goto error;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (7) */
|
/* (7) */
|
||||||
pci_set_drvdata(pci, card);
|
pci_set_drvdata(pci, card);
|
||||||
dev++;
|
dev++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
snd_card_free(card);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destructor -- see the "Destructor" sub-section */
|
/* destructor -- see the "Destructor" sub-section */
|
||||||
static void snd_mychip_remove(struct pci_dev *pci)
|
static void snd_mychip_remove(struct pci_dev *pci)
|
||||||
{
|
{
|
||||||
snd_card_free(pci_get_drvdata(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;
|
struct mychip *chip;
|
||||||
....
|
....
|
||||||
err = snd_mychip_create(card, pci, &chip);
|
err = snd_mychip_create(card, pci, &chip);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_card_free(card);
|
goto error;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
The details will be explained in the section `PCI Resource
|
The details will be explained in the section `PCI Resource
|
||||||
Management`_.
|
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.
|
4) Set the driver ID and name strings.
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -486,10 +462,8 @@ too.
|
||||||
::
|
::
|
||||||
|
|
||||||
err = snd_card_register(card);
|
err = snd_card_register(card);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_card_free(card);
|
goto error;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
Will be explained in the section `Management of Cards and
|
Will be explained in the section `Management of Cards and
|
||||||
Components`_, too.
|
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
|
the ALSA middle layer will release all the attached components
|
||||||
automatically.
|
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)
|
static void snd_mychip_remove(struct pci_dev *pci)
|
||||||
{
|
{
|
||||||
snd_card_free(pci_get_drvdata(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.
|
without module options don't need them.
|
||||||
|
|
||||||
In addition to these headers, you'll need ``<linux/interrupt.h>`` for
|
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
|
:c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need
|
||||||
to include ``<linux/delay.h>`` too.
|
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.
|
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
|
Registration and Release
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -905,10 +885,8 @@ Resource Allocation
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
The allocation of I/O ports and irqs is done via standard kernel
|
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
|
functions. These resources must be released in the destructor
|
||||||
these resources must be released in the destructor function (see below).
|
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.
|
|
||||||
|
|
||||||
Now assume that the PCI device has an I/O port with 8 bytes and an
|
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
|
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);
|
kfree(chip);
|
||||||
return err;
|
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
|
PCI Entries
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -1154,13 +1148,6 @@ And at last, the module entries:
|
||||||
Note that these module entries are tagged with ``__init`` and ``__exit``
|
Note that these module entries are tagged with ``__init`` and ``__exit``
|
||||||
prefixes.
|
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!
|
That's all!
|
||||||
|
|
||||||
PCM Interface
|
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
|
address. Some examples will be explained in the later section `Buffer
|
||||||
and Memory Management`_, too.
|
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
|
PCM Interrupt Handler
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
@ -2370,6 +2367,27 @@ to define the inverse rule:
|
||||||
hw_rule_format_by_channels, NULL,
|
hw_rule_format_by_channels, NULL,
|
||||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
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
|
I won't give more details here, rather I would like to say, “Luke, use
|
||||||
the source.”
|
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
|
contiguous, you need to set the ``page`` callback to obtain the physical
|
||||||
address at every offset.
|
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
|
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
|
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
|
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
|
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 __maybe_unused snd_my_suspend(struct device *dev)
|
||||||
static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
|
|
||||||
{
|
{
|
||||||
.... /* do things for suspend */
|
.... /* do things for suspend */
|
||||||
return 0;
|
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 */
|
.... /* do things for suspend */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
The scheme of the real suspend job is as follows.
|
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.
|
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:
|
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) */
|
/* (1) */
|
||||||
struct snd_card *card = pci_get_drvdata(pci);
|
struct snd_card *card = dev_get_drvdata(dev);
|
||||||
struct mychip *chip = card->private_data;
|
struct mychip *chip = card->private_data;
|
||||||
/* (2) */
|
/* (2) */
|
||||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||||
|
@ -3932,9 +3953,6 @@ A typical code would be like:
|
||||||
snd_mychip_save_registers(chip);
|
snd_mychip_save_registers(chip);
|
||||||
/* (6) */
|
/* (6) */
|
||||||
snd_mychip_stop_hardware(chip);
|
snd_mychip_stop_hardware(chip);
|
||||||
/* (7) */
|
|
||||||
pci_disable_device(pci);
|
|
||||||
pci_save_state(pci);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3943,44 +3961,35 @@ The scheme of the real resume job is as follows.
|
||||||
|
|
||||||
1. Retrieve the card and the chip data.
|
1. Retrieve the card and the chip data.
|
||||||
|
|
||||||
2. Set up PCI. First, call :c:func:`pci_restore_state()`. Then
|
2. Re-initialize the chip.
|
||||||
enable the pci device again by calling
|
|
||||||
:c:func:`pci_enable_device()`. Call
|
|
||||||
:c:func:`pci_set_master()` if necessary, too.
|
|
||||||
|
|
||||||
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).
|
6. Call :c:func:`snd_power_change_state()` with
|
||||||
|
|
||||||
7. Call :c:func:`snd_power_change_state()` with
|
|
||||||
``SNDRV_CTL_POWER_D0`` to notify the processes.
|
``SNDRV_CTL_POWER_D0`` to notify the processes.
|
||||||
|
|
||||||
A typical code would be like:
|
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) */
|
/* (1) */
|
||||||
struct snd_card *card = pci_get_drvdata(pci);
|
struct snd_card *card = dev_get_drvdata(dev);
|
||||||
struct mychip *chip = card->private_data;
|
struct mychip *chip = card->private_data;
|
||||||
/* (2) */
|
/* (2) */
|
||||||
pci_restore_state(pci);
|
|
||||||
pci_enable_device(pci);
|
|
||||||
pci_set_master(pci);
|
|
||||||
/* (3) */
|
|
||||||
snd_mychip_reinit_chip(chip);
|
snd_mychip_reinit_chip(chip);
|
||||||
/* (4) */
|
/* (3) */
|
||||||
snd_mychip_restore_registers(chip);
|
snd_mychip_restore_registers(chip);
|
||||||
/* (5) */
|
/* (4) */
|
||||||
snd_ac97_resume(chip->ac97);
|
snd_ac97_resume(chip->ac97);
|
||||||
/* (6) */
|
/* (5) */
|
||||||
snd_mychip_restart_chip(chip);
|
snd_mychip_restart_chip(chip);
|
||||||
/* (7) */
|
/* (6) */
|
||||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||||
return 0;
|
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 = {
|
static struct pci_driver driver = {
|
||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = snd_my_ids,
|
.id_table = snd_my_ids,
|
||||||
.probe = snd_my_probe,
|
.probe = snd_my_probe,
|
||||||
.remove = snd_my_remove,
|
.remove = snd_my_remove,
|
||||||
#ifdef CONFIG_PM
|
.driver.pm = &snd_my_pm_ops,
|
||||||
.suspend = snd_my_suspend,
|
|
||||||
.resume = snd_my_resume,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Module Parameters
|
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.
|
case, but it would be better to have a dummy option for compatibility.
|
||||||
|
|
||||||
The module parameters must be declared with the standard
|
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.
|
:c:func:`MODULE_PARM_DESC()` macros.
|
||||||
|
|
||||||
The typical coding would be like below:
|
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_param_array(enable, bool, NULL, 0444);
|
||||||
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
|
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
|
||||||
|
|
||||||
Also, don't forget to define the module description, classes, license
|
Also, don't forget to define the module description and the license.
|
||||||
and devices. Especially, the recent modprobe requires to define the
|
Especially, the recent modprobe requires to define the
|
||||||
module license as GPL, etc., otherwise the system is shown as “tainted”.
|
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_LICENSE("GPL");
|
||||||
MODULE_SUPPORTED_DEVICE("{{Vendor,My Chip Name}}");
|
|
||||||
|
|
||||||
|
|
||||||
How To Put Your Driver Into ALSA Tree
|
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
|
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
|
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
|
alsa-driver tree, ``sound/pci`` directory in the case of PCI
|
||||||
cards. Then the driver is evaluated, audited and tested by developers
|
cards.
|
||||||
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``).
|
|
||||||
|
|
||||||
In the following sections, the driver code is supposed to be put into
|
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.
|
single source file and one consisting of several source files.
|
||||||
|
|
||||||
Driver with A Single Source File
|
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
|
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.
|
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
|
Drivers with Several Source Files
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
Suppose that the driver snd-xyz have several source files. They are
|
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
|
1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile``
|
||||||
below
|
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
|
snd-xyz-objs := xyz.o abc.o def.o
|
||||||
|
|
||||||
obj-$(CONFIG_SND_XYZ) += snd-xyz.o
|
obj-$(CONFIG_SND_XYZ) += snd-xyz.o
|
||||||
|
|
||||||
include $(SND_TOPDIR)/Rules.make
|
|
||||||
|
|
||||||
3. Create the Kconfig entry
|
3. Create the Kconfig entry
|
||||||
|
|
||||||
This procedure is as same as in the last section.
|
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
|
Useful Functions
|
||||||
================
|
================
|
||||||
|
|
||||||
:c:func:`snd_printk()` and friends
|
: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.
|
ALSA provides a verbose version of the :c:func:`printk()` function.
|
||||||
If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this 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.
|
the debugging flag, it's ignored.
|
||||||
|
|
||||||
:c:func:`snd_printdd()` is compiled in only when
|
:c:func:`snd_printdd()` is compiled in only when
|
||||||
``CONFIG_SND_DEBUG_VERBOSE`` is set. Please note that
|
``CONFIG_SND_DEBUG_VERBOSE`` is set.
|
||||||
``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.
|
|
||||||
|
|
||||||
:c:func:`snd_BUG()`
|
:c:func:`snd_BUG()`
|
||||||
------------------------
|
-------------------
|
||||||
|
|
||||||
It shows the ``BUG?`` message and stack trace as well as
|
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
|
: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.
|
When no debug flag is set, this macro is ignored.
|
||||||
|
|
||||||
:c:func:`snd_BUG_ON()`
|
:c:func:`snd_BUG_ON()`
|
||||||
----------------------------
|
----------------------
|
||||||
|
|
||||||
:c:func:`snd_BUG_ON()` macro is similar with
|
:c:func:`snd_BUG_ON()` macro is similar with
|
||||||
:c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or
|
:c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or
|
||||||
|
|
|
@ -14759,6 +14759,13 @@ L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/ethernet/ti/netcp*
|
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
|
TI TAS571X FAMILY ASoC CODEC DRIVER
|
||||||
M: Kevin Cernekee <cernekee@chromium.org>
|
M: Kevin Cernekee <cernekee@chromium.org>
|
||||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
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_UNKNOWN 0 /* not defined */
|
||||||
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
|
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
|
||||||
#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */
|
#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */
|
||||||
|
#define SNDRV_DMA_TYPE_DEV_UC 5 /* continuous non-cahced */
|
||||||
#ifdef CONFIG_SND_DMA_SGBUF
|
#ifdef CONFIG_SND_DMA_SGBUF
|
||||||
#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */
|
#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */
|
||||||
|
#define SNDRV_DMA_TYPE_DEV_UC_SG 6 /* SG non-cached */
|
||||||
#else
|
#else
|
||||||
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */
|
#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
|
#endif
|
||||||
#ifdef CONFIG_GENERIC_ALLOCATOR
|
#ifdef CONFIG_GENERIC_ALLOCATOR
|
||||||
#define SNDRV_DMA_TYPE_DEV_IRAM 4 /* generic device iram-buffer */
|
#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);
|
unsigned char *buffer, int count);
|
||||||
int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
|
int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
|
||||||
int count);
|
int count);
|
||||||
|
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
|
||||||
|
|
||||||
/* main midi functions */
|
/* 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) \
|
#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, \
|
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) \
|
#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,\
|
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,
|
int asoc_simple_card_parse_clk(struct device *dev,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
struct device_node *dai_of_node,
|
struct device_node *dai_of_node,
|
||||||
struct asoc_simple_dai *simple_dai,
|
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);
|
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
|
||||||
void asoc_simple_card_clk_disable(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, \
|
#define asoc_simple_card_parse_cpu(node, dai_link, \
|
||||||
list_name, cells_name, is_single_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)
|
&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) \
|
#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \
|
||||||
asoc_simple_card_parse_dai(node, &dai_link->codec_of_node, \
|
asoc_simple_card_parse_dai(node, dai_link->codecs, \
|
||||||
&dai_link->codec_dai_name, list_name, cells_name, NULL)
|
&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) \
|
#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)
|
NULL, list_name, cells_name, NULL)
|
||||||
int asoc_simple_card_parse_dai(struct device_node *node,
|
int asoc_simple_card_parse_dai(struct device_node *node,
|
||||||
|
struct snd_soc_dai_link_component *dlc,
|
||||||
struct device_node **endpoint_np,
|
struct device_node **endpoint_np,
|
||||||
const char **dai_name,
|
const char **dai_name,
|
||||||
const char *list_name,
|
const char *list_name,
|
||||||
|
@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node,
|
||||||
int *is_single_links);
|
int *is_single_links);
|
||||||
|
|
||||||
#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
|
#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)
|
&dai_link->cpu_dai_name)
|
||||||
#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
|
#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)
|
&dai_link->codec_dai_name)
|
||||||
int asoc_simple_card_parse_graph_dai(struct device_node *ep,
|
int asoc_simple_card_parse_graph_dai(struct device_node *ep,
|
||||||
|
struct snd_soc_dai_link_component *dlc,
|
||||||
struct device_node **endpoint_np,
|
struct device_node **endpoint_np,
|
||||||
const char **dai_name);
|
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_glk_machines[];
|
||||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_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
|
#endif
|
||||||
|
|
|
@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
|
||||||
struct snd_soc_dai *dai);
|
struct snd_soc_dai *dai);
|
||||||
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
|
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);
|
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 */
|
/* dapm path setup */
|
||||||
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
|
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 */
|
void *priv; /* widget specific data */
|
||||||
struct regulator *regulator; /* attached regulator */
|
struct regulator *regulator; /* attached regulator */
|
||||||
struct pinctrl *pinctrl; /* attached pinctrl */
|
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 */
|
/* dapm control */
|
||||||
int reg; /* negative reg = no direct dapm */
|
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 */
|
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 */
|
/* can this BE stop and free */
|
||||||
int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
|
int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
|
||||||
struct snd_soc_pcm_runtime *be, int stream);
|
struct snd_soc_pcm_runtime *be, int stream);
|
||||||
|
|
|
@ -372,6 +372,11 @@
|
||||||
#define SND_SOC_COMP_ORDER_LATE 1
|
#define SND_SOC_COMP_ORDER_LATE 1
|
||||||
#define SND_SOC_COMP_ORDER_LAST 2
|
#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
|
* Bias levels
|
||||||
*
|
*
|
||||||
|
@ -859,6 +864,11 @@ struct snd_soc_component {
|
||||||
#endif
|
#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_rtdcom_list {
|
||||||
struct snd_soc_component *component;
|
struct snd_soc_component *component;
|
||||||
struct list_head list; /* rtd::component_list */
|
struct list_head list; /* rtd::component_list */
|
||||||
|
@ -915,6 +925,8 @@ struct snd_soc_dai_link {
|
||||||
*/
|
*/
|
||||||
const char *platform_name;
|
const char *platform_name;
|
||||||
struct device_node *platform_of_node;
|
struct device_node *platform_of_node;
|
||||||
|
struct snd_soc_dai_link_component *platform;
|
||||||
|
|
||||||
int id; /* optional ID for machine driver link identification */
|
int id; /* optional ID for machine driver link identification */
|
||||||
|
|
||||||
const struct snd_soc_pcm_stream *params;
|
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 list_head list; /* DAI link list of the soc card */
|
||||||
struct snd_soc_dobj dobj; /* For topology */
|
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 {
|
struct snd_soc_codec_conf {
|
||||||
/*
|
/*
|
||||||
|
@ -1054,7 +1070,6 @@ struct snd_soc_card {
|
||||||
struct snd_soc_dai_link *dai_link; /* predefined links only */
|
struct snd_soc_dai_link *dai_link; /* predefined links only */
|
||||||
int num_links; /* predefined links only */
|
int num_links; /* predefined links only */
|
||||||
struct list_head dai_link_list; /* all links */
|
struct list_head dai_link_list; /* all links */
|
||||||
int num_dai_links;
|
|
||||||
|
|
||||||
struct list_head rtd_list;
|
struct list_head rtd_list;
|
||||||
int num_rtd;
|
int num_rtd;
|
||||||
|
@ -1092,6 +1107,7 @@ struct snd_soc_card {
|
||||||
|
|
||||||
/* lists of probed devices belonging to this card */
|
/* lists of probed devices belonging to this card */
|
||||||
struct list_head component_dev_list;
|
struct list_head component_dev_list;
|
||||||
|
struct list_head list;
|
||||||
|
|
||||||
struct list_head widgets;
|
struct list_head widgets;
|
||||||
struct list_head paths;
|
struct list_head paths;
|
||||||
|
@ -1114,6 +1130,23 @@ struct snd_soc_card {
|
||||||
|
|
||||||
void *drvdata;
|
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 */
|
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||||
struct snd_soc_pcm_runtime {
|
struct snd_soc_pcm_runtime {
|
||||||
|
@ -1124,6 +1157,8 @@ struct snd_soc_pcm_runtime {
|
||||||
enum snd_soc_pcm_subclass pcm_subclass;
|
enum snd_soc_pcm_subclass pcm_subclass;
|
||||||
struct snd_pcm_ops ops;
|
struct snd_pcm_ops ops;
|
||||||
|
|
||||||
|
unsigned int params_select; /* currently selected param for dai link */
|
||||||
|
|
||||||
/* Dynamic PCM BE runtime data */
|
/* Dynamic PCM BE runtime data */
|
||||||
struct snd_soc_dpcm_runtime dpcm[2];
|
struct snd_soc_dpcm_runtime dpcm[2];
|
||||||
int fe_compr;
|
int fe_compr;
|
||||||
|
@ -1152,6 +1187,13 @@ struct snd_soc_pcm_runtime {
|
||||||
unsigned int dev_registered:1;
|
unsigned int dev_registered:1;
|
||||||
unsigned int pop_wait: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 */
|
/* mixer control */
|
||||||
struct soc_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->dapm_list);
|
||||||
INIT_LIST_HEAD(&card->aux_comp_list);
|
INIT_LIST_HEAD(&card->aux_comp_list);
|
||||||
INIT_LIST_HEAD(&card->component_dev_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)
|
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 */
|
#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */
|
||||||
|
|
||||||
struct snd_timer_params {
|
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 ticks; /* requested resolution in ticks */
|
||||||
unsigned int queue_size; /* total size of queue (32-1024) */
|
unsigned int queue_size; /* total size of queue (32-1024) */
|
||||||
unsigned int reserved0; /* reserved, was: failure locations */
|
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 device_node *child = NULL, *sound = NULL;
|
||||||
struct resource *r;
|
struct resource *r;
|
||||||
int i, layout = 0, rlen, ok = force;
|
int i, layout = 0, rlen, ok = force;
|
||||||
static const char *rnames[] = { "i2sbus: %s (control)",
|
char node_name[6];
|
||||||
"i2sbus: %s (tx)",
|
static const char *rnames[] = { "i2sbus: %pOFn (control)",
|
||||||
"i2sbus: %s (rx)" };
|
"i2sbus: %pOFn (tx)",
|
||||||
|
"i2sbus: %pOFn (rx)" };
|
||||||
static irq_handler_t ints[] = {
|
static irq_handler_t ints[] = {
|
||||||
i2sbus_bus_intr,
|
i2sbus_bus_intr,
|
||||||
i2sbus_tx_intr,
|
i2sbus_tx_intr,
|
||||||
i2sbus_rx_intr
|
i2sbus_rx_intr
|
||||||
};
|
};
|
||||||
|
|
||||||
if (strlen(np->name) != 5)
|
if (snprintf(node_name, sizeof(node_name), "%pOFn", np) != 5)
|
||||||
return 0;
|
return 0;
|
||||||
if (strncmp(np->name, "i2s-", 4))
|
if (strncmp(node_name, "i2s-", 4))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
|
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->sound.pcmid = -1;
|
||||||
dev->macio = macio;
|
dev->macio = macio;
|
||||||
dev->control = control;
|
dev->control = control;
|
||||||
dev->bus_number = np->name[4] - 'a';
|
dev->bus_number = node_name[4] - 'a';
|
||||||
INIT_LIST_HEAD(&dev->sound.codec_list);
|
INIT_LIST_HEAD(&dev->sound.codec_list);
|
||||||
|
|
||||||
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
|
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
|
||||||
dev->interrupts[i] = -1;
|
dev->interrupts[i] = -1;
|
||||||
snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
|
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++) {
|
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
|
||||||
int irq = irq_of_parse_and_map(np, i);
|
int irq = irq_of_parse_and_map(np, i);
|
||||||
|
|
|
@ -31,7 +31,6 @@ endif # SND_ARM
|
||||||
|
|
||||||
config SND_PXA2XX_LIB
|
config SND_PXA2XX_LIB
|
||||||
tristate
|
tristate
|
||||||
select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
|
|
||||||
select SND_DMAENGINE_PCM
|
select SND_DMAENGINE_PCM
|
||||||
|
|
||||||
config SND_PXA2XX_LIB_AC97
|
config SND_PXA2XX_LIB_AC97
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/genalloc.h>
|
#include <linux/genalloc.h>
|
||||||
|
#ifdef CONFIG_X86
|
||||||
|
#include <asm/set_memory.h>
|
||||||
|
#endif
|
||||||
#include <sound/memalloc.h>
|
#include <sound/memalloc.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,31 +85,32 @@ EXPORT_SYMBOL(snd_free_pages);
|
||||||
|
|
||||||
#ifdef CONFIG_HAS_DMA
|
#ifdef CONFIG_HAS_DMA
|
||||||
/* allocate the coherent DMA pages */
|
/* 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;
|
gfp_t gfp_flags;
|
||||||
|
|
||||||
if (WARN_ON(!dma))
|
|
||||||
return NULL;
|
|
||||||
pg = get_order(size);
|
|
||||||
gfp_flags = GFP_KERNEL
|
gfp_flags = GFP_KERNEL
|
||||||
| __GFP_COMP /* compound page lets parts be mapped */
|
| __GFP_COMP /* compound page lets parts be mapped */
|
||||||
| __GFP_NORETRY /* don't trigger OOM-killer */
|
| __GFP_NORETRY /* don't trigger OOM-killer */
|
||||||
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
|
| __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 */
|
/* free the coherent DMA pages */
|
||||||
static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
|
static void snd_free_dev_pages(struct snd_dma_buffer *dmab)
|
||||||
dma_addr_t dma)
|
|
||||||
{
|
{
|
||||||
int pg;
|
#ifdef CONFIG_X86
|
||||||
|
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
|
||||||
if (ptr == NULL)
|
set_memory_wb((unsigned long)dmab->area,
|
||||||
return;
|
PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
|
||||||
pg = get_order(size);
|
#endif
|
||||||
dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
|
dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GENERIC_ALLOCATOR
|
#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;
|
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||||
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
||||||
|
/* fall through */
|
||||||
case SNDRV_DMA_TYPE_DEV:
|
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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SND_DMA_SGBUF
|
#ifdef CONFIG_SND_DMA_SGBUF
|
||||||
case SNDRV_DMA_TYPE_DEV_SG:
|
case SNDRV_DMA_TYPE_DEV_SG:
|
||||||
|
case SNDRV_DMA_TYPE_DEV_UC_SG:
|
||||||
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
|
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -275,11 +282,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
||||||
case SNDRV_DMA_TYPE_DEV:
|
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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SND_DMA_SGBUF
|
#ifdef CONFIG_SND_DMA_SGBUF
|
||||||
case SNDRV_DMA_TYPE_DEV_SG:
|
case SNDRV_DMA_TYPE_DEV_SG:
|
||||||
|
case SNDRV_DMA_TYPE_DEV_UC_SG:
|
||||||
snd_free_sgbuf_pages(dmab);
|
snd_free_sgbuf_pages(dmab);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
|
||||||
while (plugin->next) {
|
while (plugin->next) {
|
||||||
if (plugin->dst_frames)
|
if (plugin->dst_frames)
|
||||||
frames = plugin->dst_frames(plugin, 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;
|
return -ENXIO;
|
||||||
plugin = plugin->next;
|
plugin = plugin->next;
|
||||||
err = snd_pcm_plugin_alloc(plugin, frames);
|
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) {
|
while (plugin->prev) {
|
||||||
if (plugin->src_frames)
|
if (plugin->src_frames)
|
||||||
frames = plugin->src_frames(plugin, 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;
|
return -ENXIO;
|
||||||
plugin = plugin->prev;
|
plugin = plugin->prev;
|
||||||
err = snd_pcm_plugin_alloc(plugin, frames);
|
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)
|
if (err < 0)
|
||||||
goto _end_unlock;
|
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;
|
runtime->twake = runtime->control->avail_min ? : 1;
|
||||||
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
||||||
snd_pcm_update_hw_ptr(substream);
|
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);
|
avail = snd_pcm_avail(substream);
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
|
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
|
||||||
snd_pcm_uframes_t cont;
|
snd_pcm_uframes_t cont;
|
||||||
|
|
|
@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_transmit);
|
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,
|
static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
|
||||||
const unsigned char __user *userbuf,
|
const unsigned char __user *userbuf,
|
||||||
const unsigned char *kernelbuf,
|
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:
|
case TMR_WAIT_REL:
|
||||||
parm += rec->cur_tick;
|
parm += rec->cur_tick;
|
||||||
rec->realtime = 0;
|
rec->realtime = 0;
|
||||||
/* fall through and continue to next */
|
/* fall through */
|
||||||
case TMR_WAIT_ABS:
|
case TMR_WAIT_ABS:
|
||||||
if (parm == 0) {
|
if (parm == 0) {
|
||||||
rec->realtime = 1;
|
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_callback pcallbacks;
|
||||||
struct snd_seq_port_info *port;
|
struct snd_seq_port_info *port;
|
||||||
|
int err;
|
||||||
|
|
||||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||||
if (!port)
|
if (!port)
|
||||||
|
@ -134,6 +135,10 @@ int __init snd_seq_system_client_init(void)
|
||||||
|
|
||||||
/* register client */
|
/* register client */
|
||||||
sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
|
sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
|
||||||
|
if (sysclient < 0) {
|
||||||
|
kfree(port);
|
||||||
|
return sysclient;
|
||||||
|
}
|
||||||
|
|
||||||
/* register timer */
|
/* register timer */
|
||||||
strcpy(port->name, "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->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
|
||||||
port->addr.client = sysclient;
|
port->addr.client = sysclient;
|
||||||
port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
|
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 */
|
/* register announcement port */
|
||||||
strcpy(port->name, "Announce");
|
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->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
|
||||||
port->addr.client = sysclient;
|
port->addr.client = sysclient;
|
||||||
port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
|
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;
|
announce_port = port->addr.port;
|
||||||
|
|
||||||
kfree(port);
|
kfree(port);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error_port:
|
||||||
|
snd_seq_system_client_done();
|
||||||
|
kfree(port);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* unregister our internal client */
|
/* unregister our internal client */
|
||||||
void __exit snd_seq_system_client_done(void)
|
void snd_seq_system_client_done(void)
|
||||||
{
|
{
|
||||||
int oldsysclient = sysclient;
|
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 */
|
/* discard the outputs in dispatch mode unless subscribed */
|
||||||
if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
|
if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
|
||||||
!(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
|
!(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
|
||||||
char buf[32];
|
snd_rawmidi_proceed(substream);
|
||||||
while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0)
|
|
||||||
; /* ignored */
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <asm/pgtable.h>
|
||||||
#include <sound/memalloc.h>
|
#include <sound/memalloc.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
|
||||||
dmab->area = NULL;
|
dmab->area = NULL;
|
||||||
|
|
||||||
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
|
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;
|
tmpb.dev.dev = sgbuf->dev;
|
||||||
for (i = 0; i < sgbuf->pages; i++) {
|
for (i = 0; i < sgbuf->pages; i++) {
|
||||||
if (!(sgbuf->table[i].addr & ~PAGE_MASK))
|
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_dma_buffer tmpb;
|
||||||
struct snd_sg_page *table;
|
struct snd_sg_page *table;
|
||||||
struct page **pgtable;
|
struct page **pgtable;
|
||||||
|
int type = SNDRV_DMA_TYPE_DEV;
|
||||||
|
pgprot_t prot = PAGE_KERNEL;
|
||||||
|
|
||||||
dmab->area = NULL;
|
dmab->area = NULL;
|
||||||
dmab->addr = 0;
|
dmab->addr = 0;
|
||||||
dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
|
dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
|
||||||
if (! sgbuf)
|
if (! sgbuf)
|
||||||
return NULL;
|
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;
|
sgbuf->dev = device;
|
||||||
pages = snd_sgbuf_aligned_pages(size);
|
pages = snd_sgbuf_aligned_pages(size);
|
||||||
sgbuf->tblsize = sgbuf_align_table(pages);
|
sgbuf->tblsize = sgbuf_align_table(pages);
|
||||||
|
@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
|
||||||
if (chunk > maxpages)
|
if (chunk > maxpages)
|
||||||
chunk = maxpages;
|
chunk = maxpages;
|
||||||
chunk <<= PAGE_SHIFT;
|
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) {
|
chunk, &tmpb) < 0) {
|
||||||
if (!sgbuf->pages)
|
if (!sgbuf->pages)
|
||||||
goto _failed;
|
goto _failed;
|
||||||
|
@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
|
||||||
}
|
}
|
||||||
|
|
||||||
sgbuf->size = size;
|
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)
|
if (! dmab->area)
|
||||||
goto _failed;
|
goto _failed;
|
||||||
if (res_size)
|
if (res_size)
|
||||||
|
|
|
@ -147,7 +147,9 @@ config SND_FIREWIRE_MOTU
|
||||||
help
|
help
|
||||||
Say Y here to enable support for FireWire devices which MOTU produced:
|
Say Y here to enable support for FireWire devices which MOTU produced:
|
||||||
* 828mk2
|
* 828mk2
|
||||||
|
* Traveler
|
||||||
* 828mk3
|
* 828mk3
|
||||||
|
* Audio Express
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called snd-firewire-motu.
|
will be called snd-firewire-motu.
|
||||||
|
|
|
@ -140,6 +140,59 @@ const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = {
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL(amdtp_rate_table);
|
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
|
* amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
|
||||||
* @s: the AMDTP stream, which must be initialized.
|
* @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,
|
* number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
|
||||||
* depending on its sampling rate. For accurate period interrupt, it's
|
* depending on its sampling rate. For accurate period interrupt, it's
|
||||||
* preferrable to align period/buffer sizes to current SYT_INTERVAL.
|
* 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,
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
|
||||||
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
|
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)
|
if (err < 0)
|
||||||
goto end;
|
goto end;
|
||||||
err = snd_pcm_hw_constraint_step(runtime, 0,
|
|
||||||
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
|
|
||||||
end:
|
end:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,23 +126,6 @@ end:
|
||||||
return err;
|
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
|
static void
|
||||||
bebob_card_free(struct snd_card *card)
|
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);
|
clear_bit(bebob->card_index, devices_used);
|
||||||
mutex_unlock(&devices_mutex);
|
mutex_unlock(&devices_mutex);
|
||||||
|
|
||||||
bebob_free(card->private_data);
|
snd_bebob_stream_destroy_duplex(bebob);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snd_bebob_spec *
|
static const struct snd_bebob_spec *
|
||||||
|
@ -192,7 +175,6 @@ do_registration(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&devices_mutex);
|
mutex_lock(&devices_mutex);
|
||||||
|
|
||||||
for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
|
for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
|
||||||
if (!test_bit(card_index, devices_used) && enable[card_index])
|
if (!test_bit(card_index, devices_used) && enable[card_index])
|
||||||
break;
|
break;
|
||||||
|
@ -208,6 +190,11 @@ do_registration(struct work_struct *work)
|
||||||
mutex_unlock(&devices_mutex);
|
mutex_unlock(&devices_mutex);
|
||||||
return;
|
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);
|
err = name_device(bebob);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -248,23 +235,10 @@ do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
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;
|
bebob->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
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);
|
snd_card_free(bebob->card);
|
||||||
dev_info(&bebob->unit->device,
|
dev_info(&bebob->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"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. */
|
/* Allocate this independent of sound card instance. */
|
||||||
bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL);
|
bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob),
|
||||||
if (bebob == NULL)
|
GFP_KERNEL);
|
||||||
|
if (!bebob)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
bebob->unit = fw_unit_get(unit);
|
bebob->unit = fw_unit_get(unit);
|
||||||
bebob->entry = entry;
|
|
||||||
bebob->spec = spec;
|
|
||||||
dev_set_drvdata(&unit->device, bebob);
|
dev_set_drvdata(&unit->device, bebob);
|
||||||
|
|
||||||
|
bebob->entry = entry;
|
||||||
|
bebob->spec = spec;
|
||||||
mutex_init(&bebob->mutex);
|
mutex_init(&bebob->mutex);
|
||||||
spin_lock_init(&bebob->lock);
|
spin_lock_init(&bebob->lock);
|
||||||
init_waitqueue_head(&bebob->hwdep_wait);
|
init_waitqueue_head(&bebob->hwdep_wait);
|
||||||
|
@ -379,12 +353,12 @@ static void bebob_remove(struct fw_unit *unit)
|
||||||
cancel_delayed_work_sync(&bebob->dwork);
|
cancel_delayed_work_sync(&bebob->dwork);
|
||||||
|
|
||||||
if (bebob->registered) {
|
if (bebob->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(bebob->card);
|
snd_card_free(bebob->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
bebob_free(bebob);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&bebob->mutex);
|
||||||
|
fw_unit_put(bebob->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snd_bebob_rate_spec normal_rate_spec = {
|
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;
|
struct special_params *params;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
params = kzalloc(sizeof(struct special_params), GFP_KERNEL);
|
params = devm_kzalloc(&bebob->card->card_dev,
|
||||||
if (params == NULL)
|
sizeof(struct special_params), GFP_KERNEL);
|
||||||
|
if (!params)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mutex_lock(&bebob->mutex);
|
mutex_lock(&bebob->mutex);
|
||||||
|
|
|
@ -122,25 +122,12 @@ static void dice_card_strings(struct snd_dice *dice)
|
||||||
strcpy(card->mixername, "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)
|
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)
|
static void do_registration(struct work_struct *work)
|
||||||
|
@ -155,6 +142,8 @@ static void do_registration(struct work_struct *work)
|
||||||
&dice->card);
|
&dice->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return;
|
return;
|
||||||
|
dice->card->private_free = dice_card_free;
|
||||||
|
dice->card->private_data = dice;
|
||||||
|
|
||||||
err = snd_dice_transaction_init(dice);
|
err = snd_dice_transaction_init(dice);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -192,19 +181,10 @@ static void do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
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;
|
dice->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
snd_dice_stream_destroy_duplex(dice);
|
|
||||||
snd_dice_transaction_destroy(dice);
|
|
||||||
snd_dice_stream_destroy_duplex(dice);
|
|
||||||
snd_card_free(dice->card);
|
snd_card_free(dice->card);
|
||||||
dev_info(&dice->unit->device,
|
dev_info(&dice->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"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. */
|
/* Allocate this independent of sound card instance. */
|
||||||
dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
|
dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL);
|
||||||
if (dice == NULL)
|
if (!dice)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dice->unit = fw_unit_get(unit);
|
dice->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, dice);
|
dev_set_drvdata(&unit->device, dice);
|
||||||
|
|
||||||
|
@ -263,10 +242,10 @@ static void dice_remove(struct fw_unit *unit)
|
||||||
if (dice->registered) {
|
if (dice->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
/* No need to wait for releasing card object in this context. */
|
||||||
snd_card_free_when_closed(dice->card);
|
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)
|
static void dice_bus_reset(struct fw_unit *unit)
|
||||||
|
|
|
@ -41,20 +41,12 @@ static int name_card(struct snd_dg00x *dg00x)
|
||||||
return 0;
|
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)
|
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)
|
static void do_registration(struct work_struct *work)
|
||||||
|
@ -70,6 +62,8 @@ static void do_registration(struct work_struct *work)
|
||||||
&dg00x->card);
|
&dg00x->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return;
|
return;
|
||||||
|
dg00x->card->private_free = dg00x_card_free;
|
||||||
|
dg00x->card->private_data = dg00x;
|
||||||
|
|
||||||
err = name_card(dg00x);
|
err = name_card(dg00x);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -101,14 +95,10 @@ static void do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
dg00x->card->private_free = dg00x_card_free;
|
|
||||||
dg00x->card->private_data = dg00x;
|
|
||||||
dg00x->registered = true;
|
dg00x->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
snd_dg00x_transaction_unregister(dg00x);
|
|
||||||
snd_dg00x_stream_destroy_duplex(dg00x);
|
|
||||||
snd_card_free(dg00x->card);
|
snd_card_free(dg00x->card);
|
||||||
dev_info(&dg00x->unit->device,
|
dev_info(&dg00x->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"Sound card registration failed: %d\n", err);
|
||||||
|
@ -120,8 +110,9 @@ static int snd_dg00x_probe(struct fw_unit *unit,
|
||||||
struct snd_dg00x *dg00x;
|
struct snd_dg00x *dg00x;
|
||||||
|
|
||||||
/* Allocate this independent of sound card instance. */
|
/* Allocate this independent of sound card instance. */
|
||||||
dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL);
|
dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x),
|
||||||
if (dg00x == NULL)
|
GFP_KERNEL);
|
||||||
|
if (!dg00x)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dg00x->unit = fw_unit_get(unit);
|
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);
|
cancel_delayed_work_sync(&dg00x->dwork);
|
||||||
|
|
||||||
if (dg00x->registered) {
|
if (dg00x->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(dg00x->card);
|
snd_card_free(dg00x->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
dg00x_free(dg00x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&dg00x->mutex);
|
||||||
|
fw_unit_put(dg00x->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ieee1394_device_id snd_dg00x_id_table[] = {
|
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);
|
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)
|
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)
|
static void do_registration(struct work_struct *work)
|
||||||
|
@ -55,6 +47,8 @@ static void do_registration(struct work_struct *work)
|
||||||
&ff->card);
|
&ff->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return;
|
return;
|
||||||
|
ff->card->private_free = ff_card_free;
|
||||||
|
ff->card->private_data = ff;
|
||||||
|
|
||||||
err = snd_ff_transaction_register(ff);
|
err = snd_ff_transaction_register(ff);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -84,14 +78,10 @@ static void do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ff->card->private_free = ff_card_free;
|
|
||||||
ff->card->private_data = ff;
|
|
||||||
ff->registered = true;
|
ff->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
snd_ff_transaction_unregister(ff);
|
|
||||||
snd_ff_stream_destroy_duplex(ff);
|
|
||||||
snd_card_free(ff->card);
|
snd_card_free(ff->card);
|
||||||
dev_info(&ff->unit->device,
|
dev_info(&ff->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"Sound card registration failed: %d\n", err);
|
||||||
|
@ -102,11 +92,9 @@ static int snd_ff_probe(struct fw_unit *unit,
|
||||||
{
|
{
|
||||||
struct snd_ff *ff;
|
struct snd_ff *ff;
|
||||||
|
|
||||||
ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL);
|
ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL);
|
||||||
if (ff == NULL)
|
if (!ff)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* initialize myself */
|
|
||||||
ff->unit = fw_unit_get(unit);
|
ff->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, ff);
|
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);
|
cancel_work_sync(&ff->dwork.work);
|
||||||
|
|
||||||
if (ff->registered) {
|
if (ff->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(ff->card);
|
snd_card_free(ff->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
ff_free(ff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&ff->mutex);
|
||||||
|
fw_unit_put(ff->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snd_ff_spec spec_ff400 = {
|
static const struct snd_ff_spec spec_ff400 = {
|
||||||
|
|
|
@ -184,36 +184,17 @@ end:
|
||||||
return err;
|
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
|
static void
|
||||||
efw_card_free(struct snd_card *card)
|
efw_card_free(struct snd_card *card)
|
||||||
{
|
{
|
||||||
struct snd_efw *efw = card->private_data;
|
struct snd_efw *efw = card->private_data;
|
||||||
|
|
||||||
if (efw->card_index >= 0) {
|
mutex_lock(&devices_mutex);
|
||||||
mutex_lock(&devices_mutex);
|
clear_bit(efw->card_index, devices_used);
|
||||||
clear_bit(efw->card_index, devices_used);
|
mutex_unlock(&devices_mutex);
|
||||||
mutex_unlock(&devices_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
efw_free(card->private_data);
|
snd_efw_stream_destroy_duplex(efw);
|
||||||
|
snd_efw_transaction_remove_instance(efw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -226,9 +207,8 @@ do_registration(struct work_struct *work)
|
||||||
if (efw->registered)
|
if (efw->registered)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&devices_mutex);
|
|
||||||
|
|
||||||
/* check registered cards */
|
/* check registered cards */
|
||||||
|
mutex_lock(&devices_mutex);
|
||||||
for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
|
for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
|
||||||
if (!test_bit(card_index, devices_used) && enable[card_index])
|
if (!test_bit(card_index, devices_used) && enable[card_index])
|
||||||
break;
|
break;
|
||||||
|
@ -244,12 +224,18 @@ do_registration(struct work_struct *work)
|
||||||
mutex_unlock(&devices_mutex);
|
mutex_unlock(&devices_mutex);
|
||||||
return;
|
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 */
|
/* prepare response buffer */
|
||||||
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
|
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
|
||||||
SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
|
SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
|
||||||
efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL);
|
efw->resp_buf = devm_kzalloc(&efw->card->card_dev,
|
||||||
if (efw->resp_buf == NULL) {
|
snd_efw_resp_buf_size, GFP_KERNEL);
|
||||||
|
if (!efw->resp_buf) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -284,25 +270,11 @@ do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
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;
|
efw->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
mutex_unlock(&devices_mutex);
|
|
||||||
snd_efw_transaction_remove_instance(efw);
|
|
||||||
snd_efw_stream_destroy_duplex(efw);
|
|
||||||
snd_card_free(efw->card);
|
snd_card_free(efw->card);
|
||||||
kfree(efw->resp_buf);
|
|
||||||
efw->resp_buf = NULL;
|
|
||||||
dev_info(&efw->unit->device,
|
dev_info(&efw->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"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;
|
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)
|
if (efw == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
efw->unit = fw_unit_get(unit);
|
efw->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, efw);
|
dev_set_drvdata(&unit->device, efw);
|
||||||
|
|
||||||
|
@ -363,12 +334,12 @@ static void efw_remove(struct fw_unit *unit)
|
||||||
cancel_delayed_work_sync(&efw->dwork);
|
cancel_delayed_work_sync(&efw->dwork);
|
||||||
|
|
||||||
if (efw->registered) {
|
if (efw->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(efw->card);
|
snd_card_free(efw->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
efw_free(efw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&efw->mutex);
|
||||||
|
fw_unit_put(efw->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ieee1394_device_id efw_id_table[] = {
|
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;
|
struct isight *isight = card->private_data;
|
||||||
|
|
||||||
fw_iso_resources_destroy(&isight->resources);
|
fw_iso_resources_destroy(&isight->resources);
|
||||||
fw_unit_put(isight->unit);
|
|
||||||
mutex_destroy(&isight->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 get_unit_base(struct fw_unit *unit)
|
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) {
|
if (!isight->audio_base) {
|
||||||
dev_err(&unit->device, "audio unit base not found\n");
|
dev_err(&unit->device, "audio unit base not found\n");
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
goto err_unit;
|
goto error;
|
||||||
}
|
}
|
||||||
fw_iso_resources_init(&isight->resources, unit);
|
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);
|
dev_set_drvdata(&unit->device, isight);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_unit:
|
|
||||||
fw_unit_put(isight->unit);
|
|
||||||
mutex_destroy(&isight->mutex);
|
|
||||||
error:
|
error:
|
||||||
snd_card_free(card);
|
snd_card_free(card);
|
||||||
|
|
||||||
|
mutex_destroy(&isight->mutex);
|
||||||
|
fw_unit_put(isight->unit);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +701,11 @@ static void isight_remove(struct fw_unit *unit)
|
||||||
isight_stop_streaming(isight);
|
isight_stop_streaming(isight);
|
||||||
mutex_unlock(&isight->mutex);
|
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[] = {
|
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);
|
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)
|
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)
|
static void do_registration(struct work_struct *work)
|
||||||
|
@ -86,6 +72,8 @@ static void do_registration(struct work_struct *work)
|
||||||
&motu->card);
|
&motu->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return;
|
return;
|
||||||
|
motu->card->private_free = motu_card_free;
|
||||||
|
motu->card->private_data = motu;
|
||||||
|
|
||||||
name_card(motu);
|
name_card(motu);
|
||||||
|
|
||||||
|
@ -120,18 +108,10 @@ static void do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
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;
|
motu->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
snd_motu_transaction_unregister(motu);
|
|
||||||
snd_motu_stream_destroy_duplex(motu);
|
|
||||||
snd_card_free(motu->card);
|
snd_card_free(motu->card);
|
||||||
dev_info(&motu->unit->device,
|
dev_info(&motu->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"Sound card registration failed: %d\n", err);
|
||||||
|
@ -143,14 +123,13 @@ static int motu_probe(struct fw_unit *unit,
|
||||||
struct snd_motu *motu;
|
struct snd_motu *motu;
|
||||||
|
|
||||||
/* Allocate this independently of sound card instance. */
|
/* Allocate this independently of sound card instance. */
|
||||||
motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
|
motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL);
|
||||||
if (motu == NULL)
|
if (!motu)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
|
|
||||||
motu->unit = fw_unit_get(unit);
|
motu->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, motu);
|
dev_set_drvdata(&unit->device, motu);
|
||||||
|
|
||||||
|
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
|
||||||
mutex_init(&motu->mutex);
|
mutex_init(&motu->mutex);
|
||||||
spin_lock_init(&motu->lock);
|
spin_lock_init(&motu->lock);
|
||||||
init_waitqueue_head(&motu->hwdep_wait);
|
init_waitqueue_head(&motu->hwdep_wait);
|
||||||
|
@ -174,12 +153,12 @@ static void motu_remove(struct fw_unit *unit)
|
||||||
cancel_delayed_work_sync(&motu->dwork);
|
cancel_delayed_work_sync(&motu->dwork);
|
||||||
|
|
||||||
if (motu->registered) {
|
if (motu->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(motu->card);
|
snd_card_free(motu->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
motu_free(motu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&motu->mutex);
|
||||||
|
fw_unit_put(motu->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void motu_bus_update(struct fw_unit *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;
|
struct fw_scs1x *scs;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL);
|
scs = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_scs1x),
|
||||||
if (scs == NULL)
|
GFP_KERNEL);
|
||||||
|
if (!scs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
scs->fw_dev = fw_parent_device(oxfw->unit);
|
scs->fw_dev = fw_parent_device(oxfw->unit);
|
||||||
oxfw->spec = scs;
|
oxfw->spec = scs;
|
||||||
|
|
|
@ -270,8 +270,9 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
|
||||||
unsigned int i, first_ch;
|
unsigned int i, first_ch;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL);
|
spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr),
|
||||||
if (spkr == NULL)
|
GFP_KERNEL);
|
||||||
|
if (!spkr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
oxfw->spec = spkr;
|
oxfw->spec = spkr;
|
||||||
|
|
||||||
|
|
|
@ -517,8 +517,9 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
|
formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
|
||||||
if (formats[eid] == NULL) {
|
GFP_KERNEL);
|
||||||
|
if (!formats[eid]) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -535,7 +536,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
eid++;
|
eid++;
|
||||||
formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
|
formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
|
||||||
|
GFP_KERNEL);
|
||||||
if (formats[eid] == NULL) {
|
if (formats[eid] == NULL) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -597,8 +599,9 @@ static int fill_stream_formats(struct snd_oxfw *oxfw,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
formats[eid] = kmemdup(buf, len, GFP_KERNEL);
|
formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
|
||||||
if (formats[eid] == NULL) {
|
GFP_KERNEL);
|
||||||
|
if (!formats[eid]) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,35 +113,13 @@ end:
|
||||||
return err;
|
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);
|
snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
|
||||||
if (oxfw->has_output)
|
if (oxfw->has_output)
|
||||||
snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
|
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)
|
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)
|
static void do_registration(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
|
struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
|
||||||
int i;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (oxfw->registered)
|
if (oxfw->registered)
|
||||||
|
@ -218,6 +195,8 @@ static void do_registration(struct work_struct *work)
|
||||||
&oxfw->card);
|
&oxfw->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return;
|
return;
|
||||||
|
oxfw->card->private_free = oxfw_card_free;
|
||||||
|
oxfw->card->private_data = oxfw;
|
||||||
|
|
||||||
err = name_card(oxfw);
|
err = name_card(oxfw);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -258,28 +237,11 @@ static void do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
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;
|
oxfw->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
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);
|
snd_card_free(oxfw->card);
|
||||||
kfree(oxfw->spec);
|
|
||||||
oxfw->spec = NULL;
|
|
||||||
dev_info(&oxfw->unit->device,
|
dev_info(&oxfw->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"Sound card registration failed: %d\n", err);
|
||||||
}
|
}
|
||||||
|
@ -293,14 +255,13 @@ static int oxfw_probe(struct fw_unit *unit,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* Allocate this independent of sound card instance. */
|
/* Allocate this independent of sound card instance. */
|
||||||
oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL);
|
oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL);
|
||||||
if (oxfw == NULL)
|
if (!oxfw)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
oxfw->entry = entry;
|
|
||||||
oxfw->unit = fw_unit_get(unit);
|
oxfw->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, oxfw);
|
dev_set_drvdata(&unit->device, oxfw);
|
||||||
|
|
||||||
|
oxfw->entry = entry;
|
||||||
mutex_init(&oxfw->mutex);
|
mutex_init(&oxfw->mutex);
|
||||||
spin_lock_init(&oxfw->lock);
|
spin_lock_init(&oxfw->lock);
|
||||||
init_waitqueue_head(&oxfw->hwdep_wait);
|
init_waitqueue_head(&oxfw->hwdep_wait);
|
||||||
|
@ -347,12 +308,12 @@ static void oxfw_remove(struct fw_unit *unit)
|
||||||
cancel_delayed_work_sync(&oxfw->dwork);
|
cancel_delayed_work_sync(&oxfw->dwork);
|
||||||
|
|
||||||
if (oxfw->registered) {
|
if (oxfw->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(oxfw->card);
|
snd_card_free(oxfw->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
oxfw_free(oxfw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&oxfw->mutex);
|
||||||
|
fw_unit_put(oxfw->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct compat_info griffin_firewave = {
|
static const struct compat_info griffin_firewave = {
|
||||||
|
|
|
@ -85,20 +85,12 @@ static int identify_model(struct snd_tscm *tscm)
|
||||||
return 0;
|
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)
|
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)
|
static void do_registration(struct work_struct *work)
|
||||||
|
@ -110,6 +102,8 @@ static void do_registration(struct work_struct *work)
|
||||||
&tscm->card);
|
&tscm->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return;
|
return;
|
||||||
|
tscm->card->private_free = tscm_card_free;
|
||||||
|
tscm->card->private_data = tscm;
|
||||||
|
|
||||||
err = identify_model(tscm);
|
err = identify_model(tscm);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -141,18 +135,10 @@ static void do_registration(struct work_struct *work)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
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;
|
tscm->registered = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
snd_tscm_transaction_unregister(tscm);
|
|
||||||
snd_tscm_stream_destroy_duplex(tscm);
|
|
||||||
snd_card_free(tscm->card);
|
snd_card_free(tscm->card);
|
||||||
dev_info(&tscm->unit->device,
|
dev_info(&tscm->unit->device,
|
||||||
"Sound card registration failed: %d\n", err);
|
"Sound card registration failed: %d\n", err);
|
||||||
|
@ -164,11 +150,9 @@ static int snd_tscm_probe(struct fw_unit *unit,
|
||||||
struct snd_tscm *tscm;
|
struct snd_tscm *tscm;
|
||||||
|
|
||||||
/* Allocate this independent of sound card instance. */
|
/* Allocate this independent of sound card instance. */
|
||||||
tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL);
|
tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL);
|
||||||
if (tscm == NULL)
|
if (!tscm)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* initialize myself */
|
|
||||||
tscm->unit = fw_unit_get(unit);
|
tscm->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, tscm);
|
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);
|
cancel_delayed_work_sync(&tscm->dwork);
|
||||||
|
|
||||||
if (tscm->registered) {
|
if (tscm->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
// Block till all of ALSA character devices are released.
|
||||||
snd_card_free_when_closed(tscm->card);
|
snd_card_free(tscm->card);
|
||||||
} else {
|
|
||||||
/* Don't forget this case. */
|
|
||||||
tscm_free(tscm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_destroy(&tscm->mutex);
|
||||||
|
fw_unit_put(tscm->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ieee1394_device_id snd_tscm_id_table[] = {
|
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)
|
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
|
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);
|
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)
|
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
|
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);
|
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)
|
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);
|
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;
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
||||||
snd_hdac_updatel(hlink->ml_addr,
|
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
|
||||||
AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
|
AZX_MLCTL_SPA, AZX_MLCTL_SPA);
|
||||||
ret = check_hdac_link_power_active(hlink, true);
|
ret = check_hdac_link_power_active(hlink, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(hlink, &bus->hlink_list, list) {
|
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);
|
ret = check_hdac_link_power_active(hlink, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -118,7 +118,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
|
||||||
struct cs8427 *chip = device->private_data;
|
struct cs8427 *chip = device->private_data;
|
||||||
char *hw_data = udata ?
|
char *hw_data = udata ?
|
||||||
chip->playback.hw_udata : chip->playback.hw_status;
|
chip->playback.hw_udata : chip->playback.hw_status;
|
||||||
char data[32];
|
unsigned char data[32];
|
||||||
int err, idx;
|
int err, idx;
|
||||||
|
|
||||||
if (!memcmp(hw_data, ndata, count))
|
if (!memcmp(hw_data, ndata, count))
|
||||||
|
|
|
@ -389,7 +389,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||||
case OPTi9XX_HW_82C931:
|
case OPTi9XX_HW_82C931:
|
||||||
/* disable 3D sound (set GPIO1 as output, low) */
|
/* disable 3D sound (set GPIO1 as output, low) */
|
||||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
|
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
|
* The BTC 1817DW has QS1000 wavetable which is connected
|
||||||
* to the serial digital input of the OPTI931.
|
* 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.
|
* or digital input signal.
|
||||||
*/
|
*/
|
||||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
|
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(6), 0x02, 0x03);
|
||||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
|
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
|
||||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
|
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;
|
chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SB_HW_201:
|
case SB_HW_201:
|
||||||
if (rate > 23000) {
|
if (rate > 23000) {
|
||||||
chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
|
chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SB_HW_20:
|
case SB_HW_20:
|
||||||
chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
|
chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
|
||||||
break;
|
break;
|
||||||
|
@ -287,7 +287,7 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
|
||||||
chip->capture_format = SB_DSP_HI_INPUT_AUTO;
|
chip->capture_format = SB_DSP_HI_INPUT_AUTO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SB_HW_20:
|
case SB_HW_20:
|
||||||
chip->capture_format = SB_DSP_LO_INPUT_AUTO;
|
chip->capture_format = SB_DSP_LO_INPUT_AUTO;
|
||||||
break;
|
break;
|
||||||
|
@ -387,7 +387,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
|
||||||
case SB_MODE_PLAYBACK_16: /* ok.. playback is active */
|
case SB_MODE_PLAYBACK_16: /* ok.. playback is active */
|
||||||
if (chip->hardware != SB_HW_JAZZ16)
|
if (chip->hardware != SB_HW_JAZZ16)
|
||||||
break;
|
break;
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SB_MODE_PLAYBACK_8:
|
case SB_MODE_PLAYBACK_8:
|
||||||
substream = chip->playback_substream;
|
substream = chip->playback_substream;
|
||||||
if (chip->playback_format == SB_DSP_OUTPUT)
|
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:
|
case SB_MODE_CAPTURE_16:
|
||||||
if (chip->hardware != SB_HW_JAZZ16)
|
if (chip->hardware != SB_HW_JAZZ16)
|
||||||
break;
|
break;
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SB_MODE_CAPTURE_8:
|
case SB_MODE_CAPTURE_8:
|
||||||
substream = chip->capture_substream;
|
substream = chip->capture_substream;
|
||||||
if (chip->capture_format == SB_DSP_INPUT)
|
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 |
|
.info = (SNDRV_PCM_INFO_MMAP |
|
||||||
SNDRV_PCM_INFO_MMAP_VALID |
|
SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
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,
|
.formats = SNDRV_PCM_FMTBIT_S16_BE,
|
||||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||||
.rate_min = 8000,
|
.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);
|
dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
|
||||||
memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
|
memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
|
||||||
dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
|
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->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
|
||||||
dac->substream = substream;
|
dac->substream = substream;
|
||||||
hal2_setup_dac(hal2);
|
hal2_setup_dac(hal2);
|
||||||
|
@ -575,9 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
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);
|
hal2_start_dac(hal2);
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
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 snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
|
||||||
struct hal2_codec *dac = &hal2->dac;
|
struct hal2_codec *dac = &hal2->dac;
|
||||||
|
|
||||||
dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
|
|
||||||
return snd_pcm_indirect_playback_transfer(substream,
|
return snd_pcm_indirect_playback_transfer(substream,
|
||||||
&dac->pcm_indirect,
|
&dac->pcm_indirect,
|
||||||
hal2_playback_transfer);
|
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));
|
memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
|
||||||
adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
|
adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
|
||||||
adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
|
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->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
|
||||||
adc->substream = substream;
|
adc->substream = substream;
|
||||||
hal2_setup_adc(hal2);
|
hal2_setup_adc(hal2);
|
||||||
|
@ -667,9 +667,6 @@ static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
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);
|
hal2_start_adc(hal2);
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
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? */
|
/*?? any benefit in using managed dmam_alloc_coherent? */
|
||||||
p_mem_area->vaddr =
|
p_mem_area->vaddr =
|
||||||
dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
|
dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
|
||||||
GFP_DMA32 | GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
||||||
if (p_mem_area->vaddr) {
|
if (p_mem_area->vaddr) {
|
||||||
HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",
|
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:
|
case 8:
|
||||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
|
data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
|
||||||
ATI_REG_OUT_DMA_SLOT_BIT(11);
|
ATI_REG_OUT_DMA_SLOT_BIT(11);
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case 6:
|
case 6:
|
||||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
|
data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
|
||||||
ATI_REG_OUT_DMA_SLOT_BIT(8);
|
ATI_REG_OUT_DMA_SLOT_BIT(8);
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case 4:
|
case 4:
|
||||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
|
data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
|
||||||
ATI_REG_OUT_DMA_SLOT_BIT(9);
|
ATI_REG_OUT_DMA_SLOT_BIT(9);
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
|
data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
|
||||||
ATI_REG_OUT_DMA_SLOT_BIT(4);
|
ATI_REG_OUT_DMA_SLOT_BIT(4);
|
||||||
|
|
|
@ -1115,6 +1115,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
|
||||||
hwwrite(vortex->mmio,
|
hwwrite(vortex->mmio,
|
||||||
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
|
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
|
||||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
|
snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
|
||||||
|
/* fall through */
|
||||||
/* 3 pages */
|
/* 3 pages */
|
||||||
case 3:
|
case 3:
|
||||||
dma->cfg0 |= 0x12000000;
|
dma->cfg0 |= 0x12000000;
|
||||||
|
@ -1122,12 +1123,14 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
|
||||||
hwwrite(vortex->mmio,
|
hwwrite(vortex->mmio,
|
||||||
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
|
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
|
||||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
|
snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
|
||||||
|
/* fall through */
|
||||||
/* 2 pages */
|
/* 2 pages */
|
||||||
case 2:
|
case 2:
|
||||||
dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
|
dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
|
||||||
hwwrite(vortex->mmio,
|
hwwrite(vortex->mmio,
|
||||||
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
|
VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
|
||||||
snd_pcm_sgbuf_get_addr(dma->substream, psize));
|
snd_pcm_sgbuf_get_addr(dma->substream, psize));
|
||||||
|
/* fall through */
|
||||||
/* 1 page */
|
/* 1 page */
|
||||||
case 1:
|
case 1:
|
||||||
dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
|
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);
|
dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
|
||||||
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
|
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
|
||||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
|
snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
|
||||||
|
/* fall through */
|
||||||
/* 3 pages */
|
/* 3 pages */
|
||||||
case 3:
|
case 3:
|
||||||
dma->cfg0 |= 0x12000000;
|
dma->cfg0 |= 0x12000000;
|
||||||
dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
|
dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
|
||||||
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x8,
|
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x8,
|
||||||
snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
|
snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
|
||||||
|
/* fall through */
|
||||||
/* 2 pages */
|
/* 2 pages */
|
||||||
case 2:
|
case 2:
|
||||||
dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
|
dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
|
||||||
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
|
hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
|
||||||
snd_pcm_sgbuf_get_addr(dma->substream, psize));
|
snd_pcm_sgbuf_get_addr(dma->substream, psize));
|
||||||
|
/* fall through */
|
||||||
/* 1 page */
|
/* 1 page */
|
||||||
case 1:
|
case 1:
|
||||||
dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
|
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 |
|
.info = (SNDRV_PCM_INFO_MMAP |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
|
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 |
|
.formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
|
||||||
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
|
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
|
||||||
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_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 |
|
.info = (SNDRV_PCM_INFO_MMAP |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
|
SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
|
||||||
/*SNDRV_PCM_INFO_RESUME*/),
|
/*SNDRV_PCM_INFO_RESUME*/ |
|
||||||
|
SNDRV_PCM_INFO_SYNC_APPLPTR),
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
|
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
|
||||||
.rate_min = 5500,
|
.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 |
|
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_RESUME |
|
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,
|
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.rates = SNDRV_PCM_RATE_48000,
|
.rates = SNDRV_PCM_RATE_48000,
|
||||||
.rate_min = 48000,
|
.rate_min = 48000,
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/sort.h>
|
#include <linux/sort.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#ifndef __SOUND_HDA_BEEP_H
|
#ifndef __SOUND_HDA_BEEP_H
|
||||||
#define __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_OFF 0
|
||||||
#define HDA_BEEP_MODE_ON 1
|
#define HDA_BEEP_MODE_ON 1
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
|
||||||
hda_codec_patch_t patch;
|
hda_codec_patch_t patch;
|
||||||
int err;
|
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))
|
if (WARN_ON(!codec->preset))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct hda_codec *codec = dev_to_hda_codec(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)
|
if (codec->patch_ops.free)
|
||||||
codec->patch_ops.free(codec);
|
codec->patch_ops.free(codec);
|
||||||
snd_hda_codec_cleanup_for_unbind(codec);
|
snd_hda_codec_cleanup_for_unbind(codec);
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
#include <sound/tlv.h>
|
#include <sound/tlv.h>
|
||||||
#include <sound/initval.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.bufsize = 0;
|
||||||
azx_dev->core.period_bytes = 0;
|
azx_dev->core.period_bytes = 0;
|
||||||
azx_dev->core.format_val = 0;
|
azx_dev->core.format_val = 0;
|
||||||
ret = chip->ops->substream_alloc_pages(chip, substream,
|
ret = snd_pcm_lib_malloc_pages(substream,
|
||||||
params_buffer_bytes(hw_params));
|
params_buffer_bytes(hw_params));
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
dsp_unlock(azx_dev);
|
dsp_unlock(azx_dev);
|
||||||
return ret;
|
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_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||||
struct azx_dev *azx_dev = get_azx_dev(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);
|
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
|
||||||
int err;
|
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);
|
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;
|
azx_stream(azx_dev)->prepared = 0;
|
||||||
dsp_unlock(azx_dev);
|
dsp_unlock(azx_dev);
|
||||||
return err;
|
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;
|
int pcm_dev = cpcm->device;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
int s, err;
|
int s, err;
|
||||||
|
int type = SNDRV_DMA_TYPE_DEV_SG;
|
||||||
|
|
||||||
list_for_each_entry(apcm, &chip->pcm_list, list) {
|
list_for_each_entry(apcm, &chip->pcm_list, list) {
|
||||||
if (apcm->pcm->device == pcm_dev) {
|
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;
|
size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
|
||||||
if (size > MAX_PREALLOC_SIZE)
|
if (size > MAX_PREALLOC_SIZE)
|
||||||
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,
|
chip->card->dev,
|
||||||
size, MAX_PREALLOC_SIZE);
|
size, MAX_PREALLOC_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1220,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus)
|
||||||
bus->in_reset = 0;
|
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 */
|
/* HD-audio bus initialization */
|
||||||
int azx_bus_init(struct azx *chip, const char *model,
|
int azx_bus_init(struct azx *chip, const char *model,
|
||||||
const struct hdac_io_ops *io_ops)
|
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);
|
err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
continue;
|
continue;
|
||||||
codec->jackpoll_interval = get_jackpoll_interval(chip);
|
codec->jackpoll_interval = chip->jackpoll_interval;
|
||||||
codec->beep_mode = chip->beep_mode;
|
codec->beep_mode = chip->beep_mode;
|
||||||
codecs++;
|
codecs++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include <sound/hda_register.h>
|
#include <sound/hda_register.h>
|
||||||
|
|
||||||
#define AZX_MAX_CODECS HDA_MAX_CODECS
|
#define AZX_MAX_CODECS HDA_MAX_CODECS
|
||||||
|
@ -76,7 +76,6 @@ struct azx_dev {
|
||||||
* when link position is not greater than FIFO size
|
* when link position is not greater than FIFO size
|
||||||
*/
|
*/
|
||||||
unsigned int insufficient:1;
|
unsigned int insufficient:1;
|
||||||
unsigned int wc_marked:1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define azx_stream(dev) (&(dev)->core)
|
#define azx_stream(dev) (&(dev)->core)
|
||||||
|
@ -88,11 +87,6 @@ struct azx;
|
||||||
struct hda_controller_ops {
|
struct hda_controller_ops {
|
||||||
/* Disable msi if supported, PCI only */
|
/* Disable msi if supported, PCI only */
|
||||||
int (*disable_msi_reset_irq)(struct azx *);
|
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,
|
void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
|
||||||
struct vm_area_struct *area);
|
struct vm_area_struct *area);
|
||||||
/* Check if current position is acceptable */
|
/* Check if current position is acceptable */
|
||||||
|
@ -127,7 +121,7 @@ struct azx {
|
||||||
int capture_streams;
|
int capture_streams;
|
||||||
int capture_index_offset;
|
int capture_index_offset;
|
||||||
int num_streams;
|
int num_streams;
|
||||||
const int *jackpoll_ms; /* per-card jack poll interval */
|
int jackpoll_interval; /* jack poll interval in jiffies */
|
||||||
|
|
||||||
/* Register interaction. */
|
/* Register interaction. */
|
||||||
const struct hda_controller_ops *ops;
|
const struct hda_controller_ops *ops;
|
||||||
|
@ -160,6 +154,7 @@ struct azx {
|
||||||
unsigned int msi:1;
|
unsigned int msi:1;
|
||||||
unsigned int probing:1; /* codec probing phase */
|
unsigned int probing:1; /* codec probing phase */
|
||||||
unsigned int snoop:1;
|
unsigned int snoop:1;
|
||||||
|
unsigned int uc_buffer:1; /* non-cached pages for stream buffers */
|
||||||
unsigned int align_buffer_size:1;
|
unsigned int align_buffer_size:1;
|
||||||
unsigned int region_requested:1;
|
unsigned int region_requested:1;
|
||||||
unsigned int disabled:1; /* disabled by vga_switcheroo */
|
unsigned int disabled:1; /* disabled by vga_switcheroo */
|
||||||
|
@ -175,11 +170,10 @@ struct azx {
|
||||||
#define azx_bus(chip) (&(chip)->bus.core)
|
#define azx_bus(chip) (&(chip)->bus.core)
|
||||||
#define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core)
|
#define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core)
|
||||||
|
|
||||||
#ifdef CONFIG_X86
|
static inline bool azx_snoop(struct azx *chip)
|
||||||
#define azx_snoop(chip) ((chip)->snoop)
|
{
|
||||||
#else
|
return !IS_ENABLED(CONFIG_X86) || chip->snoop;
|
||||||
#define azx_snoop(chip) true
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* macros for easy use
|
* macros for easy use
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include <sound/hda_chmap.h>
|
#include <sound/hda_chmap.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
|
|
||||||
enum eld_versions {
|
enum eld_versions {
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
#include <sound/tlv.h>
|
#include <sound/tlv.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/nospec.h>
|
#include <linux/nospec.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include <sound/hda_hwdep.h>
|
#include <sound/hda_hwdep.h>
|
||||||
#include <sound/minors.h>
|
#include <sound/minors.h>
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
#include <linux/vgaarb.h>
|
#include <linux/vgaarb.h>
|
||||||
#include <linux/vga_switcheroo.h>
|
#include <linux/vga_switcheroo.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_controller.h"
|
#include "hda_controller.h"
|
||||||
#include "hda_intel.h"
|
#include "hda_intel.h"
|
||||||
|
|
||||||
|
@ -399,61 +399,6 @@ static char *driver_short_names[] = {
|
||||||
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
|
[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 int azx_acquire_irq(struct azx *chip, int do_disconnect);
|
||||||
static void set_default_power_save(struct azx *chip);
|
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",
|
dev_info(chip->card->dev, "Force to %s mode by module option\n",
|
||||||
snoop ? "snoop" : "non-snoop");
|
snoop ? "snoop" : "non-snoop");
|
||||||
chip->snoop = snoop;
|
chip->snoop = snoop;
|
||||||
|
chip->uc_buffer = !snoop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1698,8 +1644,12 @@ static void azx_check_snoop_available(struct azx *chip)
|
||||||
snoop = false;
|
snoop = false;
|
||||||
|
|
||||||
chip->snoop = snoop;
|
chip->snoop = snoop;
|
||||||
if (!snoop)
|
if (!snoop) {
|
||||||
dev_info(chip->card->dev, "Force to non-snoop mode\n");
|
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)
|
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;
|
chip->driver_type = driver_caps & 0xff;
|
||||||
check_msi(chip);
|
check_msi(chip);
|
||||||
chip->dev_index = dev;
|
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_LIST_HEAD(&chip->pcm_list);
|
||||||
INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
|
INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
|
||||||
INIT_LIST_HEAD(&hda->list);
|
INIT_LIST_HEAD(&hda->list);
|
||||||
|
@ -2090,55 +2041,24 @@ static int dma_alloc_pages(struct hdac_bus *bus,
|
||||||
struct snd_dma_buffer *buf)
|
struct snd_dma_buffer *buf)
|
||||||
{
|
{
|
||||||
struct azx *chip = bus_to_azx(bus);
|
struct azx *chip = bus_to_azx(bus);
|
||||||
int err;
|
|
||||||
|
|
||||||
err = snd_dma_alloc_pages(type,
|
if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV)
|
||||||
bus->dev,
|
type = SNDRV_DMA_TYPE_DEV_UC;
|
||||||
size, buf);
|
return snd_dma_alloc_pages(type, bus->dev, size, buf);
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
mark_pages_wc(chip, buf, true);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *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);
|
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,
|
static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
|
||||||
struct vm_area_struct *area)
|
struct vm_area_struct *area)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||||
struct azx *chip = apcm->chip;
|
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);
|
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -2156,8 +2076,6 @@ static const struct hdac_io_ops pci_hda_io_ops = {
|
||||||
|
|
||||||
static const struct hda_controller_ops pci_hda_ops = {
|
static const struct hda_controller_ops pci_hda_ops = {
|
||||||
.disable_msi_reset_irq = disable_msi_reset_irq,
|
.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,
|
.pcm_mmap_prepare = pcm_mmap_prepare,
|
||||||
.position_check = azx_position_check,
|
.position_check = azx_position_check,
|
||||||
.link_power = azx_intel_link_power,
|
.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 */
|
/* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
|
||||||
SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
|
SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
|
||||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
|
/* 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 */
|
/* 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),
|
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 */
|
/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
|
||||||
SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
|
SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
|
||||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
|
/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
|
|
||||||
static int dump_coef = -1;
|
static int dump_coef = -1;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include <sound/hda_hwdep.h>
|
#include <sound/hda_hwdep.h>
|
||||||
#include <sound/minors.h>
|
#include <sound/minors.h>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_controller.h"
|
#include "hda_controller.h"
|
||||||
|
|
||||||
/* Defines for Nvidia Tegra HDA support */
|
/* 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);
|
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.
|
* 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,
|
.dma_free_pages = dma_free_pages,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct hda_controller_ops hda_tegra_ops = {
|
static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
|
||||||
.substream_alloc_pages = substream_alloc_pages,
|
|
||||||
.substream_free_pages = substream_free_pages,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void hda_tegra_init(struct hda_tegra *hda)
|
static void hda_tegra_init(struct hda_tegra *hda)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_beep.h"
|
#include "hda_beep.h"
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/tlv.h>
|
#include <sound/tlv.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
|
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_beep.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, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
|
||||||
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", 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, 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, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
|
||||||
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", 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),
|
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include <sound/hdaudio.h>
|
#include <sound/hdaudio.h>
|
||||||
#include <sound/hda_i915.h>
|
#include <sound/hda_i915.h>
|
||||||
#include <sound/hda_chmap.h>
|
#include <sound/hda_chmap.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
@ -6841,6 +6841,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
|
||||||
{0x1a, 0x02a11040},
|
{0x1a, 0x02a11040},
|
||||||
{0x1b, 0x01014020},
|
{0x1b, 0x01014020},
|
||||||
{0x21, 0x0221101f}),
|
{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,
|
SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
|
||||||
{0x14, 0x90170110},
|
{0x14, 0x90170110},
|
||||||
{0x19, 0x02a11020},
|
{0x19, 0x02a11020},
|
||||||
|
@ -7738,6 +7744,8 @@ enum {
|
||||||
ALC662_FIXUP_ASUS_Nx50,
|
ALC662_FIXUP_ASUS_Nx50,
|
||||||
ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
|
ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
|
||||||
ALC668_FIXUP_ASUS_Nx51,
|
ALC668_FIXUP_ASUS_Nx51,
|
||||||
|
ALC668_FIXUP_MIC_COEF,
|
||||||
|
ALC668_FIXUP_ASUS_G751,
|
||||||
ALC891_FIXUP_HEADSET_MODE,
|
ALC891_FIXUP_HEADSET_MODE,
|
||||||
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
|
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
|
||||||
ALC662_FIXUP_ACER_VERITON,
|
ALC662_FIXUP_ACER_VERITON,
|
||||||
|
@ -8007,6 +8015,23 @@ static const struct hda_fixup alc662_fixups[] = {
|
||||||
.chained = true,
|
.chained = true,
|
||||||
.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
|
.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] = {
|
[ALC891_FIXUP_HEADSET_MODE] = {
|
||||||
.type = HDA_FIXUP_FUNC,
|
.type = HDA_FIXUP_FUNC,
|
||||||
.v.func = alc_fixup_headset_mode,
|
.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, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
|
||||||
SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
|
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, 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, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
|
||||||
SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
|
SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
|
||||||
SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
|
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 = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
|
||||||
{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
|
{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
|
||||||
{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
|
{.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_HEADSET_MODE, .name = "alc891-headset"},
|
||||||
{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
|
{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
|
||||||
{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
|
{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
|
|
||||||
/* si3054 verbs */
|
/* si3054 verbs */
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/jack.h>
|
#include <sound/jack.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_beep.h"
|
#include "hda_beep.h"
|
||||||
|
@ -77,6 +77,7 @@ enum {
|
||||||
STAC_DELL_M6_BOTH,
|
STAC_DELL_M6_BOTH,
|
||||||
STAC_DELL_EQ,
|
STAC_DELL_EQ,
|
||||||
STAC_ALIENWARE_M17X,
|
STAC_ALIENWARE_M17X,
|
||||||
|
STAC_ELO_VUPOINT_15MX,
|
||||||
STAC_92HD89XX_HP_FRONT_JACK,
|
STAC_92HD89XX_HP_FRONT_JACK,
|
||||||
STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
|
STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
|
||||||
STAC_92HD73XX_ASUS_MOBO,
|
STAC_92HD73XX_ASUS_MOBO,
|
||||||
|
@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
|
||||||
codec->no_jack_detect = 1;
|
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[] = {
|
static const struct hda_fixup stac92hd73xx_fixups[] = {
|
||||||
[STAC_92HD73XX_REF] = {
|
[STAC_92HD73XX_REF] = {
|
||||||
.type = HDA_FIXUP_FUNC,
|
.type = HDA_FIXUP_FUNC,
|
||||||
|
@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
|
||||||
.type = HDA_FIXUP_FUNC,
|
.type = HDA_FIXUP_FUNC,
|
||||||
.v.func = stac92hd73xx_fixup_alienware_m17x,
|
.v.func = stac92hd73xx_fixup_alienware_m17x,
|
||||||
},
|
},
|
||||||
|
[STAC_ELO_VUPOINT_15MX] = {
|
||||||
|
.type = HDA_FIXUP_FUNC,
|
||||||
|
.v.func = stac92hd73xx_disable_automute,
|
||||||
|
},
|
||||||
[STAC_92HD73XX_INTEL] = {
|
[STAC_92HD73XX_INTEL] = {
|
||||||
.type = HDA_FIXUP_PINS,
|
.type = HDA_FIXUP_PINS,
|
||||||
.v.pins = intel_dg45id_pin_configs,
|
.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_M6_BOTH, .name = "dell-m6" },
|
||||||
{ .id = STAC_DELL_EQ, .name = "dell-eq" },
|
{ .id = STAC_DELL_EQ, .name = "dell-eq" },
|
||||||
{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
|
{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
|
||||||
|
{ .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
|
||||||
{ .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
|
{ .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),
|
"Alienware M17x", STAC_ALIENWARE_M17X),
|
||||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
|
||||||
"Alienware M17x R3", STAC_DELL_EQ),
|
"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,
|
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
|
||||||
"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
|
"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
|
||||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
|
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
#include "hda_codec.h"
|
#include <sound/hda_codec.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
|
|
|
@ -38,11 +38,6 @@
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
#include <sound/initval.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_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
|
||||||
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
|
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 */
|
unsigned int ali_slot; /* ALI DMA slot */
|
||||||
struct ac97_pcm *pcm;
|
struct ac97_pcm *pcm;
|
||||||
int pcm_open_flag;
|
int pcm_open_flag;
|
||||||
unsigned int page_attr_changed: 1;
|
|
||||||
unsigned int suspended: 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);
|
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
|
* Interrupt handler
|
||||||
*/
|
*/
|
||||||
|
@ -850,7 +825,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
ichdev->suspended = 0;
|
ichdev->suspended = 0;
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
val = ICH_IOCE | ICH_STARTBM;
|
val = ICH_IOCE | ICH_STARTBM;
|
||||||
|
@ -858,7 +833,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
ichdev->suspended = 1;
|
ichdev->suspended = 1;
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
val = 0;
|
val = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -892,7 +867,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
ichdev->suspended = 0;
|
ichdev->suspended = 0;
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
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;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
ichdev->suspended = 1;
|
ichdev->suspended = 1;
|
||||||
/* fallthru */
|
/* fall through */
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
/* pause */
|
/* 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 intel8x0 *chip = snd_pcm_substream_chip(substream);
|
||||||
struct ichdev *ichdev = get_ichdev(substream);
|
struct ichdev *ichdev = get_ichdev(substream);
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
int dbl = params_rate(hw_params) > 48000;
|
int dbl = params_rate(hw_params) > 48000;
|
||||||
int err;
|
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));
|
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
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) {
|
if (ichdev->pcm_open_flag) {
|
||||||
snd_ac97_pcm_close(ichdev->pcm);
|
snd_ac97_pcm_close(ichdev->pcm);
|
||||||
ichdev->pcm_open_flag = 0;
|
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)
|
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);
|
struct ichdev *ichdev = get_ichdev(substream);
|
||||||
|
|
||||||
if (ichdev->pcm_open_flag) {
|
if (ichdev->pcm_open_flag) {
|
||||||
snd_ac97_pcm_close(ichdev->pcm);
|
snd_ac97_pcm_close(ichdev->pcm);
|
||||||
ichdev->pcm_open_flag = 0;
|
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);
|
return snd_pcm_lib_free_pages(substream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1510,6 +1469,9 @@ struct ich_pcm_table {
|
||||||
int ac97_idx;
|
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,
|
static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
|
||||||
struct ich_pcm_table *rec)
|
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);
|
strcpy(pcm->name, chip->card->shortname);
|
||||||
chip->pcm[device] = pcm;
|
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),
|
snd_dma_pci_data(chip->pci),
|
||||||
rec->prealloc_size, rec->prealloc_max_size);
|
rec->prealloc_size, rec->prealloc_max_size);
|
||||||
|
|
||||||
|
@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
|
||||||
__hw_end:
|
__hw_end:
|
||||||
if (chip->irq >= 0)
|
if (chip->irq >= 0)
|
||||||
free_irq(chip->irq, chip);
|
free_irq(chip->irq, chip);
|
||||||
if (chip->bdbars.area) {
|
if (chip->bdbars.area)
|
||||||
if (chip->fix_nocache)
|
|
||||||
fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
|
|
||||||
snd_dma_free_pages(&chip->bdbars);
|
snd_dma_free_pages(&chip->bdbars);
|
||||||
}
|
|
||||||
if (chip->addr)
|
if (chip->addr)
|
||||||
pci_iounmap(chip->pci, chip->addr);
|
pci_iounmap(chip->pci, chip->addr);
|
||||||
if (chip->bmaddr)
|
if (chip->bmaddr)
|
||||||
|
@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev)
|
||||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||||
for (i = 0; i < chip->pcm_devs; i++)
|
for (i = 0; i < chip->pcm_devs; i++)
|
||||||
snd_pcm_suspend_all(chip->pcm[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++)
|
for (i = 0; i < chip->ncodecs; i++)
|
||||||
snd_ac97_suspend(chip->ac97[i]);
|
snd_ac97_suspend(chip->ac97[i]);
|
||||||
if (chip->device_type == DEVICE_INTEL_ICH4)
|
if (chip->device_type == DEVICE_INTEL_ICH4)
|
||||||
|
@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev)
|
||||||
ICH_PCM_SPDIF_1011);
|
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++)
|
for (i = 0; i < chip->ncodecs; i++)
|
||||||
snd_ac97_resume(chip->ac97[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 */
|
/* resume status */
|
||||||
for (i = 0; i < chip->bdbars_count; i++) {
|
for (i = 0; i < chip->bdbars_count; i++) {
|
||||||
struct ichdev *ichdev = &chip->ichd[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);
|
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 &&
|
if (pci->vendor == PCI_VENDOR_ID_INTEL &&
|
||||||
pci->device == PCI_DEVICE_ID_INTEL_440MX)
|
pci->device == PCI_DEVICE_ID_INTEL_440MX)
|
||||||
chip->fix_nocache = 1; /* enable workaround */
|
chip->fix_nocache = 1; /* enable workaround */
|
||||||
|
@ -3128,7 +3066,7 @@ static int snd_intel8x0_create(struct snd_card *card,
|
||||||
|
|
||||||
/* allocate buffer descriptor lists */
|
/* allocate buffer descriptor lists */
|
||||||
/* the start of each lists must be aligned to 8 bytes */
|
/* 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_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
|
||||||
&chip->bdbars) < 0) {
|
&chip->bdbars) < 0) {
|
||||||
snd_intel8x0_free(chip);
|
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
|
/* tables must be aligned to 8 bytes here, but the kernel pages
|
||||||
are much bigger, so we don't care (on i386) */
|
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;
|
int_sta_masks = 0;
|
||||||
for (i = 0; i < chip->bdbars_count; i++) {
|
for (i = 0; i < chip->bdbars_count; i++) {
|
||||||
ichdev = &chip->ichd[i];
|
ichdev = &chip->ichd[i];
|
||||||
|
|
|
@ -1171,16 +1171,6 @@ static int snd_intel8x0m_create(struct snd_card *card,
|
||||||
}
|
}
|
||||||
|
|
||||||
port_inited:
|
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 */
|
/* initialize offsets */
|
||||||
chip->bdbars_count = 2;
|
chip->bdbars_count = 2;
|
||||||
tbl = intel_regs;
|
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_reg = ICH_REG_GLOB_STA;
|
||||||
chip->int_sta_mask = int_sta_masks;
|
chip->int_sta_mask = int_sta_masks;
|
||||||
|
|
||||||
|
pci_set_master(pci);
|
||||||
|
|
||||||
if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
|
if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
|
||||||
snd_intel8x0m_free(chip);
|
snd_intel8x0m_free(chip);
|
||||||
return err;
|
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) {
|
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
|
||||||
snd_intel8x0m_free(chip);
|
snd_intel8x0m_free(chip);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -319,7 +319,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_info = {
|
||||||
SNDRV_PCM_INFO_MMAP_VALID |
|
SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_PAUSE |
|
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 |
|
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||||
SNDRV_PCM_FMTBIT_S32_LE),
|
SNDRV_PCM_FMTBIT_S32_LE),
|
||||||
.rates = (SNDRV_PCM_RATE_32000 |
|
.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_MMAP_VALID |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_PAUSE |
|
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,
|
.formats= SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.rates = (SNDRV_PCM_RATE_44100 |
|
.rates = (SNDRV_PCM_RATE_44100 |
|
||||||
SNDRV_PCM_RATE_48000),
|
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_MMAP_VALID |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_PAUSE |
|
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 |
|
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||||
SNDRV_PCM_FMTBIT_S32_LE),
|
SNDRV_PCM_FMTBIT_S32_LE),
|
||||||
.rates = (SNDRV_PCM_RATE_32000 |
|
.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_MMAP_VALID |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_PAUSE |
|
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,
|
.formats= SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.rates = (SNDRV_PCM_RATE_44100 |
|
.rates = (SNDRV_PCM_RATE_44100 |
|
||||||
SNDRV_PCM_RATE_48000),
|
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);
|
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) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
if (rme32->running && ! RME32_ISWORKING(rme32))
|
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");
|
dev_dbg(card->dev, "Update mixer controls...\n");
|
||||||
hdspm_update_simple_mixer_controls(hdspm);
|
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);
|
err = snd_card_register(card);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include "../codecs/da7219.h"
|
#include "../codecs/da7219.h"
|
||||||
#include "../codecs/da7219-aad.h"
|
#include "../codecs/da7219-aad.h"
|
||||||
|
|
||||||
#define CZ_PLAT_CLK 25000000
|
#define CZ_PLAT_CLK 48000000
|
||||||
#define DUAL_CHANNEL 2
|
#define DUAL_CHANNEL 2
|
||||||
|
|
||||||
static struct snd_soc_jack cz_jack;
|
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");
|
da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
|
||||||
|
|
||||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
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_0 | SND_JACK_BTN_1 |
|
||||||
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
||||||
&cz_jack, NULL, 0);
|
&cz_jack, NULL, 0);
|
||||||
|
@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
|
||||||
.mask = 0,
|
.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_pcm_runtime *runtime = substream->runtime;
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
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,
|
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||||
&constraints_rates);
|
&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;
|
machine->capture_channel = CAP_CHANNEL1;
|
||||||
return da7219_clk_enable(substream);
|
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)
|
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_pcm_runtime *rtd = substream->private_data;
|
||||||
struct snd_soc_card *card = rtd->card;
|
struct snd_soc_card *card = rtd->card;
|
||||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(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);
|
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)
|
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_pcm_runtime *rtd = substream->private_data;
|
||||||
struct snd_soc_card *card = rtd->card;
|
struct snd_soc_card *card = rtd->card;
|
||||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(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);
|
return da7219_clk_enable(substream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cz_dmic1_startup(struct snd_pcm_substream *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_pcm_runtime *rtd = substream->private_data;
|
||||||
struct snd_soc_card *card = rtd->card;
|
struct snd_soc_card *card = rtd->card;
|
||||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(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;
|
machine->capture_channel = CAP_CHANNEL0;
|
||||||
return da7219_clk_enable(substream);
|
return da7219_clk_enable(substream);
|
||||||
}
|
}
|
||||||
|
@ -201,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
|
||||||
da7219_clk_disable();
|
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 = {
|
static const struct snd_soc_ops cz_da7219_cap_ops = {
|
||||||
.startup = cz_da7219_startup,
|
.startup = cz_da7219_cap_startup,
|
||||||
.shutdown = cz_da7219_shutdown,
|
.shutdown = cz_da7219_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||||
| SND_SOC_DAIFMT_CBM_CFM,
|
| SND_SOC_DAIFMT_CBM_CFM,
|
||||||
.init = cz_da7219_init,
|
.init = cz_da7219_init,
|
||||||
.dpcm_playback = 1,
|
.dpcm_playback = 1,
|
||||||
.ops = &cz_da7219_cap_ops,
|
.ops = &cz_da7219_play_ops,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "amd-da7219-cap",
|
.name = "amd-da7219-cap",
|
||||||
|
|
|
@ -867,8 +867,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (pinfo) {
|
if (pinfo) {
|
||||||
rtd->i2s_instance = pinfo->i2s_instance;
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
rtd->capture_channel = pinfo->capture_channel;
|
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) {
|
if (adata->asic_type == CHIP_STONEY) {
|
||||||
val = acp_reg_read(adata->acp_mmio,
|
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) {
|
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||||
period_bytes = frames_to_bytes(runtime, runtime->period_size);
|
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);
|
bytescount = acp_get_byte_count(rtd);
|
||||||
if (bytescount > rtd->bytescount)
|
if (bytescount >= rtd->bytescount)
|
||||||
bytescount -= rtd->bytescount;
|
bytescount -= rtd->bytescount;
|
||||||
delay = do_div(bytescount, period_bytes);
|
if (bytescount < period_bytes) {
|
||||||
runtime->delay = bytes_to_frames(runtime, delay);
|
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 {
|
} else {
|
||||||
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
||||||
bytescount = acp_get_byte_count(rtd);
|
bytescount = acp_get_byte_count(rtd);
|
||||||
|
|
|
@ -158,7 +158,8 @@ struct audio_drv_data {
|
||||||
* and dma driver
|
* and dma driver
|
||||||
*/
|
*/
|
||||||
struct acp_platform_info {
|
struct acp_platform_info {
|
||||||
u16 i2s_instance;
|
u16 play_i2s_instance;
|
||||||
|
u16 cap_i2s_instance;
|
||||||
u16 capture_channel;
|
u16 capture_channel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -97,4 +97,16 @@ config SND_ATMEL_SOC_I2S
|
||||||
help
|
help
|
||||||
Say Y or M if you want to add support for Atmel ASoc driver for boards
|
Say Y or M if you want to add support for Atmel ASoc driver for boards
|
||||||
using I2S.
|
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
|
endif
|
||||||
|
|
|
@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
|
||||||
snd-atmel-soc-classd-objs := atmel-classd.o
|
snd-atmel-soc-classd-objs := atmel-classd.o
|
||||||
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
|
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
|
||||||
snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.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_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||||
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.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_CLASSD) += snd-atmel-soc-classd.o
|
||||||
obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.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_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);
|
struct ssc_device *ssc = dev_get_drvdata(dev);
|
||||||
int ret;
|
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);
|
&atmel_ssc_dai, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Could not register DAI: %d\n", ret);
|
dev_err(dev, "Could not register DAI: %d\n", ret);
|
||||||
goto err;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssc->pdata->use_dma)
|
if (ssc->pdata->use_dma)
|
||||||
|
@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev)
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Could not register PCM: %d\n", ret);
|
dev_err(dev, "Could not register PCM: %d\n", ret);
|
||||||
goto err_unregister_dai;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_unregister_dai:
|
|
||||||
snd_soc_unregister_component(dev);
|
|
||||||
err:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asoc_ssc_exit(struct device *dev)
|
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);
|
atmel_pcm_dma_platform_unregister(dev);
|
||||||
else
|
else
|
||||||
atmel_pcm_pdc_platform_unregister(dev);
|
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