sound updates for 5.6-rc1

As diffstat shows we've had again a lot of works done for this cycle:
 majority of changes are the continued componentization and code
 refactoring in ASoC, the tree-wide PCM API updates and cleanups
 and SOF updates while a few ASoC driver updates are seen, too.
 
 Here we go, some highlights:
 
 Core:
 - Finally y2038 support landed to ALSA ABI;
   some ioctls have been extended and lots of tricks were applied
 - Applying the new managed PCM buffer API to all drivers;
   the API itself was already merged in 5.5
 - The already deprecated dimension support in ALSA control API is
   dropped completely now
 - Verification of ALSA control elements to catch API misuses
 
 ASoC:
 - Further code refactorings and moving things to the component level
 - Lots of updates and improvements on SOF / Intel drivers;
   now including common HDMI driver and SoundWire support
 - New driver support for Ingenic JZ4770, Mediatek MT6660, Qualcomm
   WCD934x and WSA881x, and Realtek RT700, RT711, RT715, RT1011, RT1015
   and RT1308
 
 HD-audio:
 - Improved ring-buffer communications using waitqueue
 - Drop the superfluous buffer preallocation on x86
 
 Others:
 - Many code cleanups, mostly constifications over the whole tree
 - USB-audio: quirks for MOTU, Corsair Virtuoso, Line6 Helix
 - FireWire: code refactoring for oxfw and dice drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAl4v7qsOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE9s7hAAoeqwRF+WffBaSMZKShDyFD5L7Z/YeXxh2b81
 ErnVaSbXmWMhzgx7G7dj3bchkJWYsqAH//j3/AHYCF22slJdeTof0cpqaRgC0qEv
 eIj9ALu2Hh+z5jJHOlbpcYevtK89frY9zu4Su/5YAfZloUNLqAbl59SNOiS99/hu
 SR5rF0UCGngHf+pjiBpruQv2hahD5Y0a4rIGMaZB/GAa3p7eQ42koMmIEje/rjF0
 bSpiYmmAwGJ62RlTUFCBNlj9w78eUfqrf8SHr91d7zNHUZpHR9GoFswmLGM0UtGS
 5gIm+6UkBmTQcqgKhYsLl2eT/PSLVHpbYUeABjP62EqxWpksOl2/fQfrGuVT1Vjm
 QVoc345dKoKcNxVH1iuVg+/JYsmuPIpSmviFCKbH5IUlTWWyOYzWxZVdrZ/gIyXh
 fY/vDL2yOdR9mTnHYAfsJ8IB2ABY4pDahC6Dbvh5JoN/vmsND2Wv2l+HIIdLTarj
 R/n7+Rn6HLQmCJvgIWLniG6FxYxx4gqd/VVVaL7eJKYrcqvQq6VNZ/36Fgh3Ahdi
 HnKxyer3K7vC8CGM3cNH/Dq/iGTNgTcX6pnhVepl/elSZTMDrxZcWbbA0nPhBe8J
 5SWGEstv11OBi/JL3vGdTmV4ceZ/yIBg9pIGg4j0rH3hKT83G7O5E++PixKCmmMc
 fZPCeAg=
 =PGgQ
 -----END PGP SIGNATURE-----

Merge tag 'sound-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "As the diffstat shows we've had again a lot of works done for this
  cycle: the majority of changes are the continued componentization and
  code refactoring in ASoC, the tree-wide PCM API updates and cleanups
  and SOF updates while a few ASoC driver updates are seen, too.

  Here we go, some highlights:

  Core:
   - Finally y2038 support landed to ALSA ABI; some ioctls have been
     extended and lots of tricks were applied
   - Applying the new managed PCM buffer API to all drivers; the API
     itself was already merged in 5.5
   - The already deprecated dimension support in ALSA control API is
     dropped completely now
   - Verification of ALSA control elements to catch API misuses

  ASoC:
   - Further code refactorings and moving things to the component level
   - Lots of updates and improvements on SOF / Intel drivers; now
     including common HDMI driver and SoundWire support
   - New driver support for Ingenic JZ4770, Mediatek MT6660, Qualcomm
     WCD934x and WSA881x, and Realtek RT700, RT711, RT715, RT1011,
     RT1015 and RT1308

  HD-audio:
   - Improved ring-buffer communications using waitqueue
   - Drop the superfluous buffer preallocation on x86

  Others:
   - Many code cleanups, mostly constifications over the whole tree
   - USB-audio: quirks for MOTU, Corsair Virtuoso, Line6 Helix
   - FireWire: code refactoring for oxfw and dice drivers"

* tag 'sound-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (638 commits)
  ALSA: usb-audio: add quirks for Line6 Helix devices fw>=2.82
  ALSA: hda: Add Clevo W65_67SB the power_save blacklist
  ASoC: soc-core: remove null_snd_soc_ops
  ASoC: soc-pcm: add soc_rtd_trigger()
  ASoC: soc-pcm: add soc_rtd_hw_free()
  ASoC: soc-pcm: add soc_rtd_hw_params()
  ASoC: soc-pcm: add soc_rtd_prepare()
  ASoC: soc-pcm: add soc_rtd_shutdown()
  ASoC: soc-pcm: add soc_rtd_startup()
  ASoC: rt1015: add rt1015 amplifier driver
  ASoC: madera: Correct some kernel doc
  ASoC: topology: fix soc_tplg_fe_link_create() - link->dobj initialization order
  ASoC: Intel: skl_hda_dsp_common: Fix global-out-of-bounds bug
  ASoC: madera: Correct DMIC only input hook ups
  ALSA: cs46xx: fix spelling mistake "to" -> "too"
  ALSA: hda - Add docking station support for Lenovo Thinkpad T420s
  ASoC: Add MediaTek MT6660 Speaker Amp Driver
  ASoC: dt-bindings: rt5645: add suppliers
  ASoC: max98090: fix deadlock in max98090_dapm_put_enum_double()
  ASoC: dapm: add snd_soc_dapm_put_enum_double_locked
  ...
This commit is contained in:
Linus Torvalds 2020-01-28 16:26:57 -08:00
commit fb95aae6e6
617 changed files with 27604 additions and 8125 deletions

View File

@ -17,6 +17,9 @@ Required properties:
* "arb" : memory ARB line (required) * "arb" : memory ARB line (required)
* "rst" : dedicated device reset line (optional) * "rst" : dedicated device reset line (optional)
- #sound-dai-cells: must be 0. - #sound-dai-cells: must be 0.
- amlogic,fifo-depth: The size of the controller's fifo in bytes. This
is useful for determining certain configuration such
as the flush threshold of the fifo
Example of FRDDR A on the A113 SoC: Example of FRDDR A on the A113 SoC:
@ -27,4 +30,5 @@ frddr_a: audio-controller@1c0 {
interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>; interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; clocks = <&clkc_audio AUD_CLKID_FRDDR_A>;
resets = <&arb AXG_ARB_FRDDR_A>; resets = <&arb AXG_ARB_FRDDR_A>;
fifo-depth = <512>;
}; };

View File

@ -8,7 +8,12 @@ three substreams within totally 10 channels.
Required properties: Required properties:
- compatible : Contains "fsl,imx35-asrc" or "fsl,imx53-asrc". - compatible : Compatible list, should contain one of the following
compatibles:
"fsl,imx35-asrc",
"fsl,imx53-asrc",
"fsl,imx8qm-asrc",
"fsl,imx8qxp-asrc",
- reg : Offset and length of the register set for the device. - reg : Offset and length of the register set for the device.
@ -35,6 +40,11 @@ Required properties:
- fsl,asrc-width : Defines a mutual sample width used by DPCM Back Ends. - fsl,asrc-width : Defines a mutual sample width used by DPCM Back Ends.
- fsl,asrc-clk-map : Defines clock map used in driver. which is required
by imx8qm/imx8qxp platform
<0> - select the map for asrc0 in imx8qm/imx8qxp
<1> - select the map for asrc1 in imx8qm/imx8qxp
Optional properties: Optional properties:
- big-endian : If this property is absent, the little endian mode - big-endian : If this property is absent, the little endian mode

View File

@ -1,10 +1,16 @@
GTM601 UMTS modem audio interface CODEC GTM601 UMTS modem audio interface CODEC
This device has no configuration interface. Sample rate is fixed - 8kHz. This device has no configuration interface. The sample rate and channels are
based on the compatible string
"option,gtm601" = 8kHz mono
"broadmobi,bm818" = 48KHz stereo
Required properties: Required properties:
- compatible : "option,gtm601" - compatible : one of
"option,gtm601"
"broadmobi,bm818"
Example: Example:

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ingenic,codec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ingenic JZ47xx internal codec DT bindings
maintainers:
- Paul Cercueil <paul@crapouillou.net>
properties:
$nodename:
pattern: '^audio-codec@.*'
compatible:
oneOf:
- const: ingenic,jz4770-codec
- const: ingenic,jz4725b-codec
- const: ingenic,jz4740-codec
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: aic
'#sound-dai-cells':
const: 0
additionalProperties: false
required:
- compatible
- reg
- clocks
- clock-names
- '#sound-dai-cells'
examples:
- |
#include <dt-bindings/clock/jz4740-cgu.h>
codec: audio-codec@10020080 {
compatible = "ingenic,jz4740-codec";
reg = <0x10020080 0x8>;
#sound-dai-cells = <0>;
clocks = <&cgu JZ4740_CLK_AIC>;
clock-names = "aic";
};
...

View File

@ -1,20 +0,0 @@
Ingenic JZ4725B codec controller
Required properties:
- compatible : "ingenic,jz4725b-codec"
- reg : codec registers location and length
- clocks : phandle to the AIC clock.
- clock-names: must be set to "aic".
- #sound-dai-cells: Must be set to 0.
Example:
codec: audio-codec@100200a4 {
compatible = "ingenic,jz4725b-codec";
reg = <0x100200a4 0x8>;
#sound-dai-cells = <0>;
clocks = <&cgu JZ4725B_CLK_AIC>;
clock-names = "aic";
};

View File

@ -1,20 +0,0 @@
Ingenic JZ4740 codec controller
Required properties:
- compatible : "ingenic,jz4740-codec"
- reg : codec registers location and length
- clocks : phandle to the AIC clock.
- clock-names: must be set to "aic".
- #sound-dai-cells: Must be set to 0.
Example:
codec: audio-codec@10020080 {
compatible = "ingenic,jz4740-codec";
reg = <0x10020080 0x8>;
#sound-dai-cells = <0>;
clocks = <&cgu JZ4740_CLK_AIC>;
clock-names = "aic";
};

View File

@ -5,7 +5,10 @@ This binding describes the SDM845 sound card, which uses qdsp for audio.
- compatible: - compatible:
Usage: required Usage: required
Value type: <stringlist> Value type: <stringlist>
Definition: must be "qcom,sdm845-sndcard" Definition: must be one of this
"qcom,sdm845-sndcard"
"qcom,db845c-sndcard"
"lenovo,yoga-c630-sndcard"
- audio-routing: - audio-routing:
Usage: Optional Usage: Optional

View File

@ -0,0 +1,175 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wcd934x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bindings for Qualcomm WCD9340/WCD9341 Audio Codec
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
Qualcomm WCD9340/WCD9341 Codec is a standalone Hi-Fi audio codec IC.
It has in-built Soundwire controller, pin controller, interrupt mux and
supports both I2S/I2C and SLIMbus audio interfaces.
properties:
compatible:
const: slim217,250
reg:
maxItems: 1
interrupts:
maxItems: 1
reset-gpios:
description: GPIO spec for reset line to use
maxItems: 1
slim-ifc-dev: true
clocks:
maxItems: 1
clock-names:
const: extclk
vdd-buck-supply:
description: A reference to the 1.8V buck supply
vdd-buck-sido-supply:
description: A reference to the 1.8V SIDO buck supply
vdd-rx-supply:
description: A reference to the 1.8V rx supply
vdd-tx-supply:
description: A reference to the 1.8V tx supply
vdd-vbat-supply:
description: A reference to the vbat supply
vdd-io-supply:
description: A reference to the 1.8V I/O supply
vdd-micbias-supply:
description: A reference to the micbias supply
qcom,micbias1-microvolt:
description: micbias1 voltage
minimum: 1800000
maximum: 2850000
qcom,micbias2-microvolt:
description: micbias2 voltage
minimum: 1800000
maximum: 2850000
qcom,micbias3-microvolt:
description: micbias3 voltage
minimum: 1800000
maximum: 2850000
qcom,micbias4-microvolt:
description: micbias4 voltage
minimum: 1800000
maximum: 2850000
clock-output-names:
const: mclk
clock-frequency:
description: Clock frequency of output clk in Hz
interrupt-controller: true
'#interrupt-cells':
const: 1
'#clock-cells':
const: 0
'#sound-dai-cells':
const: 1
"#address-cells":
const: 1
"#size-cells":
const: 1
gpio@42:
type: object
allOf:
- $ref: ../gpio/qcom,wcd934x-gpio.yaml#
patternProperties:
"^.*@[0-9a-f]+$":
type: object
description: |
WCD934x subnode for each slave devices. Bindings of each subnodes
depends on the specific driver providing the functionality and
documented in their respective bindings.
properties:
reg:
maxItems: 1
required:
- reg
required:
- compatible
- reg
- reset-gpios
- slim-ifc-dev
- interrupts
- interrupt-controller
- clock-frequency
- clock-output-names
- qcom,micbias1-microvolt
- qcom,micbias2-microvolt
- qcom,micbias3-microvolt
- qcom,micbias4-microvolt
- "#interrupt-cells"
- "#clock-cells"
- "#sound-dai-cells"
- "#address-cells"
- "#size-cells"
examples:
- |
codec@1,0{
compatible = "slim217,250";
reg = <1 0>;
reset-gpios = <&tlmm 64 0>;
slim-ifc-dev = <&wcd9340_ifd>;
#sound-dai-cells = <1>;
interrupt-parent = <&tlmm>;
interrupts = <54 4>;
interrupt-controller;
#interrupt-cells = <1>;
#clock-cells = <0>;
clock-frequency = <9600000>;
clock-output-names = "mclk";
qcom,micbias1-microvolt = <1800000>;
qcom,micbias2-microvolt = <1800000>;
qcom,micbias3-microvolt = <1800000>;
qcom,micbias4-microvolt = <1800000>;
clock-names = "extclk";
clocks = <&rpmhcc 2>;
#address-cells = <1>;
#size-cells = <1>;
gpio@42 {
compatible = "qcom,wcd9340-gpio";
reg = <0x42 0x2>;
gpio-controller;
#gpio-cells = <2>;
};
};
...

View File

@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wsa881x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bindings for Qualcomm WSA8810/WSA8815 Class-D Smart Speaker Amplifier
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
WSA8810 is a class-D smart speaker amplifier and WSA8815
is a high-output power class-D smart speaker amplifier.
Their primary operating mode uses a SoundWire digital audio
interface. This binding is for SoundWire interface.
properties:
compatible:
const: sdw10217201000
reg:
maxItems: 1
powerdown-gpios:
description: GPIO spec for Powerdown/Shutdown line to use
maxItems: 1
'#thermal-sensor-cells':
const: 0
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
- powerdown-gpios
- "#thermal-sensor-cells"
- "#sound-dai-cells"
additionalProperties: false
examples:
- |
soundwire@c2d0000 {
#address-cells = <2>;
#size-cells = <0>;
reg = <0x0c2d0000 0x2000>;
speaker@0,1 {
compatible = "sdw10217201000";
reg = <0 1>;
powerdown-gpios = <&wcdpinctrl 2 0>;
#thermal-sensor-cells = <0>;
#sound-dai-cells = <0>;
};
speaker@0,2 {
compatible = "sdw10217201000";
reg = <0 2>;
powerdown-gpios = <&wcdpinctrl 2 0>;
#thermal-sensor-cells = <0>;
#sound-dai-cells = <0>;
};
};
...

View File

@ -0,0 +1,17 @@
RT1015 Mono Class D Audio Amplifier
This device supports I2C only.
Required properties:
- compatible : "realtek,rt1015".
- reg : The I2C address of the device.
Example:
rt1015: codec@28 {
compatible = "realtek,rt1015";
reg = <0x28>;
};

View File

@ -10,6 +10,10 @@ Required properties:
- interrupts : The CODEC's interrupt output. - interrupts : The CODEC's interrupt output.
- avdd-supply: Power supply for AVDD, providing 1.8V.
- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
Optional properties: Optional properties:
- hp-detect-gpios: - hp-detect-gpios:

View File

@ -495,7 +495,8 @@ Module for C-Media CMI8338/8738/8768/8770 PCI sound cards.
mpu_port mpu_port
port address of MIDI interface (8338 only): port address of MIDI interface (8338 only):
0x300,0x310,0x320,0x330 = legacy port, 0x300,0x310,0x320,0x330 = legacy port,
0 = disable (default) 1 = integrated PCI port (default on 8738),
0 = disable
fm_port fm_port
port address of OPL-3 FM synthesizer (8x38 only): port address of OPL-3 FM synthesizer (8x38 only):
0x388 = legacy port, 0x388 = legacy port,

View File

@ -259,7 +259,7 @@ to details explained in the following section.
{ {
struct mychip *chip; struct mychip *chip;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_mychip_dev_free, .dev_free = snd_mychip_dev_free,
}; };
@ -675,7 +675,7 @@ low-level device with a specified ``ops``,
:: ::
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_mychip_dev_free, .dev_free = snd_mychip_dev_free,
}; };
.... ....
@ -761,7 +761,7 @@ destructor and PCI entries. Example code is shown first, below.
{ {
struct mychip *chip; struct mychip *chip;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_mychip_dev_free, .dev_free = snd_mychip_dev_free,
}; };
@ -3912,7 +3912,7 @@ For a raw-data proc-file, set the attributes as follows:
:: ::
static struct snd_info_entry_ops my_file_io_ops = { static const struct snd_info_entry_ops my_file_io_ops = {
.read = my_file_io_read, .read = my_file_io_read,
}; };

View File

@ -529,17 +529,24 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf); intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
} }
static int intel_config_stream(struct sdw_intel *sdw, static int intel_params_stream(struct sdw_intel *sdw,
struct snd_pcm_substream *substream, struct snd_pcm_substream *substream,
struct snd_soc_dai *dai, struct snd_soc_dai *dai,
struct snd_pcm_hw_params *hw_params, int link_id) struct snd_pcm_hw_params *hw_params,
int link_id, int alh_stream_id)
{ {
struct sdw_intel_link_res *res = sdw->res; struct sdw_intel_link_res *res = sdw->res;
struct sdw_intel_stream_params_data params_data;
if (res->ops && res->ops->config_stream && res->arg) params_data.substream = substream;
return res->ops->config_stream(res->arg, params_data.dai = dai;
substream, dai, hw_params, link_id); params_data.hw_params = hw_params;
params_data.link_id = link_id;
params_data.alh_stream_id = alh_stream_id;
if (res->ops && res->ops->params_stream && res->dev)
return res->ops->params_stream(res->dev,
&params_data);
return -EIO; return -EIO;
} }
@ -654,7 +661,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
/* Inform DSP about PDI stream number */ /* Inform DSP about PDI stream number */
ret = intel_config_stream(sdw, substream, dai, params, ret = intel_params_stream(sdw, substream, dai, params,
sdw->instance,
pdi->intel_alh_id); pdi->intel_alh_id);
if (ret) if (ret)
goto error; goto error;

View File

@ -5,23 +5,26 @@
#define __SDW_INTEL_LOCAL_H #define __SDW_INTEL_LOCAL_H
/** /**
* struct sdw_intel_link_res - Soundwire link resources * struct sdw_intel_link_res - Soundwire Intel link resource structure,
* typically populated by the controller driver.
* @pdev: platform_device
* @mmio_base: mmio base of SoundWire registers
* @registers: Link IO registers base * @registers: Link IO registers base
* @shim: Audio shim pointer * @shim: Audio shim pointer
* @alh: ALH (Audio Link Hub) pointer * @alh: ALH (Audio Link Hub) pointer
* @irq: Interrupt line * @irq: Interrupt line
* @ops: Shim callback ops * @ops: Shim callback ops
* @arg: Shim callback ops argument * @dev: device implementing hw_params and free callbacks
*
* This is set as pdata for each link instance.
*/ */
struct sdw_intel_link_res { struct sdw_intel_link_res {
struct platform_device *pdev;
void __iomem *mmio_base; /* not strictly needed, useful for debug */
void __iomem *registers; void __iomem *registers;
void __iomem *shim; void __iomem *shim;
void __iomem *alh; void __iomem *alh;
int irq; int irq;
const struct sdw_intel_ops *ops; const struct sdw_intel_ops *ops;
void *arg; struct device *dev;
}; };
#endif /* __SDW_INTEL_LOCAL_H */ #endif /* __SDW_INTEL_LOCAL_H */

View File

@ -27,19 +27,9 @@ static int link_mask;
module_param_named(sdw_link_mask, link_mask, int, 0444); module_param_named(sdw_link_mask, link_mask, int, 0444);
MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
struct sdw_link_data {
struct sdw_intel_link_res res;
struct platform_device *pdev;
};
struct sdw_intel_ctx {
int count;
struct sdw_link_data *links;
};
static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx) static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx)
{ {
struct sdw_link_data *link = ctx->links; struct sdw_intel_link_res *link = ctx->links;
int i; int i;
if (!link) if (!link)
@ -62,7 +52,7 @@ static struct sdw_intel_ctx
{ {
struct platform_device_info pdevinfo; struct platform_device_info pdevinfo;
struct platform_device *pdev; struct platform_device *pdev;
struct sdw_link_data *link; struct sdw_intel_link_res *link;
struct sdw_intel_ctx *ctx; struct sdw_intel_ctx *ctx;
struct acpi_device *adev; struct acpi_device *adev;
int ret, i; int ret, i;
@ -123,14 +113,13 @@ static struct sdw_intel_ctx
continue; continue;
} }
link->res.irq = res->irq; link->registers = res->mmio_base + SDW_LINK_BASE
link->res.registers = res->mmio_base + SDW_LINK_BASE
+ (SDW_LINK_SIZE * i); + (SDW_LINK_SIZE * i);
link->res.shim = res->mmio_base + SDW_SHIM_BASE; link->shim = res->mmio_base + SDW_SHIM_BASE;
link->res.alh = res->mmio_base + SDW_ALH_BASE; link->alh = res->mmio_base + SDW_ALH_BASE;
link->res.ops = res->ops; link->ops = res->ops;
link->res.arg = res->arg; link->dev = res->dev;
memset(&pdevinfo, 0, sizeof(pdevinfo)); memset(&pdevinfo, 0, sizeof(pdevinfo));
@ -138,8 +127,6 @@ static struct sdw_intel_ctx
pdevinfo.name = "int-sdw"; pdevinfo.name = "int-sdw";
pdevinfo.id = i; pdevinfo.id = i;
pdevinfo.fwnode = acpi_fwnode_handle(adev); pdevinfo.fwnode = acpi_fwnode_handle(adev);
pdevinfo.data = &link->res;
pdevinfo.size_data = sizeof(link->res);
pdev = platform_device_register_full(&pdevinfo); pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) { if (IS_ERR(pdev)) {
@ -216,7 +203,6 @@ void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res)
return sdw_intel_add_controller(res); return sdw_intel_add_controller(res);
} }
EXPORT_SYMBOL(sdw_intel_init);
/** /**
* sdw_intel_exit() - SoundWire Intel exit * sdw_intel_exit() - SoundWire Intel exit
@ -224,10 +210,8 @@ EXPORT_SYMBOL(sdw_intel_init);
* *
* Delete the controller instances created and cleanup * Delete the controller instances created and cleanup
*/ */
void sdw_intel_exit(void *arg) void sdw_intel_exit(struct sdw_intel_ctx *ctx)
{ {
struct sdw_intel_ctx *ctx = arg;
sdw_intel_cleanup_pdev(ctx); sdw_intel_cleanup_pdev(ctx);
kfree(ctx); kfree(ctx);
} }

View File

@ -547,6 +547,20 @@ struct sdw_slave_ops {
* @node: node for bus list * @node: node for bus list
* @port_ready: Port ready completion flag for each Slave port * @port_ready: Port ready completion flag for each Slave port
* @dev_num: Device Number assigned by Bus * @dev_num: Device Number assigned by Bus
* @probed: boolean tracking driver state
* @probe_complete: completion utility to control potential races
* on startup between driver probe/initialization and SoundWire
* Slave state changes/implementation-defined interrupts
* @enumeration_complete: completion utility to control potential races
* on startup between device enumeration and read/write access to the
* Slave device
* @initialization_complete: completion utility to control potential races
* on startup between device enumeration and settings being restored
* @unattach_request: mask field to keep track why the Slave re-attached and
* was re-initialized. This is useful to deal with potential race conditions
* between the Master suspending and the codec resuming, and make sure that
* when the Master triggered a reset the Slave is properly enumerated and
* initialized
*/ */
struct sdw_slave { struct sdw_slave {
struct sdw_slave_id id; struct sdw_slave_id id;
@ -561,6 +575,11 @@ struct sdw_slave {
struct list_head node; struct list_head node;
struct completion *port_ready; struct completion *port_ready;
u16 dev_num; u16 dev_num;
bool probed;
struct completion probe_complete;
struct completion enumeration_complete;
struct completion initialization_complete;
u32 unattach_request;
}; };
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev) #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)

View File

@ -4,36 +4,174 @@
#ifndef __SDW_INTEL_H #ifndef __SDW_INTEL_H
#define __SDW_INTEL_H #define __SDW_INTEL_H
#include <linux/irqreturn.h>
/** /**
* struct sdw_intel_ops: Intel audio driver callback ops * struct sdw_intel_stream_params_data: configuration passed during
* * the @params_stream callback, e.g. for interaction with DSP
* @config_stream: configure the stream with the hw_params * firmware.
* the first argument containing the context is mandatory
*/ */
struct sdw_intel_ops { struct sdw_intel_stream_params_data {
int (*config_stream)(void *arg, void *substream, struct snd_pcm_substream *substream;
void *dai, void *hw_params, int stream_num); struct snd_soc_dai *dai;
struct snd_pcm_hw_params *hw_params;
int link_id;
int alh_stream_id;
}; };
/** /**
* struct sdw_intel_res - Soundwire Intel resource structure * struct sdw_intel_stream_free_data: configuration passed during
* the @free_stream callback, e.g. for interaction with DSP
* firmware.
*/
struct sdw_intel_stream_free_data {
struct snd_pcm_substream *substream;
struct snd_soc_dai *dai;
int link_id;
};
/**
* struct sdw_intel_ops: Intel audio driver callback ops
*
*/
struct sdw_intel_ops {
int (*params_stream)(struct device *dev,
struct sdw_intel_stream_params_data *params_data);
int (*free_stream)(struct device *dev,
struct sdw_intel_stream_free_data *free_data);
};
/**
* struct sdw_intel_acpi_info - Soundwire Intel information found in ACPI tables
* @handle: ACPI controller handle
* @count: link count found with "sdw-master-count" property
* @link_mask: bit-wise mask listing links enabled by BIOS menu
*
* this structure could be expanded to e.g. provide all the _ADR
* information in case the link_mask is not sufficient to identify
* platform capabilities.
*/
struct sdw_intel_acpi_info {
acpi_handle handle;
int count;
u32 link_mask;
};
struct sdw_intel_link_res;
/* Intel clock-stop/pm_runtime quirk definitions */
/*
* Force the clock to remain on during pm_runtime suspend. This might
* be needed if Slave devices do not have an alternate clock source or
* if the latency requirements are very strict.
*/
#define SDW_INTEL_CLK_STOP_NOT_ALLOWED BIT(0)
/*
* Stop the bus during pm_runtime suspend. If set, a complete bus
* reset and re-enumeration will be performed when the bus
* restarts. This mode shall not be used if Slave devices can generate
* in-band wakes.
*/
#define SDW_INTEL_CLK_STOP_TEARDOWN BIT(1)
/*
* Stop the bus during pm_suspend if Slaves are not wake capable
* (e.g. speaker amplifiers). The clock-stop mode is typically
* slightly higher power than when the IP is completely powered-off.
*/
#define SDW_INTEL_CLK_STOP_WAKE_CAPABLE_ONLY BIT(2)
/*
* Require a bus reset (and complete re-enumeration) when exiting
* clock stop modes. This may be needed if the controller power was
* turned off and all context lost. This quirk shall not be used if a
* Slave device needs to remain enumerated and keep its context,
* e.g. to provide the reasons for the wake, report acoustic events or
* pass a history buffer.
*/
#define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3)
/**
* struct sdw_intel_ctx - context allocated by the controller
* driver probe
* @count: link count
* @mmio_base: mmio base of SoundWire registers, only used to check
* hardware capabilities after all power dependencies are settled.
* @link_mask: bit-wise mask listing SoundWire links reported by the
* Controller
* @handle: ACPI parent handle
* @links: information for each link (controller-specific and kept
* opaque here)
* @link_list: list to handle interrupts across all links
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
*/
struct sdw_intel_ctx {
int count;
void __iomem *mmio_base;
u32 link_mask;
acpi_handle handle;
struct sdw_intel_link_res *links;
struct list_head link_list;
struct mutex shim_lock; /* lock for access to shared SHIM registers */
};
/**
* struct sdw_intel_res - Soundwire Intel global resource structure,
* typically populated by the DSP driver
*
* @count: link count
* @mmio_base: mmio base of SoundWire registers * @mmio_base: mmio base of SoundWire registers
* @irq: interrupt number * @irq: interrupt number
* @handle: ACPI parent handle * @handle: ACPI parent handle
* @parent: parent device * @parent: parent device
* @ops: callback ops * @ops: callback ops
* @arg: callback arg * @dev: device implementing hwparams and free callbacks
* @link_mask: bit-wise mask listing links selected by the DSP driver
* This mask may be a subset of the one reported by the controller since
* machine-specific quirks are handled in the DSP driver.
* @clock_stop_quirks: mask array of possible behaviors requested by the
* DSP driver. The quirks are common for all links for now.
*/ */
struct sdw_intel_res { struct sdw_intel_res {
int count;
void __iomem *mmio_base; void __iomem *mmio_base;
int irq; int irq;
acpi_handle handle; acpi_handle handle;
struct device *parent; struct device *parent;
const struct sdw_intel_ops *ops; const struct sdw_intel_ops *ops;
void *arg; struct device *dev;
u32 link_mask;
u32 clock_stop_quirks;
}; };
void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res); /*
void sdw_intel_exit(void *arg); * On Intel platforms, the SoundWire IP has dependencies on power
* rails shared with the DSP, and the initialization steps are split
* in three. First an ACPI scan to check what the firmware describes
* in DSDT tables, then an allocation step (with no hardware
* configuration but with all the relevant devices created) and last
* the actual hardware configuration. The final stage is a global
* interrupt enable which is controlled by the DSP driver. Splitting
* these phases helps simplify the boot flow and make early decisions
* on e.g. which machine driver to select (I2S mode, HDaudio or
* SoundWire).
*/
int sdw_intel_acpi_scan(acpi_handle *parent_handle,
struct sdw_intel_acpi_info *info);
void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx);
struct sdw_intel_ctx *
sdw_intel_probe(struct sdw_intel_res *res);
int sdw_intel_startup(struct sdw_intel_ctx *ctx);
void sdw_intel_exit(struct sdw_intel_ctx *ctx);
void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable);
irqreturn_t sdw_intel_thread(int irq, void *dev_id);
#endif #endif

View File

@ -197,7 +197,7 @@ struct snd_ac97_bus_ops {
struct snd_ac97_bus { struct snd_ac97_bus {
/* -- lowlevel (hardware) driver specific -- */ /* -- lowlevel (hardware) driver specific -- */
struct snd_ac97_bus_ops *ops; const struct snd_ac97_bus_ops *ops;
void *private_data; void *private_data;
void (*private_free) (struct snd_ac97_bus *bus); void (*private_free) (struct snd_ac97_bus *bus);
/* --- */ /* --- */
@ -310,7 +310,8 @@ static inline int ac97_can_spdif(struct snd_ac97 * ac97)
/* functions */ /* functions */
/* create new AC97 bus */ /* create new AC97 bus */
int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops, int snd_ac97_bus(struct snd_card *card, int num,
const struct snd_ac97_bus_ops *ops,
void *private_data, struct snd_ac97_bus **rbus); void *private_data, struct snd_ac97_bus **rbus);
/* create mixer controls */ /* create mixer controls */
int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,

View File

@ -22,6 +22,16 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
unsigned int size, unsigned int size,
unsigned int __user *tlv); unsigned int __user *tlv);
/* internal flag for skipping validations */
#ifdef CONFIG_SND_CTL_VALIDATION
#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 27)
#define snd_ctl_skip_validation(info) \
((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK)
#else
#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK 0
#define snd_ctl_skip_validation(info) true
#endif
enum { enum {
SNDRV_CTL_TLV_OP_READ = 0, SNDRV_CTL_TLV_OP_READ = 0,
SNDRV_CTL_TLV_OP_WRITE = 1, SNDRV_CTL_TLV_OP_WRITE = 1,

View File

@ -69,7 +69,7 @@ struct snd_device {
enum snd_device_state state; /* state of the device */ enum snd_device_state state; /* state of the device */
enum snd_device_type type; /* device type */ enum snd_device_type type; /* device type */
void *device_data; /* device structure */ void *device_data; /* device structure */
struct snd_device_ops *ops; /* operations */ const struct snd_device_ops *ops; /* operations */
}; };
#define snd_device(n) list_entry(n, struct snd_device, list) #define snd_device(n) list_entry(n, struct snd_device, list)
@ -120,6 +120,9 @@ struct snd_card {
int sync_irq; /* assigned irq, used for PCM sync */ int sync_irq; /* assigned irq, used for PCM sync */
wait_queue_head_t remove_sleep; wait_queue_head_t remove_sleep;
size_t total_pcm_alloc_bytes; /* total amount of allocated buffers */
struct mutex memory_mutex; /* protection for the above */
#ifdef CONFIG_PM #ifdef CONFIG_PM
unsigned int power_state; /* power state */ unsigned int power_state; /* power state */
wait_queue_head_t power_sleep; wait_queue_head_t power_sleep;
@ -256,7 +259,7 @@ static inline void snd_card_unref(struct snd_card *card)
/* device.c */ /* device.c */
int snd_device_new(struct snd_card *card, enum snd_device_type type, int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops); void *device_data, const struct snd_device_ops *ops);
int snd_device_register(struct snd_card *card, void *device_data); int snd_device_register(struct snd_card *card, void *device_data);
int snd_device_register_all(struct snd_card *card); int snd_device_register_all(struct snd_card *card);
void snd_device_disconnect(struct snd_card *card, void *device_data); void snd_device_disconnect(struct snd_card *card, void *device_data);

View File

@ -51,7 +51,6 @@ struct hda_bus {
DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
/* misc op flags */ /* misc op flags */
unsigned int needs_damn_long_delay :1;
unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
/* status for codec/controller */ /* status for codec/controller */
unsigned int shutdown :1; /* being unloaded */ unsigned int shutdown :1; /* being unloaded */

View File

@ -24,6 +24,9 @@ int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
unsigned int val); unsigned int val);
int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg, int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val);
int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,
unsigned int mask, unsigned int val);
void snd_hdac_regmap_sync(struct hdac_device *codec);
/** /**
* snd_hdac_regmap_encode_verb - encode the verb to a pseudo register * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register

View File

@ -8,6 +8,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/timecounter.h> #include <linux/timecounter.h>
#include <sound/core.h> #include <sound/core.h>
@ -86,6 +87,7 @@ struct hdac_device {
/* regmap */ /* regmap */
struct regmap *regmap; struct regmap *regmap;
struct mutex regmap_lock;
struct snd_array vendor_verbs; struct snd_array vendor_verbs;
bool lazy_cache:1; /* don't wake up for writes */ bool lazy_cache:1; /* don't wake up for writes */
bool caps_overwriting:1; /* caps overwrite being in process */ bool caps_overwriting:1; /* caps overwrite being in process */
@ -317,6 +319,7 @@ struct hdac_bus {
struct hdac_rb corb; struct hdac_rb corb;
struct hdac_rb rirb; struct hdac_rb rirb;
unsigned int last_cmd[HDA_MAX_CODECS]; /* last sent command */ unsigned int last_cmd[HDA_MAX_CODECS]; /* last sent command */
wait_queue_head_t rirb_wq;
/* CORB/RIRB and position buffers */ /* CORB/RIRB and position buffers */
struct snd_dma_buffer rb; struct snd_dma_buffer rb;
@ -330,6 +333,7 @@ struct hdac_bus {
bool chip_init:1; /* h/w initialized */ bool chip_init:1; /* h/w initialized */
/* behavior flags */ /* behavior flags */
bool aligned_mmio:1; /* aligned MMIO access */
bool sync_write:1; /* sync after verb write */ bool sync_write:1; /* sync after verb write */
bool use_posbuf:1; /* use position buffer */ bool use_posbuf:1; /* use position buffer */
bool snoop:1; /* enable snooping */ bool snoop:1; /* enable snooping */
@ -337,6 +341,7 @@ struct hdac_bus {
bool reverse_assign:1; /* assign devices in reverse order */ bool reverse_assign:1; /* assign devices in reverse order */
bool corbrp_self_clear:1; /* CORBRP clears itself after reset */ bool corbrp_self_clear:1; /* CORBRP clears itself after reset */
bool polling_mode:1; bool polling_mode:1;
bool needs_damn_long_delay:1;
int poll_count; int poll_count;
@ -405,34 +410,61 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus);
unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask); unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask);
void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
unsigned int mask); unsigned int mask);
#define snd_hdac_reg_writeb(v, addr) snd_hdac_aligned_write(v, addr, 0xff) #define snd_hdac_aligned_mmio(bus) (bus)->aligned_mmio
#define snd_hdac_reg_writew(v, addr) snd_hdac_aligned_write(v, addr, 0xffff) #else
#define snd_hdac_reg_readb(addr) snd_hdac_aligned_read(addr, 0xff) #define snd_hdac_aligned_mmio(bus) false
#define snd_hdac_reg_readw(addr) snd_hdac_aligned_read(addr, 0xffff) #define snd_hdac_aligned_read(addr, mask) 0
#else /* CONFIG_SND_HDA_ALIGNED_MMIO */ #define snd_hdac_aligned_write(val, addr, mask) do {} while (0)
#define snd_hdac_reg_writeb(val, addr) writeb(val, addr) #endif
#define snd_hdac_reg_writew(val, addr) writew(val, addr)
#define snd_hdac_reg_readb(addr) readb(addr) static inline void snd_hdac_reg_writeb(struct hdac_bus *bus, void __iomem *addr,
#define snd_hdac_reg_readw(addr) readw(addr) u8 val)
#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ {
#define snd_hdac_reg_writel(val, addr) writel(val, addr) if (snd_hdac_aligned_mmio(bus))
#define snd_hdac_reg_readl(addr) readl(addr) snd_hdac_aligned_write(val, addr, 0xff);
else
writeb(val, addr);
}
static inline void snd_hdac_reg_writew(struct hdac_bus *bus, void __iomem *addr,
u16 val)
{
if (snd_hdac_aligned_mmio(bus))
snd_hdac_aligned_write(val, addr, 0xffff);
else
writew(val, addr);
}
static inline u8 snd_hdac_reg_readb(struct hdac_bus *bus, void __iomem *addr)
{
return snd_hdac_aligned_mmio(bus) ?
snd_hdac_aligned_read(addr, 0xff) : readb(addr);
}
static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr)
{
return snd_hdac_aligned_mmio(bus) ?
snd_hdac_aligned_read(addr, 0xffff) : readw(addr);
}
#define snd_hdac_reg_writel(bus, addr, val) writel(val, addr)
#define snd_hdac_reg_readl(bus, addr) readl(addr)
/* /*
* macros for easy use * macros for easy use
*/ */
#define _snd_hdac_chip_writeb(chip, reg, value) \ #define _snd_hdac_chip_writeb(chip, reg, value) \
snd_hdac_reg_writeb(value, (chip)->remap_addr + (reg)) snd_hdac_reg_writeb(chip, (chip)->remap_addr + (reg), value)
#define _snd_hdac_chip_readb(chip, reg) \ #define _snd_hdac_chip_readb(chip, reg) \
snd_hdac_reg_readb((chip)->remap_addr + (reg)) snd_hdac_reg_readb(chip, (chip)->remap_addr + (reg))
#define _snd_hdac_chip_writew(chip, reg, value) \ #define _snd_hdac_chip_writew(chip, reg, value) \
snd_hdac_reg_writew(value, (chip)->remap_addr + (reg)) snd_hdac_reg_writew(chip, (chip)->remap_addr + (reg), value)
#define _snd_hdac_chip_readw(chip, reg) \ #define _snd_hdac_chip_readw(chip, reg) \
snd_hdac_reg_readw((chip)->remap_addr + (reg)) snd_hdac_reg_readw(chip, (chip)->remap_addr + (reg))
#define _snd_hdac_chip_writel(chip, reg, value) \ #define _snd_hdac_chip_writel(chip, reg, value) \
snd_hdac_reg_writel(value, (chip)->remap_addr + (reg)) snd_hdac_reg_writel(chip, (chip)->remap_addr + (reg), value)
#define _snd_hdac_chip_readl(chip, reg) \ #define _snd_hdac_chip_readl(chip, reg) \
snd_hdac_reg_readl((chip)->remap_addr + (reg)) snd_hdac_reg_readl(chip, (chip)->remap_addr + (reg))
/* read/write a register, pass without AZX_REG_ prefix */ /* read/write a register, pass without AZX_REG_ prefix */
#define snd_hdac_chip_writel(chip, reg, value) \ #define snd_hdac_chip_writel(chip, reg, value) \
@ -540,17 +572,17 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
*/ */
/* read/write a register, pass without AZX_REG_ prefix */ /* read/write a register, pass without AZX_REG_ prefix */
#define snd_hdac_stream_writel(dev, reg, value) \ #define snd_hdac_stream_writel(dev, reg, value) \
snd_hdac_reg_writel(value, (dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_writel((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value)
#define snd_hdac_stream_writew(dev, reg, value) \ #define snd_hdac_stream_writew(dev, reg, value) \
snd_hdac_reg_writew(value, (dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_writew((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value)
#define snd_hdac_stream_writeb(dev, reg, value) \ #define snd_hdac_stream_writeb(dev, reg, value) \
snd_hdac_reg_writeb(value, (dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_writeb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg, value)
#define snd_hdac_stream_readl(dev, reg) \ #define snd_hdac_stream_readl(dev, reg) \
snd_hdac_reg_readl((dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_readl((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
#define snd_hdac_stream_readw(dev, reg) \ #define snd_hdac_stream_readw(dev, reg) \
snd_hdac_reg_readw((dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_readw((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
#define snd_hdac_stream_readb(dev, reg) \ #define snd_hdac_stream_readb(dev, reg) \
snd_hdac_reg_readb((dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_readb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
/* update a register, pass without AZX_REG_ prefix */ /* update a register, pass without AZX_REG_ prefix */
#define snd_hdac_stream_updatel(dev, reg, mask, val) \ #define snd_hdac_stream_updatel(dev, reg, mask, val) \

View File

@ -64,7 +64,7 @@ struct snd_info_entry {
unsigned short content; unsigned short content;
union { union {
struct snd_info_entry_text text; struct snd_info_entry_text text;
struct snd_info_entry_ops *ops; const struct snd_info_entry_ops *ops;
} c; } c;
struct snd_info_entry *parent; struct snd_info_entry *parent;
struct module *module; struct module *module;

View File

@ -37,7 +37,7 @@
#define SNDRV_DEFAULT_PTR SNDRV_DEFAULT_STR #define SNDRV_DEFAULT_PTR SNDRV_DEFAULT_STR
#ifdef SNDRV_LEGACY_FIND_FREE_IOPORT #ifdef SNDRV_LEGACY_FIND_FREE_IOPORT
static long snd_legacy_find_free_ioport(long *port_table, long size) static long snd_legacy_find_free_ioport(const long *port_table, long size)
{ {
while (*port_table != -1) { while (*port_table != -1) {
if (request_region(*port_table, size, "ALSA test")) { if (request_region(*port_table, size, "ALSA test")) {
@ -58,7 +58,7 @@ static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int snd_legacy_find_free_irq(int *irq_table) static int snd_legacy_find_free_irq(const int *irq_table)
{ {
while (*irq_table != -1) { while (*irq_table != -1) {
if (!request_irq(*irq_table, snd_legacy_empty_irq_handler, if (!request_irq(*irq_table, snd_legacy_empty_irq_handler,
@ -74,7 +74,7 @@ static int snd_legacy_find_free_irq(int *irq_table)
#endif #endif
#ifdef SNDRV_LEGACY_FIND_FREE_DMA #ifdef SNDRV_LEGACY_FIND_FREE_DMA
static int snd_legacy_find_free_dma(int *dma_table) static int snd_legacy_find_free_dma(const int *dma_table)
{ {
while (*dma_table != -1) { while (*dma_table != -1) {
if (!request_dma(*dma_table, "ALSA Test DMA")) { if (!request_dma(*dma_table, "ALSA Test DMA")) {

View File

@ -44,6 +44,7 @@ struct snd_pcm_hardware {
size_t fifo_size; /* fifo size in bytes */ size_t fifo_size; /* fifo size in bytes */
}; };
struct snd_pcm_status64;
struct snd_pcm_substream; struct snd_pcm_substream;
struct snd_pcm_audio_tstamp_config; /* definitions further down */ struct snd_pcm_audio_tstamp_config; /* definitions further down */
@ -62,7 +63,7 @@ struct snd_pcm_ops {
int (*sync_stop)(struct snd_pcm_substream *substream); int (*sync_stop)(struct snd_pcm_substream *substream);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
int (*get_time_info)(struct snd_pcm_substream *substream, int (*get_time_info)(struct snd_pcm_substream *substream,
struct timespec *system_ts, struct timespec *audio_ts, struct timespec64 *system_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report); struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
int (*fill_silence)(struct snd_pcm_substream *substream, int channel, int (*fill_silence)(struct snd_pcm_substream *substream, int channel,
@ -343,7 +344,7 @@ static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy
struct snd_pcm_runtime { struct snd_pcm_runtime {
/* -- Status -- */ /* -- Status -- */
struct snd_pcm_substream *trigger_master; struct snd_pcm_substream *trigger_master;
struct timespec trigger_tstamp; /* trigger timestamp */ struct timespec64 trigger_tstamp; /* trigger timestamp */
bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */ bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */
int overrange; int overrange;
snd_pcm_uframes_t avail_max; snd_pcm_uframes_t avail_max;
@ -421,7 +422,7 @@ struct snd_pcm_runtime {
/* -- audio timestamp config -- */ /* -- audio timestamp config -- */
struct snd_pcm_audio_tstamp_config audio_tstamp_config; struct snd_pcm_audio_tstamp_config audio_tstamp_config;
struct snd_pcm_audio_tstamp_report audio_tstamp_report; struct snd_pcm_audio_tstamp_report audio_tstamp_report;
struct timespec driver_tstamp; struct timespec64 driver_tstamp;
#if IS_ENABLED(CONFIG_SND_PCM_OSS) #if IS_ENABLED(CONFIG_SND_PCM_OSS)
/* -- OSS things -- */ /* -- OSS things -- */
@ -558,8 +559,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
int snd_pcm_info_user(struct snd_pcm_substream *substream, int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user *info); struct snd_pcm_info __user *info);
int snd_pcm_status(struct snd_pcm_substream *substream, int snd_pcm_status64(struct snd_pcm_substream *substream,
struct snd_pcm_status *status); struct snd_pcm_status64 *status);
int snd_pcm_start(struct snd_pcm_substream *substream); int snd_pcm_start(struct snd_pcm_substream *substream);
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status); int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream); int snd_pcm_drain_done(struct snd_pcm_substream *substream);
@ -1155,22 +1156,22 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea
} }
/** /**
* snd_pcm_gettime - Fill the timespec depending on the timestamp mode * snd_pcm_gettime - Fill the timespec64 depending on the timestamp mode
* @runtime: PCM runtime instance * @runtime: PCM runtime instance
* @tv: timespec to fill * @tv: timespec64 to fill
*/ */
static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime, static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
struct timespec *tv) struct timespec64 *tv)
{ {
switch (runtime->tstamp_type) { switch (runtime->tstamp_type) {
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC: case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
ktime_get_ts(tv); ktime_get_ts64(tv);
break; break;
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW: case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
getrawmonotonic(tv); ktime_get_raw_ts64(tv);
break; break;
default: default:
getnstimeofday(tv); ktime_get_real_ts64(tv);
break; break;
} }
} }
@ -1422,4 +1423,55 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
#define pcm_dbg(pcm, fmt, args...) \ #define pcm_dbg(pcm, fmt, args...) \
dev_dbg((pcm)->card->dev, fmt, ##args) dev_dbg((pcm)->card->dev, fmt, ##args)
struct snd_pcm_status64 {
snd_pcm_state_t state; /* stream state */
u8 rsvd[4];
s64 trigger_tstamp_sec; /* time when stream was started/stopped/paused */
s64 trigger_tstamp_nsec;
s64 tstamp_sec; /* reference timestamp */
s64 tstamp_nsec;
snd_pcm_uframes_t appl_ptr; /* appl ptr */
snd_pcm_uframes_t hw_ptr; /* hw ptr */
snd_pcm_sframes_t delay; /* current delay in frames */
snd_pcm_uframes_t avail; /* number of frames available */
snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */
snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */
snd_pcm_state_t suspended_state; /* suspended stream state */
__u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */
s64 audio_tstamp_sec; /* sample counter, wall clock, PHC or on-demand sync'ed */
s64 audio_tstamp_nsec;
s64 driver_tstamp_sec; /* useful in case reference system tstamp is reported with delay */
s64 driver_tstamp_nsec;
__u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
unsigned char reserved[52-4*sizeof(s64)]; /* must be filled with zero */
};
#define SNDRV_PCM_IOCTL_STATUS64 _IOR('A', 0x20, struct snd_pcm_status64)
#define SNDRV_PCM_IOCTL_STATUS_EXT64 _IOWR('A', 0x24, struct snd_pcm_status64)
struct snd_pcm_status32 {
s32 state; /* stream state */
s32 trigger_tstamp_sec; /* time when stream was started/stopped/paused */
s32 trigger_tstamp_nsec;
s32 tstamp_sec; /* reference timestamp */
s32 tstamp_nsec;
u32 appl_ptr; /* appl ptr */
u32 hw_ptr; /* hw ptr */
s32 delay; /* current delay in frames */
u32 avail; /* number of frames available */
u32 avail_max; /* max frames available on hw since last status */
u32 overrange; /* count of ADC (capture) overrange detections from last status */
s32 suspended_state; /* suspended stream state */
u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */
s32 audio_tstamp_sec; /* sample counter, wall clock, PHC or on-demand sync'ed */
s32 audio_tstamp_nsec;
s32 driver_tstamp_sec; /* useful in case reference system tstamp is reported with delay */
s32 driver_tstamp_nsec;
u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
unsigned char reserved[52-4*sizeof(s32)]; /* must be filled with zero */
};
#define SNDRV_PCM_IOCTL_STATUS32 _IOR('A', 0x20, struct snd_pcm_status32)
#define SNDRV_PCM_IOCTL_STATUS_EXT32 _IOWR('A', 0x24, struct snd_pcm_status32)
#endif /* __SOUND_PCM_H */ #endif /* __SOUND_PCM_H */

View File

@ -174,7 +174,8 @@ enum {
}; };
/* Prototypes for midi_process.c */ /* Prototypes for midi_process.c */
void snd_midi_process_event(struct snd_midi_op *ops, struct snd_seq_event *ev, void snd_midi_process_event(const struct snd_midi_op *ops,
struct snd_seq_event *ev,
struct snd_midi_channel_set *chanset); struct snd_midi_channel_set *chanset);
void snd_midi_channel_set_clear(struct snd_midi_channel_set *chset); void snd_midi_channel_set_clear(struct snd_midi_channel_set *chset);
struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n); struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n);

View File

@ -31,6 +31,12 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[];
/* /*
* generic table used for HDA codec-based platforms, possibly with * generic table used for HDA codec-based platforms, possibly with
* additional ACPI-enumerated codecs * additional ACPI-enumerated codecs

View File

@ -61,6 +61,8 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
* @platform: string used for HDaudio codec support * @platform: string used for HDaudio codec support
* @codec_mask: used for HDAudio support * @codec_mask: used for HDAudio support
* @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver
* @link_mask: links enabled on the board
* @links: array of link _ADR descriptors, null terminated
*/ */
struct snd_soc_acpi_mach_params { struct snd_soc_acpi_mach_params {
u32 acpi_ipc_irq_index; u32 acpi_ipc_irq_index;
@ -68,6 +70,23 @@ struct snd_soc_acpi_mach_params {
u32 codec_mask; u32 codec_mask;
u32 dmic_num; u32 dmic_num;
bool common_hdmi_codec_drv; bool common_hdmi_codec_drv;
u32 link_mask;
const struct snd_soc_acpi_link_adr *links;
};
/**
* snd_soc_acpi_link_adr: ACPI-based list of _ADR, with a variable
* number of devices per link
*
* @mask: one bit set indicates the link this list applies to
* @num_adr: ARRAY_SIZE of adr
* @adr: array of _ADR (represented as u64).
*/
struct snd_soc_acpi_link_adr {
const u32 mask;
const u32 num_adr;
const u64 *adr;
}; };
/** /**
@ -78,6 +97,7 @@ struct snd_soc_acpi_mach_params {
* *
* @id: ACPI ID (usually the codec's) used to find a matching machine driver. * @id: ACPI ID (usually the codec's) used to find a matching machine driver.
* @link_mask: describes required board layout, e.g. for SoundWire. * @link_mask: describes required board layout, e.g. for SoundWire.
* @links: array of link _ADR descriptors, null terminated.
* @drv_name: machine driver name * @drv_name: machine driver name
* @fw_filename: firmware file name. Used when SOF is not enabled. * @fw_filename: firmware file name. Used when SOF is not enabled.
* @board: board name * @board: board name
@ -94,6 +114,7 @@ struct snd_soc_acpi_mach_params {
struct snd_soc_acpi_mach { struct snd_soc_acpi_mach {
const u8 id[ACPI_ID_LEN]; const u8 id[ACPI_ID_LEN];
const u32 link_mask; const u32 link_mask;
const struct snd_soc_acpi_link_adr *links;
const char *drv_name; const char *drv_name;
const char *fw_filename; const char *fw_filename;
const char *board; const char *board;

View File

@ -93,8 +93,8 @@ struct snd_soc_component_driver {
snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component, snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component,
struct snd_pcm_substream *substream); struct snd_pcm_substream *substream);
int (*get_time_info)(struct snd_soc_component *component, int (*get_time_info)(struct snd_soc_component *component,
struct snd_pcm_substream *substream, struct timespec *system_ts, struct snd_pcm_substream *substream, struct timespec64 *system_ts,
struct timespec *audio_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report); struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
int (*copy_user)(struct snd_soc_component *component, int (*copy_user)(struct snd_soc_component *component,

View File

@ -286,8 +286,6 @@ struct snd_soc_dai_driver {
/* DAI driver callbacks */ /* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai); int (*probe)(struct snd_soc_dai *dai);
int (*remove)(struct snd_soc_dai *dai); int (*remove)(struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_dai *dai);
int (*resume)(struct snd_soc_dai *dai);
/* compress dai */ /* compress dai */
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
/* Optional Callback used at pcm creation*/ /* Optional Callback used at pcm creation*/
@ -304,7 +302,6 @@ struct snd_soc_dai_driver {
unsigned int symmetric_rates:1; unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1; unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1; unsigned int symmetric_samplebits:1;
unsigned int bus_control:1; /* DAI is also used for the control bus */
/* probe ordering - for components with runtime dependencies */ /* probe ordering - for components with runtime dependencies */
int probe_order; int probe_order;

View File

@ -392,6 +392,8 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double_locked(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol, int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo); struct snd_ctl_elem_info *uinfo);
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
@ -434,6 +436,7 @@ void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm);
/* dapm events */ /* dapm events */
void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
int event); int event);
void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream);
void snd_soc_dapm_shutdown(struct snd_soc_card *card); void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* external DAPM widget events */ /* external DAPM widget events */

View File

@ -464,10 +464,8 @@ static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
void snd_soc_disconnect_sync(struct device *dev); void snd_soc_disconnect_sync(struct device *dev);
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
const char *dai_link, int stream);
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
const char *dai_link); struct snd_soc_dai_link *dai_link);
bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd); bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream); void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
@ -738,19 +736,9 @@ struct snd_soc_compr_ops {
int (*trigger)(struct snd_compr_stream *); int (*trigger)(struct snd_compr_stream *);
}; };
struct snd_soc_rtdcom_list {
struct snd_soc_component *component;
struct list_head list; /* rtd::component_list */
};
struct snd_soc_component* struct snd_soc_component*
snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
const char *driver_name); const char *driver_name);
#define for_each_rtd_components(rtd, rtdcom, _component) \
for (rtdcom = list_first_entry(&(rtd)->component_list, \
typeof(*rtdcom), list); \
(&rtdcom->list != &(rtd)->component_list) && \
(_component = rtdcom->component); \
rtdcom = list_next_entry(rtdcom, list))
struct snd_soc_dai_link_component { struct snd_soc_dai_link_component {
const char *name; const char *name;
@ -852,7 +840,6 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */ /* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1; unsigned int ignore:1;
struct list_head list; /* DAI link list of the soc card */
#ifdef CONFIG_SND_SOC_TOPOLOGY #ifdef CONFIG_SND_SOC_TOPOLOGY
struct snd_soc_dobj dobj; /* For topology */ struct snd_soc_dobj dobj; /* For topology */
#endif #endif
@ -952,6 +939,7 @@ struct snd_soc_dai_link {
#define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, } #define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, }
#define COMP_PLATFORM(_name) { .name = _name } #define COMP_PLATFORM(_name) { .name = _name }
#define COMP_AUX(_name) { .name = _name } #define COMP_AUX(_name) { .name = _name }
#define COMP_CODEC_CONF(_name) { .name = _name }
#define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", } #define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", }
extern struct snd_soc_dai_link_component null_dailink_component[0]; extern struct snd_soc_dai_link_component null_dailink_component[0];
@ -962,8 +950,7 @@ struct snd_soc_codec_conf {
* specify device either by device name, or by * specify device either by device name, or by
* DT/OF node, but not both. * DT/OF node, but not both.
*/ */
const char *dev_name; struct snd_soc_dai_link_component dlc;
struct device_node *of_node;
/* /*
* optional map of kcontrol, widget and path name prefixes that are * optional map of kcontrol, widget and path name prefixes that are
@ -989,7 +976,9 @@ struct snd_soc_card {
const char *long_name; const char *long_name;
const char *driver_name; const char *driver_name;
const char *components; const char *components;
#ifdef CONFIG_DMI
char dmi_longname[80]; char dmi_longname[80];
#endif /* CONFIG_DMI */
char topology_shortname[32]; char topology_shortname[32];
struct device *dev; struct device *dev;
@ -1037,7 +1026,6 @@ struct snd_soc_card {
/* CPU <--> Codec DAI links */ /* CPU <--> Codec DAI links */
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 rtd_list; struct list_head rtd_list;
int num_rtd; int num_rtd;
@ -1107,11 +1095,6 @@ struct snd_soc_card {
((i) < (card)->num_aux_devs) && ((aux) = &(card)->aux_dev[i]); \ ((i) < (card)->num_aux_devs) && ((aux) = &(card)->aux_dev[i]); \
(i)++) (i)++)
#define for_each_card_links(card, link) \
list_for_each_entry(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) \ #define for_each_card_rtds(card, rtd) \
list_for_each_entry(rtd, &(card)->rtd_list, list) list_for_each_entry(rtd, &(card)->rtd_list, list)
#define for_each_card_rtds_safe(card, rtd, _rtd) \ #define for_each_card_rtds_safe(card, rtd, _rtd) \
@ -1157,12 +1140,18 @@ struct snd_soc_pcm_runtime {
unsigned int num; /* 0-based and monotonic increasing */ unsigned int num; /* 0-based and monotonic increasing */
struct list_head list; /* rtd list of the soc card */ struct list_head list; /* rtd list of the soc card */
struct list_head component_list; /* list of connected components */
/* bit field */ /* bit field */
unsigned int pop_wait:1; unsigned int pop_wait:1;
unsigned int fe_compr:1; /* for Dynamic PCM */ unsigned int fe_compr:1; /* for Dynamic PCM */
int num_components;
struct snd_soc_component *components[0]; /* CPU/Codec/Platform */
}; };
#define for_each_rtd_components(rtd, i, component) \
for ((i) = 0; \
((i) < rtd->num_components) && ((component) = rtd->components[i]);\
(i)++)
#define for_each_rtd_codec_dai(rtd, i, dai)\ #define for_each_rtd_codec_dai(rtd, i, dai)\
for ((i) = 0; \ for ((i) = 0; \
((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
@ -1170,6 +1159,7 @@ struct snd_soc_pcm_runtime {
#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \ #define for_each_rtd_codec_dai_rollback(rtd, i, dai) \
for (; ((--i) >= 0) && ((dai) = rtd->codec_dais[i]);) for (; ((--i) >= 0) && ((dai) = rtd->codec_dais[i]);)
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
/* mixer control */ /* mixer control */
struct soc_mixer_control { struct soc_mixer_control {
@ -1333,13 +1323,10 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
struct snd_soc_dai_link *dai_link); struct snd_soc_dai_link *dai_link);
void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link); void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link);
int snd_soc_add_dai_link(struct snd_soc_card *card, int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link); struct snd_soc_dai_link *dai_link);
void snd_soc_remove_dai_link(struct snd_soc_card *card, void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link); struct snd_soc_pcm_runtime *rtd);
struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card,
int id, const char *name,
const char *stream_name);
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, struct snd_soc_dai_driver *dai_drv,
@ -1409,11 +1396,6 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
mutex_unlock(&dapm->card->dapm_mutex); mutex_unlock(&dapm->card->dapm_mutex);
} }
/* bypass */
int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
#include <sound/soc-component.h> #include <sound/soc-component.h>
#endif #endif

View File

@ -22,7 +22,6 @@ struct snd_sof_dsp_ops;
*/ */
struct snd_sof_pdata { struct snd_sof_pdata {
const struct firmware *fw; const struct firmware *fw;
const char *drv_name;
const char *name; const char *name;
const char *platform; const char *platform;
@ -84,20 +83,18 @@ struct sof_dev_desc {
const void *chip_info; const void *chip_info;
/* defaults for no codec mode */ /* defaults for no codec mode */
const char *nocodec_fw_filename;
const char *nocodec_tplg_filename; const char *nocodec_tplg_filename;
/* defaults paths for firmware and topology files */ /* defaults paths for firmware and topology files */
const char *default_fw_path; const char *default_fw_path;
const char *default_tplg_path; const char *default_tplg_path;
/* default firmware name */
const char *default_fw_filename;
const struct snd_sof_dsp_ops *ops; const struct snd_sof_dsp_ops *ops;
const struct sof_arch_ops *arch_ops;
}; };
int sof_nocodec_setup(struct device *dev, int sof_nocodec_setup(struct device *dev,
struct snd_sof_pdata *sof_pdata,
struct snd_soc_acpi_mach *mach,
const struct sof_dev_desc *desc,
const struct snd_sof_dsp_ops *ops); const struct snd_sof_dsp_ops *ops);
#endif #endif

View File

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2019 Intel Corporation. All rights reserved.
*/
#ifndef __IPC_CHANNEL_MAP_H__
#define __IPC_CHANNEL_MAP_H__
#include <uapi/sound/sof/header.h>
#include <sound/sof/header.h>
/**
* \brief Channel map, specifies transformation of one-to-many or many-to-one.
*
* In case of one-to-many specifies how the output channels are computed out of
* a single source channel,
* in case of many-to-one specifies how a single target channel is computed
* from a multichannel input stream.
*
* Channel index specifies position of the channel in the stream on the 'one'
* side.
*
* Ext ID is the identifier of external part of the transformation. Depending
* on the context, it may be pipeline ID, dai ID, ...
*
* Channel mask describes which channels are taken into account on the "many"
* side. Bit[i] set to 1 means that i-th channel is used for computation
* (either as source or as a target).
*
* Channel mask is followed by array of coefficients in Q2.30 format,
* one per each channel set in the mask (left to right, LS bit set in the
* mask corresponds to ch_coeffs[0]).
*/
struct sof_ipc_channel_map {
uint32_t ch_index;
uint32_t ext_id;
uint32_t ch_mask;
uint32_t reserved;
int32_t ch_coeffs[0];
} __packed;
/**
* \brief Complete map for each channel of a multichannel stream.
*
* num_ch_map Specifies number of items in the ch_map.
* More than one transformation per a single channel is allowed (in case
* multiple external entities are transformed).
* A channel may be skipped in the transformation list, then it is filled
* with 0's by the transformation function.
*/
struct sof_ipc_stream_map {
struct sof_ipc_cmd_hdr hdr;
uint32_t num_ch_map;
uint32_t reserved[3];
struct sof_ipc_channel_map ch_map[0];
} __packed;
#endif /* __IPC_CHANNEL_MAP_H__ */

View File

@ -31,4 +31,24 @@ struct sof_ipc_dai_esai_params {
uint16_t reserved2; /* alignment */ uint16_t reserved2; /* alignment */
} __packed; } __packed;
/* SAI Configuration Request - SOF_IPC_DAI_SAI_CONFIG */
struct sof_ipc_dai_sai_params {
struct sof_ipc_hdr hdr;
/* MCLK */
uint16_t reserved1;
uint16_t mclk_id;
uint32_t mclk_direction;
uint32_t mclk_rate; /* MCLK frequency in Hz */
uint32_t fsync_rate; /* FSYNC frequency in Hz */
uint32_t bclk_rate; /* BCLK frequency in Hz */
/* TDM */
uint32_t tdm_slots;
uint32_t rx_slots;
uint32_t tx_slots;
uint16_t tdm_slot_width;
uint16_t reserved2; /* alignment */
} __packed;
#endif #endif

View File

@ -75,6 +75,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_hda_params hda; struct sof_ipc_dai_hda_params hda;
struct sof_ipc_dai_alh_params alh; struct sof_ipc_dai_alh_params alh;
struct sof_ipc_dai_esai_params esai; struct sof_ipc_dai_esai_params esai;
struct sof_ipc_dai_sai_params sai;
}; };
} __packed; } __packed;

View File

@ -30,6 +30,7 @@
enum sof_ipc_ext_data { enum sof_ipc_ext_data {
SOF_IPC_EXT_DMA_BUFFER = 0, SOF_IPC_EXT_DMA_BUFFER = 0,
SOF_IPC_EXT_WINDOW, SOF_IPC_EXT_WINDOW,
SOF_IPC_EXT_CC_INFO,
}; };
/* FW version - SOF_IPC_GLB_VERSION */ /* FW version - SOF_IPC_GLB_VERSION */
@ -115,4 +116,18 @@ struct sof_ipc_window {
struct sof_ipc_window_elem window[]; struct sof_ipc_window_elem window[];
} __packed; } __packed;
struct sof_ipc_cc_version {
struct sof_ipc_ext_data_hdr ext_hdr;
uint32_t major;
uint32_t minor;
uint32_t micro;
/* reserved for future use */
uint32_t reserved[4];
char name[16]; /* null terminated compiler name */
char optim[4]; /* null terminated compiler -O flag value */
char desc[]; /* null terminated compiler description */
} __packed;
#endif #endif

View File

@ -36,6 +36,7 @@ enum sof_comp_type {
SOF_COMP_KPB, /* A key phrase buffer component */ SOF_COMP_KPB, /* A key phrase buffer component */
SOF_COMP_SELECTOR, /**< channel selector component */ SOF_COMP_SELECTOR, /**< channel selector component */
SOF_COMP_DEMUX, SOF_COMP_DEMUX,
SOF_COMP_ASRC, /**< Asynchronous sample rate converter */
/* keep FILEREAD/FILEWRITE as the last ones */ /* keep FILEREAD/FILEWRITE as the last ones */
SOF_COMP_FILEREAD = 10000, /**< host test based file IO */ SOF_COMP_FILEREAD = 10000, /**< host test based file IO */
SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */ SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */
@ -147,6 +148,32 @@ struct sof_ipc_comp_src {
uint32_t rate_mask; /**< SOF_RATE_ supported rates */ uint32_t rate_mask; /**< SOF_RATE_ supported rates */
} __packed; } __packed;
/* generic ASRC component */
struct sof_ipc_comp_asrc {
struct sof_ipc_comp comp;
struct sof_ipc_comp_config config;
/* either source or sink rate must be non zero */
uint32_t source_rate; /**< Define fixed source rate or */
/**< use 0 to indicate need to get */
/**< the rate from stream */
uint32_t sink_rate; /**< Define fixed sink rate or */
/**< use 0 to indicate need to get */
/**< the rate from stream */
uint32_t asynchronous_mode; /**< synchronous 0, asynchronous 1 */
/**< When 1 the ASRC tracks and */
/**< compensates for drift. */
uint32_t operation_mode; /**< push 0, pull 1, In push mode the */
/**< ASRC consumes a defined number */
/**< of frames at input, with varying */
/**< number of frames at output. */
/**< In pull mode the ASRC outputs */
/**< a defined number of frames while */
/**< number of input frames varies. */
/* reserved for future use */
uint32_t reserved[4];
} __attribute__((packed));
/* generic MUX component */ /* generic MUX component */
struct sof_ipc_comp_mux { struct sof_ipc_comp_mux {
struct sof_ipc_comp comp; struct sof_ipc_comp comp;

View File

@ -89,7 +89,7 @@ struct snd_timer_instance {
unsigned long ticks, unsigned long resolution); unsigned long ticks, unsigned long resolution);
void (*ccallback) (struct snd_timer_instance * timeri, void (*ccallback) (struct snd_timer_instance * timeri,
int event, int event,
struct timespec * tstamp, struct timespec64 * tstamp,
unsigned long resolution); unsigned long resolution);
void (*disconnect)(struct snd_timer_instance *timeri); void (*disconnect)(struct snd_timer_instance *timeri);
void *callback_data; void *callback_data;
@ -113,7 +113,7 @@ struct snd_timer_instance {
*/ */
int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, struct snd_timer **rtimer); int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, struct snd_timer **rtimer);
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp); void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp);
int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer); int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
int snd_timer_global_free(struct snd_timer *timer); int snd_timer_global_free(struct snd_timer *timer);
int snd_timer_global_register(struct snd_timer *timer); int snd_timer_global_register(struct snd_timer *timer);

View File

@ -147,8 +147,8 @@ struct vx_core {
/* ports are defined externally */ /* ports are defined externally */
/* low-level functions */ /* low-level functions */
struct snd_vx_hardware *hw; const struct snd_vx_hardware *hw;
struct snd_vx_ops *ops; const struct snd_vx_ops *ops;
struct mutex lock; struct mutex lock;
@ -193,8 +193,9 @@ struct vx_core {
/* /*
* constructor * constructor
*/ */
struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw, struct vx_core *snd_vx_create(struct snd_card *card,
struct snd_vx_ops *ops, int extra_size); const struct snd_vx_hardware *hw,
const struct snd_vx_ops *ops, int extra_size);
int snd_vx_setup_firmware(struct vx_core *chip); int snd_vx_setup_firmware(struct vx_core *chip);
int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *dsp); int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *dsp);
int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *dsp); int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *dsp);

View File

@ -17,7 +17,6 @@
#define __LINUX_UAPI_SND_ASOC_H #define __LINUX_UAPI_SND_ASOC_H
#include <linux/types.h> #include <linux/types.h>
#include <sound/asound.h>
/* /*
* Maximum number of channels topology kcontrol can represent. * Maximum number of channels topology kcontrol can represent.

View File

@ -26,7 +26,9 @@
#if defined(__KERNEL__) || defined(__linux__) #if defined(__KERNEL__) || defined(__linux__)
#include <linux/types.h> #include <linux/types.h>
#include <asm/byteorder.h>
#else #else
#include <endian.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#endif #endif
@ -154,7 +156,7 @@ struct snd_hwdep_dsp_image {
* * * *
*****************************************************************************/ *****************************************************************************/
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) #define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 15)
typedef unsigned long snd_pcm_uframes_t; typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t; typedef signed long snd_pcm_sframes_t;
@ -301,7 +303,9 @@ typedef int __bitwise snd_pcm_subformat_t;
#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
#if (__BITS_PER_LONG == 32 && defined(__USE_TIME_BITS64)) || defined __KERNEL__
#define __SND_STRUCT_TIME64
#endif
typedef int __bitwise snd_pcm_state_t; typedef int __bitwise snd_pcm_state_t;
#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
@ -317,8 +321,17 @@ typedef int __bitwise snd_pcm_state_t;
enum { enum {
SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, SNDRV_PCM_MMAP_OFFSET_STATUS_OLD = 0x80000000,
SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD = 0x81000000,
SNDRV_PCM_MMAP_OFFSET_STATUS_NEW = 0x82000000,
SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW = 0x83000000,
#ifdef __SND_STRUCT_TIME64
SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_NEW,
SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW,
#else
SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_OLD,
SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD,
#endif
}; };
union snd_pcm_sync_id { union snd_pcm_sync_id {
@ -456,8 +469,13 @@ enum {
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
}; };
#ifndef __KERNEL__
/* explicit padding avoids incompatibility between i386 and x86-64 */
typedef struct { unsigned char pad[sizeof(time_t) - sizeof(int)]; } __time_pad;
struct snd_pcm_status { struct snd_pcm_status {
snd_pcm_state_t state; /* stream state */ snd_pcm_state_t state; /* stream state */
__time_pad pad1; /* align to timespec */
struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */
struct timespec tstamp; /* reference timestamp */ struct timespec tstamp; /* reference timestamp */
snd_pcm_uframes_t appl_ptr; /* appl ptr */ snd_pcm_uframes_t appl_ptr; /* appl ptr */
@ -473,17 +491,48 @@ struct snd_pcm_status {
__u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
}; };
#endif
struct snd_pcm_mmap_status { /*
* For mmap operations, we need the 64-bit layout, both for compat mode,
* and for y2038 compatibility. For 64-bit applications, the two definitions
* are identical, so we keep the traditional version.
*/
#ifdef __SND_STRUCT_TIME64
#define __snd_pcm_mmap_status64 snd_pcm_mmap_status
#define __snd_pcm_mmap_control64 snd_pcm_mmap_control
#define __snd_pcm_sync_ptr64 snd_pcm_sync_ptr
#ifdef __KERNEL__
#define __snd_timespec64 __kernel_timespec
#else
#define __snd_timespec64 timespec
#endif
struct __snd_timespec {
__s32 tv_sec;
__s32 tv_nsec;
};
#else
#define __snd_pcm_mmap_status snd_pcm_mmap_status
#define __snd_pcm_mmap_control snd_pcm_mmap_control
#define __snd_pcm_sync_ptr snd_pcm_sync_ptr
#define __snd_timespec timespec
struct __snd_timespec64 {
__s64 tv_sec;
__s64 tv_nsec;
};
#endif
struct __snd_pcm_mmap_status {
snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */
int pad1; /* Needed for 64 bit alignment */ int pad1; /* Needed for 64 bit alignment */
snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */
struct timespec tstamp; /* Timestamp */ struct __snd_timespec tstamp; /* Timestamp */
snd_pcm_state_t suspended_state; /* RO: suspended stream state */ snd_pcm_state_t suspended_state; /* RO: suspended stream state */
struct timespec audio_tstamp; /* from sample counter or wall clock */ struct __snd_timespec audio_tstamp; /* from sample counter or wall clock */
}; };
struct snd_pcm_mmap_control { struct __snd_pcm_mmap_control {
snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */
snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */
}; };
@ -492,14 +541,59 @@ struct snd_pcm_mmap_control {
#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */ #define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */
#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */ #define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */
struct snd_pcm_sync_ptr { struct __snd_pcm_sync_ptr {
unsigned int flags; unsigned int flags;
union { union {
struct snd_pcm_mmap_status status; struct __snd_pcm_mmap_status status;
unsigned char reserved[64]; unsigned char reserved[64];
} s; } s;
union { union {
struct snd_pcm_mmap_control control; struct __snd_pcm_mmap_control control;
unsigned char reserved[64];
} c;
};
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN)
typedef char __pad_before_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)];
typedef char __pad_after_uframe[0];
#endif
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN)
typedef char __pad_before_uframe[0];
typedef char __pad_after_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)];
#endif
struct __snd_pcm_mmap_status64 {
__s32 state; /* RO: state - SNDRV_PCM_STATE_XXXX */
__u32 pad1; /* Needed for 64 bit alignment */
__pad_before_uframe __pad1;
snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */
__pad_after_uframe __pad2;
struct __snd_timespec64 tstamp; /* Timestamp */
__s32 suspended_state; /* RO: suspended stream state */
__u32 pad3; /* Needed for 64 bit alignment */
struct __snd_timespec64 audio_tstamp; /* sample counter or wall clock */
};
struct __snd_pcm_mmap_control64 {
__pad_before_uframe __pad1;
snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */
__pad_before_uframe __pad2;
__pad_before_uframe __pad3;
snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */
__pad_after_uframe __pad4;
};
struct __snd_pcm_sync_ptr64 {
__u32 flags;
__u32 pad1;
union {
struct __snd_pcm_mmap_status64 status;
unsigned char reserved[64];
} s;
union {
struct __snd_pcm_mmap_control64 control;
unsigned char reserved[64]; unsigned char reserved[64];
} c; } c;
}; };
@ -584,6 +678,8 @@ enum {
#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) #define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) #define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
#define __SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct __snd_pcm_sync_ptr)
#define __SNDRV_PCM_IOCTL_SYNC_PTR64 _IOWR('A', 0x23, struct __snd_pcm_sync_ptr64)
#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) #define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) #define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
@ -614,7 +710,7 @@ enum {
* Raw MIDI section - /dev/snd/midi?? * Raw MIDI section - /dev/snd/midi??
*/ */
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) #define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1)
enum { enum {
SNDRV_RAWMIDI_STREAM_OUTPUT = 0, SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
@ -648,13 +744,16 @@ struct snd_rawmidi_params {
unsigned char reserved[16]; /* reserved for future use */ unsigned char reserved[16]; /* reserved for future use */
}; };
#ifndef __KERNEL__
struct snd_rawmidi_status { struct snd_rawmidi_status {
int stream; int stream;
__time_pad pad1;
struct timespec tstamp; /* Timestamp */ struct timespec tstamp; /* Timestamp */
size_t avail; /* available bytes */ size_t avail; /* available bytes */
size_t xruns; /* count of overruns since last status (in bytes) */ size_t xruns; /* count of overruns since last status (in bytes) */
unsigned char reserved[16]; /* reserved for future use */ unsigned char reserved[16]; /* reserved for future use */
}; };
#endif
#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) #define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) #define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
@ -667,7 +766,7 @@ struct snd_rawmidi_status {
* Timer section - /dev/snd/timer * Timer section - /dev/snd/timer
*/ */
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) #define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7)
enum { enum {
SNDRV_TIMER_CLASS_NONE = -1, SNDRV_TIMER_CLASS_NONE = -1,
@ -761,6 +860,7 @@ struct snd_timer_params {
unsigned char reserved[60]; /* reserved */ unsigned char reserved[60]; /* reserved */
}; };
#ifndef __KERNEL__
struct snd_timer_status { struct snd_timer_status {
struct timespec tstamp; /* Timestamp - last update */ struct timespec tstamp; /* Timestamp - last update */
unsigned int resolution; /* current period resolution in ns */ unsigned int resolution; /* current period resolution in ns */
@ -769,10 +869,11 @@ struct snd_timer_status {
unsigned int queue; /* used queue size */ unsigned int queue; /* used queue size */
unsigned char reserved[64]; /* reserved */ unsigned char reserved[64]; /* reserved */
}; };
#endif
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) #define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) #define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) #define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int)
#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) #define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) #define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) #define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
@ -785,6 +886,15 @@ struct snd_timer_status {
#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) #define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) #define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) #define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int)
#if __BITS_PER_LONG == 64
#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD
#else
#define SNDRV_TIMER_IOCTL_TREAD ((sizeof(__kernel_long_t) >= sizeof(time_t)) ? \
SNDRV_TIMER_IOCTL_TREAD_OLD : \
SNDRV_TIMER_IOCTL_TREAD64)
#endif
struct snd_timer_read { struct snd_timer_read {
unsigned int resolution; unsigned int resolution;
@ -810,11 +920,15 @@ enum {
SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
}; };
#ifndef __KERNEL__
struct snd_timer_tread { struct snd_timer_tread {
int event; int event;
__time_pad pad1;
struct timespec tstamp; struct timespec tstamp;
unsigned int val; unsigned int val;
__time_pad pad2;
}; };
#endif
/**************************************************************************** /****************************************************************************
* * * *
@ -822,7 +936,7 @@ struct snd_timer_tread {
* * * *
****************************************************************************/ ****************************************************************************/
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) #define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8)
struct snd_ctl_card_info { struct snd_ctl_card_info {
int card; /* card number */ int card; /* card number */
@ -860,7 +974,7 @@ typedef int __bitwise snd_ctl_elem_iface_t;
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) #define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) #define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */ #define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */ // (1 << 3) is unused.
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */ #define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */ #define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */
#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) #define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
@ -926,11 +1040,7 @@ struct snd_ctl_elem_info {
} enumerated; } enumerated;
unsigned char reserved[128]; unsigned char reserved[128];
} value; } value;
union { unsigned char reserved[64];
unsigned short d[4]; /* dimensions */
unsigned short *d_ptr; /* indirect - obsoleted */
} dimen;
unsigned char reserved[64-4*sizeof(unsigned short)];
}; };
struct snd_ctl_elem_value { struct snd_ctl_elem_value {
@ -955,8 +1065,7 @@ struct snd_ctl_elem_value {
} bytes; } bytes;
struct snd_aes_iec958 iec958; struct snd_aes_iec958 iec958;
} value; /* RO */ } value; /* RO */
struct timespec tstamp; unsigned char reserved[128];
unsigned char reserved[128-sizeof(struct timespec)];
}; };
struct snd_ctl_tlv { struct snd_ctl_tlv {

View File

@ -23,8 +23,9 @@
#ifndef _UAPI__SOUND_EMU10K1_H #ifndef _UAPI__SOUND_EMU10K1_H
#define _UAPI__SOUND_EMU10K1_H #define _UAPI__SOUND_EMU10K1_H
#ifdef __linux__
#include <linux/types.h> #include <linux/types.h>
#include <sound/asound.h> #endif
/* /*
* ---- FX8010 ---- * ---- FX8010 ----
@ -282,8 +283,22 @@ struct snd_emu10k1_fx8010_info {
#define EMU10K1_GPR_TRANSLATION_TREBLE 3 #define EMU10K1_GPR_TRANSLATION_TREBLE 3
#define EMU10K1_GPR_TRANSLATION_ONOFF 4 #define EMU10K1_GPR_TRANSLATION_ONOFF 4
enum emu10k1_ctl_elem_iface {
EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */
EMU10K1_CTL_ELEM_IFACE_PCM = 3, /* PCM device */
};
struct emu10k1_ctl_elem_id {
unsigned int pad; /* don't use */
int iface; /* interface identifier */
unsigned int device; /* device/client number */
unsigned int subdevice; /* subdevice (substream) number */
unsigned char name[44]; /* ASCII name of item */
unsigned int index; /* index of item */
};
struct snd_emu10k1_fx8010_control_gpr { struct snd_emu10k1_fx8010_control_gpr {
struct snd_ctl_elem_id id; /* full control ID definition */ struct emu10k1_ctl_elem_id id; /* full control ID definition */
unsigned int vcount; /* visible count */ unsigned int vcount; /* visible count */
unsigned int count; /* count of GPR (1..16) */ unsigned int count; /* count of GPR (1..16) */
unsigned short gpr[32]; /* GPR number(s) */ unsigned short gpr[32]; /* GPR number(s) */
@ -296,7 +311,7 @@ struct snd_emu10k1_fx8010_control_gpr {
/* old ABI without TLV support */ /* old ABI without TLV support */
struct snd_emu10k1_fx8010_control_old_gpr { struct snd_emu10k1_fx8010_control_old_gpr {
struct snd_ctl_elem_id id; struct emu10k1_ctl_elem_id id;
unsigned int vcount; unsigned int vcount;
unsigned int count; unsigned int count;
unsigned short gpr[32]; unsigned short gpr[32];
@ -310,24 +325,24 @@ struct snd_emu10k1_fx8010_code {
char name[128]; char name[128];
__EMU10K1_DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */ __EMU10K1_DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */
__u32 __user *gpr_map; /* initializers */ __u32 *gpr_map; /* initializers */
unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */ unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */
struct snd_emu10k1_fx8010_control_gpr __user *gpr_add_controls; /* GPR controls to add/replace */ struct snd_emu10k1_fx8010_control_gpr *gpr_add_controls; /* GPR controls to add/replace */
unsigned int gpr_del_control_count; /* count of GPR controls to remove */ unsigned int gpr_del_control_count; /* count of GPR controls to remove */
struct snd_ctl_elem_id __user *gpr_del_controls; /* IDs of GPR controls to remove */ struct emu10k1_ctl_elem_id *gpr_del_controls; /* IDs of GPR controls to remove */
unsigned int gpr_list_control_count; /* count of GPR controls to list */ unsigned int gpr_list_control_count; /* count of GPR controls to list */
unsigned int gpr_list_control_total; /* total count of GPR controls */ unsigned int gpr_list_control_total; /* total count of GPR controls */
struct snd_emu10k1_fx8010_control_gpr __user *gpr_list_controls; /* listed GPR controls */ struct snd_emu10k1_fx8010_control_gpr *gpr_list_controls; /* listed GPR controls */
__EMU10K1_DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */ __EMU10K1_DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */
__u32 __user *tram_data_map; /* data initializers */ __u32 *tram_data_map; /* data initializers */
__u32 __user *tram_addr_map; /* map initializers */ __u32 *tram_addr_map; /* map initializers */
__EMU10K1_DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */ __EMU10K1_DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */
__u32 __user *code; /* one instruction - 64 bits */ __u32 *code; /* one instruction - 64 bits */
}; };
struct snd_emu10k1_fx8010_tram { struct snd_emu10k1_fx8010_tram {
@ -371,11 +386,4 @@ struct snd_emu10k1_fx8010_pcm_rec {
#define SNDRV_EMU10K1_IOCTL_SINGLE_STEP _IOW ('H', 0x83, int) #define SNDRV_EMU10K1_IOCTL_SINGLE_STEP _IOW ('H', 0x83, int)
#define SNDRV_EMU10K1_IOCTL_DBG_READ _IOR ('H', 0x84, int) #define SNDRV_EMU10K1_IOCTL_DBG_READ _IOR ('H', 0x84, int)
/* typedefs for compatibility to user-space */
typedef struct snd_emu10k1_fx8010_info emu10k1_fx8010_info_t;
typedef struct snd_emu10k1_fx8010_control_gpr emu10k1_fx8010_control_gpr_t;
typedef struct snd_emu10k1_fx8010_code emu10k1_fx8010_code_t;
typedef struct snd_emu10k1_fx8010_tram emu10k1_fx8010_tram_t;
typedef struct snd_emu10k1_fx8010_pcm_rec emu10k1_fx8010_pcm_t;
#endif /* _UAPI__SOUND_EMU10K1_H */ #endif /* _UAPI__SOUND_EMU10K1_H */

View File

@ -20,7 +20,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#ifdef __linux__
#include <linux/types.h> #include <linux/types.h>
#endif
#define HDSP_MATRIX_MIXER_SIZE 2048 #define HDSP_MATRIX_MIXER_SIZE 2048
@ -74,7 +76,7 @@ struct hdsp_config_info {
#define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, struct hdsp_config_info) #define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, struct hdsp_config_info)
struct hdsp_firmware { struct hdsp_firmware {
void __user *firmware_data; /* 24413 x 4 bytes */ void *firmware_data; /* 24413 x 4 bytes */
}; };
#define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, struct hdsp_firmware) #define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, struct hdsp_firmware)
@ -99,13 +101,4 @@ struct hdsp_9632_aeb {
#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, struct hdsp_9632_aeb) #define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, struct hdsp_9632_aeb)
/* typedefs for compatibility to user-space */
typedef enum HDSP_IO_Type HDSP_IO_Type;
typedef struct hdsp_peak_rms hdsp_peak_rms_t;
typedef struct hdsp_config_info hdsp_config_info_t;
typedef struct hdsp_firmware hdsp_firmware_t;
typedef struct hdsp_version hdsp_version_t;
typedef struct hdsp_mixer hdsp_mixer_t;
typedef struct hdsp_9632_aeb hdsp_9632_aeb_t;
#endif /* __SOUND_HDSP_H */ #endif /* __SOUND_HDSP_H */

View File

@ -21,7 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#ifdef __linux__
#include <linux/types.h> #include <linux/types.h>
#endif
/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
#define HDSPM_MAX_CHANNELS 64 #define HDSPM_MAX_CHANNELS 64
@ -221,12 +223,4 @@ struct hdspm_mixer_ioctl {
/* use indirect access due to the limit of ioctl bit size */ /* use indirect access due to the limit of ioctl bit size */
#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct hdspm_mixer_ioctl) #define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct hdspm_mixer_ioctl)
/* typedefs for compatibility to user-space */
typedef struct hdspm_peak_rms hdspm_peak_rms_t;
typedef struct hdspm_config_info hdspm_config_info_t;
typedef struct hdspm_version hdspm_version_t;
typedef struct hdspm_channelfader snd_hdspm_channelfader_t;
typedef struct hdspm_mixer hdspm_mixer_t;
#endif #endif

View File

@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */ /* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3 #define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 11 #define SOF_ABI_MINOR 12
#define SOF_ABI_PATCH 0 #define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */ /* SOF ABI version number. Format within 32bit word is MMmmmppp */

View File

@ -57,6 +57,12 @@
#define SOF_TKN_SRC_RATE_IN 300 #define SOF_TKN_SRC_RATE_IN 300
#define SOF_TKN_SRC_RATE_OUT 301 #define SOF_TKN_SRC_RATE_OUT 301
/* ASRC */
#define SOF_TKN_ASRC_RATE_IN 320
#define SOF_TKN_ASRC_RATE_OUT 321
#define SOF_TKN_ASRC_ASYNCHRONOUS_MODE 322
#define SOF_TKN_ASRC_OPERATION_MODE 323
/* PCM */ /* PCM */
#define SOF_TKN_PCM_DMAC_CONFIG 353 #define SOF_TKN_PCM_DMAC_CONFIG 353
@ -107,8 +113,7 @@
#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE #define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE
/* SAI */ /* SAI */
#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000 #define SOF_TKN_IMX_SAI_MCLK_ID 1000
/* TODO: Add SAI tokens */
/* ESAI */ /* ESAI */
#define SOF_TKN_IMX_ESAI_MCLK_ID 1100 #define SOF_TKN_IMX_ESAI_MCLK_ID 1100

View File

@ -53,7 +53,7 @@ static unsigned short compat_ac97_read(struct snd_ac97 *ac97,
return actrl->ops->read(actrl, ac97->num, reg); return actrl->ops->read(actrl, ac97->num, reg);
} }
static struct snd_ac97_bus_ops compat_snd_ac97_bus_ops = { static const struct snd_ac97_bus_ops compat_snd_ac97_bus_ops = {
.reset = compat_ac97_reset, .reset = compat_ac97_reset,
.warm_reset = compat_ac97_warm_reset, .warm_reset = compat_ac97_warm_reset,
.write = compat_ac97_write, .write = compat_ac97_write,

View File

@ -55,7 +55,7 @@ static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id, int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
unsigned int id_mask) unsigned int id_mask)
{ {
struct snd_ac97_bus_ops *ops = ac97->bus->ops; const struct snd_ac97_bus_ops *ops = ac97->bus->ops;
if (try_warm && ops->warm_reset) { if (try_warm && ops->warm_reset) {
ops->warm_reset(ac97); ops->warm_reset(ac97);

View File

@ -116,7 +116,7 @@ struct aoa_card {
}; };
extern int aoa_snd_device_new(enum snd_device_type type, extern int aoa_snd_device_new(enum snd_device_type type,
void * device_data, struct snd_device_ops * ops); void *device_data, const struct snd_device_ops *ops);
extern struct snd_card *aoa_get_card(void); extern struct snd_card *aoa_get_card(void);
extern int aoa_snd_ctl_add(struct snd_kcontrol* control); extern int aoa_snd_ctl_add(struct snd_kcontrol* control);

View File

@ -97,7 +97,7 @@ static int onyx_dev_register(struct snd_device *dev)
return 0; return 0;
} }
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_register = onyx_dev_register, .dev_register = onyx_dev_register,
}; };
@ -413,7 +413,7 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
} }
#define SINGLE_BIT(n, type, description, address, mask, flags) \ #define SINGLE_BIT(n, type, description, address, mask, flags) \
static struct snd_kcontrol_new n##_control = { \ static const struct snd_kcontrol_new n##_control = { \
.iface = SNDRV_CTL_ELEM_IFACE_##type, \ .iface = SNDRV_CTL_ELEM_IFACE_##type, \
.name = description, \ .name = description, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
@ -543,7 +543,7 @@ static const struct snd_kcontrol_new onyx_spdif_ctrl = {
/* our registers */ /* our registers */
static u8 register_map[] = { static const u8 register_map[] = {
ONYX_REG_DAC_ATTEN_LEFT, ONYX_REG_DAC_ATTEN_LEFT,
ONYX_REG_DAC_ATTEN_RIGHT, ONYX_REG_DAC_ATTEN_RIGHT,
ONYX_REG_CONTROL, ONYX_REG_CONTROL,
@ -559,7 +559,7 @@ static u8 register_map[] = {
ONYX_REG_DIG_INFO4 ONYX_REG_DIG_INFO4
}; };
static u8 initial_values[ARRAY_SIZE(register_map)] = { static const u8 initial_values[ARRAY_SIZE(register_map)] = {
0x80, 0x80, /* muted */ 0x80, 0x80, /* muted */
ONYX_MRST | ONYX_SRST, /* but handled specially! */ ONYX_MRST | ONYX_SRST, /* but handled specially! */
ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT, ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT,

View File

@ -13,7 +13,7 @@
#define TAS3004_TREBLE_ZERO 36 #define TAS3004_TREBLE_ZERO 36
#define TAS3004_BASS_ZERO 36 #define TAS3004_BASS_ZERO 36
static u8 tas3004_treble_table[] = { static const u8 tas3004_treble_table[] = {
150, /* -18 dB */ 150, /* -18 dB */
149, 149,
148, 148,
@ -99,7 +99,7 @@ static inline u8 tas3004_treble(int idx)
* I have also ignored completely differences of * I have also ignored completely differences of
* +/- 1 * +/- 1
*/ */
static s8 tas3004_bass_diff_to_treble[] = { static const s8 tas3004_bass_diff_to_treble[] = {
2, /* 7 dB, offset 50 */ 2, /* 7 dB, offset 50 */
2, 2,
2, 2,

View File

@ -27,7 +27,7 @@ int main() {
* as easy as calculating * as easy as calculating
* hwvalue = 1048576.0*exp(0.057564628*dB*2) * hwvalue = 1048576.0*exp(0.057564628*dB*2)
* :) */ * :) */
static int tas_gaintable[] = { static const int tas_gaintable[] = {
0x000000, /* -infinity dB */ 0x000000, /* -infinity dB */
0x00014b, /* -70.0 dB */ 0x00014b, /* -70.0 dB */
0x00015f, /* -69.5 dB */ 0x00015f, /* -69.5 dB */

View File

@ -217,7 +217,7 @@ static int tas_dev_register(struct snd_device *dev)
return 0; return 0;
} }
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_register = tas_dev_register, .dev_register = tas_dev_register,
}; };
@ -369,7 +369,7 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
} }
#define MIXER_CONTROL(n,descr,idx) \ #define MIXER_CONTROL(n,descr,idx) \
static struct snd_kcontrol_new n##_control = { \ static const struct snd_kcontrol_new n##_control = { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = descr " Playback Volume", \ .name = descr " Playback Volume", \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \

View File

@ -30,7 +30,7 @@ static int toonie_dev_register(struct snd_device *dev)
return 0; return 0;
} }
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_register = toonie_dev_register, .dev_register = toonie_dev_register,
}; };

View File

@ -59,7 +59,7 @@ void aoa_alsa_cleanup(void)
} }
int aoa_snd_device_new(enum snd_device_type type, int aoa_snd_device_new(enum snd_device_type type,
void * device_data, struct snd_device_ops * ops) void *device_data, const struct snd_device_ops *ops)
{ {
struct snd_card *card = aoa_get_card(); struct snd_card *card = aoa_get_card();
int err; int err;

View File

@ -655,7 +655,7 @@ static int n##_control_put(struct snd_kcontrol *kcontrol, \
!!ucontrol->value.integer.value[0]); \ !!ucontrol->value.integer.value[0]); \
return 1; \ return 1; \
} \ } \
static struct snd_kcontrol_new n##_ctl = { \ static const struct snd_kcontrol_new n##_ctl = { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = description, \ .name = description, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \

View File

@ -160,7 +160,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
static const char *rnames[] = { "i2sbus: %pOFn (control)", static const char *rnames[] = { "i2sbus: %pOFn (control)",
"i2sbus: %pOFn (tx)", "i2sbus: %pOFn (tx)",
"i2sbus: %pOFn (rx)" }; "i2sbus: %pOFn (rx)" };
static irq_handler_t ints[] = { static const irq_handler_t ints[] = {
i2sbus_bus_intr, i2sbus_bus_intr,
i2sbus_tx_intr, i2sbus_tx_intr,
i2sbus_rx_intr i2sbus_rx_intr

View File

@ -294,12 +294,6 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
} }
#endif #endif
static int i2sbus_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in) static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{ {
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
@ -308,7 +302,6 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
get_pcm_info(i2sdev, in, &pi, NULL); get_pcm_info(i2sdev, in, &pi, NULL);
if (pi->dbdma_ring.stopping) if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi); i2sbus_wait_for_stop(i2sdev, pi);
snd_pcm_lib_free_pages(substream);
return 0; return 0;
} }
@ -780,8 +773,6 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_playback_ops = { static const struct snd_pcm_ops i2sbus_playback_ops = {
.open = i2sbus_playback_open, .open = i2sbus_playback_open,
.close = i2sbus_playback_close, .close = i2sbus_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = i2sbus_hw_params,
.hw_free = i2sbus_playback_hw_free, .hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare, .prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger, .trigger = i2sbus_playback_trigger,
@ -850,8 +841,6 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_record_ops = { static const struct snd_pcm_ops i2sbus_record_ops = {
.open = i2sbus_record_open, .open = i2sbus_record_open,
.close = i2sbus_record_close, .close = i2sbus_record_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = i2sbus_hw_params,
.hw_free = i2sbus_record_hw_free, .hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare, .prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger, .trigger = i2sbus_record_trigger,
@ -1026,7 +1015,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
dev->pcm->private_free = i2sbus_private_free; dev->pcm->private_free = i2sbus_private_free;
/* well, we really should support scatter/gather DMA */ /* well, we really should support scatter/gather DMA */
snd_pcm_lib_preallocate_pages_for_all( snd_pcm_set_managed_buffer_all(
dev->pcm, SNDRV_DMA_TYPE_DEV, dev->pcm, SNDRV_DMA_TYPE_DEV,
&macio_get_pci_dev(i2sdev->macio)->dev, &macio_get_pci_dev(i2sdev->macio)->dev,
64 * 1024, 64 * 1024); 64 * 1024, 64 * 1024);

View File

@ -380,7 +380,7 @@ static const struct snd_pcm_hardware aaci_hw_info = {
static int aaci_rule_channels(struct snd_pcm_hw_params *p, static int aaci_rule_channels(struct snd_pcm_hw_params *p,
struct snd_pcm_hw_rule *rule) struct snd_pcm_hw_rule *rule)
{ {
static unsigned int channel_list[] = { 2, 4, 6 }; static const unsigned int channel_list[] = { 2, 4, 6 };
struct aaci *aaci = rule->private; struct aaci *aaci = rule->private;
unsigned int mask = 1 << 0, slots; unsigned int mask = 1 << 0, slots;
@ -483,11 +483,6 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
snd_ac97_pcm_close(aacirun->pcm); snd_ac97_pcm_close(aacirun->pcm);
aacirun->pcm_open = 0; aacirun->pcm_open = 0;
/*
* Clear out the DMA and any allocated buffers.
*/
snd_pcm_lib_free_pages(substream);
return 0; return 0;
} }
@ -502,6 +497,7 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct aaci_runtime *aacirun = substream->runtime->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data;
struct aaci *aaci = substream->private_data;
unsigned int channels = params_channels(params); unsigned int channels = params_channels(params);
unsigned int rate = params_rate(params); unsigned int rate = params_rate(params);
int dbl = rate > 48000; int dbl = rate > 48000;
@ -517,25 +513,19 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
if (dbl && channels != 2) if (dbl && channels != 2)
return -EINVAL; return -EINVAL;
err = snd_pcm_lib_malloc_pages(substream, err = snd_ac97_pcm_open(aacirun->pcm, rate, channels,
params_buffer_bytes(params)); aacirun->pcm->r[dbl].slots);
if (err >= 0) {
struct aaci *aaci = substream->private_data;
err = snd_ac97_pcm_open(aacirun->pcm, rate, channels, aacirun->pcm_open = err == 0;
aacirun->pcm->r[dbl].slots); aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16;
aacirun->cr |= channels_to_slotmask[channels + dbl * 2];
aacirun->pcm_open = err == 0; /*
aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; * fifo_bytes is the number of bytes we transfer to/from
aacirun->cr |= channels_to_slotmask[channels + dbl * 2]; * the FIFO, including padding. So that's x4. As we're
* in compact mode, the FIFO is half the size.
/* */
* fifo_bytes is the number of bytes we transfer to/from aacirun->fifo_bytes = aaci->fifo_depth * 4 / 2;
* the FIFO, including padding. So that's x4. As we're
* in compact mode, the FIFO is half the size.
*/
aacirun->fifo_bytes = aaci->fifo_depth * 4 / 2;
}
return err; return err;
} }
@ -635,7 +625,6 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm
static const struct snd_pcm_ops aaci_playback_ops = { static const struct snd_pcm_ops aaci_playback_ops = {
.open = aaci_pcm_open, .open = aaci_pcm_open,
.close = aaci_pcm_close, .close = aaci_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = aaci_pcm_hw_params, .hw_params = aaci_pcm_hw_params,
.hw_free = aaci_pcm_hw_free, .hw_free = aaci_pcm_hw_free,
.prepare = aaci_pcm_prepare, .prepare = aaci_pcm_prepare,
@ -738,7 +727,6 @@ static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops aaci_capture_ops = { static const struct snd_pcm_ops aaci_capture_ops = {
.open = aaci_pcm_open, .open = aaci_pcm_open,
.close = aaci_pcm_close, .close = aaci_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = aaci_pcm_hw_params, .hw_params = aaci_pcm_hw_params,
.hw_free = aaci_pcm_hw_free, .hw_free = aaci_pcm_hw_free,
.prepare = aaci_pcm_capture_prepare, .prepare = aaci_pcm_capture_prepare,
@ -823,7 +811,7 @@ static const struct ac97_pcm ac97_defs[] = {
} }
}; };
static struct snd_ac97_bus_ops aaci_bus_ops = { static const struct snd_ac97_bus_ops aaci_bus_ops = {
.write = aaci_ac97_write, .write = aaci_ac97_write,
.read = aaci_ac97_read, .read = aaci_ac97_read,
}; };
@ -937,9 +925,9 @@ static int aaci_init_pcm(struct aaci *aaci)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
aaci->card->dev, aaci->card->dev,
0, 64 * 1024); 0, 64 * 1024);
} }
return ret; return ret;

View File

@ -52,7 +52,7 @@ static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
ret = pxa2xx_ac97_write(ac97->num, reg, val); ret = pxa2xx_ac97_write(ac97->num, reg, val);
} }
static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { static const struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.read = pxa2xx_ac97_legacy_read, .read = pxa2xx_ac97_legacy_read,
.write = pxa2xx_ac97_legacy_write, .write = pxa2xx_ac97_legacy_write,
.reset = pxa2xx_ac97_legacy_reset, .reset = pxa2xx_ac97_legacy_reset,
@ -173,7 +173,6 @@ static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_re
static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = { static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
.open = pxa2xx_ac97_pcm_open, .open = pxa2xx_ac97_pcm_open,
.close = pxa2xx_ac97_pcm_close, .close = pxa2xx_ac97_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pxa2xx_pcm_hw_params, .hw_params = pxa2xx_pcm_hw_params,
.hw_free = pxa2xx_pcm_hw_free, .hw_free = pxa2xx_pcm_hw_free,
.prepare = pxa2xx_ac97_pcm_prepare, .prepare = pxa2xx_ac97_pcm_prepare,

View File

@ -159,12 +159,6 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params) struct snd_pcm_hw_params *hw_params)
{ {
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
int retval;
retval = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (retval < 0)
return retval;
/* Set restrictions to params. */ /* Set restrictions to params. */
mutex_lock(&opened_mutex); mutex_lock(&opened_mutex);
@ -172,19 +166,13 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
chip->cur_format = params_format(hw_params); chip->cur_format = params_format(hw_params);
mutex_unlock(&opened_mutex); mutex_unlock(&opened_mutex);
return retval; return 0;
} }
static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params) struct snd_pcm_hw_params *hw_params)
{ {
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
int retval;
retval = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (retval < 0)
return retval;
/* Set restrictions to params. */ /* Set restrictions to params. */
mutex_lock(&opened_mutex); mutex_lock(&opened_mutex);
@ -192,7 +180,7 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
chip->cur_format = params_format(hw_params); chip->cur_format = params_format(hw_params);
mutex_unlock(&opened_mutex); mutex_unlock(&opened_mutex);
return retval; return 0;
} }
static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
@ -459,9 +447,7 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops atmel_ac97_playback_ops = { static const struct snd_pcm_ops atmel_ac97_playback_ops = {
.open = atmel_ac97c_playback_open, .open = atmel_ac97c_playback_open,
.close = atmel_ac97c_playback_close, .close = atmel_ac97c_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = atmel_ac97c_playback_hw_params, .hw_params = atmel_ac97c_playback_hw_params,
.hw_free = snd_pcm_lib_free_pages,
.prepare = atmel_ac97c_playback_prepare, .prepare = atmel_ac97c_playback_prepare,
.trigger = atmel_ac97c_playback_trigger, .trigger = atmel_ac97c_playback_trigger,
.pointer = atmel_ac97c_playback_pointer, .pointer = atmel_ac97c_playback_pointer,
@ -470,9 +456,7 @@ static const struct snd_pcm_ops atmel_ac97_playback_ops = {
static const struct snd_pcm_ops atmel_ac97_capture_ops = { static const struct snd_pcm_ops atmel_ac97_capture_ops = {
.open = atmel_ac97c_capture_open, .open = atmel_ac97c_capture_open,
.close = atmel_ac97c_capture_close, .close = atmel_ac97c_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = atmel_ac97c_capture_hw_params, .hw_params = atmel_ac97c_capture_hw_params,
.hw_free = snd_pcm_lib_free_pages,
.prepare = atmel_ac97c_capture_prepare, .prepare = atmel_ac97c_capture_prepare,
.trigger = atmel_ac97c_capture_trigger, .trigger = atmel_ac97c_capture_trigger,
.pointer = atmel_ac97c_capture_pointer, .pointer = atmel_ac97c_capture_pointer,
@ -600,7 +584,7 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &atmel_ac97_capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &atmel_ac97_capture_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_ac97_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_ac97_playback_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pdev->dev, hw.periods_min * hw.period_bytes_min, &chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
hw.buffer_bytes_max); hw.buffer_bytes_max);
@ -718,7 +702,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
struct atmel_ac97c *chip; struct atmel_ac97c *chip;
struct resource *regs; struct resource *regs;
struct clk *pclk; struct clk *pclk;
static struct snd_ac97_bus_ops ops = { static const struct snd_ac97_bus_ops ops = {
.write = atmel_ac97c_write, .write = atmel_ac97c_write,
.read = atmel_ac97c_read, .read = atmel_ac97c_read,
}; };

View File

@ -178,6 +178,15 @@ config SND_PCM_XRUN_DEBUG
sound clicking when system is loaded, it may help to determine sound clicking when system is loaded, it may help to determine
the process or driver which causes the scheduling gaps. the process or driver which causes the scheduling gaps.
config SND_CTL_VALIDATION
bool "Perform sanity-checks for each control element access"
depends on SND_DEBUG
help
Say Y to enable the additional validation of each control element
access, including sanity-checks like whether the values returned
from the driver are in the proper ranges or the check of the invalid
access at out-of-array areas.
config SND_VMASTER config SND_VMASTER
bool bool

View File

@ -1099,7 +1099,7 @@ static int snd_compress_dev_free(struct snd_device *device)
int snd_compress_new(struct snd_card *card, int device, int snd_compress_new(struct snd_card *card, int device,
int dirn, const char *id, struct snd_compr *compr) int dirn, const char *id, struct snd_compr *compr)
{ {
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_compress_dev_free, .dev_free = snd_compress_dev_free,
.dev_register = snd_compress_dev_register, .dev_register = snd_compress_dev_register,
.dev_disconnect = snd_compress_dev_disconnect, .dev_disconnect = snd_compress_dev_disconnect,

View File

@ -11,6 +11,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/math64.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/minors.h> #include <sound/minors.h>
@ -248,7 +249,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
SNDRV_CTL_ELEM_ACCESS_INACTIVE | SNDRV_CTL_ELEM_ACCESS_INACTIVE |
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND | SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK |
SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK);
err = snd_ctl_new(&kctl, count, access, NULL); err = snd_ctl_new(&kctl, count, access, NULL);
if (err < 0) if (err < 0)
@ -758,51 +760,199 @@ static int snd_ctl_elem_list(struct snd_card *card,
return err; return err;
} }
static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) /* Check whether the given kctl info is valid */
static int snd_ctl_check_elem_info(struct snd_card *card,
const struct snd_ctl_elem_info *info)
{ {
unsigned int members; static const unsigned int max_value_counts[] = {
unsigned int i; [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = 128,
[SNDRV_CTL_ELEM_TYPE_INTEGER] = 128,
[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128,
[SNDRV_CTL_ELEM_TYPE_BYTES] = 512,
[SNDRV_CTL_ELEM_TYPE_IEC958] = 1,
[SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64,
};
if (info->dimen.d[0] == 0) if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
return true; info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) {
if (card)
members = 1; dev_err(card->dev,
for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) { "control %i:%i:%i:%s:%i: invalid type %d\n",
if (info->dimen.d[i] == 0) info->id.iface, info->id.device,
break; info->id.subdevice, info->id.name,
members *= info->dimen.d[i]; info->id.index, info->type);
return -EINVAL;
/* }
* info->count should be validated in advance, to guarantee if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED &&
* calculation soundness. info->value.enumerated.items == 0) {
*/ if (card)
if (members > info->count) dev_err(card->dev,
return false; "control %i:%i:%i:%s:%i: zero enum items\n",
info->id.iface, info->id.device,
info->id.subdevice, info->id.name,
info->id.index);
return -EINVAL;
}
if (info->count > max_value_counts[info->type]) {
if (card)
dev_err(card->dev,
"control %i:%i:%i:%s:%i: invalid count %d\n",
info->id.iface, info->id.device,
info->id.subdevice, info->id.name,
info->id.index, info->count);
return -EINVAL;
} }
for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) { return 0;
if (info->dimen.d[i] > 0)
return false;
}
return members == info->count;
} }
static int snd_ctl_elem_info(struct snd_ctl_file *ctl, /* The capacity of struct snd_ctl_elem_value.value.*/
struct snd_ctl_elem_info *info) static const unsigned int value_sizes[] = {
[SNDRV_CTL_ELEM_TYPE_BOOLEAN] = sizeof(long),
[SNDRV_CTL_ELEM_TYPE_INTEGER] = sizeof(long),
[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int),
[SNDRV_CTL_ELEM_TYPE_BYTES] = sizeof(unsigned char),
[SNDRV_CTL_ELEM_TYPE_IEC958] = sizeof(struct snd_aes_iec958),
[SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
};
#ifdef CONFIG_SND_CTL_VALIDATION
/* fill the remaining snd_ctl_elem_value data with the given pattern */
static void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
struct snd_ctl_elem_info *info,
u32 pattern)
{
size_t offset = value_sizes[info->type] * info->count;
offset = (offset + sizeof(u32) - 1) / sizeof(u32);
memset32((u32 *)control->value.bytes.data + offset, pattern,
sizeof(control->value) / sizeof(u32) - offset);
}
/* check whether the given integer ctl value is valid */
static int sanity_check_int_value(struct snd_card *card,
const struct snd_ctl_elem_value *control,
const struct snd_ctl_elem_info *info,
int i)
{
long long lval, lmin, lmax, lstep;
u64 rem;
switch (info->type) {
default:
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
lval = control->value.integer.value[i];
lmin = 0;
lmax = 1;
lstep = 0;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
lval = control->value.integer.value[i];
lmin = info->value.integer.min;
lmax = info->value.integer.max;
lstep = info->value.integer.step;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
lval = control->value.integer64.value[i];
lmin = info->value.integer64.min;
lmax = info->value.integer64.max;
lstep = info->value.integer64.step;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
lval = control->value.enumerated.item[i];
lmin = 0;
lmax = info->value.enumerated.items - 1;
lstep = 0;
break;
}
if (lval < lmin || lval > lmax) {
dev_err(card->dev,
"control %i:%i:%i:%s:%i: value out of range %lld (%lld/%lld) at count %i\n",
control->id.iface, control->id.device,
control->id.subdevice, control->id.name,
control->id.index, lval, lmin, lmax, i);
return -EINVAL;
}
if (lstep) {
div64_u64_rem(lval, lstep, &rem);
if (rem) {
dev_err(card->dev,
"control %i:%i:%i:%s:%i: unaligned value %lld (step %lld) at count %i\n",
control->id.iface, control->id.device,
control->id.subdevice, control->id.name,
control->id.index, lval, lstep, i);
return -EINVAL;
}
}
return 0;
}
/* perform sanity checks to the given snd_ctl_elem_value object */
static int sanity_check_elem_value(struct snd_card *card,
const struct snd_ctl_elem_value *control,
const struct snd_ctl_elem_info *info,
u32 pattern)
{
size_t offset;
int i, ret = 0;
u32 *p;
switch (info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
for (i = 0; i < info->count; i++) {
ret = sanity_check_int_value(card, control, info, i);
if (ret < 0)
return ret;
}
break;
default:
break;
}
/* check whether the remaining area kept untouched */
offset = value_sizes[info->type] * info->count;
offset = (offset + sizeof(u32) - 1) / sizeof(u32);
p = (u32 *)control->value.bytes.data + offset;
for (; offset < sizeof(control->value) / sizeof(u32); offset++, p++) {
if (*p != pattern) {
ret = -EINVAL;
break;
}
*p = 0; /* clear the checked area */
}
return ret;
}
#else
static inline void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
struct snd_ctl_elem_info *info,
u32 pattern)
{
}
static inline int sanity_check_elem_value(struct snd_card *card,
struct snd_ctl_elem_value *control,
struct snd_ctl_elem_info *info,
u32 pattern)
{
return 0;
}
#endif
static int __snd_ctl_elem_info(struct snd_card *card,
struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *info,
struct snd_ctl_file *ctl)
{ {
struct snd_card *card = ctl->card;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd; struct snd_kcontrol_volatile *vd;
unsigned int index_offset; unsigned int index_offset;
int result; int result;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &info->id);
if (kctl == NULL) {
up_read(&card->controls_rwsem);
return -ENOENT;
}
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
info->access = 0; info->access = 0;
#endif #endif
@ -821,7 +971,26 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
} else { } else {
info->owner = -1; info->owner = -1;
} }
if (!snd_ctl_skip_validation(info) &&
snd_ctl_check_elem_info(card, info) < 0)
result = -EINVAL;
} }
return result;
}
static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info *info)
{
struct snd_card *card = ctl->card;
struct snd_kcontrol *kctl;
int result;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &info->id);
if (kctl == NULL)
result = -ENOENT;
else
result = __snd_ctl_elem_info(card, kctl, info, ctl);
up_read(&card->controls_rwsem); up_read(&card->controls_rwsem);
return result; return result;
} }
@ -840,6 +1009,8 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
result = snd_ctl_elem_info(ctl, &info); result = snd_ctl_elem_info(ctl, &info);
if (result < 0) if (result < 0)
return result; return result;
/* drop internal access flags */
info.access &= ~SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK;
if (copy_to_user(_info, &info, sizeof(info))) if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT; return -EFAULT;
return result; return result;
@ -851,6 +1022,9 @@ static int snd_ctl_elem_read(struct snd_card *card,
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd; struct snd_kcontrol_volatile *vd;
unsigned int index_offset; unsigned int index_offset;
struct snd_ctl_elem_info info;
const u32 pattern = 0xdeadbeef;
int ret;
kctl = snd_ctl_find_id(card, &control->id); kctl = snd_ctl_find_id(card, &control->id);
if (kctl == NULL) if (kctl == NULL)
@ -862,7 +1036,31 @@ static int snd_ctl_elem_read(struct snd_card *card,
return -EPERM; return -EPERM;
snd_ctl_build_ioff(&control->id, kctl, index_offset); snd_ctl_build_ioff(&control->id, kctl, index_offset);
return kctl->get(kctl, control);
#ifdef CONFIG_SND_CTL_VALIDATION
/* info is needed only for validation */
memset(&info, 0, sizeof(info));
info.id = control->id;
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
if (ret < 0)
return ret;
#endif
if (!snd_ctl_skip_validation(&info))
fill_remaining_elem_value(control, &info, pattern);
ret = kctl->get(kctl, control);
if (ret < 0)
return ret;
if (!snd_ctl_skip_validation(&info) &&
sanity_check_elem_value(card, control, &info, pattern) < 0) {
dev_err(card->dev,
"control %i:%i:%i:%s:%i: access overflow\n",
control->id.iface, control->id.device,
control->id.subdevice, control->id.name,
control->id.index);
return -EINVAL;
}
return ret;
} }
static int snd_ctl_elem_read_user(struct snd_card *card, static int snd_ctl_elem_read_user(struct snd_card *card,
@ -1203,23 +1401,6 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
static int snd_ctl_elem_add(struct snd_ctl_file *file, static int snd_ctl_elem_add(struct snd_ctl_file *file,
struct snd_ctl_elem_info *info, int replace) struct snd_ctl_elem_info *info, int replace)
{ {
/* The capacity of struct snd_ctl_elem_value.value.*/
static const unsigned int value_sizes[] = {
[SNDRV_CTL_ELEM_TYPE_BOOLEAN] = sizeof(long),
[SNDRV_CTL_ELEM_TYPE_INTEGER] = sizeof(long),
[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int),
[SNDRV_CTL_ELEM_TYPE_BYTES] = sizeof(unsigned char),
[SNDRV_CTL_ELEM_TYPE_IEC958] = sizeof(struct snd_aes_iec958),
[SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
};
static const unsigned int max_value_counts[] = {
[SNDRV_CTL_ELEM_TYPE_BOOLEAN] = 128,
[SNDRV_CTL_ELEM_TYPE_INTEGER] = 128,
[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128,
[SNDRV_CTL_ELEM_TYPE_BYTES] = 512,
[SNDRV_CTL_ELEM_TYPE_IEC958] = 1,
[SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64,
};
struct snd_card *card = file->card; struct snd_card *card = file->card;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
unsigned int count; unsigned int count;
@ -1271,16 +1452,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
* Check information and calculate the size of data specific to * Check information and calculate the size of data specific to
* this userspace control. * this userspace control.
*/ */
if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN || /* pass NULL to card for suppressing error messages */
info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) err = snd_ctl_check_elem_info(NULL, info);
return -EINVAL; if (err < 0)
if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && return err;
info->value.enumerated.items == 0) /* user-space control doesn't allow zero-size data */
return -EINVAL; if (info->count < 1)
if (info->count < 1 ||
info->count > max_value_counts[info->type])
return -EINVAL;
if (!validate_element_member_dimension(info))
return -EINVAL; return -EINVAL;
private_size = value_sizes[info->type] * info->count; private_size = value_sizes[info->type] * info->count;
@ -1430,8 +1607,9 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
if (kctl->tlv.c == NULL) if (kctl->tlv.c == NULL)
return -ENXIO; return -ENXIO;
/* When locked, this is unavailable. */ /* Write and command operations are not allowed for locked element. */
if (vd->owner != NULL && vd->owner != file) if (op_flag != SNDRV_CTL_TLV_OP_READ &&
vd->owner != NULL && vd->owner != file)
return -EPERM; return -EPERM;
return kctl->tlv.c(kctl, op_flag, size, buf); return kctl->tlv.c(kctl, op_flag, size, buf);
@ -1854,7 +2032,7 @@ static int snd_ctl_dev_free(struct snd_device *device)
*/ */
int snd_ctl_create(struct snd_card *card) int snd_ctl_create(struct snd_card *card)
{ {
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_ctl_dev_free, .dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register, .dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect, .dev_disconnect = snd_ctl_dev_disconnect,

View File

@ -27,7 +27,7 @@
* Return: Zero if successful, or a negative error code on failure. * Return: Zero if successful, or a negative error code on failure.
*/ */
int snd_device_new(struct snd_card *card, enum snd_device_type type, int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops) void *device_data, const struct snd_device_ops *ops)
{ {
struct snd_device *dev; struct snd_device *dev;
struct list_head *p; struct list_head *p;

View File

@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
{ {
struct snd_hwdep *hwdep; struct snd_hwdep *hwdep;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_hwdep_dev_free, .dev_free = snd_hwdep_dev_free,
.dev_register = snd_hwdep_dev_register, .dev_register = snd_hwdep_dev_register,
.dev_disconnect = snd_hwdep_dev_disconnect, .dev_disconnect = snd_hwdep_dev_disconnect,

View File

@ -20,7 +20,7 @@
int snd_info_check_reserved_words(const char *str) int snd_info_check_reserved_words(const char *str)
{ {
static char *reserved[] = static const char * const reserved[] =
{ {
"version", "version",
"meminfo", "meminfo",
@ -35,7 +35,7 @@ int snd_info_check_reserved_words(const char *str)
"seq", "seq",
NULL NULL
}; };
char **xstr = reserved; const char * const *xstr = reserved;
while (*xstr) { while (*xstr) {
if (!strcmp(*xstr, str)) if (!strcmp(*xstr, str))

View File

@ -211,6 +211,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
INIT_LIST_HEAD(&card->ctl_files); INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock); spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list); INIT_LIST_HEAD(&card->files_list);
mutex_init(&card->memory_mutex);
#ifdef CONFIG_PM #ifdef CONFIG_PM
init_waitqueue_head(&card->power_sleep); init_waitqueue_head(&card->power_sleep);
#endif #endif

View File

@ -19,7 +19,7 @@ struct snd_jack_kctl {
}; };
#ifdef CONFIG_SND_JACK_INPUT_DEV #ifdef CONFIG_SND_JACK_INPUT_DEV
static int jack_switch_types[SND_JACK_SWITCH_TYPES] = { static const int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
SW_HEADPHONE_INSERT, SW_HEADPHONE_INSERT,
SW_MICROPHONE_INSERT, SW_MICROPHONE_INSERT,
SW_LINEOUT_INSERT, SW_LINEOUT_INSERT,
@ -201,7 +201,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
struct snd_jack *jack; struct snd_jack *jack;
struct snd_jack_kctl *jack_kctl = NULL; struct snd_jack_kctl *jack_kctl = NULL;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_jack_dev_free, .dev_free = snd_jack_dev_free,
#ifdef CONFIG_SND_JACK_INPUT_DEV #ifdef CONFIG_SND_JACK_INPUT_DEV
.dev_register = snd_jack_dev_register, .dev_register = snd_jack_dev_register,

View File

@ -486,7 +486,7 @@ struct slot {
unsigned int channels; unsigned int channels;
unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT]; unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
unsigned int capture_item; unsigned int capture_item;
struct snd_mixer_oss_assign_table *assigned; const struct snd_mixer_oss_assign_table *assigned;
unsigned int allocated: 1; unsigned int allocated: 1;
}; };
@ -934,8 +934,8 @@ static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
struct slot *p = chn->private_data; struct slot *p = chn->private_data;
if (p) { if (p) {
if (p->allocated && p->assigned) { if (p->allocated && p->assigned) {
kfree(p->assigned->name); kfree_const(p->assigned->name);
kfree(p->assigned); kfree_const(p->assigned);
} }
kfree(p); kfree(p);
} }
@ -953,7 +953,7 @@ static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
/* In a separate function to keep gcc 3.2 happy - do NOT merge this in /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
snd_mixer_oss_build_input! */ snd_mixer_oss_build_input! */
static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer, static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
struct snd_mixer_oss_assign_table *ptr, const struct snd_mixer_oss_assign_table *ptr,
struct slot *slot) struct slot *slot)
{ {
char str[64]; char str[64];
@ -1017,7 +1017,9 @@ static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
* ptr_allocated means the entry is dynamically allocated (change via proc file). * ptr_allocated means the entry is dynamically allocated (change via proc file).
* when replace_old = 1, the old entry is replaced with the new one. * when replace_old = 1, the old entry is replaced with the new one.
*/ */
static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
const struct snd_mixer_oss_assign_table *ptr,
int ptr_allocated, int replace_old)
{ {
struct slot slot; struct slot slot;
struct slot *pslot; struct slot *pslot;
@ -1107,7 +1109,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
/* /*
*/ */
#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { static const char * const oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
MIXER_VOL(VOLUME), MIXER_VOL(VOLUME),
MIXER_VOL(BASS), MIXER_VOL(BASS),
MIXER_VOL(TREBLE), MIXER_VOL(TREBLE),
@ -1255,7 +1257,7 @@ static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
{ {
static struct snd_mixer_oss_assign_table table[] = { static const struct snd_mixer_oss_assign_table table[] = {
{ SOUND_MIXER_VOLUME, "Master", 0 }, { SOUND_MIXER_VOLUME, "Master", 0 },
{ SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */
{ SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, { SOUND_MIXER_BASS, "Tone Control - Bass", 0 },

View File

@ -288,7 +288,7 @@ static int snd_pcm_plug_formats(const struct snd_mask *mask,
return snd_mask_test(&formats, (__force int)format); return snd_mask_test(&formats, (__force int)format);
} }
static snd_pcm_format_t preferred_formats[] = { static const snd_pcm_format_t preferred_formats[] = {
SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_LE,
SNDRV_PCM_FORMAT_S16_BE, SNDRV_PCM_FORMAT_S16_BE,
SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_LE,

View File

@ -163,7 +163,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
#define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
static char *snd_pcm_format_names[] = { static const char * const snd_pcm_format_names[] = {
FORMAT(S8), FORMAT(S8),
FORMAT(U8), FORMAT(U8),
FORMAT(S16_LE), FORMAT(S16_LE),
@ -237,12 +237,12 @@ EXPORT_SYMBOL_GPL(snd_pcm_format_name);
#define START(v) [SNDRV_PCM_START_##v] = #v #define START(v) [SNDRV_PCM_START_##v] = #v
#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v #define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
static char *snd_pcm_stream_names[] = { static const char * const snd_pcm_stream_names[] = {
STREAM(PLAYBACK), STREAM(PLAYBACK),
STREAM(CAPTURE), STREAM(CAPTURE),
}; };
static char *snd_pcm_state_names[] = { static const char * const snd_pcm_state_names[] = {
STATE(OPEN), STATE(OPEN),
STATE(SETUP), STATE(SETUP),
STATE(PREPARED), STATE(PREPARED),
@ -253,7 +253,7 @@ static char *snd_pcm_state_names[] = {
STATE(SUSPENDED), STATE(SUSPENDED),
}; };
static char *snd_pcm_access_names[] = { static const char * const snd_pcm_access_names[] = {
ACCESS(MMAP_INTERLEAVED), ACCESS(MMAP_INTERLEAVED),
ACCESS(MMAP_NONINTERLEAVED), ACCESS(MMAP_NONINTERLEAVED),
ACCESS(MMAP_COMPLEX), ACCESS(MMAP_COMPLEX),
@ -261,11 +261,11 @@ static char *snd_pcm_access_names[] = {
ACCESS(RW_NONINTERLEAVED), ACCESS(RW_NONINTERLEAVED),
}; };
static char *snd_pcm_subformat_names[] = { static const char * const snd_pcm_subformat_names[] = {
SUBFORMAT(STD), SUBFORMAT(STD),
}; };
static char *snd_pcm_tstamp_mode_names[] = { static const char * const snd_pcm_tstamp_mode_names[] = {
TSTAMP(NONE), TSTAMP(NONE),
TSTAMP(ENABLE), TSTAMP(ENABLE),
}; };
@ -443,7 +443,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
{ {
struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_substream *substream = entry->private_data;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct snd_pcm_status status; struct snd_pcm_status64 status;
int err; int err;
mutex_lock(&substream->pcm->open_mutex); mutex_lock(&substream->pcm->open_mutex);
@ -453,17 +453,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
goto unlock; goto unlock;
} }
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
err = snd_pcm_status(substream, &status); err = snd_pcm_status64(substream, &status);
if (err < 0) { if (err < 0) {
snd_iprintf(buffer, "error %d\n", err); snd_iprintf(buffer, "error %d\n", err);
goto unlock; goto unlock;
} }
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", snd_iprintf(buffer, "trigger_time: %lld.%09lld\n",
status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); status.trigger_tstamp_sec, status.trigger_tstamp_nsec);
snd_iprintf(buffer, "tstamp : %ld.%09ld\n", snd_iprintf(buffer, "tstamp : %lld.%09lld\n",
status.tstamp.tv_sec, status.tstamp.tv_nsec); status.tstamp_sec, status.tstamp_nsec);
snd_iprintf(buffer, "delay : %ld\n", status.delay); snd_iprintf(buffer, "delay : %ld\n", status.delay);
snd_iprintf(buffer, "avail : %ld\n", status.avail); snd_iprintf(buffer, "avail : %ld\n", status.avail);
snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max); snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max);
@ -706,12 +706,12 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
{ {
struct snd_pcm *pcm; struct snd_pcm *pcm;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free, .dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register, .dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect, .dev_disconnect = snd_pcm_dev_disconnect,
}; };
static struct snd_device_ops internal_ops = { static const struct snd_device_ops internal_ops = {
.dev_free = snd_pcm_dev_free, .dev_free = snd_pcm_dev_free,
}; };

View File

@ -83,19 +83,6 @@ struct snd_pcm_sw_params32 {
unsigned char reserved[56]; unsigned char reserved[56];
}; };
/* recalcuate the boundary within 32bit */
static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t boundary;
if (! runtime->buffer_size)
return 0;
boundary = runtime->buffer_size;
while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
boundary *= 2;
return boundary;
}
static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream,
struct snd_pcm_sw_params32 __user *src) struct snd_pcm_sw_params32 __user *src)
{ {
@ -168,10 +155,13 @@ static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
snd_pcm_channel_info_user(s, p) snd_pcm_channel_info_user(s, p)
#endif /* CONFIG_X86_X32 */ #endif /* CONFIG_X86_X32 */
struct snd_pcm_status32 { struct compat_snd_pcm_status64 {
s32 state; s32 state;
struct compat_timespec trigger_tstamp; u8 rsvd[4]; /* alignment */
struct compat_timespec tstamp; s64 trigger_tstamp_sec;
s64 trigger_tstamp_nsec;
s64 tstamp_sec;
s64 tstamp_nsec;
u32 appl_ptr; u32 appl_ptr;
u32 hw_ptr; u32 hw_ptr;
s32 delay; s32 delay;
@ -180,85 +170,24 @@ struct snd_pcm_status32 {
u32 overrange; u32 overrange;
s32 suspended_state; s32 suspended_state;
u32 audio_tstamp_data; u32 audio_tstamp_data;
struct compat_timespec audio_tstamp; s64 audio_tstamp_sec;
struct compat_timespec driver_tstamp; s64 audio_tstamp_nsec;
s64 driver_tstamp_sec;
s64 driver_tstamp_nsec;
u32 audio_tstamp_accuracy; u32 audio_tstamp_accuracy;
unsigned char reserved[52-2*sizeof(struct compat_timespec)]; unsigned char reserved[52-4*sizeof(s64)];
} __attribute__((packed));
static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
struct snd_pcm_status32 __user *src,
bool ext)
{
struct snd_pcm_status status;
int err;
memset(&status, 0, sizeof(status));
/*
* with extension, parameters are read/write,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
if (ext && get_user(status.audio_tstamp_data,
(u32 __user *)(&src->audio_tstamp_data)))
return -EFAULT;
err = snd_pcm_status(substream, &status);
if (err < 0)
return err;
if (clear_user(src, sizeof(*src)))
return -EFAULT;
if (put_user(status.state, &src->state) ||
compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
compat_put_timespec(&status.tstamp, &src->tstamp) ||
put_user(status.appl_ptr, &src->appl_ptr) ||
put_user(status.hw_ptr, &src->hw_ptr) ||
put_user(status.delay, &src->delay) ||
put_user(status.avail, &src->avail) ||
put_user(status.avail_max, &src->avail_max) ||
put_user(status.overrange, &src->overrange) ||
put_user(status.suspended_state, &src->suspended_state) ||
put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
return -EFAULT;
return err;
}
#ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_pcm_status_x32 {
s32 state;
u32 rsvd; /* alignment */
struct timespec trigger_tstamp;
struct timespec tstamp;
u32 appl_ptr;
u32 hw_ptr;
s32 delay;
u32 avail;
u32 avail_max;
u32 overrange;
s32 suspended_state;
u32 audio_tstamp_data;
struct timespec audio_tstamp;
struct timespec driver_tstamp;
u32 audio_tstamp_accuracy;
unsigned char reserved[52-2*sizeof(struct timespec)];
} __packed; } __packed;
#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) static int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream,
struct compat_snd_pcm_status64 __user *src,
static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream, bool ext)
struct snd_pcm_status_x32 __user *src,
bool ext)
{ {
struct snd_pcm_status status; struct snd_pcm_status64 status;
struct compat_snd_pcm_status64 compat_status64;
int err; int err;
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
memset(&compat_status64, 0, sizeof(compat_status64));
/* /*
* with extension, parameters are read/write, * with extension, parameters are read/write,
* get audio_tstamp_data from user, * get audio_tstamp_data from user,
@ -267,31 +196,39 @@ static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
if (ext && get_user(status.audio_tstamp_data, if (ext && get_user(status.audio_tstamp_data,
(u32 __user *)(&src->audio_tstamp_data))) (u32 __user *)(&src->audio_tstamp_data)))
return -EFAULT; return -EFAULT;
err = snd_pcm_status(substream, &status); err = snd_pcm_status64(substream, &status);
if (err < 0) if (err < 0)
return err; return err;
if (clear_user(src, sizeof(*src))) if (clear_user(src, sizeof(*src)))
return -EFAULT; return -EFAULT;
if (put_user(status.state, &src->state) ||
put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || compat_status64 = (struct compat_snd_pcm_status64) {
put_timespec(&status.tstamp, &src->tstamp) || .state = status.state,
put_user(status.appl_ptr, &src->appl_ptr) || .trigger_tstamp_sec = status.trigger_tstamp_sec,
put_user(status.hw_ptr, &src->hw_ptr) || .trigger_tstamp_nsec = status.trigger_tstamp_nsec,
put_user(status.delay, &src->delay) || .tstamp_sec = status.tstamp_sec,
put_user(status.avail, &src->avail) || .tstamp_nsec = status.tstamp_nsec,
put_user(status.avail_max, &src->avail_max) || .appl_ptr = status.appl_ptr,
put_user(status.overrange, &src->overrange) || .hw_ptr = status.hw_ptr,
put_user(status.suspended_state, &src->suspended_state) || .delay = status.delay,
put_user(status.audio_tstamp_data, &src->audio_tstamp_data) || .avail = status.avail,
put_timespec(&status.audio_tstamp, &src->audio_tstamp) || .avail_max = status.avail_max,
put_timespec(&status.driver_tstamp, &src->driver_tstamp) || .overrange = status.overrange,
put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy)) .suspended_state = status.suspended_state,
.audio_tstamp_data = status.audio_tstamp_data,
.audio_tstamp_sec = status.audio_tstamp_sec,
.audio_tstamp_nsec = status.audio_tstamp_nsec,
.driver_tstamp_sec = status.audio_tstamp_sec,
.driver_tstamp_nsec = status.audio_tstamp_nsec,
.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
};
if (copy_to_user(src, &compat_status64, sizeof(compat_status64)))
return -EFAULT; return -EFAULT;
return err; return err;
} }
#endif /* CONFIG_X86_X32 */
/* both for HW_PARAMS and HW_REFINE */ /* both for HW_PARAMS and HW_REFINE */
static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
@ -436,91 +373,6 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
return err; return err;
} }
struct snd_pcm_mmap_status32 {
s32 state;
s32 pad1;
u32 hw_ptr;
struct compat_timespec tstamp;
s32 suspended_state;
struct compat_timespec audio_tstamp;
} __attribute__((packed));
struct snd_pcm_mmap_control32 {
u32 appl_ptr;
u32 avail_min;
};
struct snd_pcm_sync_ptr32 {
u32 flags;
union {
struct snd_pcm_mmap_status32 status;
unsigned char reserved[64];
} s;
union {
struct snd_pcm_mmap_control32 control;
unsigned char reserved[64];
} c;
} __attribute__((packed));
static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr32 __user *src)
{
struct snd_pcm_runtime *runtime = substream->runtime;
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
u32 sflags;
struct snd_pcm_mmap_control scontrol;
struct snd_pcm_mmap_status sstatus;
snd_pcm_uframes_t boundary;
int err;
if (snd_BUG_ON(!runtime))
return -EINVAL;
if (get_user(sflags, &src->flags) ||
get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
get_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
if (err < 0)
return err;
}
status = runtime->status;
control = runtime->control;
boundary = recalculate_boundary(runtime);
if (! boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
compat_put_timespec(&sstatus.audio_tstamp,
&src->s.status.audio_tstamp) ||
put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
put_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
return 0;
}
#ifdef CONFIG_X86_X32 #ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */ /* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_pcm_mmap_status_x32 { struct snd_pcm_mmap_status_x32 {
@ -528,10 +380,12 @@ struct snd_pcm_mmap_status_x32 {
s32 pad1; s32 pad1;
u32 hw_ptr; u32 hw_ptr;
u32 pad2; /* alignment */ u32 pad2; /* alignment */
struct timespec tstamp; s64 tstamp_sec;
s64 tstamp_nsec;
s32 suspended_state; s32 suspended_state;
s32 pad3; s32 pad3;
struct timespec audio_tstamp; s64 audio_tstamp_sec;
s64 audio_tstamp_nsec;
} __packed; } __packed;
struct snd_pcm_mmap_control_x32 { struct snd_pcm_mmap_control_x32 {
@ -599,9 +453,11 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
snd_pcm_stream_unlock_irq(substream); snd_pcm_stream_unlock_irq(substream);
if (put_user(sstatus.state, &src->s.status.state) || if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
put_user(sstatus.suspended_state, &src->s.status.suspended_state) || put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) || put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
put_user(scontrol.avail_min, &src->c.control.avail_min)) put_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT; return -EFAULT;
@ -616,8 +472,8 @@ enum {
SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32), SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32), SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32), SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32), SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct snd_pcm_status32),
SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32), SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32), SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32), SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32), SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
@ -626,11 +482,10 @@ enum {
SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32), SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32), SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32), SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32), SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
#ifdef CONFIG_X86_X32 #ifdef CONFIG_X86_X32
SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info), SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32),
SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32),
SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32), SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
#endif /* CONFIG_X86_X32 */ #endif /* CONFIG_X86_X32 */
}; };
@ -650,8 +505,8 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
/* /*
* When PCM is used on 32bit mode, we need to disable * When PCM is used on 32bit mode, we need to disable
* mmap of PCM status/control records because of the size * mmap of the old PCM status/control records because
* incompatibility. * of the size incompatibility.
*/ */
pcm_file->no_compat_mmap = 1; pcm_file->no_compat_mmap = 1;
@ -673,6 +528,13 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
case SNDRV_PCM_IOCTL_XRUN: case SNDRV_PCM_IOCTL_XRUN:
case SNDRV_PCM_IOCTL_LINK: case SNDRV_PCM_IOCTL_LINK:
case SNDRV_PCM_IOCTL_UNLINK: case SNDRV_PCM_IOCTL_UNLINK:
case __SNDRV_PCM_IOCTL_SYNC_PTR32:
return snd_pcm_common_ioctl(file, substream, cmd, argp);
case __SNDRV_PCM_IOCTL_SYNC_PTR64:
#ifdef CONFIG_X86_X32
if (in_x32_syscall())
return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
#endif /* CONFIG_X86_X32 */
return snd_pcm_common_ioctl(file, substream, cmd, argp); return snd_pcm_common_ioctl(file, substream, cmd, argp);
case SNDRV_PCM_IOCTL_HW_REFINE32: case SNDRV_PCM_IOCTL_HW_REFINE32:
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
@ -680,12 +542,10 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
return snd_pcm_ioctl_hw_params_compat(substream, 0, argp); return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
case SNDRV_PCM_IOCTL_SW_PARAMS32: case SNDRV_PCM_IOCTL_SW_PARAMS32:
return snd_pcm_ioctl_sw_params_compat(substream, argp); return snd_pcm_ioctl_sw_params_compat(substream, argp);
case SNDRV_PCM_IOCTL_STATUS32: case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
return snd_pcm_status_user_compat(substream, argp, false); return snd_pcm_status_user32(substream, argp, false);
case SNDRV_PCM_IOCTL_STATUS_EXT32: case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
return snd_pcm_status_user_compat(substream, argp, true); return snd_pcm_status_user32(substream, argp, true);
case SNDRV_PCM_IOCTL_SYNC_PTR32:
return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
case SNDRV_PCM_IOCTL_CHANNEL_INFO32: case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
return snd_pcm_ioctl_channel_info_compat(substream, argp); return snd_pcm_ioctl_channel_info_compat(substream, argp);
case SNDRV_PCM_IOCTL_WRITEI_FRAMES32: case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
@ -702,13 +562,11 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
return snd_pcm_ioctl_rewind_compat(substream, argp); return snd_pcm_ioctl_rewind_compat(substream, argp);
case SNDRV_PCM_IOCTL_FORWARD32: case SNDRV_PCM_IOCTL_FORWARD32:
return snd_pcm_ioctl_forward_compat(substream, argp); return snd_pcm_ioctl_forward_compat(substream, argp);
case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
return snd_pcm_status_user_compat64(substream, argp, false);
case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
return snd_pcm_status_user_compat64(substream, argp, true);
#ifdef CONFIG_X86_X32 #ifdef CONFIG_X86_X32
case SNDRV_PCM_IOCTL_STATUS_X32:
return snd_pcm_status_user_x32(substream, argp, false);
case SNDRV_PCM_IOCTL_STATUS_EXT_X32:
return snd_pcm_status_user_x32(substream, argp, true);
case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32: case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
return snd_pcm_ioctl_channel_info_x32(substream, argp); return snd_pcm_ioctl_channel_info_x32(substream, argp);
#endif /* CONFIG_X86_X32 */ #endif /* CONFIG_X86_X32 */

View File

@ -144,8 +144,13 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
trace_xrun(substream); trace_xrun(substream);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); struct timespec64 tstamp;
snd_pcm_gettime(runtime, &tstamp);
runtime->status->tstamp.tv_sec = tstamp.tv_sec;
runtime->status->tstamp.tv_nsec = tstamp.tv_nsec;
}
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
char name[16]; char name[16];
@ -200,12 +205,12 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
} }
static void update_audio_tstamp(struct snd_pcm_substream *substream, static void update_audio_tstamp(struct snd_pcm_substream *substream,
struct timespec *curr_tstamp, struct timespec64 *curr_tstamp,
struct timespec *audio_tstamp) struct timespec64 *audio_tstamp)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
u64 audio_frames, audio_nsecs; u64 audio_frames, audio_nsecs;
struct timespec driver_tstamp; struct timespec64 driver_tstamp;
if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
return; return;
@ -229,18 +234,23 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream,
} }
audio_nsecs = div_u64(audio_frames * 1000000000LL, audio_nsecs = div_u64(audio_frames * 1000000000LL,
runtime->rate); runtime->rate);
*audio_tstamp = ns_to_timespec(audio_nsecs); *audio_tstamp = ns_to_timespec64(audio_nsecs);
} }
if (!timespec_equal(&runtime->status->audio_tstamp, audio_tstamp)) {
runtime->status->audio_tstamp = *audio_tstamp; if (runtime->status->audio_tstamp.tv_sec != audio_tstamp->tv_sec ||
runtime->status->tstamp = *curr_tstamp; runtime->status->audio_tstamp.tv_nsec != audio_tstamp->tv_nsec) {
runtime->status->audio_tstamp.tv_sec = audio_tstamp->tv_sec;
runtime->status->audio_tstamp.tv_nsec = audio_tstamp->tv_nsec;
runtime->status->tstamp.tv_sec = curr_tstamp->tv_sec;
runtime->status->tstamp.tv_nsec = curr_tstamp->tv_nsec;
} }
/* /*
* re-take a driver timestamp to let apps detect if the reference tstamp * re-take a driver timestamp to let apps detect if the reference tstamp
* read by low-level hardware was provided with a delay * read by low-level hardware was provided with a delay
*/ */
snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp); snd_pcm_gettime(substream->runtime, &driver_tstamp);
runtime->driver_tstamp = driver_tstamp; runtime->driver_tstamp = driver_tstamp;
} }
@ -253,8 +263,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
snd_pcm_sframes_t hdelta, delta; snd_pcm_sframes_t hdelta, delta;
unsigned long jdelta; unsigned long jdelta;
unsigned long curr_jiffies; unsigned long curr_jiffies;
struct timespec curr_tstamp; struct timespec64 curr_tstamp;
struct timespec audio_tstamp; struct timespec64 audio_tstamp;
int crossed_boundary = 0; int crossed_boundary = 0;
old_hw_ptr = runtime->status->hw_ptr; old_hw_ptr = runtime->status->hw_ptr;
@ -277,9 +287,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
/* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */ /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT) if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); snd_pcm_gettime(runtime, &curr_tstamp);
} else } else
snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); snd_pcm_gettime(runtime, &curr_tstamp);
} }
if (pos == SNDRV_PCM_POS_XRUN) { if (pos == SNDRV_PCM_POS_XRUN) {
@ -1442,7 +1452,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{ {
static unsigned int pow2_sizes[] = { static const unsigned int pow2_sizes[] = {
1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7, 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23, 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
@ -2308,7 +2318,6 @@ static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 0;
uinfo->count = info->max_channels; uinfo->count = info->max_channels;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = SNDRV_CHMAP_LAST; uinfo->value.integer.max = SNDRV_CHMAP_LAST;
@ -2332,7 +2341,7 @@ static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
if (!substream) if (!substream)
return -ENODEV; return -ENODEV;
memset(ucontrol->value.integer.value, 0, memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value)); sizeof(long) * info->max_channels);
if (!substream->runtime) if (!substream->runtime)
return 0; /* no channels set */ return 0; /* no channels set */
for (map = info->chmap; map->channels; map++) { for (map = info->chmap; map->channels; map++) {

View File

@ -20,9 +20,6 @@ void snd_interval_muldivk(const struct snd_interval *a,
void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
const struct snd_interval *b, struct snd_interval *c); const struct snd_interval *b, struct snd_interval *c);
int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream);
int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream);
int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime,
snd_pcm_hw_param_t var, u_int32_t mask); snd_pcm_hw_param_t var, u_int32_t mask);

View File

@ -27,6 +27,38 @@ MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA m
static const size_t snd_minimum_buffer = 16384; static const size_t snd_minimum_buffer = 16384;
static unsigned long max_alloc_per_card = 32UL * 1024UL * 1024UL;
module_param(max_alloc_per_card, ulong, 0644);
MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card.");
static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
size_t size, struct snd_dma_buffer *dmab)
{
int err;
if (max_alloc_per_card &&
card->total_pcm_alloc_bytes + size > max_alloc_per_card)
return -ENOMEM;
err = snd_dma_alloc_pages(type, dev, size, dmab);
if (!err) {
mutex_lock(&card->memory_mutex);
card->total_pcm_alloc_bytes += dmab->bytes;
mutex_unlock(&card->memory_mutex);
}
return err;
}
static void do_free_pages(struct snd_card *card, struct snd_dma_buffer *dmab)
{
if (!dmab->area)
return;
mutex_lock(&card->memory_mutex);
WARN_ON(card->total_pcm_alloc_bytes < dmab->bytes);
card->total_pcm_alloc_bytes -= dmab->bytes;
mutex_unlock(&card->memory_mutex);
snd_dma_free_pages(dmab);
dmab->area = NULL;
}
/* /*
* try to allocate as the large pages as possible. * try to allocate as the large pages as possible.
@ -37,16 +69,15 @@ static const size_t snd_minimum_buffer = 16384;
static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size) static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
{ {
struct snd_dma_buffer *dmab = &substream->dma_buffer; struct snd_dma_buffer *dmab = &substream->dma_buffer;
struct snd_card *card = substream->pcm->card;
size_t orig_size = size; size_t orig_size = size;
int err; int err;
do { do {
if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, err = do_alloc_pages(card, dmab->dev.type, dmab->dev.dev,
size, dmab)) < 0) { size, dmab);
if (err != -ENOMEM) if (err != -ENOMEM)
return err; /* fatal error */ return err;
} else
return 0;
size >>= 1; size >>= 1;
} while (size >= snd_minimum_buffer); } while (size >= snd_minimum_buffer);
dmab->bytes = 0; /* tell error */ dmab->bytes = 0; /* tell error */
@ -62,10 +93,7 @@ static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t siz
*/ */
static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream) static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream)
{ {
if (substream->dma_buffer.area == NULL) do_free_pages(substream->pcm->card, &substream->dma_buffer);
return;
snd_dma_free_pages(&substream->dma_buffer);
substream->dma_buffer.area = NULL;
} }
/** /**
@ -130,6 +158,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
struct snd_info_buffer *buffer) struct snd_info_buffer *buffer)
{ {
struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_substream *substream = entry->private_data;
struct snd_card *card = substream->pcm->card;
char line[64], str[64]; char line[64], str[64];
size_t size; size_t size;
struct snd_dma_buffer new_dmab; struct snd_dma_buffer new_dmab;
@ -150,9 +179,10 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
memset(&new_dmab, 0, sizeof(new_dmab)); memset(&new_dmab, 0, sizeof(new_dmab));
new_dmab.dev = substream->dma_buffer.dev; new_dmab.dev = substream->dma_buffer.dev;
if (size > 0) { if (size > 0) {
if (snd_dma_alloc_pages(substream->dma_buffer.dev.type, if (do_alloc_pages(card,
substream->dma_buffer.dev.dev, substream->dma_buffer.dev.type,
size, &new_dmab) < 0) { substream->dma_buffer.dev.dev,
size, &new_dmab) < 0) {
buffer->error = -ENOMEM; buffer->error = -ENOMEM;
return; return;
} }
@ -161,7 +191,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
substream->buffer_bytes_max = UINT_MAX; substream->buffer_bytes_max = UINT_MAX;
} }
if (substream->dma_buffer.area) if (substream->dma_buffer.area)
snd_dma_free_pages(&substream->dma_buffer); do_free_pages(card, &substream->dma_buffer);
substream->dma_buffer = new_dmab; substream->dma_buffer = new_dmab;
} else { } else {
buffer->error = -EINVAL; buffer->error = -EINVAL;
@ -346,6 +376,7 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
*/ */
int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
{ {
struct snd_card *card = substream->pcm->card;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct snd_dma_buffer *dmab = NULL; struct snd_dma_buffer *dmab = NULL;
@ -374,9 +405,10 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
if (! dmab) if (! dmab)
return -ENOMEM; return -ENOMEM;
dmab->dev = substream->dma_buffer.dev; dmab->dev = substream->dma_buffer.dev;
if (snd_dma_alloc_pages(substream->dma_buffer.dev.type, if (do_alloc_pages(card,
substream->dma_buffer.dev.dev, substream->dma_buffer.dev.type,
size, dmab) < 0) { substream->dma_buffer.dev.dev,
size, dmab) < 0) {
kfree(dmab); kfree(dmab);
return -ENOMEM; return -ENOMEM;
} }
@ -397,6 +429,7 @@ EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
*/ */
int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
{ {
struct snd_card *card = substream->pcm->card;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream)) if (PCM_RUNTIME_CHECK(substream))
@ -406,7 +439,7 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
return 0; return 0;
if (runtime->dma_buffer_p != &substream->dma_buffer) { if (runtime->dma_buffer_p != &substream->dma_buffer) {
/* it's a newly allocated buffer. release it now. */ /* it's a newly allocated buffer. release it now. */
snd_dma_free_pages(runtime->dma_buffer_p); do_free_pages(card, runtime->dma_buffer_p);
kfree(runtime->dma_buffer_p); kfree(runtime->dma_buffer_p);
} }
snd_pcm_set_runtime_buffer(substream, NULL); snd_pcm_set_runtime_buffer(substream, NULL);

View File

@ -42,7 +42,7 @@ struct pcm_format_data {
/* we do lots of calculations on snd_pcm_format_t; shut up sparse */ /* we do lots of calculations on snd_pcm_format_t; shut up sparse */
#define INT __force int #define INT __force int
static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
[SNDRV_PCM_FORMAT_S8] = { [SNDRV_PCM_FORMAT_S8] = {
.width = 8, .phys = 8, .le = -1, .signd = 1, .width = 8, .phys = 8, .le = -1, .signd = 1,
.silence = {}, .silence = {},
@ -415,7 +415,8 @@ EXPORT_SYMBOL(snd_pcm_format_silence_64);
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
{ {
int width; int width;
unsigned char *dst, *pat; unsigned char *dst;
const unsigned char *pat;
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL; return -EINVAL;

View File

@ -4,6 +4,7 @@
* Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*/ */
#include <linux/compat.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/file.h> #include <linux/file.h>
@ -895,8 +896,8 @@ snd_pcm_calc_delay(struct snd_pcm_substream *substream)
return delay + substream->runtime->delay; return delay + substream->runtime->delay;
} }
int snd_pcm_status(struct snd_pcm_substream *substream, int snd_pcm_status64(struct snd_pcm_substream *substream,
struct snd_pcm_status *status) struct snd_pcm_status64 *status)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
@ -922,14 +923,22 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
status->suspended_state = runtime->status->suspended_state; status->suspended_state = runtime->status->suspended_state;
if (status->state == SNDRV_PCM_STATE_OPEN) if (status->state == SNDRV_PCM_STATE_OPEN)
goto _end; goto _end;
status->trigger_tstamp = runtime->trigger_tstamp; status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
if (snd_pcm_running(substream)) { if (snd_pcm_running(substream)) {
snd_pcm_update_hw_ptr(substream); snd_pcm_update_hw_ptr(substream);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
status->tstamp = runtime->status->tstamp; status->tstamp_sec = runtime->status->tstamp.tv_sec;
status->driver_tstamp = runtime->driver_tstamp; status->tstamp_nsec =
status->audio_tstamp = runtime->status->tstamp.tv_nsec;
runtime->status->audio_tstamp; status->driver_tstamp_sec =
runtime->driver_tstamp.tv_sec;
status->driver_tstamp_nsec =
runtime->driver_tstamp.tv_nsec;
status->audio_tstamp_sec =
runtime->status->audio_tstamp.tv_sec;
status->audio_tstamp_nsec =
runtime->status->audio_tstamp.tv_nsec;
if (runtime->audio_tstamp_report.valid == 1) if (runtime->audio_tstamp_report.valid == 1)
/* backwards compatibility, no report provided in COMPAT mode */ /* backwards compatibility, no report provided in COMPAT mode */
snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data, snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
@ -940,8 +949,13 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
} }
} else { } else {
/* get tstamp only in fallback mode and only if enabled */ /* get tstamp only in fallback mode and only if enabled */
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
snd_pcm_gettime(runtime, &status->tstamp); struct timespec64 tstamp;
snd_pcm_gettime(runtime, &tstamp);
status->tstamp_sec = tstamp.tv_sec;
status->tstamp_nsec = tstamp.tv_nsec;
}
} }
_tstamp_end: _tstamp_end:
status->appl_ptr = runtime->control->appl_ptr; status->appl_ptr = runtime->control->appl_ptr;
@ -958,11 +972,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int snd_pcm_status_user(struct snd_pcm_substream *substream, static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
struct snd_pcm_status __user * _status, struct snd_pcm_status64 __user * _status,
bool ext) bool ext)
{ {
struct snd_pcm_status status; struct snd_pcm_status64 status;
int res; int res;
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
@ -974,7 +988,7 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
if (ext && get_user(status.audio_tstamp_data, if (ext && get_user(status.audio_tstamp_data,
(u32 __user *)(&_status->audio_tstamp_data))) (u32 __user *)(&_status->audio_tstamp_data)))
return -EFAULT; return -EFAULT;
res = snd_pcm_status(substream, &status); res = snd_pcm_status64(substream, &status);
if (res < 0) if (res < 0)
return res; return res;
if (copy_to_user(_status, &status, sizeof(status))) if (copy_to_user(_status, &status, sizeof(status)))
@ -982,6 +996,55 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
struct snd_pcm_status32 __user * _status,
bool ext)
{
struct snd_pcm_status64 status64;
struct snd_pcm_status32 status32;
int res;
memset(&status64, 0, sizeof(status64));
memset(&status32, 0, sizeof(status32));
/*
* with extension, parameters are read/write,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
if (ext && get_user(status64.audio_tstamp_data,
(u32 __user *)(&_status->audio_tstamp_data)))
return -EFAULT;
res = snd_pcm_status64(substream, &status64);
if (res < 0)
return res;
status32 = (struct snd_pcm_status32) {
.state = status64.state,
.trigger_tstamp_sec = status64.trigger_tstamp_sec,
.trigger_tstamp_nsec = status64.trigger_tstamp_nsec,
.tstamp_sec = status64.tstamp_sec,
.tstamp_nsec = status64.tstamp_nsec,
.appl_ptr = status64.appl_ptr,
.hw_ptr = status64.hw_ptr,
.delay = status64.delay,
.avail = status64.avail,
.avail_max = status64.avail_max,
.overrange = status64.overrange,
.suspended_state = status64.suspended_state,
.audio_tstamp_data = status64.audio_tstamp_data,
.audio_tstamp_sec = status64.audio_tstamp_sec,
.audio_tstamp_nsec = status64.audio_tstamp_nsec,
.driver_tstamp_sec = status64.audio_tstamp_sec,
.driver_tstamp_nsec = status64.audio_tstamp_nsec,
.audio_tstamp_accuracy = status64.audio_tstamp_accuracy,
};
if (copy_to_user(_status, &status32, sizeof(status32)))
return -EFAULT;
return 0;
}
static int snd_pcm_channel_info(struct snd_pcm_substream *substream, static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info * info) struct snd_pcm_channel_info * info)
{ {
@ -2245,7 +2308,7 @@ static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t); return snd_interval_refine(hw_param_interval(params, rule->var), &t);
} }
int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
@ -2369,7 +2432,7 @@ int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
return 0; return 0;
} }
int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw; struct snd_pcm_hardware *hw = &runtime->hw;
@ -2830,6 +2893,107 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
return 0; return 0;
} }
struct snd_pcm_mmap_status32 {
s32 state;
s32 pad1;
u32 hw_ptr;
s32 tstamp_sec;
s32 tstamp_nsec;
s32 suspended_state;
s32 audio_tstamp_sec;
s32 audio_tstamp_nsec;
} __attribute__((packed));
struct snd_pcm_mmap_control32 {
u32 appl_ptr;
u32 avail_min;
};
struct snd_pcm_sync_ptr32 {
u32 flags;
union {
struct snd_pcm_mmap_status32 status;
unsigned char reserved[64];
} s;
union {
struct snd_pcm_mmap_control32 control;
unsigned char reserved[64];
} c;
} __attribute__((packed));
/* recalcuate the boundary within 32bit */
static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t boundary;
if (! runtime->buffer_size)
return 0;
boundary = runtime->buffer_size;
while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
boundary *= 2;
return boundary;
}
static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr32 __user *src)
{
struct snd_pcm_runtime *runtime = substream->runtime;
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
u32 sflags;
struct snd_pcm_mmap_control scontrol;
struct snd_pcm_mmap_status sstatus;
snd_pcm_uframes_t boundary;
int err;
if (snd_BUG_ON(!runtime))
return -EINVAL;
if (get_user(sflags, &src->flags) ||
get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
get_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
if (err < 0)
return err;
}
status = runtime->status;
control = runtime->control;
boundary = recalculate_boundary(runtime);
if (! boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
put_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
return 0;
}
#define __SNDRV_PCM_IOCTL_SYNC_PTR32 _IOWR('A', 0x23, struct snd_pcm_sync_ptr32)
static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
@ -2959,10 +3123,14 @@ static int snd_pcm_common_ioctl(struct file *file,
return snd_pcm_hw_free(substream); return snd_pcm_hw_free(substream);
case SNDRV_PCM_IOCTL_SW_PARAMS: case SNDRV_PCM_IOCTL_SW_PARAMS:
return snd_pcm_sw_params_user(substream, arg); return snd_pcm_sw_params_user(substream, arg);
case SNDRV_PCM_IOCTL_STATUS: case SNDRV_PCM_IOCTL_STATUS32:
return snd_pcm_status_user(substream, arg, false); return snd_pcm_status_user32(substream, arg, false);
case SNDRV_PCM_IOCTL_STATUS_EXT: case SNDRV_PCM_IOCTL_STATUS_EXT32:
return snd_pcm_status_user(substream, arg, true); return snd_pcm_status_user32(substream, arg, true);
case SNDRV_PCM_IOCTL_STATUS64:
return snd_pcm_status_user64(substream, arg, false);
case SNDRV_PCM_IOCTL_STATUS_EXT64:
return snd_pcm_status_user64(substream, arg, true);
case SNDRV_PCM_IOCTL_CHANNEL_INFO: case SNDRV_PCM_IOCTL_CHANNEL_INFO:
return snd_pcm_channel_info_user(substream, arg); return snd_pcm_channel_info_user(substream, arg);
case SNDRV_PCM_IOCTL_PREPARE: case SNDRV_PCM_IOCTL_PREPARE:
@ -2994,7 +3162,9 @@ static int snd_pcm_common_ioctl(struct file *file,
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case SNDRV_PCM_IOCTL_SYNC_PTR: case __SNDRV_PCM_IOCTL_SYNC_PTR32:
return snd_pcm_ioctl_sync_ptr_compat(substream, arg);
case __SNDRV_PCM_IOCTL_SYNC_PTR64:
return snd_pcm_sync_ptr(substream, arg); return snd_pcm_sync_ptr(substream, arg);
#ifdef CONFIG_SND_SUPPORT_OLD_API #ifdef CONFIG_SND_SUPPORT_OLD_API
case SNDRV_PCM_IOCTL_HW_REFINE_OLD: case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
@ -3332,8 +3502,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
{ {
if (pcm_file->no_compat_mmap)
return false;
/* See pcm_control_mmap_allowed() below. /* See pcm_control_mmap_allowed() below.
* Since older alsa-lib requires both status and control mmaps to be * Since older alsa-lib requires both status and control mmaps to be
* coupled, we have to disable the status mmap for old alsa-lib, too. * coupled, we have to disable the status mmap for old alsa-lib, too.
@ -3558,11 +3726,19 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
offset = area->vm_pgoff << PAGE_SHIFT; offset = area->vm_pgoff << PAGE_SHIFT;
switch (offset) { switch (offset) {
case SNDRV_PCM_MMAP_OFFSET_STATUS: case SNDRV_PCM_MMAP_OFFSET_STATUS_OLD:
if (pcm_file->no_compat_mmap || !IS_ENABLED(CONFIG_64BIT))
return -ENXIO;
/* fallthrough */
case SNDRV_PCM_MMAP_OFFSET_STATUS_NEW:
if (!pcm_status_mmap_allowed(pcm_file)) if (!pcm_status_mmap_allowed(pcm_file))
return -ENXIO; return -ENXIO;
return snd_pcm_mmap_status(substream, file, area); return snd_pcm_mmap_status(substream, file, area);
case SNDRV_PCM_MMAP_OFFSET_CONTROL: case SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD:
if (pcm_file->no_compat_mmap || !IS_ENABLED(CONFIG_64BIT))
return -ENXIO;
/* fallthrough */
case SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW:
if (!pcm_control_mmap_allowed(pcm_file)) if (!pcm_control_mmap_allowed(pcm_file))
return -ENXIO; return -ENXIO;
return snd_pcm_mmap_control(substream, file, area); return snd_pcm_mmap_control(substream, file, area);
@ -3722,9 +3898,9 @@ static unsigned long snd_pcm_get_unmapped_area(struct file *file,
unsigned long offset = pgoff << PAGE_SHIFT; unsigned long offset = pgoff << PAGE_SHIFT;
switch (offset) { switch (offset) {
case SNDRV_PCM_MMAP_OFFSET_STATUS: case SNDRV_PCM_MMAP_OFFSET_STATUS_NEW:
return (unsigned long)runtime->status; return (unsigned long)runtime->status;
case SNDRV_PCM_MMAP_OFFSET_CONTROL: case SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW:
return (unsigned long)runtime->control; return (unsigned long)runtime->control;
default: default:
return (unsigned long)runtime->dma_area + offset; return (unsigned long)runtime->dma_area + offset;

View File

@ -75,7 +75,7 @@ static int snd_pcm_timer_stop(struct snd_timer * timer)
return 0; return 0;
} }
static struct snd_timer_hardware snd_pcm_timer = static const struct snd_timer_hardware snd_pcm_timer =
{ {
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE, .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE,
.resolution = 0, .resolution = 0,

View File

@ -50,6 +50,29 @@ static DEFINE_MUTEX(register_mutex);
#define rmidi_dbg(rmidi, fmt, args...) \ #define rmidi_dbg(rmidi, fmt, args...) \
dev_dbg(&(rmidi)->dev, fmt, ##args) dev_dbg(&(rmidi)->dev, fmt, ##args)
struct snd_rawmidi_status32 {
s32 stream;
s32 tstamp_sec; /* Timestamp */
s32 tstamp_nsec;
u32 avail; /* available bytes */
u32 xruns; /* count of overruns since last status (in bytes) */
unsigned char reserved[16]; /* reserved for future use */
};
#define SNDRV_RAWMIDI_IOCTL_STATUS32 _IOWR('W', 0x20, struct snd_rawmidi_status32)
struct snd_rawmidi_status64 {
int stream;
u8 rsvd[4]; /* alignment */
s64 tstamp_sec; /* Timestamp */
s64 tstamp_nsec;
size_t avail; /* available bytes */
size_t xruns; /* count of overruns since last status (in bytes) */
unsigned char reserved[16]; /* reserved for future use */
};
#define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64)
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{ {
struct snd_rawmidi *rawmidi; struct snd_rawmidi *rawmidi;
@ -226,7 +249,7 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
{ {
struct snd_rawmidi_substream *substream; struct snd_rawmidi_substream *substream;
struct snd_rawmidi_str *s = &rmidi->streams[stream]; struct snd_rawmidi_str *s = &rmidi->streams[stream];
static unsigned int info_flags[2] = { static const unsigned int info_flags[2] = {
[SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT, [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT,
[SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT, [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT,
}; };
@ -677,7 +700,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
EXPORT_SYMBOL(snd_rawmidi_input_params); EXPORT_SYMBOL(snd_rawmidi_input_params);
static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_status *status) struct snd_rawmidi_status64 *status)
{ {
struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_rawmidi_runtime *runtime = substream->runtime;
@ -690,7 +713,7 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
} }
static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_status *status) struct snd_rawmidi_status64 *status)
{ {
struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_rawmidi_runtime *runtime = substream->runtime;
@ -704,6 +727,80 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
return 0; return 0;
} }
static int snd_rawmidi_ioctl_status32(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status32 __user *argp)
{
int err = 0;
struct snd_rawmidi_status32 __user *status = argp;
struct snd_rawmidi_status32 status32;
struct snd_rawmidi_status64 status64;
if (copy_from_user(&status32, argp,
sizeof(struct snd_rawmidi_status32)))
return -EFAULT;
switch (status32.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (rfile->output == NULL)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status64);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (rfile->input == NULL)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status64);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
status32 = (struct snd_rawmidi_status32) {
.stream = status64.stream,
.tstamp_sec = status64.tstamp_sec,
.tstamp_nsec = status64.tstamp_nsec,
.avail = status64.avail,
.xruns = status64.xruns,
};
if (copy_to_user(status, &status32, sizeof(*status)))
return -EFAULT;
return 0;
}
static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status64 __user *argp)
{
int err = 0;
struct snd_rawmidi_status64 status;
if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status64)))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (rfile->output == NULL)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (rfile->input == NULL)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (copy_to_user(argp, &status,
sizeof(struct snd_rawmidi_status64)))
return -EFAULT;
return 0;
}
static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
struct snd_rawmidi_file *rfile; struct snd_rawmidi_file *rfile;
@ -750,33 +847,10 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
return -EINVAL; return -EINVAL;
} }
} }
case SNDRV_RAWMIDI_IOCTL_STATUS: case SNDRV_RAWMIDI_IOCTL_STATUS32:
{ return snd_rawmidi_ioctl_status32(rfile, argp);
int err = 0; case SNDRV_RAWMIDI_IOCTL_STATUS64:
struct snd_rawmidi_status status; return snd_rawmidi_ioctl_status64(rfile, argp);
if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (rfile->output == NULL)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (rfile->input == NULL)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
return 0;
}
case SNDRV_RAWMIDI_IOCTL_DROP: case SNDRV_RAWMIDI_IOCTL_DROP:
{ {
int val; int val;
@ -1547,7 +1621,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
{ {
struct snd_rawmidi *rmidi; struct snd_rawmidi *rmidi;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_rawmidi_dev_free, .dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register, .dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect, .dev_disconnect = snd_rawmidi_dev_disconnect,

View File

@ -41,19 +41,22 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
return -EINVAL; return -EINVAL;
} }
struct snd_rawmidi_status32 { struct compat_snd_rawmidi_status64 {
s32 stream; s32 stream;
struct compat_timespec tstamp; u8 rsvd[4]; /* alignment */
s64 tstamp_sec;
s64 tstamp_nsec;
u32 avail; u32 avail;
u32 xruns; u32 xruns;
unsigned char reserved[16]; unsigned char reserved[16];
} __attribute__((packed)); } __attribute__((packed));
static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, static int snd_rawmidi_ioctl_status_compat64(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status32 __user *src) struct compat_snd_rawmidi_status64 __user *src)
{ {
int err; int err;
struct snd_rawmidi_status status; struct snd_rawmidi_status64 status;
struct compat_snd_rawmidi_status64 compat_status;
if (get_user(status.stream, &src->stream)) if (get_user(status.stream, &src->stream))
return -EFAULT; return -EFAULT;
@ -75,68 +78,24 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
if (err < 0) if (err < 0)
return err; return err;
if (compat_put_timespec(&status.tstamp, &src->tstamp) || compat_status = (struct compat_snd_rawmidi_status64) {
put_user(status.avail, &src->avail) || .stream = status.stream,
put_user(status.xruns, &src->xruns)) .tstamp_sec = status.tstamp_sec,
.tstamp_nsec = status.tstamp_nsec,
.avail = status.avail,
.xruns = status.xruns,
};
if (copy_to_user(src, &compat_status, sizeof(*src)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
#ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_rawmidi_status_x32 {
s32 stream;
u32 rsvd; /* alignment */
struct timespec tstamp;
u32 avail;
u32 xruns;
unsigned char reserved[16];
} __attribute__((packed));
#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status_x32 __user *src)
{
int err;
struct snd_rawmidi_status status;
if (get_user(status.stream, &src->stream))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (!rfile->output)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (!rfile->input)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (put_timespec(&status.tstamp, &src->tstamp) ||
put_user(status.avail, &src->avail) ||
put_user(status.xruns, &src->xruns))
return -EFAULT;
return 0;
}
#endif /* CONFIG_X86_X32 */
enum { enum {
SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
#ifdef CONFIG_X86_X32 SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64 = _IOWR('W', 0x20, struct compat_snd_rawmidi_status64),
SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32),
#endif /* CONFIG_X86_X32 */
}; };
static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@ -153,12 +112,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign
return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_RAWMIDI_IOCTL_PARAMS32: case SNDRV_RAWMIDI_IOCTL_PARAMS32:
return snd_rawmidi_ioctl_params_compat(rfile, argp); return snd_rawmidi_ioctl_params_compat(rfile, argp);
case SNDRV_RAWMIDI_IOCTL_STATUS32: case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32:
return snd_rawmidi_ioctl_status_compat(rfile, argp); return snd_rawmidi_ioctl_status32(rfile, argp);
#ifdef CONFIG_X86_X32 case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64:
case SNDRV_RAWMIDI_IOCTL_STATUS_X32: return snd_rawmidi_ioctl_status_compat64(rfile, argp);
return snd_rawmidi_ioctl_status_x32(rfile, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }

View File

@ -460,10 +460,10 @@ enabled_str(int bool)
return bool ? "enabled" : "disabled"; return bool ? "enabled" : "disabled";
} }
static char * static const char *
filemode_str(int val) filemode_str(int val)
{ {
static char *str[] = { static const char * const str[] = {
"none", "read", "write", "read/write", "none", "read", "write", "read/write",
}; };
return str[val & SNDRV_SEQ_OSS_FILE_ACMODE]; return str[val & SNDRV_SEQ_OSS_FILE_ACMODE];

View File

@ -30,22 +30,25 @@ MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI emulation."
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* Prototypes for static functions */ /* Prototypes for static functions */
static void note_off(struct snd_midi_op *ops, void *drv, static void note_off(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel *chan, struct snd_midi_channel *chan,
int note, int vel); int note, int vel);
static void do_control(struct snd_midi_op *ops, void *private, static void do_control(const struct snd_midi_op *ops, void *private,
struct snd_midi_channel_set *chset, struct snd_midi_channel_set *chset,
struct snd_midi_channel *chan, struct snd_midi_channel *chan,
int control, int value); int control, int value);
static void rpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan, static void rpn(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel *chan,
struct snd_midi_channel_set *chset); struct snd_midi_channel_set *chset);
static void nrpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan, static void nrpn(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel *chan,
struct snd_midi_channel_set *chset); struct snd_midi_channel_set *chset);
static void sysex(struct snd_midi_op *ops, void *private, unsigned char *sysex, static void sysex(const struct snd_midi_op *ops, void *private,
unsigned char *sysex,
int len, struct snd_midi_channel_set *chset); int len, struct snd_midi_channel_set *chset);
static void all_sounds_off(struct snd_midi_op *ops, void *private, static void all_sounds_off(const struct snd_midi_op *ops, void *private,
struct snd_midi_channel *chan); struct snd_midi_channel *chan);
static void all_notes_off(struct snd_midi_op *ops, void *private, static void all_notes_off(const struct snd_midi_op *ops, void *private,
struct snd_midi_channel *chan); struct snd_midi_channel *chan);
static void snd_midi_reset_controllers(struct snd_midi_channel *chan); static void snd_midi_reset_controllers(struct snd_midi_channel *chan);
static void reset_all_channels(struct snd_midi_channel_set *chset); static void reset_all_channels(struct snd_midi_channel_set *chset);
@ -66,7 +69,7 @@ static void reset_all_channels(struct snd_midi_channel_set *chset);
* be interpreted. * be interpreted.
*/ */
void void
snd_midi_process_event(struct snd_midi_op *ops, snd_midi_process_event(const struct snd_midi_op *ops,
struct snd_seq_event *ev, struct snd_seq_event *ev,
struct snd_midi_channel_set *chanset) struct snd_midi_channel_set *chanset)
{ {
@ -229,7 +232,8 @@ EXPORT_SYMBOL(snd_midi_process_event);
* release note * release note
*/ */
static void static void
note_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan, note_off(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel *chan,
int note, int vel) int note, int vel)
{ {
if (chan->gm_hold) { if (chan->gm_hold) {
@ -251,7 +255,8 @@ note_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
* events that need to take place immediately to the driver. * events that need to take place immediately to the driver.
*/ */
static void static void
do_control(struct snd_midi_op *ops, void *drv, struct snd_midi_channel_set *chset, do_control(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel_set *chset,
struct snd_midi_channel *chan, int control, int value) struct snd_midi_channel *chan, int control, int value)
{ {
int i; int i;
@ -402,7 +407,7 @@ EXPORT_SYMBOL(snd_midi_channel_set_clear);
* Process a rpn message. * Process a rpn message.
*/ */
static void static void
rpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan, rpn(const struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
struct snd_midi_channel_set *chset) struct snd_midi_channel_set *chset)
{ {
int type; int type;
@ -442,7 +447,7 @@ rpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
* Process an nrpn message. * Process an nrpn message.
*/ */
static void static void
nrpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan, nrpn(const struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
struct snd_midi_channel_set *chset) struct snd_midi_channel_set *chset)
{ {
/* parse XG NRPNs here if possible */ /* parse XG NRPNs here if possible */
@ -470,15 +475,15 @@ get_channel(unsigned char cmd)
* Process a sysex message. * Process a sysex message.
*/ */
static void static void
sysex(struct snd_midi_op *ops, void *private, unsigned char *buf, int len, sysex(const struct snd_midi_op *ops, void *private, unsigned char *buf, int len,
struct snd_midi_channel_set *chset) struct snd_midi_channel_set *chset)
{ {
/* GM on */ /* GM on */
static unsigned char gm_on_macro[] = { static const unsigned char gm_on_macro[] = {
0x7e,0x7f,0x09,0x01, 0x7e,0x7f,0x09,0x01,
}; };
/* XG on */ /* XG on */
static unsigned char xg_on_macro[] = { static const unsigned char xg_on_macro[] = {
0x43,0x10,0x4c,0x00,0x00,0x7e,0x00, 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
}; };
/* GS prefix /* GS prefix
@ -487,7 +492,7 @@ sysex(struct snd_midi_op *ops, void *private, unsigned char *buf, int len,
* chorus mode: XX=0x01, YY=0x38, ZZ=0-7 * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
* master vol: XX=0x00, YY=0x04, ZZ=0-127 * master vol: XX=0x00, YY=0x04, ZZ=0-127
*/ */
static unsigned char gs_pfx_macro[] = { static const unsigned char gs_pfx_macro[] = {
0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/ 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
}; };
@ -584,7 +589,8 @@ sysex(struct snd_midi_op *ops, void *private, unsigned char *buf, int len,
* all sound off * all sound off
*/ */
static void static void
all_sounds_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan) all_sounds_off(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel *chan)
{ {
int n; int n;
@ -602,7 +608,8 @@ all_sounds_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan
* all notes off * all notes off
*/ */
static void static void
all_notes_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan) all_notes_off(const struct snd_midi_op *ops, void *drv,
struct snd_midi_channel *chan)
{ {
int n; int n;

View File

@ -422,12 +422,12 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
int count, struct snd_seq_event *ev) int count, struct snd_seq_event *ev)
{ {
unsigned char cmd; unsigned char cmd;
char *cbytes; const char *cbytes;
static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB, static const char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
MIDI_CTL_NONREG_PARM_NUM_LSB, MIDI_CTL_NONREG_PARM_NUM_LSB,
MIDI_CTL_MSB_DATA_ENTRY, MIDI_CTL_MSB_DATA_ENTRY,
MIDI_CTL_LSB_DATA_ENTRY }; MIDI_CTL_LSB_DATA_ENTRY };
static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB, static const char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB,
MIDI_CTL_REGIST_PARM_NUM_LSB, MIDI_CTL_REGIST_PARM_NUM_LSB,
MIDI_CTL_MSB_DATA_ENTRY, MIDI_CTL_MSB_DATA_ENTRY,
MIDI_CTL_LSB_DATA_ENTRY }; MIDI_CTL_LSB_DATA_ENTRY };

View File

@ -193,7 +193,7 @@ int snd_seq_device_new(struct snd_card *card, int device, const char *id,
{ {
struct snd_seq_device *dev; struct snd_seq_device *dev;
int err; int err;
static struct snd_device_ops dops = { static const struct snd_device_ops dops = {
.dev_free = snd_seq_device_dev_free, .dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register, .dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect, .dev_disconnect = snd_seq_device_dev_disconnect,

View File

@ -44,6 +44,28 @@ MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for t
MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER); MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER);
MODULE_ALIAS("devname:snd/timer"); MODULE_ALIAS("devname:snd/timer");
enum timer_tread_format {
TREAD_FORMAT_NONE = 0,
TREAD_FORMAT_TIME64,
TREAD_FORMAT_TIME32,
};
struct snd_timer_tread32 {
int event;
s32 tstamp_sec;
s32 tstamp_nsec;
unsigned int val;
};
struct snd_timer_tread64 {
int event;
u8 pad1[4];
s64 tstamp_sec;
s64 tstamp_nsec;
unsigned int val;
u8 pad2[4];
};
struct snd_timer_user { struct snd_timer_user {
struct snd_timer_instance *timeri; struct snd_timer_instance *timeri;
int tread; /* enhanced read with timestamps and events */ int tread; /* enhanced read with timestamps and events */
@ -55,16 +77,40 @@ struct snd_timer_user {
int queue_size; int queue_size;
bool disconnected; bool disconnected;
struct snd_timer_read *queue; struct snd_timer_read *queue;
struct snd_timer_tread *tqueue; struct snd_timer_tread64 *tqueue;
spinlock_t qlock; spinlock_t qlock;
unsigned long last_resolution; unsigned long last_resolution;
unsigned int filter; unsigned int filter;
struct timespec tstamp; /* trigger tstamp */ struct timespec64 tstamp; /* trigger tstamp */
wait_queue_head_t qchange_sleep; wait_queue_head_t qchange_sleep;
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct mutex ioctl_lock; struct mutex ioctl_lock;
}; };
struct snd_timer_status32 {
s32 tstamp_sec; /* Timestamp - last update */
s32 tstamp_nsec;
unsigned int resolution; /* current period resolution in ns */
unsigned int lost; /* counter of master tick lost */
unsigned int overrun; /* count of read queue overruns */
unsigned int queue; /* used queue size */
unsigned char reserved[64]; /* reserved */
};
#define SNDRV_TIMER_IOCTL_STATUS32 _IOR('T', 0x14, struct snd_timer_status32)
struct snd_timer_status64 {
s64 tstamp_sec; /* Timestamp - last update */
s64 tstamp_nsec;
unsigned int resolution; /* current period resolution in ns */
unsigned int lost; /* counter of master tick lost */
unsigned int overrun; /* count of read queue overruns */
unsigned int queue; /* used queue size */
unsigned char reserved[64]; /* reserved */
};
#define SNDRV_TIMER_IOCTL_STATUS64 _IOR('T', 0x14, struct snd_timer_status64)
/* list of timers */ /* list of timers */
static LIST_HEAD(snd_timer_list); static LIST_HEAD(snd_timer_list);
@ -453,12 +499,12 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
struct snd_timer *timer = ti->timer; struct snd_timer *timer = ti->timer;
unsigned long resolution = 0; unsigned long resolution = 0;
struct snd_timer_instance *ts; struct snd_timer_instance *ts;
struct timespec tstamp; struct timespec64 tstamp;
if (timer_tstamp_monotonic) if (timer_tstamp_monotonic)
ktime_get_ts(&tstamp); ktime_get_ts64(&tstamp);
else else
getnstimeofday(&tstamp); ktime_get_real_ts64(&tstamp);
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
event > SNDRV_TIMER_EVENT_PAUSE)) event > SNDRV_TIMER_EVENT_PAUSE))
return; return;
@ -890,7 +936,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
{ {
struct snd_timer *timer; struct snd_timer *timer;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_timer_dev_free, .dev_free = snd_timer_dev_free,
.dev_register = snd_timer_dev_register, .dev_register = snd_timer_dev_register,
.dev_disconnect = snd_timer_dev_disconnect, .dev_disconnect = snd_timer_dev_disconnect,
@ -1025,7 +1071,7 @@ static int snd_timer_dev_disconnect(struct snd_device *device)
return 0; return 0;
} }
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
{ {
unsigned long flags; unsigned long flags;
unsigned long resolution = 0; unsigned long resolution = 0;
@ -1153,7 +1199,7 @@ static int snd_timer_s_close(struct snd_timer *timer)
return 0; return 0;
} }
static struct snd_timer_hardware snd_timer_system = static const struct snd_timer_hardware snd_timer_system =
{ {
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
.resolution = 1000000000L / HZ, .resolution = 1000000000L / HZ,
@ -1305,7 +1351,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
} }
static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu, static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,
struct snd_timer_tread *tread) struct snd_timer_tread64 *tread)
{ {
if (tu->qused >= tu->queue_size) { if (tu->qused >= tu->queue_size) {
tu->overrun++; tu->overrun++;
@ -1318,11 +1364,11 @@ static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,
static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
int event, int event,
struct timespec *tstamp, struct timespec64 *tstamp,
unsigned long resolution) unsigned long resolution)
{ {
struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_user *tu = timeri->callback_data;
struct snd_timer_tread r1; struct snd_timer_tread64 r1;
unsigned long flags; unsigned long flags;
if (event >= SNDRV_TIMER_EVENT_START && if (event >= SNDRV_TIMER_EVENT_START &&
@ -1332,7 +1378,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
return; return;
memset(&r1, 0, sizeof(r1)); memset(&r1, 0, sizeof(r1));
r1.event = event; r1.event = event;
r1.tstamp = *tstamp; r1.tstamp_sec = tstamp->tv_sec;
r1.tstamp_nsec = tstamp->tv_nsec;
r1.val = resolution; r1.val = resolution;
spin_lock_irqsave(&tu->qlock, flags); spin_lock_irqsave(&tu->qlock, flags);
snd_timer_user_append_to_tqueue(tu, &r1); snd_timer_user_append_to_tqueue(tu, &r1);
@ -1354,8 +1401,8 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
unsigned long ticks) unsigned long ticks)
{ {
struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_user *tu = timeri->callback_data;
struct snd_timer_tread *r, r1; struct snd_timer_tread64 *r, r1;
struct timespec tstamp; struct timespec64 tstamp;
int prev, append = 0; int prev, append = 0;
memset(&r1, 0, sizeof(r1)); memset(&r1, 0, sizeof(r1));
@ -1368,14 +1415,15 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
} }
if (tu->last_resolution != resolution || ticks > 0) { if (tu->last_resolution != resolution || ticks > 0) {
if (timer_tstamp_monotonic) if (timer_tstamp_monotonic)
ktime_get_ts(&tstamp); ktime_get_ts64(&tstamp);
else else
getnstimeofday(&tstamp); ktime_get_real_ts64(&tstamp);
} }
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
tu->last_resolution != resolution) { tu->last_resolution != resolution) {
r1.event = SNDRV_TIMER_EVENT_RESOLUTION; r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
r1.tstamp = tstamp; r1.tstamp_sec = tstamp.tv_sec;
r1.tstamp_nsec = tstamp.tv_nsec;
r1.val = resolution; r1.val = resolution;
snd_timer_user_append_to_tqueue(tu, &r1); snd_timer_user_append_to_tqueue(tu, &r1);
tu->last_resolution = resolution; tu->last_resolution = resolution;
@ -1389,14 +1437,16 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
r = &tu->tqueue[prev]; r = &tu->tqueue[prev];
if (r->event == SNDRV_TIMER_EVENT_TICK) { if (r->event == SNDRV_TIMER_EVENT_TICK) {
r->tstamp = tstamp; r->tstamp_sec = tstamp.tv_sec;
r->tstamp_nsec = tstamp.tv_nsec;
r->val += ticks; r->val += ticks;
append++; append++;
goto __wake; goto __wake;
} }
} }
r1.event = SNDRV_TIMER_EVENT_TICK; r1.event = SNDRV_TIMER_EVENT_TICK;
r1.tstamp = tstamp; r1.tstamp_sec = tstamp.tv_sec;
r1.tstamp_nsec = tstamp.tv_nsec;
r1.val = ticks; r1.val = ticks;
snd_timer_user_append_to_tqueue(tu, &r1); snd_timer_user_append_to_tqueue(tu, &r1);
append++; append++;
@ -1411,7 +1461,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
static int realloc_user_queue(struct snd_timer_user *tu, int size) static int realloc_user_queue(struct snd_timer_user *tu, int size)
{ {
struct snd_timer_read *queue = NULL; struct snd_timer_read *queue = NULL;
struct snd_timer_tread *tqueue = NULL; struct snd_timer_tread64 *tqueue = NULL;
if (tu->tread) { if (tu->tread) {
tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL);
@ -1850,11 +1900,11 @@ static int snd_timer_user_params(struct file *file,
tu->qhead = tu->qtail = tu->qused = 0; tu->qhead = tu->qtail = tu->qused = 0;
if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
if (tu->tread) { if (tu->tread) {
struct snd_timer_tread tread; struct snd_timer_tread64 tread;
memset(&tread, 0, sizeof(tread)); memset(&tread, 0, sizeof(tread));
tread.event = SNDRV_TIMER_EVENT_EARLY; tread.event = SNDRV_TIMER_EVENT_EARLY;
tread.tstamp.tv_sec = 0; tread.tstamp_sec = 0;
tread.tstamp.tv_nsec = 0; tread.tstamp_nsec = 0;
tread.val = 0; tread.val = 0;
snd_timer_user_append_to_tqueue(tu, &tread); snd_timer_user_append_to_tqueue(tu, &tread);
} else { } else {
@ -1875,17 +1925,41 @@ static int snd_timer_user_params(struct file *file,
return err; return err;
} }
static int snd_timer_user_status(struct file *file, static int snd_timer_user_status32(struct file *file,
struct snd_timer_status __user *_status) struct snd_timer_status32 __user *_status)
{ {
struct snd_timer_user *tu; struct snd_timer_user *tu;
struct snd_timer_status status; struct snd_timer_status32 status;
tu = file->private_data; tu = file->private_data;
if (!tu->timeri) if (!tu->timeri)
return -EBADFD; return -EBADFD;
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp; status.tstamp_sec = tu->tstamp.tv_sec;
status.tstamp_nsec = tu->tstamp.tv_nsec;
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
}
static int snd_timer_user_status64(struct file *file,
struct snd_timer_status64 __user *_status)
{
struct snd_timer_user *tu;
struct snd_timer_status64 status;
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp_sec = tu->tstamp.tv_sec;
status.tstamp_nsec = tu->tstamp.tv_nsec;
status.resolution = snd_timer_resolution(tu->timeri); status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost; status.lost = tu->timeri->lost;
status.overrun = tu->overrun; status.overrun = tu->overrun;
@ -1960,6 +2034,36 @@ static int snd_timer_user_pause(struct file *file)
return 0; return 0;
} }
static int snd_timer_user_tread(void __user *argp, struct snd_timer_user *tu,
unsigned int cmd, bool compat)
{
int __user *p = argp;
int xarg, old_tread;
if (tu->timeri) /* too late */
return -EBUSY;
if (get_user(xarg, p))
return -EFAULT;
old_tread = tu->tread;
if (!xarg)
tu->tread = TREAD_FORMAT_NONE;
else if (cmd == SNDRV_TIMER_IOCTL_TREAD64 ||
(IS_ENABLED(CONFIG_64BIT) && !compat))
tu->tread = TREAD_FORMAT_TIME64;
else
tu->tread = TREAD_FORMAT_TIME32;
if (tu->tread != old_tread &&
realloc_user_queue(tu, tu->queue_size) < 0) {
tu->tread = old_tread;
return -ENOMEM;
}
return 0;
}
enum { enum {
SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20),
SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21),
@ -1968,7 +2072,7 @@ enum {
}; };
static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg, bool compat)
{ {
struct snd_timer_user *tu; struct snd_timer_user *tu;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
@ -1980,23 +2084,9 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0; return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;
case SNDRV_TIMER_IOCTL_NEXT_DEVICE: case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
return snd_timer_user_next_device(argp); return snd_timer_user_next_device(argp);
case SNDRV_TIMER_IOCTL_TREAD: case SNDRV_TIMER_IOCTL_TREAD_OLD:
{ case SNDRV_TIMER_IOCTL_TREAD64:
int xarg, old_tread; return snd_timer_user_tread(argp, tu, cmd, compat);
if (tu->timeri) /* too late */
return -EBUSY;
if (get_user(xarg, p))
return -EFAULT;
old_tread = tu->tread;
tu->tread = xarg ? 1 : 0;
if (tu->tread != old_tread &&
realloc_user_queue(tu, tu->queue_size) < 0) {
tu->tread = old_tread;
return -ENOMEM;
}
return 0;
}
case SNDRV_TIMER_IOCTL_GINFO: case SNDRV_TIMER_IOCTL_GINFO:
return snd_timer_user_ginfo(file, argp); return snd_timer_user_ginfo(file, argp);
case SNDRV_TIMER_IOCTL_GPARAMS: case SNDRV_TIMER_IOCTL_GPARAMS:
@ -2009,8 +2099,10 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
return snd_timer_user_info(file, argp); return snd_timer_user_info(file, argp);
case SNDRV_TIMER_IOCTL_PARAMS: case SNDRV_TIMER_IOCTL_PARAMS:
return snd_timer_user_params(file, argp); return snd_timer_user_params(file, argp);
case SNDRV_TIMER_IOCTL_STATUS: case SNDRV_TIMER_IOCTL_STATUS32:
return snd_timer_user_status(file, argp); return snd_timer_user_status32(file, argp);
case SNDRV_TIMER_IOCTL_STATUS64:
return snd_timer_user_status64(file, argp);
case SNDRV_TIMER_IOCTL_START: case SNDRV_TIMER_IOCTL_START:
case SNDRV_TIMER_IOCTL_START_OLD: case SNDRV_TIMER_IOCTL_START_OLD:
return snd_timer_user_start(file); return snd_timer_user_start(file);
@ -2034,7 +2126,7 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
long ret; long ret;
mutex_lock(&tu->ioctl_lock); mutex_lock(&tu->ioctl_lock);
ret = __snd_timer_user_ioctl(file, cmd, arg); ret = __snd_timer_user_ioctl(file, cmd, arg, false);
mutex_unlock(&tu->ioctl_lock); mutex_unlock(&tu->ioctl_lock);
return ret; return ret;
} }
@ -2050,13 +2142,29 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on)
static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
size_t count, loff_t *offset) size_t count, loff_t *offset)
{ {
struct snd_timer_tread64 *tread;
struct snd_timer_tread32 tread32;
struct snd_timer_user *tu; struct snd_timer_user *tu;
long result = 0, unit; long result = 0, unit;
int qhead; int qhead;
int err = 0; int err = 0;
tu = file->private_data; tu = file->private_data;
unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); switch (tu->tread) {
case TREAD_FORMAT_TIME64:
unit = sizeof(struct snd_timer_tread64);
break;
case TREAD_FORMAT_TIME32:
unit = sizeof(struct snd_timer_tread32);
break;
case TREAD_FORMAT_NONE:
unit = sizeof(struct snd_timer_read);
break;
default:
WARN_ONCE(1, "Corrupt snd_timer_user\n");
return -ENOTSUPP;
}
mutex_lock(&tu->ioctl_lock); mutex_lock(&tu->ioctl_lock);
spin_lock_irq(&tu->qlock); spin_lock_irq(&tu->qlock);
while ((long)count - result >= unit) { while ((long)count - result >= unit) {
@ -2095,14 +2203,34 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
tu->qused--; tu->qused--;
spin_unlock_irq(&tu->qlock); spin_unlock_irq(&tu->qlock);
if (tu->tread) { tread = &tu->tqueue[qhead];
if (copy_to_user(buffer, &tu->tqueue[qhead],
sizeof(struct snd_timer_tread))) switch (tu->tread) {
case TREAD_FORMAT_TIME64:
if (copy_to_user(buffer, tread,
sizeof(struct snd_timer_tread64)))
err = -EFAULT; err = -EFAULT;
} else { break;
case TREAD_FORMAT_TIME32:
memset(&tread32, 0, sizeof(tread32));
tread32 = (struct snd_timer_tread32) {
.event = tread->event,
.tstamp_sec = tread->tstamp_sec,
.tstamp_nsec = tread->tstamp_nsec,
.val = tread->val,
};
if (copy_to_user(buffer, &tread32, sizeof(tread32)))
err = -EFAULT;
break;
case TREAD_FORMAT_NONE:
if (copy_to_user(buffer, &tu->queue[qhead], if (copy_to_user(buffer, &tu->queue[qhead],
sizeof(struct snd_timer_read))) sizeof(struct snd_timer_read)))
err = -EFAULT; err = -EFAULT;
break;
default:
err = -ENOTSUPP;
break;
} }
spin_lock_irq(&tu->qlock); spin_lock_irq(&tu->qlock);

View File

@ -69,54 +69,11 @@ static int snd_timer_user_info_compat(struct file *file,
return 0; return 0;
} }
struct snd_timer_status32 {
struct compat_timespec tstamp;
u32 resolution;
u32 lost;
u32 overrun;
u32 queue;
unsigned char reserved[64];
};
static int snd_timer_user_status_compat(struct file *file,
struct snd_timer_status32 __user *_status)
{
struct snd_timer_user *tu;
struct snd_timer_status32 status;
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp.tv_sec = tu->tstamp.tv_sec;
status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
}
#ifdef CONFIG_X86_X32
/* X32 ABI has the same struct as x86-64 */
#define snd_timer_user_status_x32(file, s) \
snd_timer_user_status(file, s)
#endif /* CONFIG_X86_X32 */
/*
*/
enum { enum {
SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32), SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), SNDRV_TIMER_IOCTL_STATUS_COMPAT32 = _IOW('T', 0x14, struct snd_timer_status32),
#ifdef CONFIG_X86_X32 SNDRV_TIMER_IOCTL_STATUS_COMPAT64 = _IOW('T', 0x14, struct snd_timer_status64),
SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status),
#endif /* CONFIG_X86_X32 */
}; };
static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
@ -126,7 +83,8 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
switch (cmd) { switch (cmd) {
case SNDRV_TIMER_IOCTL_PVERSION: case SNDRV_TIMER_IOCTL_PVERSION:
case SNDRV_TIMER_IOCTL_TREAD: case SNDRV_TIMER_IOCTL_TREAD_OLD:
case SNDRV_TIMER_IOCTL_TREAD64:
case SNDRV_TIMER_IOCTL_GINFO: case SNDRV_TIMER_IOCTL_GINFO:
case SNDRV_TIMER_IOCTL_GSTATUS: case SNDRV_TIMER_IOCTL_GSTATUS:
case SNDRV_TIMER_IOCTL_SELECT: case SNDRV_TIMER_IOCTL_SELECT:
@ -140,17 +98,15 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
case SNDRV_TIMER_IOCTL_PAUSE: case SNDRV_TIMER_IOCTL_PAUSE:
case SNDRV_TIMER_IOCTL_PAUSE_OLD: case SNDRV_TIMER_IOCTL_PAUSE_OLD:
case SNDRV_TIMER_IOCTL_NEXT_DEVICE: case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp); return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true);
case SNDRV_TIMER_IOCTL_GPARAMS32: case SNDRV_TIMER_IOCTL_GPARAMS32:
return snd_timer_user_gparams_compat(file, argp); return snd_timer_user_gparams_compat(file, argp);
case SNDRV_TIMER_IOCTL_INFO32: case SNDRV_TIMER_IOCTL_INFO32:
return snd_timer_user_info_compat(file, argp); return snd_timer_user_info_compat(file, argp);
case SNDRV_TIMER_IOCTL_STATUS32: case SNDRV_TIMER_IOCTL_STATUS_COMPAT32:
return snd_timer_user_status_compat(file, argp); return snd_timer_user_status32(file, argp);
#ifdef CONFIG_X86_X32 case SNDRV_TIMER_IOCTL_STATUS_COMPAT64:
case SNDRV_TIMER_IOCTL_STATUS_X32: return snd_timer_user_status64(file, argp);
return snd_timer_user_status_x32(file, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }

View File

@ -804,7 +804,7 @@ static void loopback_snd_timer_tasklet(unsigned long arg)
static void loopback_snd_timer_event(struct snd_timer_instance *timeri, static void loopback_snd_timer_event(struct snd_timer_instance *timeri,
int event, int event,
struct timespec *tstamp, struct timespec64 *tstamp,
unsigned long resolution) unsigned long resolution)
{ {
/* Do not lock cable->lock here because timer->lock is already hold. /* Do not lock cable->lock here because timer->lock is already hold.
@ -905,12 +905,6 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
kfree(dpcm); kfree(dpcm);
} }
static int loopback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
static int loopback_hw_free(struct snd_pcm_substream *substream) static int loopback_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
@ -920,7 +914,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&dpcm->loopback->cable_lock); mutex_lock(&dpcm->loopback->cable_lock);
cable->valid &= ~(1 << substream->stream); cable->valid &= ~(1 << substream->stream);
mutex_unlock(&dpcm->loopback->cable_lock); mutex_unlock(&dpcm->loopback->cable_lock);
return snd_pcm_lib_free_pages(substream); return 0;
} }
static unsigned int get_cable_index(struct snd_pcm_substream *substream) static unsigned int get_cable_index(struct snd_pcm_substream *substream)
@ -1305,8 +1299,6 @@ static int loopback_close(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops loopback_pcm_ops = { static const struct snd_pcm_ops loopback_pcm_ops = {
.open = loopback_open, .open = loopback_open,
.close = loopback_close, .close = loopback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = loopback_hw_params,
.hw_free = loopback_hw_free, .hw_free = loopback_hw_free,
.prepare = loopback_prepare, .prepare = loopback_prepare,
.trigger = loopback_trigger, .trigger = loopback_trigger,
@ -1325,8 +1317,7 @@ static int loopback_pcm_new(struct loopback *loopback,
return err; return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
NULL, 0, 0);
pcm->private_data = loopback; pcm->private_data = loopback;
pcm->info_flags = 0; pcm->info_flags = 0;
@ -1505,7 +1496,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static struct snd_kcontrol_new loopback_controls[] = { static const struct snd_kcontrol_new loopback_controls[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_PCM, .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "PCM Rate Shift 100000", .name = "PCM Rate Shift 100000",

View File

@ -117,7 +117,7 @@ struct dummy_model {
struct snd_dummy { struct snd_dummy {
struct snd_card *card; struct snd_card *card;
struct dummy_model *model; const struct dummy_model *model;
struct snd_pcm *pcm; struct snd_pcm *pcm;
struct snd_pcm_hardware pcm_hw; struct snd_pcm_hardware pcm_hw;
spinlock_t mixer_lock; spinlock_t mixer_lock;
@ -144,13 +144,13 @@ static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
return 0; return 0;
} }
static struct dummy_model model_emu10k1 = { static const struct dummy_model model_emu10k1 = {
.name = "emu10k1", .name = "emu10k1",
.playback_constraints = emu10k1_playback_constraints, .playback_constraints = emu10k1_playback_constraints,
.buffer_bytes_max = 128 * 1024, .buffer_bytes_max = 128 * 1024,
}; };
static struct dummy_model model_rme9652 = { static const struct dummy_model model_rme9652 = {
.name = "rme9652", .name = "rme9652",
.buffer_bytes_max = 26 * 64 * 1024, .buffer_bytes_max = 26 * 64 * 1024,
.formats = SNDRV_PCM_FMTBIT_S32_LE, .formats = SNDRV_PCM_FMTBIT_S32_LE,
@ -160,7 +160,7 @@ static struct dummy_model model_rme9652 = {
.periods_max = 2, .periods_max = 2,
}; };
static struct dummy_model model_ice1712 = { static const struct dummy_model model_ice1712 = {
.name = "ice1712", .name = "ice1712",
.buffer_bytes_max = 256 * 1024, .buffer_bytes_max = 256 * 1024,
.formats = SNDRV_PCM_FMTBIT_S32_LE, .formats = SNDRV_PCM_FMTBIT_S32_LE,
@ -170,7 +170,7 @@ static struct dummy_model model_ice1712 = {
.periods_max = 1024, .periods_max = 1024,
}; };
static struct dummy_model model_uda1341 = { static const struct dummy_model model_uda1341 = {
.name = "uda1341", .name = "uda1341",
.buffer_bytes_max = 16380, .buffer_bytes_max = 16380,
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
@ -180,7 +180,7 @@ static struct dummy_model model_uda1341 = {
.periods_max = 255, .periods_max = 255,
}; };
static struct dummy_model model_ac97 = { static const struct dummy_model model_ac97 = {
.name = "ac97", .name = "ac97",
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 2, .channels_min = 2,
@ -190,7 +190,7 @@ static struct dummy_model model_ac97 = {
.rate_max = 48000, .rate_max = 48000,
}; };
static struct dummy_model model_ca0106 = { static const struct dummy_model model_ca0106 = {
.name = "ca0106", .name = "ca0106",
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
.buffer_bytes_max = ((65536-64)*8), .buffer_bytes_max = ((65536-64)*8),
@ -204,7 +204,7 @@ static struct dummy_model model_ca0106 = {
.rate_max = 192000, .rate_max = 192000,
}; };
static struct dummy_model *dummy_models[] = { static const struct dummy_model *dummy_models[] = {
&model_emu10k1, &model_emu10k1,
&model_rme9652, &model_rme9652,
&model_ice1712, &model_ice1712,
@ -529,21 +529,13 @@ static int dummy_pcm_hw_params(struct snd_pcm_substream *substream,
substream->runtime->dma_bytes = params_buffer_bytes(hw_params); substream->runtime->dma_bytes = params_buffer_bytes(hw_params);
return 0; return 0;
} }
return snd_pcm_lib_malloc_pages(substream, return 0;
params_buffer_bytes(hw_params));
}
static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
{
if (fake_buffer)
return 0;
return snd_pcm_lib_free_pages(substream);
} }
static int dummy_pcm_open(struct snd_pcm_substream *substream) static int dummy_pcm_open(struct snd_pcm_substream *substream)
{ {
struct snd_dummy *dummy = snd_pcm_substream_chip(substream); struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
struct dummy_model *model = dummy->model; const struct dummy_model *model = dummy->model;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
const struct dummy_timer_ops *ops; const struct dummy_timer_ops *ops;
int err; int err;
@ -652,23 +644,19 @@ static struct page *dummy_pcm_page(struct snd_pcm_substream *substream,
return virt_to_page(dummy_page[substream->stream]); /* the same page */ return virt_to_page(dummy_page[substream->stream]); /* the same page */
} }
static struct snd_pcm_ops dummy_pcm_ops = { static const struct snd_pcm_ops dummy_pcm_ops = {
.open = dummy_pcm_open, .open = dummy_pcm_open,
.close = dummy_pcm_close, .close = dummy_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = dummy_pcm_hw_params, .hw_params = dummy_pcm_hw_params,
.hw_free = dummy_pcm_hw_free,
.prepare = dummy_pcm_prepare, .prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger, .trigger = dummy_pcm_trigger,
.pointer = dummy_pcm_pointer, .pointer = dummy_pcm_pointer,
}; };
static struct snd_pcm_ops dummy_pcm_ops_no_buf = { static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {
.open = dummy_pcm_open, .open = dummy_pcm_open,
.close = dummy_pcm_close, .close = dummy_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = dummy_pcm_hw_params, .hw_params = dummy_pcm_hw_params,
.hw_free = dummy_pcm_hw_free,
.prepare = dummy_pcm_prepare, .prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger, .trigger = dummy_pcm_trigger,
.pointer = dummy_pcm_pointer, .pointer = dummy_pcm_pointer,
@ -682,7 +670,7 @@ static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
int substreams) int substreams)
{ {
struct snd_pcm *pcm; struct snd_pcm *pcm;
struct snd_pcm_ops *ops; const struct snd_pcm_ops *ops;
int err; int err;
err = snd_pcm_new(dummy->card, "Dummy PCM", device, err = snd_pcm_new(dummy->card, "Dummy PCM", device,
@ -700,7 +688,7 @@ static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
pcm->info_flags = 0; pcm->info_flags = 0;
strcpy(pcm->name, "Dummy PCM"); strcpy(pcm->name, "Dummy PCM");
if (!fake_buffer) { if (!fake_buffer) {
snd_pcm_lib_preallocate_pages_for_all(pcm, snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS, SNDRV_DMA_TYPE_CONTINUOUS,
NULL, NULL,
0, 64*1024); 0, 64*1024);
@ -861,7 +849,7 @@ static int snd_dummy_iobox_put(struct snd_kcontrol *kcontrol,
return changed; return changed;
} }
static struct snd_kcontrol_new snd_dummy_controls[] = { static const struct snd_kcontrol_new snd_dummy_controls[] = {
DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
@ -924,7 +912,7 @@ static void print_formats(struct snd_dummy *dummy,
static void print_rates(struct snd_dummy *dummy, static void print_rates(struct snd_dummy *dummy,
struct snd_info_buffer *buffer) struct snd_info_buffer *buffer)
{ {
static int rates[] = { static const int rates[] = {
5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
64000, 88200, 96000, 176400, 192000, 64000, 88200, 96000, 176400, 192000,
}; };
@ -956,7 +944,7 @@ struct dummy_hw_field {
.offset = offsetof(struct snd_pcm_hardware, item), \ .offset = offsetof(struct snd_pcm_hardware, item), \
.size = sizeof(dummy_pcm_hardware.item) } .size = sizeof(dummy_pcm_hardware.item) }
static struct dummy_hw_field fields[] = { static const struct dummy_hw_field fields[] = {
FIELD_ENTRY(formats, "%#llx"), FIELD_ENTRY(formats, "%#llx"),
FIELD_ENTRY(rates, "%#x"), FIELD_ENTRY(rates, "%#x"),
FIELD_ENTRY(rate_min, "%d"), FIELD_ENTRY(rate_min, "%d"),
@ -1034,7 +1022,7 @@ static int snd_dummy_probe(struct platform_device *devptr)
{ {
struct snd_card *card; struct snd_card *card;
struct snd_dummy *dummy; struct snd_dummy *dummy;
struct dummy_model *m = NULL, **mdl; const struct dummy_model *m = NULL, **mdl;
int idx, err; int idx, err;
int dev = devptr->id; int dev = devptr->id;

View File

@ -670,23 +670,6 @@ snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream)
return 0; return 0;
} }
static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream)
{
PDEBUG(WORK_INFO, "hw_free()\n");
return snd_pcm_lib_free_pages(substream);
}
static int
snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired "
"period bytes=%d\n",
params_buffer_bytes(hw_params), params_period_bytes(hw_params));
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
}
static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream) static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream)
{ {
struct snd_ml403_ac97cr *ml403_ac97cr; struct snd_ml403_ac97cr *ml403_ac97cr;
@ -748,9 +731,6 @@ static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = { static const struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = {
.open = snd_ml403_ac97cr_playback_open, .open = snd_ml403_ac97cr_playback_open,
.close = snd_ml403_ac97cr_playback_close, .close = snd_ml403_ac97cr_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_ml403_ac97cr_hw_params,
.hw_free = snd_ml403_ac97cr_hw_free,
.prepare = snd_ml403_ac97cr_pcm_playback_prepare, .prepare = snd_ml403_ac97cr_pcm_playback_prepare,
.trigger = snd_ml403_ac97cr_pcm_playback_trigger, .trigger = snd_ml403_ac97cr_pcm_playback_trigger,
.pointer = snd_ml403_ac97cr_pcm_pointer, .pointer = snd_ml403_ac97cr_pcm_pointer,
@ -759,9 +739,6 @@ static const struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = {
static const struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = { static const struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = {
.open = snd_ml403_ac97cr_capture_open, .open = snd_ml403_ac97cr_capture_open,
.close = snd_ml403_ac97cr_capture_close, .close = snd_ml403_ac97cr_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_ml403_ac97cr_hw_params,
.hw_free = snd_ml403_ac97cr_hw_free,
.prepare = snd_ml403_ac97cr_pcm_capture_prepare, .prepare = snd_ml403_ac97cr_pcm_capture_prepare,
.trigger = snd_ml403_ac97cr_pcm_capture_trigger, .trigger = snd_ml403_ac97cr_pcm_capture_trigger,
.pointer = snd_ml403_ac97cr_pcm_pointer, .pointer = snd_ml403_ac97cr_pcm_pointer,
@ -1099,7 +1076,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
{ {
struct snd_ml403_ac97cr *ml403_ac97cr; struct snd_ml403_ac97cr *ml403_ac97cr;
int err; int err;
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_ml403_ac97cr_dev_free, .dev_free = snd_ml403_ac97cr_dev_free,
}; };
struct resource *resource; struct resource *resource;
@ -1195,7 +1172,7 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr)
struct snd_ac97_bus *bus; struct snd_ac97_bus *bus;
struct snd_ac97_template ac97; struct snd_ac97_template ac97;
int err; int err;
static struct snd_ac97_bus_ops ops = { static const struct snd_ac97_bus_ops ops = {
.write = snd_ml403_ac97cr_codec_write, .write = snd_ml403_ac97cr_codec_write,
.read = snd_ml403_ac97cr_codec_read, .read = snd_ml403_ac97cr_codec_read,
}; };
@ -1241,10 +1218,10 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
strcpy(pcm->name, "ML403AC97CR DAC/ADC"); strcpy(pcm->name, "ML403AC97CR DAC/ADC");
ml403_ac97cr->pcm = pcm; ml403_ac97cr->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
NULL, NULL,
64 * 1024, 64 * 1024,
128 * 1024); 128 * 1024);
return 0; return 0;
} }

View File

@ -261,7 +261,7 @@ static int mts64_device_close(struct mts64 *mts)
*/ */
static u8 mts64_map_midi_input(u8 c) static u8 mts64_map_midi_input(u8 c)
{ {
static u8 map[] = { 0, 1, 4, 2, 3 }; static const u8 map[] = { 0, 1, 4, 2, 3 };
return map[c]; return map[c];
} }
@ -353,7 +353,7 @@ static void mts64_smpte_start(struct parport *p,
u8 seconds, u8 frames, u8 seconds, u8 frames,
u8 idx) u8 idx)
{ {
static u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24, static const u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24,
MTS64_CMD_SMPTE_FPS_25, MTS64_CMD_SMPTE_FPS_25,
MTS64_CMD_SMPTE_FPS_2997, MTS64_CMD_SMPTE_FPS_2997,
MTS64_CMD_SMPTE_FPS_30D, MTS64_CMD_SMPTE_FPS_30D,
@ -467,7 +467,7 @@ __out:
return changed; return changed;
} }
static struct snd_kcontrol_new mts64_ctl_smpte_switch = { static const struct snd_kcontrol_new mts64_ctl_smpte_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
.name = "SMPTE Playback Switch", .name = "SMPTE Playback Switch",
.index = 0, .index = 0,
@ -540,7 +540,7 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl,
return changed; return changed;
} }
static struct snd_kcontrol_new mts64_ctl_smpte_time_hours = { static const struct snd_kcontrol_new mts64_ctl_smpte_time_hours = {
.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
.name = "SMPTE Time Hours", .name = "SMPTE Time Hours",
.index = 0, .index = 0,
@ -551,7 +551,7 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_hours = {
.put = snd_mts64_ctl_smpte_time_put .put = snd_mts64_ctl_smpte_time_put
}; };
static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = { static const struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = {
.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
.name = "SMPTE Time Minutes", .name = "SMPTE Time Minutes",
.index = 0, .index = 0,
@ -562,7 +562,7 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = {
.put = snd_mts64_ctl_smpte_time_put .put = snd_mts64_ctl_smpte_time_put
}; };
static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = { static const struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = {
.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
.name = "SMPTE Time Seconds", .name = "SMPTE Time Seconds",
.index = 0, .index = 0,
@ -573,7 +573,7 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = {
.put = snd_mts64_ctl_smpte_time_put .put = snd_mts64_ctl_smpte_time_put
}; };
static struct snd_kcontrol_new mts64_ctl_smpte_time_frames = { static const struct snd_kcontrol_new mts64_ctl_smpte_time_frames = {
.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
.name = "SMPTE Time Frames", .name = "SMPTE Time Frames",
.index = 0, .index = 0,
@ -625,7 +625,7 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl,
return changed; return changed;
} }
static struct snd_kcontrol_new mts64_ctl_smpte_fps = { static const struct snd_kcontrol_new mts64_ctl_smpte_fps = {
.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
.name = "SMPTE Fps", .name = "SMPTE Fps",
.index = 0, .index = 0,
@ -641,7 +641,7 @@ static int snd_mts64_ctl_create(struct snd_card *card,
struct mts64 *mts) struct mts64 *mts)
{ {
int err, i; int err, i;
static struct snd_kcontrol_new *control[] = { static const struct snd_kcontrol_new *control[] = {
&mts64_ctl_smpte_switch, &mts64_ctl_smpte_switch,
&mts64_ctl_smpte_time_hours, &mts64_ctl_smpte_time_hours,
&mts64_ctl_smpte_time_minutes, &mts64_ctl_smpte_time_minutes,

View File

@ -7,7 +7,7 @@
#include "opl3_voice.h" #include "opl3_voice.h"
static char snd_opl3_drum_table[47] = static const char snd_opl3_drum_table[47] =
{ {
OPL3_BASSDRUM_ON, OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, /* 35 - 37 */ OPL3_BASSDRUM_ON, OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, /* 35 - 37 */
OPL3_SNAREDRUM_ON, OPL3_HIHAT_ON, OPL3_SNAREDRUM_ON, /* 38 - 40 */ OPL3_SNAREDRUM_ON, OPL3_HIHAT_ON, OPL3_SNAREDRUM_ON, /* 38 - 40 */
@ -47,25 +47,25 @@ struct snd_opl3_drum_note {
unsigned char feedback_connection; unsigned char feedback_connection;
}; };
static struct snd_opl3_drum_voice bass_op0 = {6, 0, 0x00, 0x32, 0xf8, 0x66, 0x30, 0x00}; static const struct snd_opl3_drum_voice bass_op0 = {6, 0, 0x00, 0x32, 0xf8, 0x66, 0x30, 0x00};
static struct snd_opl3_drum_voice bass_op1 = {6, 1, 0x00, 0x03, 0xf6, 0x57, 0x30, 0x00}; static const struct snd_opl3_drum_voice bass_op1 = {6, 1, 0x00, 0x03, 0xf6, 0x57, 0x30, 0x00};
static struct snd_opl3_drum_note bass_note = {6, 0x90, 0x09}; static const struct snd_opl3_drum_note bass_note = {6, 0x90, 0x09};
static struct snd_opl3_drum_voice hihat = {7, 0, 0x00, 0x03, 0xf0, 0x06, 0x20, 0x00}; static const struct snd_opl3_drum_voice hihat = {7, 0, 0x00, 0x03, 0xf0, 0x06, 0x20, 0x00};
static struct snd_opl3_drum_voice snare = {7, 1, 0x00, 0x03, 0xf0, 0x07, 0x20, 0x02}; static const struct snd_opl3_drum_voice snare = {7, 1, 0x00, 0x03, 0xf0, 0x07, 0x20, 0x02};
static struct snd_opl3_drum_note snare_note = {7, 0xf4, 0x0d}; static const struct snd_opl3_drum_note snare_note = {7, 0xf4, 0x0d};
static struct snd_opl3_drum_voice tomtom = {8, 0, 0x02, 0x03, 0xf0, 0x06, 0x10, 0x00}; static const struct snd_opl3_drum_voice tomtom = {8, 0, 0x02, 0x03, 0xf0, 0x06, 0x10, 0x00};
static struct snd_opl3_drum_note tomtom_note = {8, 0xf4, 0x09}; static const struct snd_opl3_drum_note tomtom_note = {8, 0xf4, 0x09};
static struct snd_opl3_drum_voice cymbal = {8, 1, 0x04, 0x03, 0xf0, 0x06, 0x10, 0x00}; static const struct snd_opl3_drum_voice cymbal = {8, 1, 0x04, 0x03, 0xf0, 0x06, 0x10, 0x00};
/* /*
* set drum voice characteristics * set drum voice characteristics
*/ */
static void snd_opl3_drum_voice_set(struct snd_opl3 *opl3, static void snd_opl3_drum_voice_set(struct snd_opl3 *opl3,
struct snd_opl3_drum_voice *data) const struct snd_opl3_drum_voice *data)
{ {
unsigned char op_offset = snd_opl3_regmap[data->voice][data->op]; unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
unsigned char voice_offset = data->voice; unsigned char voice_offset = data->voice;
@ -100,7 +100,7 @@ static void snd_opl3_drum_voice_set(struct snd_opl3 *opl3,
* Set drum voice pitch * Set drum voice pitch
*/ */
static void snd_opl3_drum_note_set(struct snd_opl3 *opl3, static void snd_opl3_drum_note_set(struct snd_opl3 *opl3,
struct snd_opl3_drum_note *data) const struct snd_opl3_drum_note *data)
{ {
unsigned char voice_offset = data->voice; unsigned char voice_offset = data->voice;
unsigned short opl3_reg; unsigned short opl3_reg;
@ -118,7 +118,7 @@ static void snd_opl3_drum_note_set(struct snd_opl3 *opl3,
* Set drum voice volume and position * Set drum voice volume and position
*/ */
static void snd_opl3_drum_vol_set(struct snd_opl3 *opl3, static void snd_opl3_drum_vol_set(struct snd_opl3 *opl3,
struct snd_opl3_drum_voice *data, const struct snd_opl3_drum_voice *data,
int vel, struct snd_midi_channel *chan) int vel, struct snd_midi_channel *chan)
{ {
unsigned char op_offset = snd_opl3_regmap[data->voice][data->op]; unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
@ -170,7 +170,7 @@ void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int vel, int on_off,
struct snd_midi_channel *chan) struct snd_midi_channel *chan)
{ {
unsigned char drum_mask; unsigned char drum_mask;
struct snd_opl3_drum_voice *drum_voice; const struct snd_opl3_drum_voice *drum_voice;
if (!(opl3->drum_reg & OPL3_PERCUSSION_ENABLE)) if (!(opl3->drum_reg & OPL3_PERCUSSION_ENABLE))
return; return;

View File

@ -214,7 +214,7 @@ static int snd_opl3_timer2_stop(struct snd_timer * timer)
*/ */
static struct snd_timer_hardware snd_opl3_timer1 = static const struct snd_timer_hardware snd_opl3_timer1 =
{ {
.flags = SNDRV_TIMER_HW_STOP, .flags = SNDRV_TIMER_HW_STOP,
.resolution = 80000, .resolution = 80000,
@ -223,7 +223,7 @@ static struct snd_timer_hardware snd_opl3_timer1 =
.stop = snd_opl3_timer1_stop, .stop = snd_opl3_timer1_stop,
}; };
static struct snd_timer_hardware snd_opl3_timer2 = static const struct snd_timer_hardware snd_opl3_timer2 =
{ {
.flags = SNDRV_TIMER_HW_STOP, .flags = SNDRV_TIMER_HW_STOP,
.resolution = 320000, .resolution = 320000,
@ -332,7 +332,7 @@ int snd_opl3_new(struct snd_card *card,
unsigned short hardware, unsigned short hardware,
struct snd_opl3 **ropl3) struct snd_opl3 **ropl3)
{ {
static struct snd_device_ops ops = { static const struct snd_device_ops ops = {
.dev_free = snd_opl3_dev_free, .dev_free = snd_opl3_dev_free,
}; };
struct snd_opl3 *opl3; struct snd_opl3 *opl3;

View File

@ -23,7 +23,7 @@ static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
* it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>) * it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>)
*/ */
static char opl3_volume_table[128] = static const char opl3_volume_table[128] =
{ {
-63, -48, -40, -35, -32, -29, -27, -26, -63, -48, -40, -35, -32, -29, -27, -26,
-24, -23, -21, -20, -19, -18, -18, -17, -24, -23, -21, -20, -19, -18, -18, -17,
@ -69,7 +69,7 @@ void snd_opl3_calc_volume(unsigned char *volbyte, int vel,
/* /*
* Converts the note frequency to block and fnum values for the FM chip * Converts the note frequency to block and fnum values for the FM chip
*/ */
static short opl3_note_table[16] = static const short opl3_note_table[16] =
{ {
305, 323, /* for pitch bending, -2 semitones */ 305, 323, /* for pitch bending, -2 semitones */
343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647,
@ -266,7 +266,7 @@ static void snd_opl3_start_timer(struct snd_opl3 *opl3)
/* ------------------------------ */ /* ------------------------------ */
static int snd_opl3_oss_map[MAX_OPL3_VOICES] = { static const int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14
}; };

View File

@ -16,7 +16,7 @@ static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg);
/* operators */ /* operators */
static struct snd_seq_oss_callback oss_callback = { static const struct snd_seq_oss_callback oss_callback = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = snd_opl3_open_seq_oss, .open = snd_opl3_open_seq_oss,
.close = snd_opl3_close_seq_oss, .close = snd_opl3_close_seq_oss,

View File

@ -128,7 +128,7 @@ static int snd_opl3_synth_unuse(void *private_data, struct snd_seq_port_subscrib
/* /*
* MIDI emulation operators * MIDI emulation operators
*/ */
struct snd_midi_op opl3_ops = { const struct snd_midi_op opl3_ops = {
.note_on = snd_opl3_note_on, .note_on = snd_opl3_note_on,
.note_off = snd_opl3_note_off, .note_off = snd_opl3_note_off,
.key_press = snd_opl3_key_press, .key_press = snd_opl3_key_press,

View File

@ -41,6 +41,6 @@ void snd_opl3_free_seq_oss(struct snd_opl3 *opl3);
extern char snd_opl3_regmap[MAX_OPL2_VOICES][4]; extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
extern bool use_internal_drums; extern bool use_internal_drums;
extern struct snd_midi_op opl3_ops; extern const struct snd_midi_op opl3_ops;
#endif #endif

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