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:
Linus Torvalds 2018-10-25 09:00:15 -07:00
commit 3acbd2de6b
244 changed files with 10789 additions and 2637 deletions

View File

@ -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 = <&regulator>;
DVDD-supply = <&regulator_digital>;
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
};
adau1977_i2c: adau1977@11 {
compatible = "adi,adau1977";
reg = <0x11>;
AVDD-supply = <&regulator>;
DVDD-supply = <&regulator_digital>;
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
};

View File

@ -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";
};

View File

@ -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";
};

View File

@ -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";
};

View File

@ -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";
};
};

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -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>;
}; };
}; };
}; };

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -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:

View File

@ -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>;
};

View File

@ -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).

View File

@ -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>;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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)

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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)

View File

@ -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.

View File

@ -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;
} }

View File

@ -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 = {

View File

@ -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);

View File

@ -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)

View File

@ -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[] = {

View File

@ -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 = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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 = {

View File

@ -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[] = {

View File

@ -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;

View File

@ -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))

View File

@ -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 |

View File

@ -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)

View File

@ -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:

View File

@ -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",

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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>

View File

@ -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++;
} }

View File

@ -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

View File

@ -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 {

View File

@ -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"

View File

@ -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>

View File

@ -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 */

View File

@ -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"

View File

@ -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;

View File

@ -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>

View File

@ -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)
{ {

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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),

View File

@ -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"

View File

@ -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"},

View File

@ -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 */

View File

@ -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,

View File

@ -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"

View File

@ -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];

View File

@ -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;

View File

@ -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))

View File

@ -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) {

View File

@ -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",

View File

@ -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);

View File

@ -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;
}; };

View File

@ -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

View File

@ -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

View File

@ -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);
} }
/** /**

View File

@ -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