sound updates for 6.9-rc1
This was a relatively calm development cycle. Most of changes are rather small device-specific fixes and enhancements. The only significant changes in ALSA core are code refactoring with the recent cleanup infrastructure, which should bring no functionality changes. Some highlights below: Core: - Lots of cleanups in ALSA core code with automatic kfree cleanup and locking guard macros - New ALSA core kunit test ASoC: - SoundWire support for AMD ACP 6.3 systems - Support for reporting version information for AVS firmware - Support DSPless mode for Intel Soundwire systems - Support for configuring CS35L56 amplifiers using EFI calibration data - Log which component is being operated on as part of power management trace events. - Support for Microchip SAM9x7, NXP i.MX95 and Qualcomm WCD939x HD- and USB-audio: - More Cirrus HD-audio codec support - TAS2781 HD-audio codec fixes - Scarlett2 mixer fixes Others: - Enhancement of virtio driver for audio control supports - Cleanups of legacy PM code with new macros - Firewire sound updates -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmXyzFQOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE80WQ//bQeLEUF9HQqprCW96jFiGeO3/0Zb5pdCCrZw VYRxzeGBfMfVFvXSC4/Rp3zr4Dbc+sOg9GXAD6PVAo/QudIDkuX1pk/gRN2NFXQ5 bimdZ6obM4WCl7isbDIbn/ifOx05F7p0+J9T9nAPrvBG4lpzXoMhGz75YnwaPlrh q5MKEZcuONlZPHZrBy/UsrYqWrnWUi2yWgQ5gRg/PTM4dgUAy2pH7NpKNxOiRntJ eqBfdvglSWQDH9kPgmeTggtFN8Axy+pd+g9M5pi/KOJfoBpWuv2nK31gnymdqV4H UrmwU/VAL2Y0zU34RCZQvPFre6S+487FEf/g+qgVTDqi0kxxFT2btcaTjggjLwEy p/SJlqNnA7W7D67/qf4MPNOEp88Dd6o1YN7o01vyC9RoX5FAbzvNLF8oH4BwGxs+ HI+5aJUY1f2MGwN3NpPW5E12d1RSgSi9L9l/R8oAQmonARr3drj3tkndhFjndgXG IctwHlkYRSibe6m5k6sDEcil70UNl5M6sr/IjPmDvYudjdKHisowrxqF+nPrAYdM 0z3fW333+OQf0XVd9iPLBmq+PpiAY1AhCJeF/hPr3D5qDZInhcd8CouFie+QGkHT Z5j5CvhNLgRdmlW9jvfBPBBCT7u8jr6JFszA3g6wpWUx6ndAGsI1z6iC+h23NpZj dxmJU00= =h9kz -----END PGP SIGNATURE----- Merge tag 'sound-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "This was a relatively calm development cycle. Most of changes are rather small device-specific fixes and enhancements. The only significant changes in ALSA core are code refactoring with the recent cleanup infrastructure, which should bring no functionality changes. Some highlights below: Core: - Lots of cleanups in ALSA core code with automatic kfree cleanup and locking guard macros - New ALSA core kunit test ASoC: - SoundWire support for AMD ACP 6.3 systems - Support for reporting version information for AVS firmware - Support DSPless mode for Intel Soundwire systems - Support for configuring CS35L56 amplifiers using EFI calibration data - Log which component is being operated on as part of power management trace events. - Support for Microchip SAM9x7, NXP i.MX95 and Qualcomm WCD939x HD- and USB-audio: - More Cirrus HD-audio codec support - TAS2781 HD-audio codec fixes - Scarlett2 mixer fixes Others: - Enhancement of virtio driver for audio control supports - Cleanups of legacy PM code with new macros - Firewire sound updates" * tag 'sound-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (307 commits) ALSA: usb-audio: Stop parsing channels bits when all channels are found. ALSA: hda/tas2781: remove unnecessary runtime_pm calls ALSA: hda/realtek - ALC236 fix volume mute & mic mute LED on some HP models ALSA: aaci: Delete unused variable in aaci_do_suspend ALSA: scarlett2: Fix Scarlett 4th Gen input gain range again ALSA: scarlett2: Fix Scarlett 4th Gen input gain range ALSA: scarlett2: Fix Scarlett 4th Gen autogain status values ALSA: scarlett2: Fix Scarlett 4th Gen 4i4 low-voltage detection ALSA: hda/tas2781: restore power state after system_resume ALSA: hda/tas2781: do not call pm_runtime_force_* in system_resume/suspend ALSA: hda/tas2781: do not reset cur_* values in runtime_suspend ALSA: hda/tas2781: add lock to system_suspend ALSA: hda/tas2781: use dev_dbg in system_resume ALSA: hda/realtek: fix ALC285 issues on HP Envy x360 laptops platform/x86: serial-multi-instantiate: Add support for CS35L54 and CS35L57 ALSA: hda: cs35l56: Add support for CS35L54 and CS35L57 ASoC: cs35l56: Add support for CS35L54 and CS35L57 ASoC: Intel: catpt: Carefully use PCI bitwise constants ALSA: hda: hda_component: Include sound/hda_codec.h ALSA: hda: hda_component: Add missing #include guards ...
This commit is contained in:
commit
fe46a7dd18
|
@ -0,0 +1,8 @@
|
||||||
|
What: /sys/devices/pci0000:00/<dev>/avs/fw_version
|
||||||
|
Date: February 2024
|
||||||
|
Contact: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||||
|
Description:
|
||||||
|
Version of AudioDSP firmware ASoC avs driver is communicating
|
||||||
|
with.
|
||||||
|
|
||||||
|
Format: %d.%d.%d.%d, type:major:minor:build.
|
|
@ -0,0 +1,84 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/atmel,asoc-wm8904.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Atmel wm8904 audio codec complex
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Dharma Balasubiramani <dharma.b@microchip.com>
|
||||||
|
|
||||||
|
description:
|
||||||
|
The ASoC audio complex configuration for Atmel with WM8904 audio codec.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: atmel,asoc-wm8904
|
||||||
|
|
||||||
|
atmel,model:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/string
|
||||||
|
description: The user-visible name of this sound complex.
|
||||||
|
|
||||||
|
atmel,ssc-controller:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: The phandle of the SSC controller.
|
||||||
|
|
||||||
|
atmel,audio-codec:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: The phandle of the WM8731 audio codec.
|
||||||
|
|
||||||
|
atmel,audio-routing:
|
||||||
|
description:
|
||||||
|
A list of the connections between audio components. Each entry is a pair
|
||||||
|
of strings, the first being the connection's sink, the second being the
|
||||||
|
connection's source.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||||
|
items:
|
||||||
|
enum:
|
||||||
|
# Board Connectors
|
||||||
|
- Headphone Jack
|
||||||
|
- Line In Jack
|
||||||
|
- Mic
|
||||||
|
# WM8904 CODEC Pins
|
||||||
|
- IN1L
|
||||||
|
- IN1R
|
||||||
|
- IN2L
|
||||||
|
- IN2R
|
||||||
|
- IN3L
|
||||||
|
- IN3R
|
||||||
|
- HPOUTL
|
||||||
|
- HPOUTR
|
||||||
|
- LINEOUTL
|
||||||
|
- LINEOUTR
|
||||||
|
- MICBIAS
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- atmel,model
|
||||||
|
- atmel,audio-routing
|
||||||
|
- atmel,ssc-controller
|
||||||
|
- atmel,audio-codec
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
sound {
|
||||||
|
compatible = "atmel,asoc-wm8904";
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_pck0_as_mck>;
|
||||||
|
|
||||||
|
atmel,model = "wm8904 @ AT91SAM9N12EK";
|
||||||
|
|
||||||
|
atmel,audio-routing =
|
||||||
|
"Headphone Jack", "HPOUTL",
|
||||||
|
"Headphone Jack", "HPOUTR",
|
||||||
|
"IN2L", "Line In Jack",
|
||||||
|
"IN2R", "Line In Jack",
|
||||||
|
"Mic", "MICBIAS",
|
||||||
|
"IN1L", "Mic";
|
||||||
|
|
||||||
|
atmel,ssc-controller = <&ssc0>;
|
||||||
|
atmel,audio-codec = <&wm8904>;
|
||||||
|
};
|
|
@ -0,0 +1,76 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/atmel,sam9x5-wm8731-audio.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Atmel at91sam9x5ek wm8731 audio complex
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Dharma Balasubiramani <dharma.b@microchip.com>
|
||||||
|
|
||||||
|
description:
|
||||||
|
The audio complex configuration for Atmel at91sam9x5ek with WM8731 audio codec.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: atmel,sam9x5-wm8731-audio
|
||||||
|
|
||||||
|
atmel,model:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/string
|
||||||
|
description: The user-visible name of this sound complex.
|
||||||
|
|
||||||
|
atmel,ssc-controller:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: The phandle of the SSC controller.
|
||||||
|
|
||||||
|
atmel,audio-codec:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: The phandle of the WM8731 audio codec.
|
||||||
|
|
||||||
|
atmel,audio-routing:
|
||||||
|
description:
|
||||||
|
A list of the connections between audio components. Each entry is a pair
|
||||||
|
of strings, the first being the connection's sink, the second being the
|
||||||
|
connection's source.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||||
|
items:
|
||||||
|
enum:
|
||||||
|
# Board Connectors
|
||||||
|
- Headphone Jack
|
||||||
|
- Line In Jack
|
||||||
|
|
||||||
|
# CODEC Pins
|
||||||
|
- LOUT
|
||||||
|
- ROUT
|
||||||
|
- LHPOUT
|
||||||
|
- RHPOUT
|
||||||
|
- LLINEIN
|
||||||
|
- RLINEIN
|
||||||
|
- MICIN
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- atmel,model
|
||||||
|
- atmel,ssc-controller
|
||||||
|
- atmel,audio-codec
|
||||||
|
- atmel,audio-routing
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
sound {
|
||||||
|
compatible = "atmel,sam9x5-wm8731-audio";
|
||||||
|
|
||||||
|
atmel,model = "wm8731 @ AT91SAM9X5EK";
|
||||||
|
|
||||||
|
atmel,audio-routing =
|
||||||
|
"Headphone Jack", "RHPOUT",
|
||||||
|
"Headphone Jack", "LHPOUT",
|
||||||
|
"LLINEIN", "Line In Jack",
|
||||||
|
"RLINEIN", "Line In Jack";
|
||||||
|
|
||||||
|
atmel,ssc-controller = <&ssc0>;
|
||||||
|
atmel,audio-codec = <&wm8731>;
|
||||||
|
};
|
|
@ -18,7 +18,12 @@ description:
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
const: atmel,sama5d2-classd
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- const: atmel,sama5d2-classd
|
||||||
|
- items:
|
||||||
|
- const: microchip,sam9x7-classd
|
||||||
|
- const: atmel,sama5d2-classd
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
* Atmel at91sam9x5ek wm8731 audio complex
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: "atmel,sam9x5-wm8731-audio"
|
|
||||||
- atmel,model: The user-visible name of this sound complex.
|
|
||||||
- atmel,ssc-controller: The phandle of the SSC controller
|
|
||||||
- atmel,audio-codec: The phandle of the WM8731 audio codec
|
|
||||||
- atmel,audio-routing: A list of the connections between audio components.
|
|
||||||
Each entry is a pair of strings, the first being the connection's sink,
|
|
||||||
the second being the connection's source.
|
|
||||||
|
|
||||||
Available audio endpoints for the audio-routing table:
|
|
||||||
|
|
||||||
Board connectors:
|
|
||||||
* Headphone Jack
|
|
||||||
* Line In Jack
|
|
||||||
|
|
||||||
wm8731 pins:
|
|
||||||
cf Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
|
|
||||||
|
|
||||||
Example:
|
|
||||||
sound {
|
|
||||||
compatible = "atmel,sam9x5-wm8731-audio";
|
|
||||||
|
|
||||||
atmel,model = "wm8731 @ AT91SAM9X5EK";
|
|
||||||
|
|
||||||
atmel,audio-routing =
|
|
||||||
"Headphone Jack", "RHPOUT",
|
|
||||||
"Headphone Jack", "LHPOUT",
|
|
||||||
"LLINEIN", "Line In Jack",
|
|
||||||
"RLINEIN", "Line In Jack";
|
|
||||||
|
|
||||||
atmel,ssc-controller = <&ssc0>;
|
|
||||||
atmel,audio-codec = <&wm8731>;
|
|
||||||
};
|
|
|
@ -1,55 +0,0 @@
|
||||||
Atmel ASoC driver with wm8904 audio codec complex
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: "atmel,asoc-wm8904"
|
|
||||||
- atmel,model: The user-visible name of this sound complex.
|
|
||||||
- atmel,audio-routing: A list of the connections between audio components.
|
|
||||||
Each entry is a pair of strings, the first being the connection's sink,
|
|
||||||
the second being the connection's source. Valid names for sources and
|
|
||||||
sinks are the WM8904's pins, and the jacks on the board:
|
|
||||||
|
|
||||||
WM8904 pins:
|
|
||||||
|
|
||||||
* IN1L
|
|
||||||
* IN1R
|
|
||||||
* IN2L
|
|
||||||
* IN2R
|
|
||||||
* IN3L
|
|
||||||
* IN3R
|
|
||||||
* HPOUTL
|
|
||||||
* HPOUTR
|
|
||||||
* LINEOUTL
|
|
||||||
* LINEOUTR
|
|
||||||
* MICBIAS
|
|
||||||
|
|
||||||
Board connectors:
|
|
||||||
|
|
||||||
* Headphone Jack
|
|
||||||
* Line In Jack
|
|
||||||
* Mic
|
|
||||||
|
|
||||||
- atmel,ssc-controller: The phandle of the SSC controller
|
|
||||||
- atmel,audio-codec: The phandle of the WM8904 audio codec
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
|
|
||||||
|
|
||||||
Example:
|
|
||||||
sound {
|
|
||||||
compatible = "atmel,asoc-wm8904";
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&pinctrl_pck0_as_mck>;
|
|
||||||
|
|
||||||
atmel,model = "wm8904 @ AT91SAM9N12EK";
|
|
||||||
|
|
||||||
atmel,audio-routing =
|
|
||||||
"Headphone Jack", "HPOUTL",
|
|
||||||
"Headphone Jack", "HPOUTR",
|
|
||||||
"IN2L", "Line In Jack",
|
|
||||||
"IN2R", "Line In Jack",
|
|
||||||
"Mic", "MICBIAS",
|
|
||||||
"IN1L", "Mic";
|
|
||||||
|
|
||||||
atmel,ssc-controller = <&ssc0>;
|
|
||||||
atmel,audio-codec = <&wm8904>;
|
|
||||||
};
|
|
|
@ -51,7 +51,7 @@ definitions:
|
||||||
- $ref: /schemas/types.yaml#/definitions/phandle
|
- $ref: /schemas/types.yaml#/definitions/phandle
|
||||||
clocks:
|
clocks:
|
||||||
description: Indicates system clock
|
description: Indicates system clock
|
||||||
$ref: /schemas/types.yaml#/definitions/phandle
|
maxItems: 1
|
||||||
system-clock-frequency:
|
system-clock-frequency:
|
||||||
$ref: simple-card.yaml#/definitions/system-clock-frequency
|
$ref: simple-card.yaml#/definitions/system-clock-frequency
|
||||||
system-clock-direction-out:
|
system-clock-direction-out:
|
||||||
|
|
|
@ -25,6 +25,9 @@ properties:
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
'#sound-dai-cells':
|
'#sound-dai-cells':
|
||||||
const: 1
|
const: 1
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ properties:
|
||||||
default: 0x0f
|
default: 0x0f
|
||||||
|
|
||||||
everest,mic1-src:
|
everest,mic1-src:
|
||||||
|
deprecated: true
|
||||||
$ref: /schemas/types.yaml#/definitions/uint8
|
$ref: /schemas/types.yaml#/definitions/uint8
|
||||||
description:
|
description:
|
||||||
the value of reg 2A when headset plugged.
|
the value of reg 2A when headset plugged.
|
||||||
|
@ -46,6 +47,7 @@ properties:
|
||||||
default: 0x22
|
default: 0x22
|
||||||
|
|
||||||
everest,mic2-src:
|
everest,mic2-src:
|
||||||
|
deprecated: true
|
||||||
$ref: /schemas/types.yaml#/definitions/uint8
|
$ref: /schemas/types.yaml#/definitions/uint8
|
||||||
description:
|
description:
|
||||||
the value of reg 2A when headset unplugged.
|
the value of reg 2A when headset unplugged.
|
||||||
|
@ -87,7 +89,7 @@ properties:
|
||||||
0 means the chip detect jack type again after button released.
|
0 means the chip detect jack type again after button released.
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 0x7f
|
maximum: 0x7f
|
||||||
default: 0x45
|
default: 0x00
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
|
@ -107,10 +109,8 @@ examples:
|
||||||
clocks = <&clks 10>;
|
clocks = <&clks 10>;
|
||||||
clock-names = "mclk";
|
clock-names = "mclk";
|
||||||
#sound-dai-cells = <0>;
|
#sound-dai-cells = <0>;
|
||||||
everest,mic1-src = [22];
|
|
||||||
everest,mic2-src = [44];
|
|
||||||
everest,jack-pol = [0e];
|
everest,jack-pol = [0e];
|
||||||
everest,interrupt-src = [08];
|
everest,interrupt-src = [08];
|
||||||
everest,interrupt-clk = [45];
|
everest,interrupt-clk = [00];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
Freescale Asynchronous Sample Rate Converter (ASRC) Controller
|
|
||||||
|
|
||||||
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a
|
|
||||||
signal associated with an input clock into a signal associated with a different
|
|
||||||
output clock. The driver currently works as a Front End of DPCM with other Back
|
|
||||||
Ends Audio controller such as ESAI, SSI and SAI. It has three pairs to support
|
|
||||||
three substreams within totally 10 channels.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
- interrupts : Contains the spdif interrupt.
|
|
||||||
|
|
||||||
- dmas : Generic dma devicetree binding as described in
|
|
||||||
Documentation/devicetree/bindings/dma/dma.txt.
|
|
||||||
|
|
||||||
- dma-names : Contains "rxa", "rxb", "rxc", "txa", "txb" and "txc".
|
|
||||||
|
|
||||||
- clocks : Contains an entry for each entry in clock-names.
|
|
||||||
|
|
||||||
- clock-names : Contains the following entries
|
|
||||||
"mem" Peripheral access clock to access registers.
|
|
||||||
"ipg" Peripheral clock to driver module.
|
|
||||||
"asrck_<0-f>" Clock sources for input and output clock.
|
|
||||||
"spba" The spba clock is required when ASRC is placed as a
|
|
||||||
bus slave of the Shared Peripheral Bus and when two
|
|
||||||
or more bus masters (CPU, DMA or DSP) try to access
|
|
||||||
it. This property is optional depending on the SoC
|
|
||||||
design.
|
|
||||||
|
|
||||||
- fsl,asrc-rate : Defines a mutual sample rate 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:
|
|
||||||
|
|
||||||
- big-endian : If this property is absent, the little endian mode
|
|
||||||
will be in use as default. Otherwise, the big endian
|
|
||||||
mode will be in use for all the device registers.
|
|
||||||
|
|
||||||
- fsl,asrc-format : Defines a mutual sample format used by DPCM Back
|
|
||||||
Ends, which can replace the fsl,asrc-width.
|
|
||||||
The value is 2 (S16_LE), or 6 (S24_LE).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
asrc: asrc@2034000 {
|
|
||||||
compatible = "fsl,imx53-asrc";
|
|
||||||
reg = <0x02034000 0x4000>;
|
|
||||||
interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
clocks = <&clks 107>, <&clks 107>, <&clks 0>,
|
|
||||||
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
|
|
||||||
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
|
|
||||||
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
|
|
||||||
<&clks 107>, <&clks 0>, <&clks 0>;
|
|
||||||
clock-names = "mem", "ipg", "asrck0",
|
|
||||||
"asrck_1", "asrck_2", "asrck_3", "asrck_4",
|
|
||||||
"asrck_5", "asrck_6", "asrck_7", "asrck_8",
|
|
||||||
"asrck_9", "asrck_a", "asrck_b", "asrck_c",
|
|
||||||
"asrck_d", "asrck_e", "asrck_f";
|
|
||||||
dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
|
|
||||||
<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
|
|
||||||
dma-names = "rxa", "rxb", "rxc",
|
|
||||||
"txa", "txb", "txc";
|
|
||||||
fsl,asrc-rate = <48000>;
|
|
||||||
fsl,asrc-width = <16>;
|
|
||||||
};
|
|
|
@ -51,8 +51,8 @@ properties:
|
||||||
- const: ctx3_tx
|
- const: ctx3_tx
|
||||||
|
|
||||||
firmware-name:
|
firmware-name:
|
||||||
$ref: /schemas/types.yaml#/definitions/string
|
items:
|
||||||
const: imx/easrc/easrc-imx8mn.bin
|
- const: imx/easrc/easrc-imx8mn.bin
|
||||||
description: The coefficient table for the filters
|
description: The coefficient table for the filters
|
||||||
|
|
||||||
fsl,asrc-rate:
|
fsl,asrc-rate:
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/fsl,imx-asrc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Freescale Asynchronous Sample Rate Converter (ASRC) Controller
|
||||||
|
|
||||||
|
description:
|
||||||
|
The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of
|
||||||
|
a signal associated with an input clock into a signal associated with a
|
||||||
|
different output clock. The driver currently works as a Front End of DPCM
|
||||||
|
with other Back Ends Audio controller such as ESAI, SSI and SAI. It has
|
||||||
|
three pairs to support three substreams within totally 10 channels.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Shawn Guo <shawnguo@kernel.org>
|
||||||
|
- Sascha Hauer <s.hauer@pengutronix.de>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- enum:
|
||||||
|
- fsl,imx35-asrc
|
||||||
|
- fsl,imx53-asrc
|
||||||
|
- fsl,imx8qm-asrc
|
||||||
|
- fsl,imx8qxp-asrc
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- fsl,imx6sx-asrc
|
||||||
|
- fsl,imx6ul-asrc
|
||||||
|
- const: fsl,imx53-asrc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
dmas:
|
||||||
|
maxItems: 6
|
||||||
|
|
||||||
|
dma-names:
|
||||||
|
items:
|
||||||
|
- const: rxa
|
||||||
|
- const: rxb
|
||||||
|
- const: rxc
|
||||||
|
- const: txa
|
||||||
|
- const: txb
|
||||||
|
- const: txc
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 19
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: mem
|
||||||
|
- const: ipg
|
||||||
|
- const: asrck_0
|
||||||
|
- const: asrck_1
|
||||||
|
- const: asrck_2
|
||||||
|
- const: asrck_3
|
||||||
|
- const: asrck_4
|
||||||
|
- const: asrck_5
|
||||||
|
- const: asrck_6
|
||||||
|
- const: asrck_7
|
||||||
|
- const: asrck_8
|
||||||
|
- const: asrck_9
|
||||||
|
- const: asrck_a
|
||||||
|
- const: asrck_b
|
||||||
|
- const: asrck_c
|
||||||
|
- const: asrck_d
|
||||||
|
- const: asrck_e
|
||||||
|
- const: asrck_f
|
||||||
|
- const: spba
|
||||||
|
|
||||||
|
fsl,asrc-rate:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: The mutual sample rate used by DPCM Back Ends
|
||||||
|
|
||||||
|
fsl,asrc-width:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: The mutual sample width used by DPCM Back Ends
|
||||||
|
enum: [16, 24]
|
||||||
|
|
||||||
|
fsl,asrc-clk-map:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
Defines clock map used in driver
|
||||||
|
<0> - select the map for asrc0 in imx8qm/imx8qxp
|
||||||
|
<1> - select the map for asrc1 in imx8qm/imx8qxp
|
||||||
|
enum: [0, 1]
|
||||||
|
|
||||||
|
big-endian:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
If this property is absent, the little endian mode will be in use as
|
||||||
|
default. Otherwise, the big endian mode will be in use for all the
|
||||||
|
device registers.
|
||||||
|
|
||||||
|
fsl,asrc-format:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
Defines a mutual sample format used by DPCM Back Ends, which can
|
||||||
|
replace the fsl,asrc-width. The value is 2 (S16_LE), or 6 (S24_LE).
|
||||||
|
enum: [2, 6]
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- dmas
|
||||||
|
- dma-names
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- fsl,asrc-rate
|
||||||
|
- fsl,asrc-width
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- fsl,imx8qm-asrc
|
||||||
|
- fsl,imx8qxp-asrc
|
||||||
|
then:
|
||||||
|
required:
|
||||||
|
- fsl,asrc-clk-map
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
fsl,asrc-clk-map: false
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#include <dt-bindings/clock/imx6qdl-clock.h>
|
||||||
|
asrc: asrc@2034000 {
|
||||||
|
compatible = "fsl,imx53-asrc";
|
||||||
|
reg = <0x02034000 0x4000>;
|
||||||
|
interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&clks IMX6QDL_CLK_ASRC_IPG>,
|
||||||
|
<&clks IMX6QDL_CLK_ASRC_MEM>, <&clks 0>,
|
||||||
|
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
|
||||||
|
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
|
||||||
|
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
|
||||||
|
<&clks IMX6QDL_CLK_ASRC>, <&clks 0>, <&clks 0>,
|
||||||
|
<&clks IMX6QDL_CLK_SPBA>;
|
||||||
|
clock-names = "mem", "ipg", "asrck_0",
|
||||||
|
"asrck_1", "asrck_2", "asrck_3", "asrck_4",
|
||||||
|
"asrck_5", "asrck_6", "asrck_7", "asrck_8",
|
||||||
|
"asrck_9", "asrck_a", "asrck_b", "asrck_c",
|
||||||
|
"asrck_d", "asrck_e", "asrck_f", "spba";
|
||||||
|
dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
|
||||||
|
<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
|
||||||
|
dma-names = "rxa", "rxb", "rxc",
|
||||||
|
"txa", "txb", "txc";
|
||||||
|
fsl,asrc-rate = <48000>;
|
||||||
|
fsl,asrc-width = <16>;
|
||||||
|
};
|
|
@ -15,10 +15,16 @@ description: |
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
enum:
|
oneOf:
|
||||||
- fsl,imx8mm-micfil
|
- items:
|
||||||
- fsl,imx8mp-micfil
|
- enum:
|
||||||
- fsl,imx93-micfil
|
- fsl,imx95-micfil
|
||||||
|
- const: fsl,imx93-micfil
|
||||||
|
|
||||||
|
- enum:
|
||||||
|
- fsl,imx8mm-micfil
|
||||||
|
- fsl,imx8mp-micfil
|
||||||
|
- fsl,imx93-micfil
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
|
@ -39,6 +39,7 @@ properties:
|
||||||
- fsl,imx8qm-sai
|
- fsl,imx8qm-sai
|
||||||
- fsl,imx8ulp-sai
|
- fsl,imx8ulp-sai
|
||||||
- fsl,imx93-sai
|
- fsl,imx93-sai
|
||||||
|
- fsl,imx95-sai
|
||||||
- fsl,vf610-sai
|
- fsl,vf610-sai
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
|
@ -75,12 +76,17 @@ properties:
|
||||||
- const: pll11k
|
- const: pll11k
|
||||||
minItems: 4
|
minItems: 4
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
dmas:
|
dmas:
|
||||||
|
minItems: 1
|
||||||
items:
|
items:
|
||||||
- description: DMA controller phandle and request line for RX
|
- description: DMA controller phandle and request line for RX
|
||||||
- description: DMA controller phandle and request line for TX
|
- description: DMA controller phandle and request line for TX
|
||||||
|
|
||||||
dma-names:
|
dma-names:
|
||||||
|
minItems: 1
|
||||||
items:
|
items:
|
||||||
- const: rx
|
- const: rx
|
||||||
- const: tx
|
- const: tx
|
||||||
|
|
|
@ -51,7 +51,7 @@ properties:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
firmware-name:
|
firmware-name:
|
||||||
$ref: /schemas/types.yaml#/definitions/string
|
maxItems: 1
|
||||||
description:
|
description:
|
||||||
Filters coefficients file to load. If this property is omitted, internal
|
Filters coefficients file to load. If this property is omitted, internal
|
||||||
filters are disabled.
|
filters are disabled.
|
||||||
|
|
|
@ -24,9 +24,14 @@ properties:
|
||||||
const: 0
|
const: 0
|
||||||
|
|
||||||
compatible:
|
compatible:
|
||||||
enum:
|
oneOf:
|
||||||
- microchip,sam9x60-i2smcc
|
- enum:
|
||||||
- microchip,sama7g5-i2smcc
|
- microchip,sam9x60-i2smcc
|
||||||
|
- microchip,sama7g5-i2smcc
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- microchip,sam9x7-i2smcc
|
||||||
|
- const: microchip,sam9x60-i2smcc
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
|
@ -107,7 +107,7 @@ patternProperties:
|
||||||
properties:
|
properties:
|
||||||
sound-dai:
|
sound-dai:
|
||||||
minItems: 1
|
minItems: 1
|
||||||
maxItems: 4
|
maxItems: 8
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- link-name
|
- link-name
|
||||||
|
|
|
@ -15,6 +15,7 @@ description: |
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: dai-common.yaml#
|
- $ref: dai-common.yaml#
|
||||||
|
- $ref: qcom,wcd93xx-common.yaml#
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
@ -22,92 +23,12 @@ properties:
|
||||||
- qcom,wcd9380-codec
|
- qcom,wcd9380-codec
|
||||||
- qcom,wcd9385-codec
|
- qcom,wcd9385-codec
|
||||||
|
|
||||||
reset-gpios:
|
|
||||||
description: GPIO spec for reset line to use
|
|
||||||
maxItems: 1
|
|
||||||
|
|
||||||
us-euro-gpios:
|
us-euro-gpios:
|
||||||
description: GPIO spec for swapping gnd and mic segments
|
description: GPIO spec for swapping gnd and mic segments
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
vdd-buck-supply:
|
|
||||||
description: A reference to the 1.8V buck supply
|
|
||||||
|
|
||||||
vdd-rxtx-supply:
|
|
||||||
description: A reference to the 1.8V rx supply
|
|
||||||
|
|
||||||
vdd-io-supply:
|
|
||||||
description: A reference to the 1.8V I/O supply
|
|
||||||
|
|
||||||
vdd-mic-bias-supply:
|
|
||||||
description: A reference to the 3.8V mic bias supply
|
|
||||||
|
|
||||||
qcom,tx-device:
|
|
||||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
|
||||||
description: A reference to Soundwire tx device phandle
|
|
||||||
|
|
||||||
qcom,rx-device:
|
|
||||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
|
||||||
description: A reference to Soundwire rx device phandle
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
qcom,hphl-jack-type-normally-closed:
|
|
||||||
description: Indicates that HPHL jack switch type is normally closed
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
qcom,ground-jack-type-normally-closed:
|
|
||||||
description: Indicates that Headset Ground switch type is normally closed
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
qcom,mbhc-headset-vthreshold-microvolt:
|
|
||||||
description: Voltage threshold value for headset detection
|
|
||||||
minimum: 0
|
|
||||||
maximum: 2850000
|
|
||||||
|
|
||||||
qcom,mbhc-headphone-vthreshold-microvolt:
|
|
||||||
description: Voltage threshold value for headphone detection
|
|
||||||
minimum: 0
|
|
||||||
maximum: 2850000
|
|
||||||
|
|
||||||
qcom,mbhc-buttons-vthreshold-microvolt:
|
|
||||||
description:
|
|
||||||
Array of 8 Voltage threshold values corresponding to headset
|
|
||||||
button0 - button7
|
|
||||||
minItems: 8
|
|
||||||
maxItems: 8
|
|
||||||
|
|
||||||
'#sound-dai-cells':
|
|
||||||
const: 1
|
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reset-gpios
|
|
||||||
- qcom,tx-device
|
|
||||||
- qcom,rx-device
|
|
||||||
- qcom,micbias1-microvolt
|
|
||||||
- qcom,micbias2-microvolt
|
|
||||||
- qcom,micbias3-microvolt
|
|
||||||
- qcom,micbias4-microvolt
|
|
||||||
- "#sound-dai-cells"
|
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/qcom,wcd939x-sdw.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Qualcomm SoundWire devices on WCD9390/WCD9395
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Qualcomm WCD9390/WCD9395 Codec is a standalone Hi-Fi audio codec IC.
|
||||||
|
It has RX and TX Soundwire devices. This bindings is for the devices.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: sdw20217010e00
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
qcom,tx-port-mapping:
|
||||||
|
description: |
|
||||||
|
Specifies static port mapping between device and host tx ports.
|
||||||
|
In the order of the device port index.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
minItems: 4
|
||||||
|
maxItems: 4
|
||||||
|
|
||||||
|
qcom,rx-port-mapping:
|
||||||
|
description: |
|
||||||
|
Specifies static port mapping between device and host rx ports.
|
||||||
|
In the order of device port index.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
minItems: 6
|
||||||
|
maxItems: 6
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
soundwire@3210000 {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
reg = <0x03210000 0x2000>;
|
||||||
|
wcd938x_rx: codec@0,4 {
|
||||||
|
compatible = "sdw20217010e00";
|
||||||
|
reg = <0 4>;
|
||||||
|
qcom,rx-port-mapping = <1 2 3 4 5 6>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soundwire@3230000 {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
reg = <0x03230000 0x2000>;
|
||||||
|
wcd938x_tx: codec@0,3 {
|
||||||
|
compatible = "sdw20217010e00";
|
||||||
|
reg = <0 3>;
|
||||||
|
qcom,tx-port-mapping = <2 3 4 5>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
|
@ -0,0 +1,96 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/qcom,wcd939x.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Qualcomm WCD9380/WCD9385 Audio Codec
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Qualcomm WCD9390/WCD9395 Codec is a standalone Hi-Fi audio codec IC.
|
||||||
|
It has RX and TX Soundwire devices.
|
||||||
|
The WCD9390/WCD9395 IC has a functionally separate USB-C Mux subsystem
|
||||||
|
accessible over an I2C interface.
|
||||||
|
The Audio Headphone and Microphone data path between the Codec and the USB-C Mux
|
||||||
|
subsystems are external to the IC, thus requiring DT port-endpoint graph description
|
||||||
|
to handle USB-C altmode & orientation switching for Audio Accessory Mode.
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: dai-common.yaml#
|
||||||
|
- $ref: qcom,wcd93xx-common.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- const: qcom,wcd9390-codec
|
||||||
|
- items:
|
||||||
|
- const: qcom,wcd9395-codec
|
||||||
|
- const: qcom,wcd9390-codec
|
||||||
|
|
||||||
|
mode-switch:
|
||||||
|
description: Flag the port as possible handler of altmode switching
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
orientation-switch:
|
||||||
|
description: Flag the port as possible handler of orientation switching
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
port:
|
||||||
|
$ref: /schemas/graph.yaml#/properties/port
|
||||||
|
description:
|
||||||
|
A port node to link the WCD939x Codec node to USB MUX subsystems for the
|
||||||
|
purpose of handling altmode muxing and orientation switching to detect and
|
||||||
|
enable Audio Accessory Mode.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
codec {
|
||||||
|
compatible = "qcom,wcd9390-codec";
|
||||||
|
reset-gpios = <&tlmm 32 IRQ_TYPE_NONE>;
|
||||||
|
#sound-dai-cells = <1>;
|
||||||
|
qcom,tx-device = <&wcd939x_tx>;
|
||||||
|
qcom,rx-device = <&wcd939x_rx>;
|
||||||
|
qcom,micbias1-microvolt = <1800000>;
|
||||||
|
qcom,micbias2-microvolt = <1800000>;
|
||||||
|
qcom,micbias3-microvolt = <1800000>;
|
||||||
|
qcom,micbias4-microvolt = <1800000>;
|
||||||
|
qcom,hphl-jack-type-normally-closed;
|
||||||
|
qcom,ground-jack-type-normally-closed;
|
||||||
|
qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>;
|
||||||
|
qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
soundwire@3210000 {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
reg = <0x03210000 0x2000>;
|
||||||
|
wcd939x_rx: codec@0,4 {
|
||||||
|
compatible = "sdw20217010e00";
|
||||||
|
reg = <0 4>;
|
||||||
|
qcom,rx-port-mapping = <1 2 3 4 5 6>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soundwire@3230000 {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
reg = <0x03230000 0x2000>;
|
||||||
|
wcd938x_tx: codec@0,3 {
|
||||||
|
compatible = "sdw20217010e00";
|
||||||
|
reg = <0 3>;
|
||||||
|
qcom,tx-port-mapping = <2 3 4 5>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
|
@ -0,0 +1,95 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/qcom,wcd93xx-common.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Common properties for Qualcomm WCD93xx Audio Codec
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reset-gpios:
|
||||||
|
description: GPIO spec for reset line to use
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
vdd-buck-supply:
|
||||||
|
description: A reference to the 1.8V buck supply
|
||||||
|
|
||||||
|
vdd-rxtx-supply:
|
||||||
|
description: A reference to the 1.8V rx supply
|
||||||
|
|
||||||
|
vdd-io-supply:
|
||||||
|
description: A reference to the 1.8V I/O supply
|
||||||
|
|
||||||
|
vdd-mic-bias-supply:
|
||||||
|
description: A reference to the 3.8V mic bias supply
|
||||||
|
|
||||||
|
qcom,tx-device:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||||
|
description: A reference to Soundwire tx device phandle
|
||||||
|
|
||||||
|
qcom,rx-device:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||||
|
description: A reference to Soundwire rx device phandle
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
qcom,hphl-jack-type-normally-closed:
|
||||||
|
description: Indicates that HPHL jack switch type is normally closed
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
qcom,ground-jack-type-normally-closed:
|
||||||
|
description: Indicates that Headset Ground switch type is normally closed
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
qcom,mbhc-headset-vthreshold-microvolt:
|
||||||
|
description: Voltage threshold value for headset detection
|
||||||
|
minimum: 0
|
||||||
|
maximum: 2850000
|
||||||
|
|
||||||
|
qcom,mbhc-headphone-vthreshold-microvolt:
|
||||||
|
description: Voltage threshold value for headphone detection
|
||||||
|
minimum: 0
|
||||||
|
maximum: 2850000
|
||||||
|
|
||||||
|
qcom,mbhc-buttons-vthreshold-microvolt:
|
||||||
|
description:
|
||||||
|
Array of 8 Voltage threshold values corresponding to headset
|
||||||
|
button0 - button7
|
||||||
|
minItems: 8
|
||||||
|
maxItems: 8
|
||||||
|
|
||||||
|
'#sound-dai-cells':
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reset-gpios
|
||||||
|
- qcom,tx-device
|
||||||
|
- qcom,rx-device
|
||||||
|
- qcom,micbias1-microvolt
|
||||||
|
- qcom,micbias2-microvolt
|
||||||
|
- qcom,micbias3-microvolt
|
||||||
|
- qcom,micbias4-microvolt
|
||||||
|
- "#sound-dai-cells"
|
||||||
|
|
||||||
|
additionalProperties: true
|
|
@ -28,6 +28,10 @@ properties:
|
||||||
description: Powerdown/Shutdown line to use (pin SD_N)
|
description: Powerdown/Shutdown line to use (pin SD_N)
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
reset-gpios:
|
||||||
|
description: Powerdown/Shutdown line to use (pin SD_N)
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
'#sound-dai-cells':
|
'#sound-dai-cells':
|
||||||
const: 0
|
const: 0
|
||||||
|
|
||||||
|
@ -37,11 +41,16 @@ properties:
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
- powerdown-gpios
|
|
||||||
- '#sound-dai-cells'
|
- '#sound-dai-cells'
|
||||||
- vdd-1p8-supply
|
- vdd-1p8-supply
|
||||||
- vdd-io-supply
|
- vdd-io-supply
|
||||||
|
|
||||||
|
oneOf:
|
||||||
|
- required:
|
||||||
|
- powerdown-gpios
|
||||||
|
- required:
|
||||||
|
- reset-gpios
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/sound/realtek,rt1015.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: RT1015 Mono Class D Audio Amplifier
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Jack Yu <jack.yu@realtek.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- realtek,rt1015
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
realtek,power-up-delay-ms:
|
||||||
|
description: Set a delay time for flush work to be completed,
|
||||||
|
this vlaue is adjustable depending on platform.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
codec@28 {
|
||||||
|
compatible = "realtek,rt1015";
|
||||||
|
reg = <0x28>;
|
||||||
|
realtek,power-up-delay-ms = <50>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,23 +0,0 @@
|
||||||
RT1015 Mono Class D Audio Amplifier
|
|
||||||
|
|
||||||
This device supports I2C only.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible : "realtek,rt1015".
|
|
||||||
|
|
||||||
- reg : The I2C address of the device.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
|
|
||||||
- realtek,power-up-delay-ms
|
|
||||||
Set a delay time for flush work to be completed,
|
|
||||||
this value is adjustable depending on platform.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
rt1015: codec@28 {
|
|
||||||
compatible = "realtek,rt1015";
|
|
||||||
reg = <0x28>;
|
|
||||||
realtek,power-up-delay-ms = <50>;
|
|
||||||
};
|
|
|
@ -25,8 +25,11 @@ properties:
|
||||||
description: Phandles to the codecs.
|
description: Phandles to the codecs.
|
||||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||||
items:
|
items:
|
||||||
- description: Phandle to the WM5110 audio codec.
|
- items:
|
||||||
- description: Phandle to the HDMI transmitter node.
|
- description: Phandle to the WM5110 audio codec.
|
||||||
|
- items:
|
||||||
|
- description: Phandle to the HDMI transmitter node.
|
||||||
|
|
||||||
|
|
||||||
samsung,audio-routing:
|
samsung,audio-routing:
|
||||||
description: |
|
description: |
|
||||||
|
|
|
@ -3864,14 +3864,16 @@ corresponding destructor.
|
||||||
|
|
||||||
And next, set suspend/resume callbacks to the pci_driver::
|
And next, set suspend/resume callbacks to the pci_driver::
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
|
static DEFINE_SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
|
||||||
|
|
||||||
static struct pci_driver driver = {
|
static struct pci_driver driver = {
|
||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = snd_my_ids,
|
.id_table = snd_my_ids,
|
||||||
.probe = snd_my_probe,
|
.probe = snd_my_probe,
|
||||||
.remove = snd_my_remove,
|
.remove = snd_my_remove,
|
||||||
.driver.pm = &snd_my_pm_ops,
|
.driver = {
|
||||||
|
.pm = &snd_my_pm_ops,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Module Parameters
|
Module Parameters
|
||||||
|
|
|
@ -5042,6 +5042,7 @@ F: include/linux/mfd/cs42l43*
|
||||||
F: include/sound/cs*
|
F: include/sound/cs*
|
||||||
F: sound/pci/hda/cirrus*
|
F: sound/pci/hda/cirrus*
|
||||||
F: sound/pci/hda/cs*
|
F: sound/pci/hda/cs*
|
||||||
|
F: sound/pci/hda/hda_component*
|
||||||
F: sound/pci/hda/hda_cs_dsp_ctl.*
|
F: sound/pci/hda/hda_cs_dsp_ctl.*
|
||||||
F: sound/soc/codecs/cs*
|
F: sound/soc/codecs/cs*
|
||||||
|
|
||||||
|
@ -20515,6 +20516,12 @@ F: include/uapi/sound/compress_*
|
||||||
F: sound/core/compress_offload.c
|
F: sound/core/compress_offload.c
|
||||||
F: sound/soc/soc-compress.c
|
F: sound/soc/soc-compress.c
|
||||||
|
|
||||||
|
SOUND - CORE KUNIT TEST
|
||||||
|
M: Ivan Orlov <ivan.orlov0322@gmail.com>
|
||||||
|
L: linux-sound@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
F: sound/core/sound_kunit.c
|
||||||
|
|
||||||
SOUND - DMAENGINE HELPERS
|
SOUND - DMAENGINE HELPERS
|
||||||
M: Lars-Peter Clausen <lars@metafoo.de>
|
M: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|
|
@ -1760,7 +1760,9 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
|
||||||
{"BSG1160", },
|
{"BSG1160", },
|
||||||
{"BSG2150", },
|
{"BSG2150", },
|
||||||
{"CSC3551", },
|
{"CSC3551", },
|
||||||
|
{"CSC3554", },
|
||||||
{"CSC3556", },
|
{"CSC3556", },
|
||||||
|
{"CSC3557", },
|
||||||
{"INT33FE", },
|
{"INT33FE", },
|
||||||
{"INT3515", },
|
{"INT3515", },
|
||||||
/* Non-conforming _HID for Cirrus Logic already released */
|
/* Non-conforming _HID for Cirrus Logic already released */
|
||||||
|
|
|
@ -522,7 +522,7 @@ void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
|
||||||
{
|
{
|
||||||
cs_dsp_debugfs_clear(dsp);
|
cs_dsp_debugfs_clear(dsp);
|
||||||
debugfs_remove_recursive(dsp->debugfs_root);
|
debugfs_remove_recursive(dsp->debugfs_root);
|
||||||
dsp->debugfs_root = NULL;
|
dsp->debugfs_root = ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
|
EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
|
||||||
#else
|
#else
|
||||||
|
@ -2246,6 +2246,11 @@ static int cs_dsp_common_init(struct cs_dsp *dsp)
|
||||||
|
|
||||||
mutex_init(&dsp->pwr_lock);
|
mutex_init(&dsp->pwr_lock);
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
/* Ensure this is invalid if client never provides a debugfs root */
|
||||||
|
dsp->debugfs_root = ERR_PTR(-ENODEV);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,19 @@ static const struct smi_node cs35l41_hda = {
|
||||||
.bus_type = SMI_AUTO_DETECT,
|
.bus_type = SMI_AUTO_DETECT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct smi_node cs35l54_hda = {
|
||||||
|
.instances = {
|
||||||
|
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
/* a 5th entry is an alias address, not a real device */
|
||||||
|
{ "cs35l54-hda_dummy_dev" },
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
.bus_type = SMI_AUTO_DETECT,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct smi_node cs35l56_hda = {
|
static const struct smi_node cs35l56_hda = {
|
||||||
.instances = {
|
.instances = {
|
||||||
{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
|
{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
@ -342,6 +355,19 @@ static const struct smi_node cs35l56_hda = {
|
||||||
.bus_type = SMI_AUTO_DETECT,
|
.bus_type = SMI_AUTO_DETECT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct smi_node cs35l57_hda = {
|
||||||
|
.instances = {
|
||||||
|
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||||
|
/* a 5th entry is an alias address, not a real device */
|
||||||
|
{ "cs35l57-hda_dummy_dev" },
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
.bus_type = SMI_AUTO_DETECT,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note new device-ids must also be added to ignore_serial_bus_ids in
|
* Note new device-ids must also be added to ignore_serial_bus_ids in
|
||||||
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
|
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
|
||||||
|
@ -350,7 +376,9 @@ static const struct acpi_device_id smi_acpi_ids[] = {
|
||||||
{ "BSG1160", (unsigned long)&bsg1160_data },
|
{ "BSG1160", (unsigned long)&bsg1160_data },
|
||||||
{ "BSG2150", (unsigned long)&bsg2150_data },
|
{ "BSG2150", (unsigned long)&bsg2150_data },
|
||||||
{ "CSC3551", (unsigned long)&cs35l41_hda },
|
{ "CSC3551", (unsigned long)&cs35l41_hda },
|
||||||
|
{ "CSC3554", (unsigned long)&cs35l54_hda },
|
||||||
{ "CSC3556", (unsigned long)&cs35l56_hda },
|
{ "CSC3556", (unsigned long)&cs35l56_hda },
|
||||||
|
{ "CSC3557", (unsigned long)&cs35l57_hda },
|
||||||
{ "INT3515", (unsigned long)&int3515_data },
|
{ "INT3515", (unsigned long)&int3515_data },
|
||||||
/* Non-conforming _HID for Cirrus Logic already released */
|
/* Non-conforming _HID for Cirrus Logic already released */
|
||||||
{ "CLSA0100", (unsigned long)&cs35l41_hda },
|
{ "CLSA0100", (unsigned long)&cs35l41_hda },
|
||||||
|
|
|
@ -20,7 +20,7 @@ soundwire-bus-y += irq.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#AMD driver
|
#AMD driver
|
||||||
soundwire-amd-y := amd_manager.o
|
soundwire-amd-y := amd_init.o amd_manager.o
|
||||||
obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o
|
obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o
|
||||||
|
|
||||||
#Cadence Objs
|
#Cadence Objs
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||||
|
/*
|
||||||
|
* SoundWire AMD Manager Initialize routines
|
||||||
|
*
|
||||||
|
* Initializes and creates SDW devices based on ACPI and Hardware values
|
||||||
|
*
|
||||||
|
* Copyright 2024 Advanced Micro Devices, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/export.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include "amd_init.h"
|
||||||
|
|
||||||
|
#define ACP_PAD_PULLDOWN_CTRL 0x0001448
|
||||||
|
#define ACP_SW_PAD_KEEPER_EN 0x0001454
|
||||||
|
#define AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9a
|
||||||
|
#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f
|
||||||
|
#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa
|
||||||
|
#define AMD_SDW0_PAD_EN_MASK 1
|
||||||
|
#define AMD_SDW1_PAD_EN_MASK 0x10
|
||||||
|
#define AMD_SDW_PAD_EN_MASK (AMD_SDW0_PAD_EN_MASK | AMD_SDW1_PAD_EN_MASK)
|
||||||
|
|
||||||
|
static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
u32 pad_keeper_en_mask, pad_pulldown_ctrl_mask;
|
||||||
|
|
||||||
|
switch (link_mask) {
|
||||||
|
case 1:
|
||||||
|
pad_keeper_en_mask = AMD_SDW0_PAD_EN_MASK;
|
||||||
|
pad_pulldown_ctrl_mask = AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pad_keeper_en_mask = AMD_SDW1_PAD_EN_MASK;
|
||||||
|
pad_pulldown_ctrl_mask = AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pad_keeper_en_mask = AMD_SDW_PAD_EN_MASK;
|
||||||
|
pad_pulldown_ctrl_mask = AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev, "No SDW Links are enabled\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = readl(mmio + ACP_SW_PAD_KEEPER_EN);
|
||||||
|
val |= pad_keeper_en_mask;
|
||||||
|
writel(val, mmio + ACP_SW_PAD_KEEPER_EN);
|
||||||
|
val = readl(mmio + ACP_PAD_PULLDOWN_CTRL);
|
||||||
|
val &= pad_pulldown_ctrl_mask;
|
||||||
|
writel(val, mmio + ACP_PAD_PULLDOWN_CTRL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ctx->count; i++) {
|
||||||
|
if (!(ctx->link_mask & BIT(i)))
|
||||||
|
continue;
|
||||||
|
platform_device_unregister(ctx->pdev[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
|
||||||
|
{
|
||||||
|
struct sdw_amd_ctx *ctx;
|
||||||
|
struct acpi_device *adev;
|
||||||
|
struct resource *sdw_res;
|
||||||
|
struct acp_sdw_pdata sdw_pdata[2];
|
||||||
|
struct platform_device_info pdevinfo[2];
|
||||||
|
u32 link_mask;
|
||||||
|
int count, index;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
adev = acpi_fetch_acpi_dev(res->handle);
|
||||||
|
if (!adev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!res->count)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
count = res->count;
|
||||||
|
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
|
||||||
|
ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent);
|
||||||
|
if (ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we need to alloc/free memory manually and can't use devm:
|
||||||
|
* this routine may be called from a workqueue, and not from
|
||||||
|
* the parent .probe.
|
||||||
|
* If devm_ was used, the memory might never be freed on errors.
|
||||||
|
*/
|
||||||
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||||
|
if (!ctx)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ctx->count = count;
|
||||||
|
ctx->link_mask = res->link_mask;
|
||||||
|
sdw_res = kzalloc(sizeof(*sdw_res), GFP_KERNEL);
|
||||||
|
if (!sdw_res) {
|
||||||
|
kfree(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sdw_res->flags = IORESOURCE_MEM;
|
||||||
|
sdw_res->start = res->addr;
|
||||||
|
sdw_res->end = res->addr + res->reg_range;
|
||||||
|
memset(&pdevinfo, 0, sizeof(pdevinfo));
|
||||||
|
link_mask = ctx->link_mask;
|
||||||
|
for (index = 0; index < count; index++) {
|
||||||
|
if (!(link_mask & BIT(index)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sdw_pdata[index].instance = index;
|
||||||
|
sdw_pdata[index].acp_sdw_lock = res->acp_lock;
|
||||||
|
pdevinfo[index].name = "amd_sdw_manager";
|
||||||
|
pdevinfo[index].id = index;
|
||||||
|
pdevinfo[index].parent = res->parent;
|
||||||
|
pdevinfo[index].num_res = 1;
|
||||||
|
pdevinfo[index].res = sdw_res;
|
||||||
|
pdevinfo[index].data = &sdw_pdata[index];
|
||||||
|
pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata);
|
||||||
|
pdevinfo[index].fwnode = acpi_fwnode_handle(adev);
|
||||||
|
ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
|
||||||
|
if (IS_ERR(ctx->pdev[index]))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
kfree(sdw_res);
|
||||||
|
return ctx;
|
||||||
|
err:
|
||||||
|
while (index--) {
|
||||||
|
if (!(link_mask & BIT(index)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
platform_device_unregister(ctx->pdev[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(sdw_res);
|
||||||
|
kfree(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdw_amd_startup(struct sdw_amd_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct amd_sdw_manager *amd_manager;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
/* Startup SDW Manager devices */
|
||||||
|
for (i = 0; i < ctx->count; i++) {
|
||||||
|
if (!(ctx->link_mask & BIT(i)))
|
||||||
|
continue;
|
||||||
|
amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev);
|
||||||
|
ret = amd_sdw_manager_start(amd_manager);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx)
|
||||||
|
{
|
||||||
|
*sdw_ctx = sdw_amd_probe_controller(res);
|
||||||
|
if (!*sdw_ctx)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return sdw_amd_startup(*sdw_ctx);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT);
|
||||||
|
|
||||||
|
void sdw_amd_exit(struct sdw_amd_ctx *ctx)
|
||||||
|
{
|
||||||
|
sdw_amd_cleanup(ctx);
|
||||||
|
kfree(ctx->ids);
|
||||||
|
kfree(ctx);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT);
|
||||||
|
|
||||||
|
int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct amd_sdw_manager *amd_manager;
|
||||||
|
struct sdw_bus *bus;
|
||||||
|
struct sdw_slave *slave;
|
||||||
|
struct list_head *node;
|
||||||
|
int index;
|
||||||
|
int i = 0;
|
||||||
|
int num_slaves = 0;
|
||||||
|
|
||||||
|
for (index = 0; index < ctx->count; index++) {
|
||||||
|
if (!(ctx->link_mask & BIT(index)))
|
||||||
|
continue;
|
||||||
|
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
|
||||||
|
if (!amd_manager)
|
||||||
|
return -ENODEV;
|
||||||
|
bus = &amd_manager->bus;
|
||||||
|
/* Calculate number of slaves */
|
||||||
|
list_for_each(node, &bus->slaves)
|
||||||
|
num_slaves++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
|
||||||
|
if (!ctx->ids)
|
||||||
|
return -ENOMEM;
|
||||||
|
ctx->num_slaves = num_slaves;
|
||||||
|
for (index = 0; index < ctx->count; index++) {
|
||||||
|
if (!(ctx->link_mask & BIT(index)))
|
||||||
|
continue;
|
||||||
|
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
|
||||||
|
if (amd_manager) {
|
||||||
|
bus = &amd_manager->bus;
|
||||||
|
list_for_each_entry(slave, &bus->slaves, node) {
|
||||||
|
ctx->ids[i].id = slave->id;
|
||||||
|
ctx->ids[i].link_id = bus->link_id;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, SOUNDWIRE_AMD_INIT);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
|
||||||
|
MODULE_DESCRIPTION("AMD SoundWire Init Library");
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AMD_INIT_H
|
||||||
|
#define __AMD_INIT_H
|
||||||
|
|
||||||
|
#include <linux/soundwire/sdw_amd.h>
|
||||||
|
|
||||||
|
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,8 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+
|
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||||
/*
|
/*
|
||||||
* SoundWire AMD Manager driver
|
* SoundWire AMD Manager driver
|
||||||
*
|
*
|
||||||
* Copyright 2023 Advanced Micro Devices, Inc.
|
* Copyright 2023-24 Advanced Micro Devices, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
|
@ -19,29 +19,13 @@
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
#include <sound/soc.h>
|
#include <sound/soc.h>
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
|
#include "amd_init.h"
|
||||||
#include "amd_manager.h"
|
#include "amd_manager.h"
|
||||||
|
|
||||||
#define DRV_NAME "amd_sdw_manager"
|
#define DRV_NAME "amd_sdw_manager"
|
||||||
|
|
||||||
#define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus)
|
#define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus)
|
||||||
|
|
||||||
static void amd_enable_sdw_pads(struct amd_sdw_manager *amd_manager)
|
|
||||||
{
|
|
||||||
u32 sw_pad_pulldown_val;
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
mutex_lock(amd_manager->acp_sdw_lock);
|
|
||||||
val = readl(amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN);
|
|
||||||
val |= amd_manager->reg_mask->sw_pad_enable_mask;
|
|
||||||
writel(val, amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN);
|
|
||||||
usleep_range(1000, 1500);
|
|
||||||
|
|
||||||
sw_pad_pulldown_val = readl(amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL);
|
|
||||||
sw_pad_pulldown_val &= amd_manager->reg_mask->sw_pad_pulldown_mask;
|
|
||||||
writel(sw_pad_pulldown_val, amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL);
|
|
||||||
mutex_unlock(amd_manager->acp_sdw_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
|
static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -102,12 +86,11 @@ static int amd_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
|
||||||
|
|
||||||
static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
|
static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
|
||||||
{
|
{
|
||||||
struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask;
|
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
mutex_lock(amd_manager->acp_sdw_lock);
|
mutex_lock(amd_manager->acp_sdw_lock);
|
||||||
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
||||||
val |= reg_mask->acp_sdw_intr_mask;
|
val |= sdw_manager_reg_mask_array[amd_manager->instance];
|
||||||
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
||||||
mutex_unlock(amd_manager->acp_sdw_lock);
|
mutex_unlock(amd_manager->acp_sdw_lock);
|
||||||
|
|
||||||
|
@ -120,12 +103,11 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
|
||||||
|
|
||||||
static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
|
static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
|
||||||
{
|
{
|
||||||
struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask;
|
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
mutex_lock(amd_manager->acp_sdw_lock);
|
mutex_lock(amd_manager->acp_sdw_lock);
|
||||||
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
||||||
val &= ~reg_mask->acp_sdw_intr_mask;
|
val &= ~sdw_manager_reg_mask_array[amd_manager->instance];
|
||||||
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
|
||||||
mutex_unlock(amd_manager->acp_sdw_lock);
|
mutex_unlock(amd_manager->acp_sdw_lock);
|
||||||
|
|
||||||
|
@ -864,23 +846,20 @@ static void amd_sdw_irq_thread(struct work_struct *work)
|
||||||
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7);
|
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amd_sdw_probe_work(struct work_struct *work)
|
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
|
||||||
{
|
{
|
||||||
struct amd_sdw_manager *amd_manager = container_of(work, struct amd_sdw_manager,
|
|
||||||
probe_work);
|
|
||||||
struct sdw_master_prop *prop;
|
struct sdw_master_prop *prop;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
prop = &amd_manager->bus.prop;
|
prop = &amd_manager->bus.prop;
|
||||||
if (!prop->hw_disabled) {
|
if (!prop->hw_disabled) {
|
||||||
amd_enable_sdw_pads(amd_manager);
|
|
||||||
ret = amd_init_sdw_manager(amd_manager);
|
ret = amd_init_sdw_manager(amd_manager);
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return ret;
|
||||||
amd_enable_sdw_interrupts(amd_manager);
|
amd_enable_sdw_interrupts(amd_manager);
|
||||||
ret = amd_enable_sdw_manager(amd_manager);
|
ret = amd_enable_sdw_manager(amd_manager);
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return ret;
|
||||||
amd_sdw_set_frameshape(amd_manager);
|
amd_sdw_set_frameshape(amd_manager);
|
||||||
}
|
}
|
||||||
/* Enable runtime PM */
|
/* Enable runtime PM */
|
||||||
|
@ -889,6 +868,7 @@ static void amd_sdw_probe_work(struct work_struct *work)
|
||||||
pm_runtime_mark_last_busy(amd_manager->dev);
|
pm_runtime_mark_last_busy(amd_manager->dev);
|
||||||
pm_runtime_set_active(amd_manager->dev);
|
pm_runtime_set_active(amd_manager->dev);
|
||||||
pm_runtime_enable(amd_manager->dev);
|
pm_runtime_enable(amd_manager->dev);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int amd_sdw_manager_probe(struct platform_device *pdev)
|
static int amd_sdw_manager_probe(struct platform_device *pdev)
|
||||||
|
@ -948,7 +928,6 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
amd_manager->reg_mask = &sdw_manager_reg_mask_array[amd_manager->instance];
|
|
||||||
params = &amd_manager->bus.params;
|
params = &amd_manager->bus.params;
|
||||||
|
|
||||||
params->col = AMD_SDW_DEFAULT_COLUMNS;
|
params->col = AMD_SDW_DEFAULT_COLUMNS;
|
||||||
|
@ -972,11 +951,6 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
|
||||||
dev_set_drvdata(dev, amd_manager);
|
dev_set_drvdata(dev, amd_manager);
|
||||||
INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread);
|
INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread);
|
||||||
INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
|
INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
|
||||||
INIT_WORK(&amd_manager->probe_work, amd_sdw_probe_work);
|
|
||||||
/*
|
|
||||||
* Instead of having lengthy probe sequence, use deferred probe.
|
|
||||||
*/
|
|
||||||
schedule_work(&amd_manager->probe_work);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,7 +960,6 @@ static void amd_sdw_manager_remove(struct platform_device *pdev)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
cancel_work_sync(&amd_manager->probe_work);
|
|
||||||
amd_disable_sdw_interrupts(amd_manager);
|
amd_disable_sdw_interrupts(amd_manager);
|
||||||
sdw_bus_master_delete(&amd_manager->bus);
|
sdw_bus_master_delete(&amd_manager->bus);
|
||||||
ret = amd_disable_sdw_manager(amd_manager);
|
ret = amd_disable_sdw_manager(amd_manager);
|
||||||
|
@ -1215,5 +1188,5 @@ module_platform_driver(amd_sdw_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
|
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
|
||||||
MODULE_DESCRIPTION("AMD SoundWire driver");
|
MODULE_DESCRIPTION("AMD SoundWire driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
MODULE_ALIAS("platform:" DRV_NAME);
|
MODULE_ALIAS("platform:" DRV_NAME);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
* Copyright (C) 2023-24 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AMD_MANAGER_H
|
#ifndef __AMD_MANAGER_H
|
||||||
|
@ -243,16 +243,8 @@ static struct sdw_manager_dp_reg sdw1_manager_dp_reg[AMD_SDW1_MAX_DAI] = {
|
||||||
ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0}
|
ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sdw_manager_reg_mask sdw_manager_reg_mask_array[2] = {
|
static u32 sdw_manager_reg_mask_array[AMD_SDW_MAX_MANAGER_COUNT] = {
|
||||||
{
|
AMD_SDW0_EXT_INTR_MASK,
|
||||||
AMD_SDW0_PAD_KEEPER_EN_MASK,
|
|
||||||
AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK,
|
|
||||||
AMD_SDW0_EXT_INTR_MASK
|
|
||||||
},
|
|
||||||
{
|
|
||||||
AMD_SDW1_PAD_KEEPER_EN_MASK,
|
|
||||||
AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK,
|
|
||||||
AMD_SDW1_EXT_INTR_MASK
|
AMD_SDW1_EXT_INTR_MASK
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -130,6 +130,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
|
||||||
},
|
},
|
||||||
.driver_data = (void *)intel_rooks_county,
|
.driver_data = (void *)intel_rooks_county,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/* quirk used for NUC15 LAPRC710 skew */
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
|
||||||
|
},
|
||||||
|
.driver_data = (void *)intel_rooks_county,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.matches = {
|
.matches = {
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||||
|
|
|
@ -123,7 +123,6 @@ struct cs_dsp_client_ops;
|
||||||
* @sysclk_mask: Mask of frequency bits within sysclk register (ADSP1 only)
|
* @sysclk_mask: Mask of frequency bits within sysclk register (ADSP1 only)
|
||||||
* @sysclk_shift: Shift of frequency bits within sysclk register (ADSP1 only)
|
* @sysclk_shift: Shift of frequency bits within sysclk register (ADSP1 only)
|
||||||
* @alg_regions: List of currently loaded algorithm regions
|
* @alg_regions: List of currently loaded algorithm regions
|
||||||
* @fw_file_name: Filename of the current firmware
|
|
||||||
* @fw_name: Name of the current firmware
|
* @fw_name: Name of the current firmware
|
||||||
* @fw_id: ID of the current firmware, obtained from the wmfw
|
* @fw_id: ID of the current firmware, obtained from the wmfw
|
||||||
* @fw_id_version: Version of the firmware, obtained from the wmfw
|
* @fw_id_version: Version of the firmware, obtained from the wmfw
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
* Copyright (C) 2023-24 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __SDW_AMD_H
|
#ifndef __SDW_AMD_H
|
||||||
#define __SDW_AMD_H
|
#define __SDW_AMD_H
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/soundwire/sdw.h>
|
#include <linux/soundwire/sdw.h>
|
||||||
|
|
||||||
/* AMD pm_runtime quirk definitions */
|
/* AMD pm_runtime quirk definitions */
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
#define AMD_SDW_POWER_OFF_MODE 2
|
#define AMD_SDW_POWER_OFF_MODE 2
|
||||||
#define ACP_SDW0 0
|
#define ACP_SDW0 0
|
||||||
#define ACP_SDW1 1
|
#define ACP_SDW1 1
|
||||||
|
#define AMD_SDW_MAX_MANAGER_COUNT 2
|
||||||
|
|
||||||
struct acp_sdw_pdata {
|
struct acp_sdw_pdata {
|
||||||
u16 instance;
|
u16 instance;
|
||||||
|
@ -32,12 +34,6 @@ struct acp_sdw_pdata {
|
||||||
struct mutex *acp_sdw_lock;
|
struct mutex *acp_sdw_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sdw_manager_reg_mask {
|
|
||||||
u32 sw_pad_enable_mask;
|
|
||||||
u32 sw_pad_pulldown_mask;
|
|
||||||
u32 acp_sdw_intr_mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct sdw_amd_dai_runtime: AMD sdw dai runtime data
|
* struct sdw_amd_dai_runtime: AMD sdw dai runtime data
|
||||||
*
|
*
|
||||||
|
@ -59,10 +55,8 @@ struct sdw_amd_dai_runtime {
|
||||||
* @dev: linux device
|
* @dev: linux device
|
||||||
* @mmio: SoundWire registers mmio base
|
* @mmio: SoundWire registers mmio base
|
||||||
* @acp_mmio: acp registers mmio base
|
* @acp_mmio: acp registers mmio base
|
||||||
* @reg_mask: register mask structure per manager instance
|
|
||||||
* @amd_sdw_irq_thread: SoundWire manager irq workqueue
|
* @amd_sdw_irq_thread: SoundWire manager irq workqueue
|
||||||
* @amd_sdw_work: peripheral status work queue
|
* @amd_sdw_work: peripheral status work queue
|
||||||
* @probe_work: SoundWire manager probe workqueue
|
|
||||||
* @acp_sdw_lock: mutex to protect acp share register access
|
* @acp_sdw_lock: mutex to protect acp share register access
|
||||||
* @status: peripheral devices status array
|
* @status: peripheral devices status array
|
||||||
* @num_din_ports: number of input ports
|
* @num_din_ports: number of input ports
|
||||||
|
@ -83,10 +77,8 @@ struct amd_sdw_manager {
|
||||||
void __iomem *mmio;
|
void __iomem *mmio;
|
||||||
void __iomem *acp_mmio;
|
void __iomem *acp_mmio;
|
||||||
|
|
||||||
struct sdw_manager_reg_mask *reg_mask;
|
|
||||||
struct work_struct amd_sdw_irq_thread;
|
struct work_struct amd_sdw_irq_thread;
|
||||||
struct work_struct amd_sdw_work;
|
struct work_struct amd_sdw_work;
|
||||||
struct work_struct probe_work;
|
|
||||||
/* mutex to protect acp common register access */
|
/* mutex to protect acp common register access */
|
||||||
struct mutex *acp_sdw_lock;
|
struct mutex *acp_sdw_lock;
|
||||||
|
|
||||||
|
@ -106,4 +98,71 @@ struct amd_sdw_manager {
|
||||||
|
|
||||||
struct sdw_amd_dai_runtime **dai_runtime_array;
|
struct sdw_amd_dai_runtime **dai_runtime_array;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sdw_amd_acpi_info - Soundwire AMD information found in ACPI tables
|
||||||
|
* @handle: ACPI controller handle
|
||||||
|
* @count: maximum no of soundwire manager links supported on AMD platform.
|
||||||
|
* @link_mask: bit-wise mask listing links enabled by BIOS menu
|
||||||
|
*/
|
||||||
|
struct sdw_amd_acpi_info {
|
||||||
|
acpi_handle handle;
|
||||||
|
int count;
|
||||||
|
u32 link_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sdw_amd_ctx - context allocated by the controller driver probe
|
||||||
|
*
|
||||||
|
* @count: link count
|
||||||
|
* @num_slaves: total number of devices exposed across all enabled links
|
||||||
|
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
||||||
|
* Controller
|
||||||
|
* @ids: array of slave_id, representing Slaves exposed across all enabled
|
||||||
|
* links
|
||||||
|
* @pdev: platform device structure
|
||||||
|
*/
|
||||||
|
struct sdw_amd_ctx {
|
||||||
|
int count;
|
||||||
|
int num_slaves;
|
||||||
|
u32 link_mask;
|
||||||
|
struct sdw_extended_slave_id *ids;
|
||||||
|
struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sdw_amd_res - Soundwire AMD global resource structure,
|
||||||
|
* typically populated by the DSP driver/Legacy driver
|
||||||
|
*
|
||||||
|
* @addr: acp pci device resource start address
|
||||||
|
* @reg_range: ACP register range
|
||||||
|
* @link_mask: bit-wise mask listing links selected by the DSP driver/
|
||||||
|
* legacy driver
|
||||||
|
* @count: link count
|
||||||
|
* @mmio_base: mmio base of SoundWire registers
|
||||||
|
* @handle: ACPI parent handle
|
||||||
|
* @parent: parent device
|
||||||
|
* @dev: device implementing hwparams and free callbacks
|
||||||
|
* @acp_lock: mutex protecting acp common registers access
|
||||||
|
*/
|
||||||
|
struct sdw_amd_res {
|
||||||
|
u32 addr;
|
||||||
|
u32 reg_range;
|
||||||
|
u32 link_mask;
|
||||||
|
int count;
|
||||||
|
void __iomem *mmio_base;
|
||||||
|
acpi_handle handle;
|
||||||
|
struct device *parent;
|
||||||
|
struct device *dev;
|
||||||
|
/* use to protect acp common registers access */
|
||||||
|
struct mutex *acp_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **ctx);
|
||||||
|
|
||||||
|
void sdw_amd_exit(struct sdw_amd_ctx *ctx);
|
||||||
|
|
||||||
|
int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx);
|
||||||
|
|
||||||
|
int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -420,8 +420,6 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
|
||||||
* @bus_lock_spinlock: spinlock for SPI bus locking
|
* @bus_lock_spinlock: spinlock for SPI bus locking
|
||||||
* @bus_lock_mutex: mutex for exclusion of multiple callers
|
* @bus_lock_mutex: mutex for exclusion of multiple callers
|
||||||
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
|
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
|
||||||
* @multi_cs_cap: indicates that the SPI Controller can assert/de-assert
|
|
||||||
* more than one chip select at once.
|
|
||||||
* @setup: updates the device mode and clocking records used by a
|
* @setup: updates the device mode and clocking records used by a
|
||||||
* device's SPI controller; protocol code may call this. This
|
* device's SPI controller; protocol code may call this. This
|
||||||
* must fail if an unrecognized or unsupported mode is requested.
|
* must fail if an unrecognized or unsupported mode is requested.
|
||||||
|
|
|
@ -65,6 +65,9 @@ int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void snd_ak4531_suspend(struct snd_ak4531 *ak4531);
|
void snd_ak4531_suspend(struct snd_ak4531 *ak4531);
|
||||||
void snd_ak4531_resume(struct snd_ak4531 *ak4531);
|
void snd_ak4531_resume(struct snd_ak4531 *ak4531);
|
||||||
|
#else
|
||||||
|
static inline void snd_ak4531_suspend(struct snd_ak4531 *ak4531) {}
|
||||||
|
static inline void snd_ak4531_resume(struct snd_ak4531 *ak4531) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __SOUND_AK4531_CODEC_H */
|
#endif /* __SOUND_AK4531_CODEC_H */
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Cirrus Logic, Inc. and
|
||||||
|
* Cirrus Logic International Semiconductor Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CS_AMP_LIB_H
|
||||||
|
#define CS_AMP_LIB_H
|
||||||
|
|
||||||
|
#include <linux/efi.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct cs_dsp;
|
||||||
|
|
||||||
|
struct cirrus_amp_cal_data {
|
||||||
|
u32 calTarget[2];
|
||||||
|
u32 calTime[2];
|
||||||
|
s8 calAmbient;
|
||||||
|
u8 calStatus;
|
||||||
|
u16 calR;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct cirrus_amp_efi_data {
|
||||||
|
u32 size;
|
||||||
|
u32 count;
|
||||||
|
struct cirrus_amp_cal_data data[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cirrus_amp_cal_controls - definition of firmware calibration controls
|
||||||
|
* @alg_id: ID of algorithm containing the controls.
|
||||||
|
* @mem_region: DSP memory region containing the controls.
|
||||||
|
* @ambient: Name of control for calAmbient value.
|
||||||
|
* @calr: Name of control for calR value.
|
||||||
|
* @status: Name of control for calStatus value.
|
||||||
|
* @checksum: Name of control for checksum value.
|
||||||
|
*/
|
||||||
|
struct cirrus_amp_cal_controls {
|
||||||
|
unsigned int alg_id;
|
||||||
|
int mem_region;
|
||||||
|
const char *ambient;
|
||||||
|
const char *calr;
|
||||||
|
const char *status;
|
||||||
|
const char *checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
|
||||||
|
const struct cirrus_amp_cal_controls *controls,
|
||||||
|
const struct cirrus_amp_cal_data *data);
|
||||||
|
int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
|
||||||
|
struct cirrus_amp_cal_data *out_data);
|
||||||
|
|
||||||
|
struct cs_amp_test_hooks {
|
||||||
|
efi_status_t (*get_efi_variable)(efi_char16_t *name,
|
||||||
|
efi_guid_t *guid,
|
||||||
|
unsigned long *size,
|
||||||
|
void *buf);
|
||||||
|
|
||||||
|
int (*write_cal_coeff)(struct cs_dsp *dsp,
|
||||||
|
const struct cirrus_amp_cal_controls *controls,
|
||||||
|
const char *ctl_name, u32 val);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct cs_amp_test_hooks * const cs_amp_test_hooks;
|
||||||
|
|
||||||
|
#endif /* CS_AMP_LIB_H */
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
#include <sound/cs-amp-lib.h>
|
||||||
|
|
||||||
#define CS35L56_DEVID 0x0000000
|
#define CS35L56_DEVID 0x0000000
|
||||||
#define CS35L56_REVID 0x0000004
|
#define CS35L56_REVID 0x0000004
|
||||||
|
@ -23,6 +24,9 @@
|
||||||
#define CS35L56_BLOCK_ENABLES2 0x000201C
|
#define CS35L56_BLOCK_ENABLES2 0x000201C
|
||||||
#define CS35L56_REFCLK_INPUT 0x0002C04
|
#define CS35L56_REFCLK_INPUT 0x0002C04
|
||||||
#define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C
|
#define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C
|
||||||
|
#define CS35L56_OTP_MEM_53 0x00300D4
|
||||||
|
#define CS35L56_OTP_MEM_54 0x00300D8
|
||||||
|
#define CS35L56_OTP_MEM_55 0x00300DC
|
||||||
#define CS35L56_ASP1_ENABLES1 0x0004800
|
#define CS35L56_ASP1_ENABLES1 0x0004800
|
||||||
#define CS35L56_ASP1_CONTROL1 0x0004804
|
#define CS35L56_ASP1_CONTROL1 0x0004804
|
||||||
#define CS35L56_ASP1_CONTROL2 0x0004808
|
#define CS35L56_ASP1_CONTROL2 0x0004808
|
||||||
|
@ -257,11 +261,15 @@ struct cs35l56_base {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
int irq;
|
int irq;
|
||||||
struct mutex irq_lock;
|
struct mutex irq_lock;
|
||||||
|
u8 type;
|
||||||
u8 rev;
|
u8 rev;
|
||||||
bool init_done;
|
bool init_done;
|
||||||
bool fw_patched;
|
bool fw_patched;
|
||||||
bool secured;
|
bool secured;
|
||||||
bool can_hibernate;
|
bool can_hibernate;
|
||||||
|
bool cal_data_valid;
|
||||||
|
s8 cal_index;
|
||||||
|
struct cirrus_amp_cal_data cal_data;
|
||||||
struct gpio_desc *reset_gpio;
|
struct gpio_desc *reset_gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,6 +277,8 @@ extern struct regmap_config cs35l56_regmap_i2c;
|
||||||
extern struct regmap_config cs35l56_regmap_spi;
|
extern struct regmap_config cs35l56_regmap_spi;
|
||||||
extern struct regmap_config cs35l56_regmap_sdw;
|
extern struct regmap_config cs35l56_regmap_sdw;
|
||||||
|
|
||||||
|
extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls;
|
||||||
|
|
||||||
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
|
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
|
||||||
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
|
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
|
||||||
|
|
||||||
|
@ -286,6 +296,7 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
|
||||||
int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
|
int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
|
||||||
int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
|
int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
|
||||||
void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
|
void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
|
||||||
|
int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base);
|
||||||
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
|
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
|
||||||
bool *fw_missing, unsigned int *fw_version);
|
bool *fw_missing, unsigned int *fw_version);
|
||||||
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
|
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
|
||||||
|
|
|
@ -809,8 +809,7 @@
|
||||||
#define CS42L42_PLL_LOCK_TIMEOUT_US 1250
|
#define CS42L42_PLL_LOCK_TIMEOUT_US 1250
|
||||||
#define CS42L42_HP_ADC_EN_TIME_US 20000
|
#define CS42L42_HP_ADC_EN_TIME_US 20000
|
||||||
#define CS42L42_PDN_DONE_POLL_US 1000
|
#define CS42L42_PDN_DONE_POLL_US 1000
|
||||||
#define CS42L42_PDN_DONE_TIMEOUT_US 200000
|
#define CS42L42_PDN_DONE_TIMEOUT_US 235000
|
||||||
#define CS42L42_PDN_DONE_TIME_MS 100
|
#define CS42L42_PDN_DONE_TIME_MS 65
|
||||||
#define CS42L42_FILT_DISCHARGE_TIME_MS 46
|
|
||||||
|
|
||||||
#endif /* __CS42L42_H */
|
#endif /* __CS42L42_H */
|
||||||
|
|
|
@ -103,7 +103,7 @@ struct snd_emux {
|
||||||
int ports[SNDRV_EMUX_MAX_PORTS]; /* The ports for this device */
|
int ports[SNDRV_EMUX_MAX_PORTS]; /* The ports for this device */
|
||||||
struct snd_emux_port *portptrs[SNDRV_EMUX_MAX_PORTS];
|
struct snd_emux_port *portptrs[SNDRV_EMUX_MAX_PORTS];
|
||||||
int used; /* use counter */
|
int used; /* use counter */
|
||||||
char *name; /* name of the device (internal) */
|
const char *name; /* name of the device (internal) */
|
||||||
struct snd_rawmidi **vmidi;
|
struct snd_rawmidi **vmidi;
|
||||||
struct timer_list tlist; /* for pending note-offs */
|
struct timer_list tlist; /* for pending note-offs */
|
||||||
int timer_active;
|
int timer_active;
|
||||||
|
|
|
@ -181,4 +181,4 @@ hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enabl
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_SOC_SOF_HDA */
|
#endif /* CONFIG_SND_SOC_SOF_HDA_MLINK */
|
||||||
|
|
|
@ -131,6 +131,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
||||||
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
|
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
|
||||||
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
|
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
|
||||||
|
|
||||||
|
#define AZX_REG_VS_LTRP_GB_MASK GENMASK(6, 0)
|
||||||
|
|
||||||
/* PCI space */
|
/* PCI space */
|
||||||
#define AZX_PCIREG_TCSEL 0x44
|
#define AZX_PCIREG_TCSEL 0x44
|
||||||
|
|
||||||
|
|
|
@ -659,6 +659,18 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
|
||||||
flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
|
flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/* definitions for guard(); use like guard(pcm_stream_lock) */
|
||||||
|
DEFINE_LOCK_GUARD_1(pcm_stream_lock, struct snd_pcm_substream,
|
||||||
|
snd_pcm_stream_lock(_T->lock),
|
||||||
|
snd_pcm_stream_unlock(_T->lock))
|
||||||
|
DEFINE_LOCK_GUARD_1(pcm_stream_lock_irq, struct snd_pcm_substream,
|
||||||
|
snd_pcm_stream_lock_irq(_T->lock),
|
||||||
|
snd_pcm_stream_unlock_irq(_T->lock))
|
||||||
|
DEFINE_LOCK_GUARD_1(pcm_stream_lock_irqsave, struct snd_pcm_substream,
|
||||||
|
snd_pcm_stream_lock_irqsave(_T->lock, _T->flags),
|
||||||
|
snd_pcm_stream_unlock_irqrestore(_T->lock, _T->flags),
|
||||||
|
unsigned long flags)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_pcm_group_for_each_entry - iterate over the linked substreams
|
* snd_pcm_group_for_each_entry - iterate over the linked substreams
|
||||||
* @s: the iterator
|
* @s: the iterator
|
||||||
|
|
|
@ -290,6 +290,9 @@ int snd_sbmixer_new(struct snd_sb *chip);
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void snd_sbmixer_suspend(struct snd_sb *chip);
|
void snd_sbmixer_suspend(struct snd_sb *chip);
|
||||||
void snd_sbmixer_resume(struct snd_sb *chip);
|
void snd_sbmixer_resume(struct snd_sb *chip);
|
||||||
|
#else
|
||||||
|
static inline void snd_sbmixer_suspend(struct snd_sb *chip) {}
|
||||||
|
static inline void snd_sbmixer_resume(struct snd_sb *chip) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sb8_init.c */
|
/* sb8_init.c */
|
||||||
|
|
|
@ -1401,8 +1401,8 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
|
||||||
void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
|
void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
|
||||||
struct snd_soc_dai_link_component *cpus);
|
struct snd_soc_dai_link_component *cpus);
|
||||||
struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
|
struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
|
||||||
struct of_phandle_args *args);
|
const struct of_phandle_args *args);
|
||||||
struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args);
|
struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_args);
|
||||||
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,
|
||||||
bool legacy_dai_naming);
|
bool legacy_dai_naming);
|
||||||
|
|
|
@ -26,4 +26,11 @@ struct sof_ipc_dai_acpdmic_params {
|
||||||
uint32_t pdm_ch;
|
uint32_t pdm_ch;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* ACP_SDW Configuration Request - SOF_IPC_DAI_AMD_SDW_CONFIG */
|
||||||
|
struct sof_ipc_dai_acp_sdw_params {
|
||||||
|
struct sof_ipc_hdr hdr;
|
||||||
|
u32 rate;
|
||||||
|
u32 channels;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -89,6 +89,7 @@ enum sof_ipc_dai_type {
|
||||||
SOF_DAI_AMD_SP_VIRTUAL, /**< AMD ACP SP VIRTUAL */
|
SOF_DAI_AMD_SP_VIRTUAL, /**< AMD ACP SP VIRTUAL */
|
||||||
SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
|
SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
|
||||||
SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */
|
SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */
|
||||||
|
SOF_DAI_AMD_SDW, /**< AMD ACP SDW */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* general purpose DAI configuration */
|
/* general purpose DAI configuration */
|
||||||
|
@ -119,6 +120,7 @@ struct sof_ipc_dai_config {
|
||||||
struct sof_ipc_dai_acp_params acphs;
|
struct sof_ipc_dai_acp_params acphs;
|
||||||
struct sof_ipc_dai_mtk_afe_params afe;
|
struct sof_ipc_dai_mtk_afe_params afe;
|
||||||
struct sof_ipc_dai_micfil_params micfil;
|
struct sof_ipc_dai_micfil_params micfil;
|
||||||
|
struct sof_ipc_dai_acp_sdw_params acp_sdw;
|
||||||
};
|
};
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,6 @@ struct tasdevice_priv {
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
enum device_catlog_id catlog_id;
|
enum device_catlog_id catlog_id;
|
||||||
const char *acpi_subsystem_id;
|
|
||||||
unsigned char cal_binaryname[TASDEVICE_MAX_CHANNELS][64];
|
unsigned char cal_binaryname[TASDEVICE_MAX_CHANNELS][64];
|
||||||
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
|
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
|
||||||
unsigned char coef_binaryname[64];
|
unsigned char coef_binaryname[64];
|
||||||
|
|
|
@ -17,71 +17,76 @@ struct snd_soc_card;
|
||||||
struct snd_soc_dapm_widget;
|
struct snd_soc_dapm_widget;
|
||||||
struct snd_soc_dapm_path;
|
struct snd_soc_dapm_path;
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(snd_soc_card,
|
DECLARE_EVENT_CLASS(snd_soc_dapm,
|
||||||
|
|
||||||
TP_PROTO(struct snd_soc_card *card, int val),
|
TP_PROTO(struct snd_soc_dapm_context *dapm, int val),
|
||||||
|
|
||||||
TP_ARGS(card, val),
|
TP_ARGS(dapm, val),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__string( name, card->name )
|
__string( card_name, dapm->card->name)
|
||||||
__field( int, val )
|
__string( comp_name, dapm->component ? dapm->component->name : "(none)")
|
||||||
|
__field( int, val)
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__assign_str(name, card->name);
|
__assign_str(card_name, dapm->card->name);
|
||||||
|
__assign_str(comp_name, dapm->component ? dapm->component->name : "(none)");
|
||||||
__entry->val = val;
|
__entry->val = val;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("card=%s val=%d", __get_str(name), (int)__entry->val)
|
TP_printk("card=%s component=%s val=%d",
|
||||||
|
__get_str(card_name), __get_str(comp_name), (int)__entry->val)
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_start,
|
DEFINE_EVENT(snd_soc_dapm, snd_soc_bias_level_start,
|
||||||
|
|
||||||
TP_PROTO(struct snd_soc_card *card, int val),
|
TP_PROTO(struct snd_soc_dapm_context *dapm, int val),
|
||||||
|
|
||||||
TP_ARGS(card, val)
|
TP_ARGS(dapm, val)
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_done,
|
DEFINE_EVENT(snd_soc_dapm, snd_soc_bias_level_done,
|
||||||
|
|
||||||
TP_PROTO(struct snd_soc_card *card, int val),
|
TP_PROTO(struct snd_soc_dapm_context *dapm, int val),
|
||||||
|
|
||||||
TP_ARGS(card, val)
|
TP_ARGS(dapm, val)
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(snd_soc_dapm_basic,
|
DECLARE_EVENT_CLASS(snd_soc_dapm_basic,
|
||||||
|
|
||||||
TP_PROTO(struct snd_soc_card *card),
|
TP_PROTO(struct snd_soc_card *card, int event),
|
||||||
|
|
||||||
TP_ARGS(card),
|
TP_ARGS(card, event),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__string( name, card->name )
|
__string( name, card->name )
|
||||||
|
__field( int, event )
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__assign_str(name, card->name);
|
__assign_str(name, card->name);
|
||||||
|
__entry->event = event;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("card=%s", __get_str(name))
|
TP_printk("card=%s event=%d", __get_str(name), (int)__entry->event)
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_start,
|
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_start,
|
||||||
|
|
||||||
TP_PROTO(struct snd_soc_card *card),
|
TP_PROTO(struct snd_soc_card *card, int event),
|
||||||
|
|
||||||
TP_ARGS(card)
|
TP_ARGS(card, event)
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_done,
|
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_done,
|
||||||
|
|
||||||
TP_PROTO(struct snd_soc_card *card),
|
TP_PROTO(struct snd_soc_card *card, int event),
|
||||||
|
|
||||||
TP_ARGS(card)
|
TP_ARGS(card, event)
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
|
|
||||||
#include <linux/virtio_types.h>
|
#include <linux/virtio_types.h>
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* FEATURE BITS
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
/* device supports control elements */
|
||||||
|
VIRTIO_SND_F_CTLS = 0
|
||||||
|
};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* CONFIGURATION SPACE
|
* CONFIGURATION SPACE
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +25,8 @@ struct virtio_snd_config {
|
||||||
__le32 streams;
|
__le32 streams;
|
||||||
/* # of available channel maps */
|
/* # of available channel maps */
|
||||||
__le32 chmaps;
|
__le32 chmaps;
|
||||||
|
/* # of available control elements */
|
||||||
|
__le32 controls;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -55,6 +65,15 @@ enum {
|
||||||
/* channel map control request types */
|
/* channel map control request types */
|
||||||
VIRTIO_SND_R_CHMAP_INFO = 0x0200,
|
VIRTIO_SND_R_CHMAP_INFO = 0x0200,
|
||||||
|
|
||||||
|
/* control element request types */
|
||||||
|
VIRTIO_SND_R_CTL_INFO = 0x0300,
|
||||||
|
VIRTIO_SND_R_CTL_ENUM_ITEMS,
|
||||||
|
VIRTIO_SND_R_CTL_READ,
|
||||||
|
VIRTIO_SND_R_CTL_WRITE,
|
||||||
|
VIRTIO_SND_R_CTL_TLV_READ,
|
||||||
|
VIRTIO_SND_R_CTL_TLV_WRITE,
|
||||||
|
VIRTIO_SND_R_CTL_TLV_COMMAND,
|
||||||
|
|
||||||
/* jack event types */
|
/* jack event types */
|
||||||
VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
|
VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
|
||||||
VIRTIO_SND_EVT_JACK_DISCONNECTED,
|
VIRTIO_SND_EVT_JACK_DISCONNECTED,
|
||||||
|
@ -63,6 +82,9 @@ enum {
|
||||||
VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
|
VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
|
||||||
VIRTIO_SND_EVT_PCM_XRUN,
|
VIRTIO_SND_EVT_PCM_XRUN,
|
||||||
|
|
||||||
|
/* control element event types */
|
||||||
|
VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
|
||||||
|
|
||||||
/* common status codes */
|
/* common status codes */
|
||||||
VIRTIO_SND_S_OK = 0x8000,
|
VIRTIO_SND_S_OK = 0x8000,
|
||||||
VIRTIO_SND_S_BAD_MSG,
|
VIRTIO_SND_S_BAD_MSG,
|
||||||
|
@ -331,4 +353,136 @@ struct virtio_snd_chmap_info {
|
||||||
__u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE];
|
__u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* CONTROL ELEMENTS MESSAGES
|
||||||
|
*/
|
||||||
|
struct virtio_snd_ctl_hdr {
|
||||||
|
/* VIRTIO_SND_R_CTL_XXX */
|
||||||
|
struct virtio_snd_hdr hdr;
|
||||||
|
/* 0 ... virtio_snd_config::controls - 1 */
|
||||||
|
__le32 control_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* supported roles for control elements */
|
||||||
|
enum {
|
||||||
|
VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
|
||||||
|
VIRTIO_SND_CTL_ROLE_VOLUME,
|
||||||
|
VIRTIO_SND_CTL_ROLE_MUTE,
|
||||||
|
VIRTIO_SND_CTL_ROLE_GAIN
|
||||||
|
};
|
||||||
|
|
||||||
|
/* supported value types for control elements */
|
||||||
|
enum {
|
||||||
|
VIRTIO_SND_CTL_TYPE_BOOLEAN = 0,
|
||||||
|
VIRTIO_SND_CTL_TYPE_INTEGER,
|
||||||
|
VIRTIO_SND_CTL_TYPE_INTEGER64,
|
||||||
|
VIRTIO_SND_CTL_TYPE_ENUMERATED,
|
||||||
|
VIRTIO_SND_CTL_TYPE_BYTES,
|
||||||
|
VIRTIO_SND_CTL_TYPE_IEC958
|
||||||
|
};
|
||||||
|
|
||||||
|
/* supported access rights for control elements */
|
||||||
|
enum {
|
||||||
|
VIRTIO_SND_CTL_ACCESS_READ = 0,
|
||||||
|
VIRTIO_SND_CTL_ACCESS_WRITE,
|
||||||
|
VIRTIO_SND_CTL_ACCESS_VOLATILE,
|
||||||
|
VIRTIO_SND_CTL_ACCESS_INACTIVE,
|
||||||
|
VIRTIO_SND_CTL_ACCESS_TLV_READ,
|
||||||
|
VIRTIO_SND_CTL_ACCESS_TLV_WRITE,
|
||||||
|
VIRTIO_SND_CTL_ACCESS_TLV_COMMAND
|
||||||
|
};
|
||||||
|
|
||||||
|
struct virtio_snd_ctl_info {
|
||||||
|
/* common header */
|
||||||
|
struct virtio_snd_info hdr;
|
||||||
|
/* element role (VIRTIO_SND_CTL_ROLE_XXX) */
|
||||||
|
__le32 role;
|
||||||
|
/* element value type (VIRTIO_SND_CTL_TYPE_XXX) */
|
||||||
|
__le32 type;
|
||||||
|
/* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */
|
||||||
|
__le32 access;
|
||||||
|
/* # of members in the element value */
|
||||||
|
__le32 count;
|
||||||
|
/* index for an element with a non-unique name */
|
||||||
|
__le32 index;
|
||||||
|
/* name identifier string for the element */
|
||||||
|
__u8 name[44];
|
||||||
|
/* additional information about the element's value */
|
||||||
|
union {
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_INTEGER */
|
||||||
|
struct {
|
||||||
|
/* minimum supported value */
|
||||||
|
__le32 min;
|
||||||
|
/* maximum supported value */
|
||||||
|
__le32 max;
|
||||||
|
/* fixed step size for value (0 = variable size) */
|
||||||
|
__le32 step;
|
||||||
|
} integer;
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_INTEGER64 */
|
||||||
|
struct {
|
||||||
|
/* minimum supported value */
|
||||||
|
__le64 min;
|
||||||
|
/* maximum supported value */
|
||||||
|
__le64 max;
|
||||||
|
/* fixed step size for value (0 = variable size) */
|
||||||
|
__le64 step;
|
||||||
|
} integer64;
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_ENUMERATED */
|
||||||
|
struct {
|
||||||
|
/* # of options supported for value */
|
||||||
|
__le32 items;
|
||||||
|
} enumerated;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct virtio_snd_ctl_enum_item {
|
||||||
|
/* option name */
|
||||||
|
__u8 item[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct virtio_snd_ctl_iec958 {
|
||||||
|
/* AES/IEC958 channel status bits */
|
||||||
|
__u8 status[24];
|
||||||
|
/* AES/IEC958 subcode bits */
|
||||||
|
__u8 subcode[147];
|
||||||
|
/* nothing */
|
||||||
|
__u8 pad;
|
||||||
|
/* AES/IEC958 subframe bits */
|
||||||
|
__u8 dig_subframe[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct virtio_snd_ctl_value {
|
||||||
|
union {
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */
|
||||||
|
__le32 integer[128];
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_INTEGER64 value */
|
||||||
|
__le64 integer64[64];
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */
|
||||||
|
__le32 enumerated[128];
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_BYTES value */
|
||||||
|
__u8 bytes[512];
|
||||||
|
/* VIRTIO_SND_CTL_TYPE_IEC958 value */
|
||||||
|
struct virtio_snd_ctl_iec958 iec958;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* supported event reason types */
|
||||||
|
enum {
|
||||||
|
/* element's value has changed */
|
||||||
|
VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
|
||||||
|
/* element's information has changed */
|
||||||
|
VIRTIO_SND_CTL_EVT_MASK_INFO,
|
||||||
|
/* element's metadata has changed */
|
||||||
|
VIRTIO_SND_CTL_EVT_MASK_TLV
|
||||||
|
};
|
||||||
|
|
||||||
|
struct virtio_snd_ctl_event {
|
||||||
|
/* VIRTIO_SND_EVT_CTL_NOTIFY */
|
||||||
|
struct virtio_snd_hdr hdr;
|
||||||
|
/* 0 ... virtio_snd_config::controls - 1 */
|
||||||
|
__le16 control_id;
|
||||||
|
/* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */
|
||||||
|
__le16 mask;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* VIRTIO_SND_IF_H */
|
#endif /* VIRTIO_SND_IF_H */
|
||||||
|
|
|
@ -19,6 +19,8 @@ enum avs_tplg_token {
|
||||||
AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32 = 6,
|
AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32 = 6,
|
||||||
AVS_TKN_MANIFEST_NUM_PPLCFGS_U32 = 7,
|
AVS_TKN_MANIFEST_NUM_PPLCFGS_U32 = 7,
|
||||||
AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8,
|
AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8,
|
||||||
|
AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9,
|
||||||
|
AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10,
|
||||||
|
|
||||||
/* struct avs_tplg_library */
|
/* struct avs_tplg_library */
|
||||||
AVS_TKN_LIBRARY_ID_U32 = 101,
|
AVS_TKN_LIBRARY_ID_U32 = 101,
|
||||||
|
@ -109,6 +111,8 @@ enum avs_tplg_token {
|
||||||
AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705,
|
AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705,
|
||||||
AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706,
|
AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706,
|
||||||
AVS_TKN_MOD_KCONTROL_ID_U32 = 1707,
|
AVS_TKN_MOD_KCONTROL_ID_U32 = 1707,
|
||||||
|
AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708,
|
||||||
|
AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709,
|
||||||
|
|
||||||
/* struct avs_tplg_path_template */
|
/* struct avs_tplg_path_template */
|
||||||
AVS_TKN_PATH_TMPL_ID_U32 = 1801,
|
AVS_TKN_PATH_TMPL_ID_U32 = 1801,
|
||||||
|
@ -125,6 +129,11 @@ enum avs_tplg_token {
|
||||||
|
|
||||||
/* struct avs_tplg_kcontrol */
|
/* struct avs_tplg_kcontrol */
|
||||||
AVS_TKN_KCONTROL_ID_U32 = 2301,
|
AVS_TKN_KCONTROL_ID_U32 = 2301,
|
||||||
|
|
||||||
|
/* struct avs_tplg_init_config */
|
||||||
|
AVS_TKN_INIT_CONFIG_ID_U32 = 2401,
|
||||||
|
AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402,
|
||||||
|
AVS_TKN_INIT_CONFIG_LENGTH_U32 = 2403,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -218,4 +218,8 @@
|
||||||
#define SOF_TKN_IMX_MICFIL_RATE 2000
|
#define SOF_TKN_IMX_MICFIL_RATE 2000
|
||||||
#define SOF_TKN_IMX_MICFIL_CH 2001
|
#define SOF_TKN_IMX_MICFIL_CH 2001
|
||||||
|
|
||||||
|
/* ACP SDW */
|
||||||
|
#define SOF_TKN_AMD_ACP_SDW_RATE 2100
|
||||||
|
#define SOF_TKN_AMD_ACP_SDW_CH 2101
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1126,7 +1126,6 @@ static void aoa_fabric_layout_remove(struct soundbus_dev *sdev)
|
||||||
sdev->pcmname = NULL;
|
sdev->pcmname = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
static int aoa_fabric_layout_suspend(struct device *dev)
|
static int aoa_fabric_layout_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct layout_dev *ldev = dev_get_drvdata(dev);
|
struct layout_dev *ldev = dev_get_drvdata(dev);
|
||||||
|
@ -1147,11 +1146,9 @@ static int aoa_fabric_layout_resume(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
|
static DEFINE_SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
|
||||||
aoa_fabric_layout_suspend, aoa_fabric_layout_resume);
|
aoa_fabric_layout_suspend, aoa_fabric_layout_resume);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct soundbus_driver aoa_soundbus_driver = {
|
static struct soundbus_driver aoa_soundbus_driver = {
|
||||||
.name = "snd_aoa_soundbus_drv",
|
.name = "snd_aoa_soundbus_drv",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
@ -1159,9 +1156,7 @@ static struct soundbus_driver aoa_soundbus_driver = {
|
||||||
.remove = aoa_fabric_layout_remove,
|
.remove = aoa_fabric_layout_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
.pm = &aoa_fabric_layout_pm_ops,
|
.pm = &aoa_fabric_layout_pm_ops,
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ static void soundbus_device_shutdown(struct device *dev)
|
||||||
|
|
||||||
/* soundbus_dev_attrs is declared in sysfs.c */
|
/* soundbus_dev_attrs is declared in sysfs.c */
|
||||||
ATTRIBUTE_GROUPS(soundbus_dev);
|
ATTRIBUTE_GROUPS(soundbus_dev);
|
||||||
static struct bus_type soundbus_bus_type = {
|
static const struct bus_type soundbus_bus_type = {
|
||||||
.name = "aoa-soundbus",
|
.name = "aoa-soundbus",
|
||||||
.probe = soundbus_probe,
|
.probe = soundbus_probe,
|
||||||
.uevent = soundbus_uevent,
|
.uevent = soundbus_uevent,
|
||||||
|
|
|
@ -737,10 +737,8 @@ static const struct snd_pcm_ops aaci_capture_ops = {
|
||||||
/*
|
/*
|
||||||
* Power Management.
|
* Power Management.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static int aaci_do_suspend(struct snd_card *card)
|
static int aaci_do_suspend(struct snd_card *card)
|
||||||
{
|
{
|
||||||
struct aaci *aaci = card->private_data;
|
|
||||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
|
snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -763,12 +761,7 @@ static int aaci_resume(struct device *dev)
|
||||||
return card ? aaci_do_resume(card) : 0;
|
return card ? aaci_do_resume(card) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
|
static DEFINE_SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
|
||||||
#define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
|
|
||||||
#else
|
|
||||||
#define AACI_DEV_PM_OPS NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static const struct ac97_pcm ac97_defs[] = {
|
static const struct ac97_pcm ac97_defs[] = {
|
||||||
[0] = { /* Front PCM */
|
[0] = { /* Front PCM */
|
||||||
|
@ -1081,7 +1074,7 @@ MODULE_DEVICE_TABLE(amba, aaci_ids);
|
||||||
static struct amba_driver aaci_driver = {
|
static struct amba_driver aaci_driver = {
|
||||||
.drv = {
|
.drv = {
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.pm = AACI_DEV_PM_OPS,
|
.pm = &aaci_dev_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = aaci_probe,
|
.probe = aaci_probe,
|
||||||
.remove = aaci_remove,
|
.remove = aaci_remove,
|
||||||
|
|
|
@ -111,8 +111,6 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
|
||||||
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
|
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
|
|
||||||
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
|
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
|
||||||
{
|
{
|
||||||
pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
|
pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
|
||||||
|
@ -164,8 +162,7 @@ static int pxa2xx_ac97_resume(struct device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
|
static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
|
||||||
#endif
|
|
||||||
|
|
||||||
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,
|
||||||
|
@ -277,9 +274,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
|
||||||
.remove_new = pxa2xx_ac97_remove,
|
.remove_new = pxa2xx_ac97_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "pxa2xx-ac97",
|
.name = "pxa2xx-ac97",
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
.pm = &pxa2xx_ac97_pm_ops,
|
.pm = &pxa2xx_ac97_pm_ops,
|
||||||
#endif
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,23 @@ config SND_UMP_LEGACY_RAWMIDI
|
||||||
legacy MIDI 1.0 byte streams is created for each UMP Endpoint.
|
legacy MIDI 1.0 byte streams is created for each UMP Endpoint.
|
||||||
The device contains 16 substreams corresponding to UMP groups.
|
The device contains 16 substreams corresponding to UMP groups.
|
||||||
|
|
||||||
|
config SND_CORE_TEST
|
||||||
|
tristate "Sound core KUnit test"
|
||||||
|
depends on KUNIT
|
||||||
|
select SND_PCM
|
||||||
|
default KUNIT_ALL_TESTS
|
||||||
|
help
|
||||||
|
This options enables the sound core functions KUnit test.
|
||||||
|
|
||||||
|
KUnit tests run during boot and output the results to the debug
|
||||||
|
log in TAP format (https://testanything.org/). Only useful for
|
||||||
|
kernel devs running KUnit test harness and are not for inclusion
|
||||||
|
into a production build.
|
||||||
|
|
||||||
|
For more information on KUnit and unit tests in general, refer
|
||||||
|
to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||||
|
|
||||||
|
|
||||||
config SND_COMPRESS_OFFLOAD
|
config SND_COMPRESS_OFFLOAD
|
||||||
tristate
|
tristate
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o
|
||||||
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
|
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
|
||||||
obj-$(CONFIG_SND_UMP) += snd-ump.o
|
obj-$(CONFIG_SND_UMP) += snd-ump.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_SND_CORE_TEST) += sound_kunit.o
|
||||||
|
|
||||||
obj-$(CONFIG_SND_OSSEMUL) += oss/
|
obj-$(CONFIG_SND_OSSEMUL) += oss/
|
||||||
obj-$(CONFIG_SND_SEQUENCER) += seq/
|
obj-$(CONFIG_SND_SEQUENCER) += seq/
|
||||||
|
|
||||||
|
|
|
@ -127,9 +127,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
||||||
init_waitqueue_head(&runtime->sleep);
|
init_waitqueue_head(&runtime->sleep);
|
||||||
data->stream.runtime = runtime;
|
data->stream.runtime = runtime;
|
||||||
f->private_data = (void *)data;
|
f->private_data = (void *)data;
|
||||||
mutex_lock(&compr->lock);
|
scoped_guard(mutex, &compr->lock)
|
||||||
ret = compr->ops->open(&data->stream);
|
ret = compr->ops->open(&data->stream);
|
||||||
mutex_unlock(&compr->lock);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(runtime);
|
kfree(runtime);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
@ -288,7 +287,7 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
stream = &data->stream;
|
stream = &data->stream;
|
||||||
mutex_lock(&stream->device->lock);
|
guard(mutex)(&stream->device->lock);
|
||||||
/* write is allowed when stream is running or has been steup */
|
/* write is allowed when stream is running or has been steup */
|
||||||
switch (stream->runtime->state) {
|
switch (stream->runtime->state) {
|
||||||
case SNDRV_PCM_STATE_SETUP:
|
case SNDRV_PCM_STATE_SETUP:
|
||||||
|
@ -296,7 +295,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
|
||||||
case SNDRV_PCM_STATE_RUNNING:
|
case SNDRV_PCM_STATE_RUNNING:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mutex_unlock(&stream->device->lock);
|
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +320,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
|
||||||
pr_debug("stream prepared, Houston we are good to go\n");
|
pr_debug("stream prepared, Houston we are good to go\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&stream->device->lock);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +336,7 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
stream = &data->stream;
|
stream = &data->stream;
|
||||||
mutex_lock(&stream->device->lock);
|
guard(mutex)(&stream->device->lock);
|
||||||
|
|
||||||
/* read is allowed when stream is running, paused, draining and setup
|
/* read is allowed when stream is running, paused, draining and setup
|
||||||
* (yes setup is state which we transition to after stop, so if user
|
* (yes setup is state which we transition to after stop, so if user
|
||||||
|
@ -350,11 +347,9 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
||||||
case SNDRV_PCM_STATE_PREPARED:
|
case SNDRV_PCM_STATE_PREPARED:
|
||||||
case SNDRV_PCM_STATE_SUSPENDED:
|
case SNDRV_PCM_STATE_SUSPENDED:
|
||||||
case SNDRV_PCM_STATE_DISCONNECTED:
|
case SNDRV_PCM_STATE_DISCONNECTED:
|
||||||
retval = -EBADFD;
|
return -EBADFD;
|
||||||
goto out;
|
|
||||||
case SNDRV_PCM_STATE_XRUN:
|
case SNDRV_PCM_STATE_XRUN:
|
||||||
retval = -EPIPE;
|
return -EPIPE;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
avail = snd_compr_get_avail(stream);
|
avail = snd_compr_get_avail(stream);
|
||||||
|
@ -363,17 +358,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
||||||
if (avail > count)
|
if (avail > count)
|
||||||
avail = count;
|
avail = count;
|
||||||
|
|
||||||
if (stream->ops->copy) {
|
if (stream->ops->copy)
|
||||||
retval = stream->ops->copy(stream, buf, avail);
|
retval = stream->ops->copy(stream, buf, avail);
|
||||||
} else {
|
else
|
||||||
retval = -ENXIO;
|
return -ENXIO;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (retval > 0)
|
if (retval > 0)
|
||||||
stream->runtime->total_bytes_transferred += retval;
|
stream->runtime->total_bytes_transferred += retval;
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&stream->device->lock);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,13 +393,12 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
|
||||||
|
|
||||||
stream = &data->stream;
|
stream = &data->stream;
|
||||||
|
|
||||||
mutex_lock(&stream->device->lock);
|
guard(mutex)(&stream->device->lock);
|
||||||
|
|
||||||
switch (stream->runtime->state) {
|
switch (stream->runtime->state) {
|
||||||
case SNDRV_PCM_STATE_OPEN:
|
case SNDRV_PCM_STATE_OPEN:
|
||||||
case SNDRV_PCM_STATE_XRUN:
|
case SNDRV_PCM_STATE_XRUN:
|
||||||
retval = snd_compr_get_poll(stream) | EPOLLERR;
|
return snd_compr_get_poll(stream) | EPOLLERR;
|
||||||
goto out;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -433,11 +423,9 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
|
||||||
retval = snd_compr_get_poll(stream);
|
retval = snd_compr_get_poll(stream);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
retval = snd_compr_get_poll(stream) | EPOLLERR;
|
return snd_compr_get_poll(stream) | EPOLLERR;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
mutex_unlock(&stream->device->lock);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +453,7 @@ static int
|
||||||
snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
|
snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct snd_compr_codec_caps *caps;
|
struct snd_compr_codec_caps *caps __free(kfree) = NULL;
|
||||||
|
|
||||||
if (!stream->ops->get_codec_caps)
|
if (!stream->ops->get_codec_caps)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
@ -476,12 +464,9 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
|
|
||||||
retval = stream->ops->get_codec_caps(stream, caps);
|
retval = stream->ops->get_codec_caps(stream, caps);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
return retval;
|
||||||
if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
|
if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
|
||||||
retval = -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(caps);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
|
#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
|
||||||
|
@ -586,7 +571,7 @@ static int snd_compress_check_input(struct snd_compr_params *params)
|
||||||
static int
|
static int
|
||||||
snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
|
snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct snd_compr_params *params;
|
struct snd_compr_params *params __free(kfree) = NULL;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
|
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
|
||||||
|
@ -596,24 +581,22 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
*/
|
*/
|
||||||
params = memdup_user((void __user *)arg, sizeof(*params));
|
params = memdup_user((void __user *)arg, sizeof(*params));
|
||||||
if (IS_ERR(params))
|
if (IS_ERR(params))
|
||||||
return PTR_ERR(params);
|
return PTR_ERR(no_free_ptr(params));
|
||||||
|
|
||||||
retval = snd_compress_check_input(params);
|
retval = snd_compress_check_input(params);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
retval = snd_compr_allocate_buffer(stream, params);
|
retval = snd_compr_allocate_buffer(stream, params);
|
||||||
if (retval) {
|
if (retval)
|
||||||
retval = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = stream->ops->set_params(stream, params);
|
retval = stream->ops->set_params(stream, params);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
if (stream->next_track)
|
if (stream->next_track)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
stream->metadata_set = false;
|
stream->metadata_set = false;
|
||||||
stream->next_track = false;
|
stream->next_track = false;
|
||||||
|
@ -622,15 +605,13 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
} else {
|
} else {
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
kfree(params);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
|
snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct snd_codec *params;
|
struct snd_codec *params __free(kfree) = NULL;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (!stream->ops->get_params)
|
if (!stream->ops->get_params)
|
||||||
|
@ -641,12 +622,9 @@ snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
retval = stream->ops->get_params(stream, params);
|
retval = stream->ops->get_params(stream, params);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
return retval;
|
||||||
if (copy_to_user((char __user *)arg, params, sizeof(*params)))
|
if (copy_to_user((char __user *)arg, params, sizeof(*params)))
|
||||||
retval = -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(params);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,12 +783,10 @@ static void error_delayed_work(struct work_struct *work)
|
||||||
|
|
||||||
stream = container_of(work, struct snd_compr_stream, error_work.work);
|
stream = container_of(work, struct snd_compr_stream, error_work.work);
|
||||||
|
|
||||||
mutex_lock(&stream->device->lock);
|
guard(mutex)(&stream->device->lock);
|
||||||
|
|
||||||
stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
|
stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
|
||||||
wake_up(&stream->runtime->sleep);
|
wake_up(&stream->runtime->sleep);
|
||||||
|
|
||||||
mutex_unlock(&stream->device->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -967,70 +943,52 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct snd_compr_file *data = f->private_data;
|
struct snd_compr_file *data = f->private_data;
|
||||||
struct snd_compr_stream *stream;
|
struct snd_compr_stream *stream;
|
||||||
int retval = -ENOTTY;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!data))
|
if (snd_BUG_ON(!data))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
stream = &data->stream;
|
stream = &data->stream;
|
||||||
|
|
||||||
mutex_lock(&stream->device->lock);
|
guard(mutex)(&stream->device->lock);
|
||||||
switch (_IOC_NR(cmd)) {
|
switch (_IOC_NR(cmd)) {
|
||||||
case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
|
case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
|
||||||
retval = put_user(SNDRV_COMPRESS_VERSION,
|
return put_user(SNDRV_COMPRESS_VERSION,
|
||||||
(int __user *)arg) ? -EFAULT : 0;
|
(int __user *)arg) ? -EFAULT : 0;
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
|
case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
|
||||||
retval = snd_compr_get_caps(stream, arg);
|
return snd_compr_get_caps(stream, arg);
|
||||||
break;
|
|
||||||
#ifndef COMPR_CODEC_CAPS_OVERFLOW
|
#ifndef COMPR_CODEC_CAPS_OVERFLOW
|
||||||
case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
|
case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
|
||||||
retval = snd_compr_get_codec_caps(stream, arg);
|
return snd_compr_get_codec_caps(stream, arg);
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
|
case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
|
||||||
retval = snd_compr_set_params(stream, arg);
|
return snd_compr_set_params(stream, arg);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
|
case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
|
||||||
retval = snd_compr_get_params(stream, arg);
|
return snd_compr_get_params(stream, arg);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
|
case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
|
||||||
retval = snd_compr_set_metadata(stream, arg);
|
return snd_compr_set_metadata(stream, arg);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
|
case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
|
||||||
retval = snd_compr_get_metadata(stream, arg);
|
return snd_compr_get_metadata(stream, arg);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
|
case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
|
||||||
retval = snd_compr_tstamp(stream, arg);
|
return snd_compr_tstamp(stream, arg);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_AVAIL):
|
case _IOC_NR(SNDRV_COMPRESS_AVAIL):
|
||||||
retval = snd_compr_ioctl_avail(stream, arg);
|
return snd_compr_ioctl_avail(stream, arg);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_PAUSE):
|
case _IOC_NR(SNDRV_COMPRESS_PAUSE):
|
||||||
retval = snd_compr_pause(stream);
|
return snd_compr_pause(stream);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_RESUME):
|
case _IOC_NR(SNDRV_COMPRESS_RESUME):
|
||||||
retval = snd_compr_resume(stream);
|
return snd_compr_resume(stream);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_START):
|
case _IOC_NR(SNDRV_COMPRESS_START):
|
||||||
retval = snd_compr_start(stream);
|
return snd_compr_start(stream);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_STOP):
|
case _IOC_NR(SNDRV_COMPRESS_STOP):
|
||||||
retval = snd_compr_stop(stream);
|
return snd_compr_stop(stream);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_DRAIN):
|
case _IOC_NR(SNDRV_COMPRESS_DRAIN):
|
||||||
retval = snd_compr_drain(stream);
|
return snd_compr_drain(stream);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
|
case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
|
||||||
retval = snd_compr_partial_drain(stream);
|
return snd_compr_partial_drain(stream);
|
||||||
break;
|
|
||||||
case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
|
case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
|
||||||
retval = snd_compr_next_track(stream);
|
return snd_compr_next_track(stream);
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&stream->device->lock);
|
|
||||||
return retval;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* support of 32bit userspace on 64bit platforms */
|
/* support of 32bit userspace on 64bit platforms */
|
||||||
|
|
|
@ -44,7 +44,6 @@ static int snd_ctl_remove_locked(struct snd_card *card,
|
||||||
|
|
||||||
static int snd_ctl_open(struct inode *inode, struct file *file)
|
static int snd_ctl_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
struct snd_ctl_file *ctl;
|
struct snd_ctl_file *ctl;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
@ -80,9 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
||||||
ctl->preferred_subdevice[i] = -1;
|
ctl->preferred_subdevice[i] = -1;
|
||||||
ctl->pid = get_pid(task_pid(current));
|
ctl->pid = get_pid(task_pid(current));
|
||||||
file->private_data = ctl;
|
file->private_data = ctl;
|
||||||
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock)
|
||||||
list_add_tail(&ctl->list, &card->ctl_files);
|
list_add_tail(&ctl->list, &card->ctl_files);
|
||||||
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
|
||||||
snd_card_unref(card);
|
snd_card_unref(card);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -98,21 +96,18 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
|
static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_kctl_event *cread;
|
struct snd_kctl_event *cread;
|
||||||
|
|
||||||
spin_lock_irqsave(&ctl->read_lock, flags);
|
guard(spinlock_irqsave)(&ctl->read_lock);
|
||||||
while (!list_empty(&ctl->events)) {
|
while (!list_empty(&ctl->events)) {
|
||||||
cread = snd_kctl_event(ctl->events.next);
|
cread = snd_kctl_event(ctl->events.next);
|
||||||
list_del(&cread->list);
|
list_del(&cread->list);
|
||||||
kfree(cread);
|
kfree(cread);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ctl->read_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_release(struct inode *inode, struct file *file)
|
static int snd_ctl_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
struct snd_ctl_file *ctl;
|
struct snd_ctl_file *ctl;
|
||||||
struct snd_kcontrol *control;
|
struct snd_kcontrol *control;
|
||||||
|
@ -121,15 +116,17 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
|
||||||
ctl = file->private_data;
|
ctl = file->private_data;
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
card = ctl->card;
|
card = ctl->card;
|
||||||
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
|
||||||
list_del(&ctl->list);
|
scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock)
|
||||||
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
list_del(&ctl->list);
|
||||||
down_write(&card->controls_rwsem);
|
|
||||||
list_for_each_entry(control, &card->controls, list)
|
scoped_guard(rwsem_write, &card->controls_rwsem) {
|
||||||
for (idx = 0; idx < control->count; idx++)
|
list_for_each_entry(control, &card->controls, list)
|
||||||
if (control->vd[idx].owner == ctl)
|
for (idx = 0; idx < control->count; idx++)
|
||||||
control->vd[idx].owner = NULL;
|
if (control->vd[idx].owner == ctl)
|
||||||
up_write(&card->controls_rwsem);
|
control->vd[idx].owner = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
snd_fasync_free(ctl->fasync);
|
snd_fasync_free(ctl->fasync);
|
||||||
snd_ctl_empty_read_queue(ctl);
|
snd_ctl_empty_read_queue(ctl);
|
||||||
put_pid(ctl->pid);
|
put_pid(ctl->pid);
|
||||||
|
@ -152,7 +149,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
|
||||||
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
|
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
|
||||||
struct snd_ctl_elem_id *id)
|
struct snd_ctl_elem_id *id)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_ctl_file *ctl;
|
struct snd_ctl_file *ctl;
|
||||||
struct snd_kctl_event *ev;
|
struct snd_kctl_event *ev;
|
||||||
|
|
||||||
|
@ -160,34 +156,34 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
|
||||||
return;
|
return;
|
||||||
if (card->shutdown)
|
if (card->shutdown)
|
||||||
return;
|
return;
|
||||||
read_lock_irqsave(&card->ctl_files_rwlock, flags);
|
|
||||||
|
guard(read_lock_irqsave)(&card->ctl_files_rwlock);
|
||||||
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
|
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
|
||||||
card->mixer_oss_change_count++;
|
card->mixer_oss_change_count++;
|
||||||
#endif
|
#endif
|
||||||
list_for_each_entry(ctl, &card->ctl_files, list) {
|
list_for_each_entry(ctl, &card->ctl_files, list) {
|
||||||
if (!ctl->subscribed)
|
if (!ctl->subscribed)
|
||||||
continue;
|
continue;
|
||||||
spin_lock(&ctl->read_lock);
|
scoped_guard(spinlock, &ctl->read_lock) {
|
||||||
list_for_each_entry(ev, &ctl->events, list) {
|
list_for_each_entry(ev, &ctl->events, list) {
|
||||||
if (ev->id.numid == id->numid) {
|
if (ev->id.numid == id->numid) {
|
||||||
ev->mask |= mask;
|
ev->mask |= mask;
|
||||||
goto _found;
|
goto _found;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
|
||||||
|
if (ev) {
|
||||||
|
ev->id = *id;
|
||||||
|
ev->mask = mask;
|
||||||
|
list_add_tail(&ev->list, &ctl->events);
|
||||||
|
} else {
|
||||||
|
dev_err(card->dev, "No memory available to allocate event\n");
|
||||||
|
}
|
||||||
|
_found:
|
||||||
|
wake_up(&ctl->change_sleep);
|
||||||
}
|
}
|
||||||
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
|
|
||||||
if (ev) {
|
|
||||||
ev->id = *id;
|
|
||||||
ev->mask = mask;
|
|
||||||
list_add_tail(&ev->list, &ctl->events);
|
|
||||||
} else {
|
|
||||||
dev_err(card->dev, "No memory available to allocate event\n");
|
|
||||||
}
|
|
||||||
_found:
|
|
||||||
wake_up(&ctl->change_sleep);
|
|
||||||
spin_unlock(&ctl->read_lock);
|
|
||||||
snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN);
|
snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_notify);
|
EXPORT_SYMBOL(snd_ctl_notify);
|
||||||
|
|
||||||
|
@ -210,10 +206,9 @@ void snd_ctl_notify_one(struct snd_card *card, unsigned int mask,
|
||||||
id.index += ioff;
|
id.index += ioff;
|
||||||
id.numid += ioff;
|
id.numid += ioff;
|
||||||
snd_ctl_notify(card, mask, &id);
|
snd_ctl_notify(card, mask, &id);
|
||||||
down_read(&snd_ctl_layer_rwsem);
|
guard(rwsem_read)(&snd_ctl_layer_rwsem);
|
||||||
for (lops = snd_ctl_layer; lops; lops = lops->next)
|
for (lops = snd_ctl_layer; lops; lops = lops->next)
|
||||||
lops->lnotify(card, mask, kctl, ioff);
|
lops->lnotify(card, mask, kctl, ioff);
|
||||||
up_read(&snd_ctl_layer_rwsem);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_notify_one);
|
EXPORT_SYMBOL(snd_ctl_notify_one);
|
||||||
|
|
||||||
|
@ -520,9 +515,9 @@ static int snd_ctl_add_replace(struct snd_card *card,
|
||||||
if (snd_BUG_ON(!card || !kcontrol->info))
|
if (snd_BUG_ON(!card || !kcontrol->info))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
scoped_guard(rwsem_write, &card->controls_rwsem)
|
||||||
err = __snd_ctl_add_replace(card, kcontrol, mode);
|
err = __snd_ctl_add_replace(card, kcontrol, mode);
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -616,12 +611,8 @@ static inline int snd_ctl_remove_locked(struct snd_card *card,
|
||||||
*/
|
*/
|
||||||
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
||||||
{
|
{
|
||||||
int ret;
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
|
return snd_ctl_remove_locked(card, kcontrol);
|
||||||
down_write(&card->controls_rwsem);
|
|
||||||
ret = snd_ctl_remove_locked(card, kcontrol);
|
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_remove);
|
EXPORT_SYMBOL(snd_ctl_remove);
|
||||||
|
|
||||||
|
@ -638,17 +629,12 @@ EXPORT_SYMBOL(snd_ctl_remove);
|
||||||
int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
|
int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
|
||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
int ret;
|
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, id);
|
kctl = snd_ctl_find_id_locked(card, id);
|
||||||
if (kctl == NULL) {
|
if (kctl == NULL)
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
return snd_ctl_remove_locked(card, kctl);
|
||||||
ret = snd_ctl_remove_locked(card, kctl);
|
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_remove_id);
|
EXPORT_SYMBOL(snd_ctl_remove_id);
|
||||||
|
|
||||||
|
@ -667,27 +653,18 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
|
||||||
{
|
{
|
||||||
struct snd_card *card = file->card;
|
struct snd_card *card = file->card;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
int idx, ret;
|
int idx;
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, id);
|
kctl = snd_ctl_find_id_locked(card, id);
|
||||||
if (kctl == NULL) {
|
if (kctl == NULL)
|
||||||
ret = -ENOENT;
|
return -ENOENT;
|
||||||
goto error;
|
if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER))
|
||||||
}
|
return -EINVAL;
|
||||||
if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
for (idx = 0; idx < kctl->count; idx++)
|
for (idx = 0; idx < kctl->count; idx++)
|
||||||
if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
|
if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file)
|
||||||
ret = -EBUSY;
|
return -EBUSY;
|
||||||
goto error;
|
return snd_ctl_remove_locked(card, kctl);
|
||||||
}
|
|
||||||
ret = snd_ctl_remove_locked(card, kctl);
|
|
||||||
error:
|
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -764,18 +741,15 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
int saved_numid;
|
int saved_numid;
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, src_id);
|
kctl = snd_ctl_find_id_locked(card, src_id);
|
||||||
if (kctl == NULL) {
|
if (kctl == NULL)
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
|
||||||
saved_numid = kctl->id.numid;
|
saved_numid = kctl->id.numid;
|
||||||
remove_hash_entries(card, kctl);
|
remove_hash_entries(card, kctl);
|
||||||
kctl->id = *dst_id;
|
kctl->id = *dst_id;
|
||||||
kctl->id.numid = saved_numid;
|
kctl->id.numid = saved_numid;
|
||||||
add_hash_entries(card, kctl);
|
add_hash_entries(card, kctl);
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_rename_id);
|
EXPORT_SYMBOL(snd_ctl_rename_id);
|
||||||
|
@ -793,7 +767,7 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
|
||||||
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
|
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
remove_hash_entries(card, kctl);
|
remove_hash_entries(card, kctl);
|
||||||
|
|
||||||
if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0)
|
if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0)
|
||||||
|
@ -801,7 +775,6 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||||
name, kctl->id.name);
|
name, kctl->id.name);
|
||||||
|
|
||||||
add_hash_entries(card, kctl);
|
add_hash_entries(card, kctl);
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_rename);
|
EXPORT_SYMBOL(snd_ctl_rename);
|
||||||
|
|
||||||
|
@ -859,12 +832,8 @@ EXPORT_SYMBOL(snd_ctl_find_numid_locked);
|
||||||
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
|
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
|
||||||
unsigned int numid)
|
unsigned int numid)
|
||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
|
return snd_ctl_find_numid_locked(card, numid);
|
||||||
down_read(&card->controls_rwsem);
|
|
||||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return kctl;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_find_numid);
|
EXPORT_SYMBOL(snd_ctl_find_numid);
|
||||||
|
|
||||||
|
@ -920,37 +889,30 @@ EXPORT_SYMBOL(snd_ctl_find_id_locked);
|
||||||
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
|
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
|
||||||
const struct snd_ctl_elem_id *id)
|
const struct snd_ctl_elem_id *id)
|
||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
|
return snd_ctl_find_id_locked(card, id);
|
||||||
down_read(&card->controls_rwsem);
|
|
||||||
kctl = snd_ctl_find_id_locked(card, id);
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return kctl;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_ctl_find_id);
|
EXPORT_SYMBOL(snd_ctl_find_id);
|
||||||
|
|
||||||
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
|
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
|
||||||
unsigned int cmd, void __user *arg)
|
unsigned int cmd, void __user *arg)
|
||||||
{
|
{
|
||||||
struct snd_ctl_card_info *info;
|
struct snd_ctl_card_info *info __free(kfree) = NULL;
|
||||||
|
|
||||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||||
if (! info)
|
if (! info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
down_read(&snd_ioctl_rwsem);
|
scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
|
||||||
info->card = card->number;
|
info->card = card->number;
|
||||||
strscpy(info->id, card->id, sizeof(info->id));
|
strscpy(info->id, card->id, sizeof(info->id));
|
||||||
strscpy(info->driver, card->driver, sizeof(info->driver));
|
strscpy(info->driver, card->driver, sizeof(info->driver));
|
||||||
strscpy(info->name, card->shortname, sizeof(info->name));
|
strscpy(info->name, card->shortname, sizeof(info->name));
|
||||||
strscpy(info->longname, card->longname, sizeof(info->longname));
|
strscpy(info->longname, card->longname, sizeof(info->longname));
|
||||||
strscpy(info->mixername, card->mixername, sizeof(info->mixername));
|
strscpy(info->mixername, card->mixername, sizeof(info->mixername));
|
||||||
strscpy(info->components, card->components, sizeof(info->components));
|
strscpy(info->components, card->components, sizeof(info->components));
|
||||||
up_read(&snd_ioctl_rwsem);
|
|
||||||
if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
|
|
||||||
kfree(info);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
}
|
||||||
kfree(info);
|
if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -960,37 +922,31 @@ static int snd_ctl_elem_list(struct snd_card *card,
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_ctl_elem_id id;
|
struct snd_ctl_elem_id id;
|
||||||
unsigned int offset, space, jidx;
|
unsigned int offset, space, jidx;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
offset = list->offset;
|
offset = list->offset;
|
||||||
space = list->space;
|
space = list->space;
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
list->count = card->controls_count;
|
list->count = card->controls_count;
|
||||||
list->used = 0;
|
list->used = 0;
|
||||||
if (space > 0) {
|
if (!space)
|
||||||
list_for_each_entry(kctl, &card->controls, list) {
|
return 0;
|
||||||
if (offset >= kctl->count) {
|
list_for_each_entry(kctl, &card->controls, list) {
|
||||||
offset -= kctl->count;
|
if (offset >= kctl->count) {
|
||||||
continue;
|
offset -= kctl->count;
|
||||||
}
|
continue;
|
||||||
for (jidx = offset; jidx < kctl->count; jidx++) {
|
|
||||||
snd_ctl_build_ioff(&id, kctl, jidx);
|
|
||||||
if (copy_to_user(list->pids + list->used, &id,
|
|
||||||
sizeof(id))) {
|
|
||||||
err = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
list->used++;
|
|
||||||
if (!--space)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
offset = 0;
|
|
||||||
}
|
}
|
||||||
|
for (jidx = offset; jidx < kctl->count; jidx++) {
|
||||||
|
snd_ctl_build_ioff(&id, kctl, jidx);
|
||||||
|
if (copy_to_user(list->pids + list->used, &id, sizeof(id)))
|
||||||
|
return -EFAULT;
|
||||||
|
list->used++;
|
||||||
|
if (!--space)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
offset = 0;
|
||||||
}
|
}
|
||||||
out:
|
return 0;
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_list_user(struct snd_card *card,
|
static int snd_ctl_elem_list_user(struct snd_card *card,
|
||||||
|
@ -1238,16 +1194,12 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
|
||||||
{
|
{
|
||||||
struct snd_card *card = ctl->card;
|
struct snd_card *card = ctl->card;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
int result;
|
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, &info->id);
|
kctl = snd_ctl_find_id_locked(card, &info->id);
|
||||||
if (kctl == NULL)
|
if (!kctl)
|
||||||
result = -ENOENT;
|
return -ENOENT;
|
||||||
else
|
return __snd_ctl_elem_info(card, kctl, info, ctl);
|
||||||
result = __snd_ctl_elem_info(card, kctl, info, ctl);
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
|
static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
|
||||||
|
@ -1279,19 +1231,15 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
||||||
const u32 pattern = 0xdeadbeef;
|
const u32 pattern = 0xdeadbeef;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, &control->id);
|
kctl = snd_ctl_find_id_locked(card, &control->id);
|
||||||
if (kctl == NULL) {
|
if (!kctl)
|
||||||
ret = -ENOENT;
|
return -ENOENT;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
index_offset = snd_ctl_get_ioff(kctl, &control->id);
|
index_offset = snd_ctl_get_ioff(kctl, &control->id);
|
||||||
vd = &kctl->vd[index_offset];
|
vd = &kctl->vd[index_offset];
|
||||||
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
|
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || !kctl->get)
|
||||||
ret = -EPERM;
|
return -EPERM;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_ctl_build_ioff(&control->id, kctl, index_offset);
|
snd_ctl_build_ioff(&control->id, kctl, index_offset);
|
||||||
|
|
||||||
|
@ -1301,7 +1249,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
||||||
info.id = control->id;
|
info.id = control->id;
|
||||||
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
|
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto unlock;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!snd_ctl_skip_validation(&info))
|
if (!snd_ctl_skip_validation(&info))
|
||||||
|
@ -1311,7 +1259,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
||||||
ret = kctl->get(kctl, control);
|
ret = kctl->get(kctl, control);
|
||||||
snd_power_unref(card);
|
snd_power_unref(card);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto unlock;
|
return ret;
|
||||||
if (!snd_ctl_skip_validation(&info) &&
|
if (!snd_ctl_skip_validation(&info) &&
|
||||||
sanity_check_elem_value(card, control, &info, pattern) < 0) {
|
sanity_check_elem_value(card, control, &info, pattern) < 0) {
|
||||||
dev_err(card->dev,
|
dev_err(card->dev,
|
||||||
|
@ -1319,12 +1267,9 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
||||||
control->id.iface, control->id.device,
|
control->id.iface, control->id.device,
|
||||||
control->id.subdevice, control->id.name,
|
control->id.subdevice, control->id.name,
|
||||||
control->id.index);
|
control->id.index);
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
unlock:
|
return 0;
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_read_user(struct snd_card *card,
|
static int snd_ctl_elem_read_user(struct snd_card *card,
|
||||||
|
@ -1339,12 +1284,10 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
|
||||||
|
|
||||||
result = snd_ctl_elem_read(card, control);
|
result = snd_ctl_elem_read(card, control);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto error;
|
return result;
|
||||||
|
|
||||||
if (copy_to_user(_control, control, sizeof(*control)))
|
if (copy_to_user(_control, control, sizeof(*control)))
|
||||||
result = -EFAULT;
|
return -EFAULT;
|
||||||
error:
|
|
||||||
kfree(control);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1406,23 +1349,21 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
||||||
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
|
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
|
||||||
struct snd_ctl_elem_value __user *_control)
|
struct snd_ctl_elem_value __user *_control)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_value *control;
|
struct snd_ctl_elem_value *control __free(kfree) = NULL;
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
control = memdup_user(_control, sizeof(*control));
|
control = memdup_user(_control, sizeof(*control));
|
||||||
if (IS_ERR(control))
|
if (IS_ERR(control))
|
||||||
return PTR_ERR(control);
|
return PTR_ERR(no_free_ptr(control));
|
||||||
|
|
||||||
card = file->card;
|
card = file->card;
|
||||||
result = snd_ctl_elem_write(card, file, control);
|
result = snd_ctl_elem_write(card, file, control);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto error;
|
return result;
|
||||||
|
|
||||||
if (copy_to_user(_control, control, sizeof(*control)))
|
if (copy_to_user(_control, control, sizeof(*control)))
|
||||||
result = -EFAULT;
|
return -EFAULT;
|
||||||
error:
|
|
||||||
kfree(control);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1433,25 +1374,18 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
|
||||||
struct snd_ctl_elem_id id;
|
struct snd_ctl_elem_id id;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_kcontrol_volatile *vd;
|
struct snd_kcontrol_volatile *vd;
|
||||||
int result;
|
|
||||||
|
|
||||||
if (copy_from_user(&id, _id, sizeof(id)))
|
if (copy_from_user(&id, _id, sizeof(id)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, &id);
|
kctl = snd_ctl_find_id_locked(card, &id);
|
||||||
if (kctl == NULL) {
|
if (!kctl)
|
||||||
result = -ENOENT;
|
return -ENOENT;
|
||||||
} else {
|
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
|
||||||
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
|
if (vd->owner)
|
||||||
if (vd->owner != NULL)
|
return -EBUSY;
|
||||||
result = -EBUSY;
|
vd->owner = file;
|
||||||
else {
|
return 0;
|
||||||
vd->owner = file;
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
||||||
|
@ -1461,27 +1395,20 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
||||||
struct snd_ctl_elem_id id;
|
struct snd_ctl_elem_id id;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_kcontrol_volatile *vd;
|
struct snd_kcontrol_volatile *vd;
|
||||||
int result;
|
|
||||||
|
|
||||||
if (copy_from_user(&id, _id, sizeof(id)))
|
if (copy_from_user(&id, _id, sizeof(id)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, &id);
|
kctl = snd_ctl_find_id_locked(card, &id);
|
||||||
if (kctl == NULL) {
|
if (!kctl)
|
||||||
result = -ENOENT;
|
return -ENOENT;
|
||||||
} else {
|
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
|
||||||
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
|
if (!vd->owner)
|
||||||
if (vd->owner == NULL)
|
return -EINVAL;
|
||||||
result = -EINVAL;
|
if (vd->owner != file)
|
||||||
else if (vd->owner != file)
|
return -EPERM;
|
||||||
result = -EPERM;
|
vd->owner = NULL;
|
||||||
else {
|
return 0;
|
||||||
vd->owner = NULL;
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct user_element {
|
struct user_element {
|
||||||
|
@ -1763,11 +1690,9 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
private_size = value_sizes[info->type] * info->count;
|
private_size = value_sizes[info->type] * info->count;
|
||||||
alloc_size = compute_user_elem_size(private_size, count);
|
alloc_size = compute_user_elem_size(private_size, count);
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
if (check_user_elem_overflow(card, alloc_size)) {
|
if (check_user_elem_overflow(card, alloc_size))
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep memory object for this userspace control. After passing this
|
* Keep memory object for this userspace control. After passing this
|
||||||
|
@ -1777,13 +1702,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
*/
|
*/
|
||||||
err = snd_ctl_new(&kctl, count, access, file);
|
err = snd_ctl_new(&kctl, count, access, file);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlock;
|
return err;
|
||||||
memcpy(&kctl->id, &info->id, sizeof(kctl->id));
|
memcpy(&kctl->id, &info->id, sizeof(kctl->id));
|
||||||
ue = kzalloc(alloc_size, GFP_KERNEL);
|
ue = kzalloc(alloc_size, GFP_KERNEL);
|
||||||
if (!ue) {
|
if (!ue) {
|
||||||
kfree(kctl);
|
kfree(kctl);
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
kctl->private_data = ue;
|
kctl->private_data = ue;
|
||||||
kctl->private_free = snd_ctl_elem_user_free;
|
kctl->private_free = snd_ctl_elem_user_free;
|
||||||
|
@ -1801,7 +1725,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
err = snd_ctl_elem_init_enum_names(ue);
|
err = snd_ctl_elem_init_enum_names(ue);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_ctl_free_one(kctl);
|
snd_ctl_free_one(kctl);
|
||||||
goto unlock;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1821,7 +1745,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
|
err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_ctl_free_one(kctl);
|
snd_ctl_free_one(kctl);
|
||||||
goto unlock;
|
return err;
|
||||||
}
|
}
|
||||||
offset = snd_ctl_get_ioff(kctl, &info->id);
|
offset = snd_ctl_get_ioff(kctl, &info->id);
|
||||||
snd_ctl_build_ioff(&info->id, kctl, offset);
|
snd_ctl_build_ioff(&info->id, kctl, offset);
|
||||||
|
@ -1832,9 +1756,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
* applications because the field originally means PID of a process
|
* applications because the field originally means PID of a process
|
||||||
* which locks the element.
|
* which locks the element.
|
||||||
*/
|
*/
|
||||||
unlock:
|
return 0;
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
|
static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
|
||||||
|
@ -2036,34 +1958,29 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
||||||
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
|
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
|
||||||
return snd_ctl_subscribe_events(ctl, ip);
|
return snd_ctl_subscribe_events(ctl, ip);
|
||||||
case SNDRV_CTL_IOCTL_TLV_READ:
|
case SNDRV_CTL_IOCTL_TLV_READ:
|
||||||
down_read(&ctl->card->controls_rwsem);
|
scoped_guard(rwsem_read, &ctl->card->controls_rwsem)
|
||||||
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
|
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
|
||||||
up_read(&ctl->card->controls_rwsem);
|
|
||||||
return err;
|
return err;
|
||||||
case SNDRV_CTL_IOCTL_TLV_WRITE:
|
case SNDRV_CTL_IOCTL_TLV_WRITE:
|
||||||
down_write(&ctl->card->controls_rwsem);
|
scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
|
||||||
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
|
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
|
||||||
up_write(&ctl->card->controls_rwsem);
|
|
||||||
return err;
|
return err;
|
||||||
case SNDRV_CTL_IOCTL_TLV_COMMAND:
|
case SNDRV_CTL_IOCTL_TLV_COMMAND:
|
||||||
down_write(&ctl->card->controls_rwsem);
|
scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
|
||||||
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
|
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
|
||||||
up_write(&ctl->card->controls_rwsem);
|
|
||||||
return err;
|
return err;
|
||||||
case SNDRV_CTL_IOCTL_POWER:
|
case SNDRV_CTL_IOCTL_POWER:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
case SNDRV_CTL_IOCTL_POWER_STATE:
|
case SNDRV_CTL_IOCTL_POWER_STATE:
|
||||||
return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
|
return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
|
||||||
}
|
}
|
||||||
down_read(&snd_ioctl_rwsem);
|
|
||||||
|
guard(rwsem_read)(&snd_ioctl_rwsem);
|
||||||
list_for_each_entry(p, &snd_control_ioctls, list) {
|
list_for_each_entry(p, &snd_control_ioctls, list) {
|
||||||
err = p->fioctl(card, ctl, cmd, arg);
|
err = p->fioctl(card, ctl, cmd, arg);
|
||||||
if (err != -ENOIOCTLCMD) {
|
if (err != -ENOIOCTLCMD)
|
||||||
up_read(&snd_ioctl_rwsem);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
up_read(&snd_ioctl_rwsem);
|
|
||||||
dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
|
dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -2155,9 +2072,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
|
||||||
if (pn == NULL)
|
if (pn == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
pn->fioctl = fcn;
|
pn->fioctl = fcn;
|
||||||
down_write(&snd_ioctl_rwsem);
|
guard(rwsem_write)(&snd_ioctl_rwsem);
|
||||||
list_add_tail(&pn->list, lists);
|
list_add_tail(&pn->list, lists);
|
||||||
up_write(&snd_ioctl_rwsem);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2200,16 +2116,14 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
|
||||||
|
|
||||||
if (snd_BUG_ON(!fcn))
|
if (snd_BUG_ON(!fcn))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
down_write(&snd_ioctl_rwsem);
|
guard(rwsem_write)(&snd_ioctl_rwsem);
|
||||||
list_for_each_entry(p, lists, list) {
|
list_for_each_entry(p, lists, list) {
|
||||||
if (p->fioctl == fcn) {
|
if (p->fioctl == fcn) {
|
||||||
list_del(&p->list);
|
list_del(&p->list);
|
||||||
up_write(&snd_ioctl_rwsem);
|
|
||||||
kfree(p);
|
kfree(p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
up_write(&snd_ioctl_rwsem);
|
|
||||||
snd_BUG();
|
snd_BUG();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -2256,9 +2170,8 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
|
||||||
{
|
{
|
||||||
struct snd_ctl_file *kctl;
|
struct snd_ctl_file *kctl;
|
||||||
int subdevice = -1;
|
int subdevice = -1;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
read_lock_irqsave(&card->ctl_files_rwlock, flags);
|
guard(read_lock_irqsave)(&card->ctl_files_rwlock);
|
||||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||||
if (kctl->pid == task_pid(current)) {
|
if (kctl->pid == task_pid(current)) {
|
||||||
subdevice = kctl->preferred_subdevice[type];
|
subdevice = kctl->preferred_subdevice[type];
|
||||||
|
@ -2266,7 +2179,6 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
|
||||||
return subdevice;
|
return subdevice;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
|
EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
|
||||||
|
@ -2296,13 +2208,11 @@ int snd_ctl_request_layer(const char *module_name)
|
||||||
|
|
||||||
if (module_name == NULL)
|
if (module_name == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
down_read(&snd_ctl_layer_rwsem);
|
scoped_guard(rwsem_read, &snd_ctl_layer_rwsem) {
|
||||||
for (lops = snd_ctl_layer; lops; lops = lops->next)
|
for (lops = snd_ctl_layer; lops; lops = lops->next)
|
||||||
if (strcmp(lops->module_name, module_name) == 0)
|
if (strcmp(lops->module_name, module_name) == 0)
|
||||||
break;
|
return 0;
|
||||||
up_read(&snd_ctl_layer_rwsem);
|
}
|
||||||
if (lops)
|
|
||||||
return 0;
|
|
||||||
return request_module(module_name);
|
return request_module(module_name);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
|
EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
|
||||||
|
@ -2319,16 +2229,15 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
int card_number;
|
int card_number;
|
||||||
|
|
||||||
down_write(&snd_ctl_layer_rwsem);
|
scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) {
|
||||||
lops->next = snd_ctl_layer;
|
lops->next = snd_ctl_layer;
|
||||||
snd_ctl_layer = lops;
|
snd_ctl_layer = lops;
|
||||||
up_write(&snd_ctl_layer_rwsem);
|
}
|
||||||
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
|
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
|
||||||
card = snd_card_ref(card_number);
|
card = snd_card_ref(card_number);
|
||||||
if (card) {
|
if (card) {
|
||||||
down_read(&card->controls_rwsem);
|
scoped_guard(rwsem_read, &card->controls_rwsem)
|
||||||
lops->lregister(card);
|
lops->lregister(card);
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
snd_card_unref(card);
|
snd_card_unref(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2347,7 +2256,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
|
||||||
{
|
{
|
||||||
struct snd_ctl_layer_ops *lops2, *prev_lops2;
|
struct snd_ctl_layer_ops *lops2, *prev_lops2;
|
||||||
|
|
||||||
down_write(&snd_ctl_layer_rwsem);
|
guard(rwsem_write)(&snd_ctl_layer_rwsem);
|
||||||
for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) {
|
for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) {
|
||||||
if (lops2 == lops) {
|
if (lops2 == lops) {
|
||||||
if (!prev_lops2)
|
if (!prev_lops2)
|
||||||
|
@ -2358,7 +2267,6 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
|
||||||
}
|
}
|
||||||
prev_lops2 = lops2;
|
prev_lops2 = lops2;
|
||||||
}
|
}
|
||||||
up_write(&snd_ctl_layer_rwsem);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
|
EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
|
||||||
|
|
||||||
|
@ -2379,25 +2287,29 @@ static const struct file_operations snd_ctl_f_ops =
|
||||||
.fasync = snd_ctl_fasync,
|
.fasync = snd_ctl_fasync,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* call lops under rwsems; called from snd_ctl_dev_*() below() */
|
||||||
|
#define call_snd_ctl_lops(_card, _op) \
|
||||||
|
do { \
|
||||||
|
struct snd_ctl_layer_ops *lops; \
|
||||||
|
guard(rwsem_read)(&(_card)->controls_rwsem); \
|
||||||
|
guard(rwsem_read)(&snd_ctl_layer_rwsem); \
|
||||||
|
for (lops = snd_ctl_layer; lops; lops = lops->next) \
|
||||||
|
lops->_op(_card); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* registration of the control device
|
* registration of the control device
|
||||||
*/
|
*/
|
||||||
static int snd_ctl_dev_register(struct snd_device *device)
|
static int snd_ctl_dev_register(struct snd_device *device)
|
||||||
{
|
{
|
||||||
struct snd_card *card = device->device_data;
|
struct snd_card *card = device->device_data;
|
||||||
struct snd_ctl_layer_ops *lops;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
|
err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
|
||||||
&snd_ctl_f_ops, card, card->ctl_dev);
|
&snd_ctl_f_ops, card, card->ctl_dev);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
down_read(&card->controls_rwsem);
|
call_snd_ctl_lops(card, lregister);
|
||||||
down_read(&snd_ctl_layer_rwsem);
|
|
||||||
for (lops = snd_ctl_layer; lops; lops = lops->next)
|
|
||||||
lops->lregister(card);
|
|
||||||
up_read(&snd_ctl_layer_rwsem);
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2408,23 +2320,15 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
|
||||||
{
|
{
|
||||||
struct snd_card *card = device->device_data;
|
struct snd_card *card = device->device_data;
|
||||||
struct snd_ctl_file *ctl;
|
struct snd_ctl_file *ctl;
|
||||||
struct snd_ctl_layer_ops *lops;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
read_lock_irqsave(&card->ctl_files_rwlock, flags);
|
scoped_guard(read_lock_irqsave, &card->ctl_files_rwlock) {
|
||||||
list_for_each_entry(ctl, &card->ctl_files, list) {
|
list_for_each_entry(ctl, &card->ctl_files, list) {
|
||||||
wake_up(&ctl->change_sleep);
|
wake_up(&ctl->change_sleep);
|
||||||
snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
|
snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
|
||||||
down_read(&snd_ctl_layer_rwsem);
|
|
||||||
for (lops = snd_ctl_layer; lops; lops = lops->next)
|
|
||||||
lops->ldisconnect(card);
|
|
||||||
up_read(&snd_ctl_layer_rwsem);
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
|
|
||||||
|
call_snd_ctl_lops(card, ldisconnect);
|
||||||
return snd_unregister_device(card->ctl_dev);
|
return snd_unregister_device(card->ctl_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2436,17 +2340,17 @@ static int snd_ctl_dev_free(struct snd_device *device)
|
||||||
struct snd_card *card = device->device_data;
|
struct snd_card *card = device->device_data;
|
||||||
struct snd_kcontrol *control;
|
struct snd_kcontrol *control;
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
scoped_guard(rwsem_write, &card->controls_rwsem) {
|
||||||
while (!list_empty(&card->controls)) {
|
while (!list_empty(&card->controls)) {
|
||||||
control = snd_kcontrol(card->controls.next);
|
control = snd_kcontrol(card->controls.next);
|
||||||
__snd_ctl_remove(card, control, false);
|
__snd_ctl_remove(card, control, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
|
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
|
||||||
xa_destroy(&card->ctl_numids);
|
xa_destroy(&card->ctl_numids);
|
||||||
xa_destroy(&card->ctl_hash);
|
xa_destroy(&card->ctl_hash);
|
||||||
#endif
|
#endif
|
||||||
up_write(&card->controls_rwsem);
|
}
|
||||||
put_device(card->ctl_dev);
|
put_device(card->ctl_dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,61 +79,56 @@ struct snd_ctl_elem_info32 {
|
||||||
static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
|
static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
|
||||||
struct snd_ctl_elem_info32 __user *data32)
|
struct snd_ctl_elem_info32 __user *data32)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *data;
|
struct snd_ctl_elem_info *data __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
if (! data)
|
if (! data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = -EFAULT;
|
|
||||||
/* copy id */
|
/* copy id */
|
||||||
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
|
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
/* we need to copy the item index.
|
/* we need to copy the item index.
|
||||||
* hope this doesn't break anything..
|
* hope this doesn't break anything..
|
||||||
*/
|
*/
|
||||||
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
|
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
|
|
||||||
err = snd_ctl_elem_info(ctl, data);
|
err = snd_ctl_elem_info(ctl, data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
/* restore info to 32bit */
|
/* restore info to 32bit */
|
||||||
err = -EFAULT;
|
|
||||||
/* id, type, access, count */
|
/* id, type, access, count */
|
||||||
if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
|
if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
|
||||||
copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
|
copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
if (put_user(data->owner, &data32->owner))
|
if (put_user(data->owner, &data32->owner))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
switch (data->type) {
|
switch (data->type) {
|
||||||
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
|
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
|
||||||
case SNDRV_CTL_ELEM_TYPE_INTEGER:
|
case SNDRV_CTL_ELEM_TYPE_INTEGER:
|
||||||
if (put_user(data->value.integer.min, &data32->value.integer.min) ||
|
if (put_user(data->value.integer.min, &data32->value.integer.min) ||
|
||||||
put_user(data->value.integer.max, &data32->value.integer.max) ||
|
put_user(data->value.integer.max, &data32->value.integer.max) ||
|
||||||
put_user(data->value.integer.step, &data32->value.integer.step))
|
put_user(data->value.integer.step, &data32->value.integer.step))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
|
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
|
||||||
if (copy_to_user(&data32->value.integer64,
|
if (copy_to_user(&data32->value.integer64,
|
||||||
&data->value.integer64,
|
&data->value.integer64,
|
||||||
sizeof(data->value.integer64)))
|
sizeof(data->value.integer64)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
|
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
|
||||||
if (copy_to_user(&data32->value.enumerated,
|
if (copy_to_user(&data32->value.enumerated,
|
||||||
&data->value.enumerated,
|
&data->value.enumerated,
|
||||||
sizeof(data->value.enumerated)))
|
sizeof(data->value.enumerated)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err = 0;
|
return 0;
|
||||||
error:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read / write */
|
/* read / write */
|
||||||
|
@ -169,31 +164,25 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
|
||||||
int *countp)
|
int *countp)
|
||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_ctl_elem_info *info;
|
struct snd_ctl_elem_info *info __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_id_locked(card, id);
|
kctl = snd_ctl_find_id_locked(card, id);
|
||||||
if (! kctl) {
|
if (!kctl)
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
|
||||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||||
if (info == NULL) {
|
if (info == NULL)
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
info->id = *id;
|
info->id = *id;
|
||||||
err = snd_power_ref_and_wait(card);
|
err = snd_power_ref_and_wait(card);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = kctl->info(kctl, info);
|
err = kctl->info(kctl, info);
|
||||||
snd_power_unref(card);
|
snd_power_unref(card);
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
err = info->type;
|
err = info->type;
|
||||||
*countp = info->count;
|
*countp = info->count;
|
||||||
}
|
}
|
||||||
kfree(info);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +278,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
|
||||||
static int ctl_elem_read_user(struct snd_card *card,
|
static int ctl_elem_read_user(struct snd_card *card,
|
||||||
void __user *userdata, void __user *valuep)
|
void __user *userdata, void __user *valuep)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_value *data;
|
struct snd_ctl_elem_value *data __free(kfree) = NULL;
|
||||||
int err, type, count;
|
int err, type, count;
|
||||||
|
|
||||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
|
@ -299,21 +288,18 @@ static int ctl_elem_read_user(struct snd_card *card,
|
||||||
err = copy_ctl_value_from_user(card, data, userdata, valuep,
|
err = copy_ctl_value_from_user(card, data, userdata, valuep,
|
||||||
&type, &count);
|
&type, &count);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
|
|
||||||
err = snd_ctl_elem_read(card, data);
|
err = snd_ctl_elem_read(card, data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
|
return copy_ctl_value_to_user(userdata, valuep, data, type, count);
|
||||||
error:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctl_elem_write_user(struct snd_ctl_file *file,
|
static int ctl_elem_write_user(struct snd_ctl_file *file,
|
||||||
void __user *userdata, void __user *valuep)
|
void __user *userdata, void __user *valuep)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_value *data;
|
struct snd_ctl_elem_value *data __free(kfree) = NULL;
|
||||||
struct snd_card *card = file->card;
|
struct snd_card *card = file->card;
|
||||||
int err, type, count;
|
int err, type, count;
|
||||||
|
|
||||||
|
@ -324,15 +310,12 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
|
||||||
err = copy_ctl_value_from_user(card, data, userdata, valuep,
|
err = copy_ctl_value_from_user(card, data, userdata, valuep,
|
||||||
&type, &count);
|
&type, &count);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
|
|
||||||
err = snd_ctl_elem_write(card, file, data);
|
err = snd_ctl_elem_write(card, file, data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
|
return copy_ctl_value_to_user(userdata, valuep, data, type, count);
|
||||||
error:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_read_user_compat(struct snd_card *card,
|
static int snd_ctl_elem_read_user_compat(struct snd_card *card,
|
||||||
|
@ -366,49 +349,44 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
|
||||||
struct snd_ctl_elem_info32 __user *data32,
|
struct snd_ctl_elem_info32 __user *data32,
|
||||||
int replace)
|
int replace)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *data;
|
struct snd_ctl_elem_info *data __free(kfree) = NULL;
|
||||||
int err;
|
|
||||||
|
|
||||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
if (! data)
|
if (! data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = -EFAULT;
|
|
||||||
/* id, type, access, count */ \
|
/* id, type, access, count */ \
|
||||||
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
|
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
|
||||||
copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
|
copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
if (get_user(data->owner, &data32->owner))
|
if (get_user(data->owner, &data32->owner))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
switch (data->type) {
|
switch (data->type) {
|
||||||
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
|
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
|
||||||
case SNDRV_CTL_ELEM_TYPE_INTEGER:
|
case SNDRV_CTL_ELEM_TYPE_INTEGER:
|
||||||
if (get_user(data->value.integer.min, &data32->value.integer.min) ||
|
if (get_user(data->value.integer.min, &data32->value.integer.min) ||
|
||||||
get_user(data->value.integer.max, &data32->value.integer.max) ||
|
get_user(data->value.integer.max, &data32->value.integer.max) ||
|
||||||
get_user(data->value.integer.step, &data32->value.integer.step))
|
get_user(data->value.integer.step, &data32->value.integer.step))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
|
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
|
||||||
if (copy_from_user(&data->value.integer64,
|
if (copy_from_user(&data->value.integer64,
|
||||||
&data32->value.integer64,
|
&data32->value.integer64,
|
||||||
sizeof(data->value.integer64)))
|
sizeof(data->value.integer64)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
|
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
|
||||||
if (copy_from_user(&data->value.enumerated,
|
if (copy_from_user(&data->value.enumerated,
|
||||||
&data32->value.enumerated,
|
&data32->value.enumerated,
|
||||||
sizeof(data->value.enumerated)))
|
sizeof(data->value.enumerated)))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
data->value.enumerated.names_ptr =
|
data->value.enumerated.names_ptr =
|
||||||
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
|
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err = snd_ctl_elem_add(file, data, replace);
|
return snd_ctl_elem_add(file, data, replace);
|
||||||
error:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -468,16 +446,13 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
|
||||||
#endif /* CONFIG_X86_X32_ABI */
|
#endif /* CONFIG_X86_X32_ABI */
|
||||||
}
|
}
|
||||||
|
|
||||||
down_read(&snd_ioctl_rwsem);
|
guard(rwsem_read)(&snd_ioctl_rwsem);
|
||||||
list_for_each_entry(p, &snd_control_compat_ioctls, list) {
|
list_for_each_entry(p, &snd_control_compat_ioctls, list) {
|
||||||
if (p->fioctl) {
|
if (p->fioctl) {
|
||||||
err = p->fioctl(ctl->card, ctl, cmd, arg);
|
err = p->fioctl(ctl->card, ctl, cmd, arg);
|
||||||
if (err != -ENOIOCTLCMD) {
|
if (err != -ENOIOCTLCMD)
|
||||||
up_read(&snd_ioctl_rwsem);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
up_read(&snd_ioctl_rwsem);
|
|
||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,29 +147,27 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
|
||||||
return;
|
return;
|
||||||
route = -1;
|
route = -1;
|
||||||
found = false;
|
found = false;
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
scoped_guard(mutex, &snd_ctl_led_mutex) {
|
||||||
/* the card may not be registered (active) at this point */
|
/* the card may not be registered (active) at this point */
|
||||||
if (card && !snd_ctl_led_card_valid[card->number]) {
|
if (card && !snd_ctl_led_card_valid[card->number])
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
return;
|
||||||
return;
|
list_for_each_entry(lctl, &led->controls, list) {
|
||||||
}
|
if (lctl->kctl == kctl && lctl->index_offset == ioff)
|
||||||
list_for_each_entry(lctl, &led->controls, list) {
|
found = true;
|
||||||
if (lctl->kctl == kctl && lctl->index_offset == ioff)
|
|
||||||
found = true;
|
|
||||||
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
|
|
||||||
}
|
|
||||||
if (!found && kctl && card) {
|
|
||||||
lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
|
|
||||||
if (lctl) {
|
|
||||||
lctl->card = card;
|
|
||||||
lctl->access = access;
|
|
||||||
lctl->kctl = kctl;
|
|
||||||
lctl->index_offset = ioff;
|
|
||||||
list_add(&lctl->list, &led->controls);
|
|
||||||
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
|
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
|
||||||
}
|
}
|
||||||
|
if (!found && kctl && card) {
|
||||||
|
lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
|
||||||
|
if (lctl) {
|
||||||
|
lctl->card = card;
|
||||||
|
lctl->access = access;
|
||||||
|
lctl->kctl = kctl;
|
||||||
|
lctl->index_offset = ioff;
|
||||||
|
list_add(&lctl->list, &led->controls);
|
||||||
|
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
|
||||||
switch (led->mode) {
|
switch (led->mode) {
|
||||||
case MODE_OFF: route = 1; break;
|
case MODE_OFF: route = 1; break;
|
||||||
case MODE_ON: route = 0; break;
|
case MODE_ON: route = 0; break;
|
||||||
|
@ -201,14 +199,13 @@ static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int i
|
||||||
struct snd_ctl_led_ctl *lctl;
|
struct snd_ctl_led_ctl *lctl;
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
guard(mutex)(&snd_ctl_led_mutex);
|
||||||
lctl = snd_ctl_led_find(kctl, ioff);
|
lctl = snd_ctl_led_find(kctl, ioff);
|
||||||
if (lctl && (access == 0 || access != lctl->access)) {
|
if (lctl && (access == 0 || access != lctl->access)) {
|
||||||
ret = lctl->access;
|
ret = lctl->access;
|
||||||
list_del(&lctl->list);
|
list_del(&lctl->list);
|
||||||
kfree(lctl);
|
kfree(lctl);
|
||||||
}
|
}
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,44 +236,36 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T))
|
||||||
|
|
||||||
static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
|
static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
|
||||||
unsigned int group, bool set)
|
unsigned int group, bool set)
|
||||||
{
|
{
|
||||||
struct snd_card *card;
|
struct snd_card *card __free(snd_card_unref) = NULL;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_kcontrol_volatile *vd;
|
struct snd_kcontrol_volatile *vd;
|
||||||
unsigned int ioff, access, new_access;
|
unsigned int ioff, access, new_access;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
card = snd_card_ref(card_number);
|
card = snd_card_ref(card_number);
|
||||||
if (card) {
|
if (!card)
|
||||||
down_write(&card->controls_rwsem);
|
return -ENXIO;
|
||||||
kctl = snd_ctl_find_id_locked(card, id);
|
guard(rwsem_write)(&card->controls_rwsem);
|
||||||
if (kctl) {
|
kctl = snd_ctl_find_id_locked(card, id);
|
||||||
ioff = snd_ctl_get_ioff(kctl, id);
|
if (!kctl)
|
||||||
vd = &kctl->vd[ioff];
|
return -ENOENT;
|
||||||
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
|
ioff = snd_ctl_get_ioff(kctl, id);
|
||||||
if (access != 0 && access != group_to_access(group)) {
|
vd = &kctl->vd[ioff];
|
||||||
err = -EXDEV;
|
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
|
||||||
goto unlock;
|
if (access != 0 && access != group_to_access(group))
|
||||||
}
|
return -EXDEV;
|
||||||
new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
|
new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
|
||||||
if (set)
|
if (set)
|
||||||
new_access |= group_to_access(group);
|
new_access |= group_to_access(group);
|
||||||
if (new_access != vd->access) {
|
if (new_access != vd->access) {
|
||||||
vd->access = new_access;
|
vd->access = new_access;
|
||||||
snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
|
snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = -ENOENT;
|
|
||||||
}
|
|
||||||
unlock:
|
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
snd_card_unref(card);
|
|
||||||
} else {
|
|
||||||
err = -ENXIO;
|
|
||||||
}
|
}
|
||||||
return err;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_ctl_led_refresh(void)
|
static void snd_ctl_led_refresh(void)
|
||||||
|
@ -312,7 +301,7 @@ repeat:
|
||||||
|
|
||||||
static int snd_ctl_led_reset(int card_number, unsigned int group)
|
static int snd_ctl_led_reset(int card_number, unsigned int group)
|
||||||
{
|
{
|
||||||
struct snd_card *card;
|
struct snd_card *card __free(snd_card_unref) = NULL;
|
||||||
struct snd_ctl_led *led;
|
struct snd_ctl_led *led;
|
||||||
struct snd_ctl_led_ctl *lctl;
|
struct snd_ctl_led_ctl *lctl;
|
||||||
struct snd_kcontrol_volatile *vd;
|
struct snd_kcontrol_volatile *vd;
|
||||||
|
@ -322,26 +311,22 @@ static int snd_ctl_led_reset(int card_number, unsigned int group)
|
||||||
if (!card)
|
if (!card)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
scoped_guard(mutex, &snd_ctl_led_mutex) {
|
||||||
if (!snd_ctl_led_card_valid[card_number]) {
|
if (!snd_ctl_led_card_valid[card_number])
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
return -ENXIO;
|
||||||
snd_card_unref(card);
|
led = &snd_ctl_leds[group];
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
led = &snd_ctl_leds[group];
|
|
||||||
repeat:
|
repeat:
|
||||||
list_for_each_entry(lctl, &led->controls, list)
|
list_for_each_entry(lctl, &led->controls, list)
|
||||||
if (lctl->card == card) {
|
if (lctl->card == card) {
|
||||||
vd = &lctl->kctl->vd[lctl->index_offset];
|
vd = &lctl->kctl->vd[lctl->index_offset];
|
||||||
vd->access &= ~group_to_access(group);
|
vd->access &= ~group_to_access(group);
|
||||||
snd_ctl_led_ctl_destroy(lctl);
|
snd_ctl_led_ctl_destroy(lctl);
|
||||||
change = true;
|
change = true;
|
||||||
goto repeat;
|
goto repeat;
|
||||||
}
|
}
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
}
|
||||||
if (change)
|
if (change)
|
||||||
snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
|
snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
|
||||||
snd_card_unref(card);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,9 +338,8 @@ static void snd_ctl_led_register(struct snd_card *card)
|
||||||
if (snd_BUG_ON(card->number < 0 ||
|
if (snd_BUG_ON(card->number < 0 ||
|
||||||
card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
|
card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
|
||||||
return;
|
return;
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
scoped_guard(mutex, &snd_ctl_led_mutex)
|
||||||
snd_ctl_led_card_valid[card->number] = true;
|
snd_ctl_led_card_valid[card->number] = true;
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
|
||||||
/* the register callback is already called with held card->controls_rwsem */
|
/* the register callback is already called with held card->controls_rwsem */
|
||||||
list_for_each_entry(kctl, &card->controls, list)
|
list_for_each_entry(kctl, &card->controls, list)
|
||||||
for (ioff = 0; ioff < kctl->count; ioff++)
|
for (ioff = 0; ioff < kctl->count; ioff++)
|
||||||
|
@ -367,10 +351,10 @@ static void snd_ctl_led_register(struct snd_card *card)
|
||||||
static void snd_ctl_led_disconnect(struct snd_card *card)
|
static void snd_ctl_led_disconnect(struct snd_card *card)
|
||||||
{
|
{
|
||||||
snd_ctl_led_sysfs_remove(card);
|
snd_ctl_led_sysfs_remove(card);
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
scoped_guard(mutex, &snd_ctl_led_mutex) {
|
||||||
snd_ctl_led_card_valid[card->number] = false;
|
snd_ctl_led_card_valid[card->number] = false;
|
||||||
snd_ctl_led_clean(card);
|
snd_ctl_led_clean(card);
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
}
|
||||||
snd_ctl_led_refresh();
|
snd_ctl_led_refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,9 +414,8 @@ static ssize_t mode_store(struct device *dev,
|
||||||
else
|
else
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
scoped_guard(mutex, &snd_ctl_led_mutex)
|
||||||
led->mode = mode;
|
led->mode = mode;
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
|
||||||
|
|
||||||
snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
|
snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
|
||||||
return count;
|
return count;
|
||||||
|
@ -615,15 +598,15 @@ static ssize_t list_show(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
|
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
|
||||||
struct snd_card *card;
|
struct snd_card *card __free(snd_card_unref) = NULL;
|
||||||
struct snd_ctl_led_ctl *lctl;
|
struct snd_ctl_led_ctl *lctl;
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
|
|
||||||
card = snd_card_ref(led_card->number);
|
card = snd_card_ref(led_card->number);
|
||||||
if (!card)
|
if (!card)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
mutex_lock(&snd_ctl_led_mutex);
|
guard(mutex)(&snd_ctl_led_mutex);
|
||||||
if (snd_ctl_led_card_valid[led_card->number]) {
|
if (snd_ctl_led_card_valid[led_card->number]) {
|
||||||
list_for_each_entry(lctl, &led_card->led->controls, list) {
|
list_for_each_entry(lctl, &led_card->led->controls, list) {
|
||||||
if (lctl->card != card)
|
if (lctl->card != card)
|
||||||
|
@ -634,9 +617,6 @@ static ssize_t list_show(struct device *dev,
|
||||||
lctl->kctl->id.numid + lctl->index_offset);
|
lctl->kctl->id.numid + lctl->index_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&snd_ctl_led_mutex);
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
snd_card_unref(card);
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,12 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
|
||||||
unsigned long ticks;
|
unsigned long ticks;
|
||||||
enum hrtimer_restart ret = HRTIMER_NORESTART;
|
enum hrtimer_restart ret = HRTIMER_NORESTART;
|
||||||
|
|
||||||
spin_lock(&t->lock);
|
scoped_guard(spinlock, &t->lock) {
|
||||||
if (!t->running)
|
if (!t->running)
|
||||||
goto out; /* fast path */
|
return HRTIMER_NORESTART; /* fast path */
|
||||||
stime->in_callback = true;
|
stime->in_callback = true;
|
||||||
ticks = t->sticks;
|
ticks = t->sticks;
|
||||||
spin_unlock(&t->lock);
|
}
|
||||||
|
|
||||||
/* calculate the drift */
|
/* calculate the drift */
|
||||||
delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
|
delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
|
||||||
|
@ -49,15 +49,13 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
|
||||||
|
|
||||||
snd_timer_interrupt(stime->timer, ticks);
|
snd_timer_interrupt(stime->timer, ticks);
|
||||||
|
|
||||||
spin_lock(&t->lock);
|
guard(spinlock)(&t->lock);
|
||||||
if (t->running) {
|
if (t->running) {
|
||||||
hrtimer_add_expires_ns(hrt, t->sticks * resolution);
|
hrtimer_add_expires_ns(hrt, t->sticks * resolution);
|
||||||
ret = HRTIMER_RESTART;
|
ret = HRTIMER_RESTART;
|
||||||
}
|
}
|
||||||
|
|
||||||
stime->in_callback = false;
|
stime->in_callback = false;
|
||||||
out:
|
|
||||||
spin_unlock(&t->lock);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +78,10 @@ static int snd_hrtimer_close(struct snd_timer *t)
|
||||||
struct snd_hrtimer *stime = t->private_data;
|
struct snd_hrtimer *stime = t->private_data;
|
||||||
|
|
||||||
if (stime) {
|
if (stime) {
|
||||||
spin_lock_irq(&t->lock);
|
scoped_guard(spinlock_irq, &t->lock) {
|
||||||
t->running = 0; /* just to be sure */
|
t->running = 0; /* just to be sure */
|
||||||
stime->in_callback = 1; /* skip start/stop */
|
stime->in_callback = 1; /* skip start/stop */
|
||||||
spin_unlock_irq(&t->lock);
|
}
|
||||||
|
|
||||||
hrtimer_cancel(&stime->hrt);
|
hrtimer_cancel(&stime->hrt);
|
||||||
kfree(stime);
|
kfree(stime);
|
||||||
|
|
|
@ -149,12 +149,12 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
|
||||||
struct snd_hwdep *hw = file->private_data;
|
struct snd_hwdep *hw = file->private_data;
|
||||||
struct module *mod = hw->card->module;
|
struct module *mod = hw->card->module;
|
||||||
|
|
||||||
mutex_lock(&hw->open_mutex);
|
scoped_guard(mutex, &hw->open_mutex) {
|
||||||
if (hw->ops.release)
|
if (hw->ops.release)
|
||||||
err = hw->ops.release(hw, file);
|
err = hw->ops.release(hw, file);
|
||||||
if (hw->used > 0)
|
if (hw->used > 0)
|
||||||
hw->used--;
|
hw->used--;
|
||||||
mutex_unlock(&hw->open_mutex);
|
}
|
||||||
wake_up(&hw->open_wait);
|
wake_up(&hw->open_wait);
|
||||||
|
|
||||||
snd_card_file_remove(hw->card, file);
|
snd_card_file_remove(hw->card, file);
|
||||||
|
@ -272,23 +272,23 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
|
||||||
|
|
||||||
if (get_user(device, (int __user *)arg))
|
if (get_user(device, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
|
||||||
|
|
||||||
if (device < 0)
|
scoped_guard(mutex, ®ister_mutex) {
|
||||||
device = 0;
|
if (device < 0)
|
||||||
else if (device < SNDRV_MINOR_HWDEPS)
|
device = 0;
|
||||||
device++;
|
else if (device < SNDRV_MINOR_HWDEPS)
|
||||||
else
|
device++;
|
||||||
device = SNDRV_MINOR_HWDEPS;
|
else
|
||||||
|
device = SNDRV_MINOR_HWDEPS;
|
||||||
|
|
||||||
while (device < SNDRV_MINOR_HWDEPS) {
|
while (device < SNDRV_MINOR_HWDEPS) {
|
||||||
if (snd_hwdep_search(card, device))
|
if (snd_hwdep_search(card, device))
|
||||||
break;
|
break;
|
||||||
device++;
|
device++;
|
||||||
|
}
|
||||||
|
if (device >= SNDRV_MINOR_HWDEPS)
|
||||||
|
device = -1;
|
||||||
}
|
}
|
||||||
if (device >= SNDRV_MINOR_HWDEPS)
|
|
||||||
device = -1;
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
if (put_user(device, (int __user *)arg))
|
if (put_user(device, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -296,19 +296,18 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
|
||||||
case SNDRV_CTL_IOCTL_HWDEP_INFO:
|
case SNDRV_CTL_IOCTL_HWDEP_INFO:
|
||||||
{
|
{
|
||||||
struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
|
struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
|
||||||
int device, err;
|
int device;
|
||||||
struct snd_hwdep *hwdep;
|
struct snd_hwdep *hwdep;
|
||||||
|
|
||||||
if (get_user(device, &info->device))
|
if (get_user(device, &info->device))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
scoped_guard(mutex, ®ister_mutex) {
|
||||||
hwdep = snd_hwdep_search(card, device);
|
hwdep = snd_hwdep_search(card, device);
|
||||||
if (hwdep)
|
if (!hwdep)
|
||||||
err = snd_hwdep_info(hwdep, info);
|
return -ENXIO;
|
||||||
else
|
return snd_hwdep_info(hwdep, info);
|
||||||
err = -ENXIO;
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
break;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
|
@ -422,11 +421,9 @@ static int snd_hwdep_dev_register(struct snd_device *device)
|
||||||
struct snd_card *card = hwdep->card;
|
struct snd_card *card = hwdep->card;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
if (snd_hwdep_search(card, hwdep->device)) {
|
if (snd_hwdep_search(card, hwdep->device))
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
|
||||||
list_add_tail(&hwdep->list, &snd_hwdep_devices);
|
list_add_tail(&hwdep->list, &snd_hwdep_devices);
|
||||||
err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
|
err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
|
||||||
hwdep->card, hwdep->device,
|
hwdep->card, hwdep->device,
|
||||||
|
@ -434,7 +431,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(hwdep->dev, "unable to register\n");
|
dev_err(hwdep->dev, "unable to register\n");
|
||||||
list_del(&hwdep->list);
|
list_del(&hwdep->list);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +450,6 @@ static int snd_hwdep_dev_register(struct snd_device *device)
|
||||||
hwdep->ossreg = 1;
|
hwdep->ossreg = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,12 +459,10 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
|
||||||
|
|
||||||
if (snd_BUG_ON(!hwdep))
|
if (snd_BUG_ON(!hwdep))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
|
if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep)
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
guard(mutex)(&hwdep->open_mutex);
|
||||||
mutex_lock(&hwdep->open_mutex);
|
|
||||||
wake_up(&hwdep->open_wait);
|
wake_up(&hwdep->open_wait);
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
if (hwdep->ossreg)
|
if (hwdep->ossreg)
|
||||||
|
@ -477,8 +470,6 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
|
||||||
#endif
|
#endif
|
||||||
snd_unregister_device(hwdep->dev);
|
snd_unregister_device(hwdep->dev);
|
||||||
list_del_init(&hwdep->list);
|
list_del_init(&hwdep->list);
|
||||||
mutex_unlock(&hwdep->open_mutex);
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,11 +483,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry,
|
||||||
{
|
{
|
||||||
struct snd_hwdep *hwdep;
|
struct snd_hwdep *hwdep;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
list_for_each_entry(hwdep, &snd_hwdep_devices, list)
|
list_for_each_entry(hwdep, &snd_hwdep_devices, list)
|
||||||
snd_iprintf(buffer, "%02i-%02i: %s\n",
|
snd_iprintf(buffer, "%02i-%02i: %s\n",
|
||||||
hwdep->card->number, hwdep->device, hwdep->name);
|
hwdep->card->number, hwdep->device, hwdep->name);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_info_entry *snd_hwdep_proc_entry;
|
static struct snd_info_entry *snd_hwdep_proc_entry;
|
||||||
|
|
|
@ -105,17 +105,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
|
||||||
{
|
{
|
||||||
struct snd_info_private_data *data;
|
struct snd_info_private_data *data;
|
||||||
struct snd_info_entry *entry;
|
struct snd_info_entry *entry;
|
||||||
loff_t ret = -EINVAL, size;
|
loff_t size;
|
||||||
|
|
||||||
data = file->private_data;
|
data = file->private_data;
|
||||||
entry = data->entry;
|
entry = data->entry;
|
||||||
mutex_lock(&entry->access);
|
guard(mutex)(&entry->access);
|
||||||
if (entry->c.ops->llseek) {
|
if (entry->c.ops->llseek)
|
||||||
ret = entry->c.ops->llseek(entry,
|
return entry->c.ops->llseek(entry,
|
||||||
data->file_private_data,
|
data->file_private_data,
|
||||||
file, offset, orig);
|
file, offset, orig);
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = entry->size;
|
size = entry->size;
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
|
@ -126,21 +124,18 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
|
||||||
break;
|
break;
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
if (!size)
|
if (!size)
|
||||||
goto out;
|
return -EINVAL;
|
||||||
offset += size;
|
offset += size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
goto out;
|
return -EINVAL;
|
||||||
if (size && offset > size)
|
if (size && offset > size)
|
||||||
offset = size;
|
offset = size;
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
ret = offset;
|
return offset;
|
||||||
out:
|
|
||||||
mutex_unlock(&entry->access);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
|
static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
|
||||||
|
@ -238,10 +233,10 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
|
||||||
struct snd_info_private_data *data;
|
struct snd_info_private_data *data;
|
||||||
int mode, err;
|
int mode, err;
|
||||||
|
|
||||||
mutex_lock(&info_mutex);
|
guard(mutex)(&info_mutex);
|
||||||
err = alloc_info_private(entry, &data);
|
err = alloc_info_private(entry, &data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlock;
|
return err;
|
||||||
|
|
||||||
mode = file->f_flags & O_ACCMODE;
|
mode = file->f_flags & O_ACCMODE;
|
||||||
if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
|
if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
|
||||||
|
@ -257,14 +252,11 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
|
||||||
}
|
}
|
||||||
|
|
||||||
file->private_data = data;
|
file->private_data = data;
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
module_put(entry->module);
|
module_put(entry->module);
|
||||||
unlock:
|
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +298,6 @@ static ssize_t snd_info_text_entry_write(struct file *file,
|
||||||
struct snd_info_buffer *buf;
|
struct snd_info_buffer *buf;
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
size_t next;
|
size_t next;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!entry->c.text.write)
|
if (!entry->c.text.write)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -317,34 +308,24 @@ static ssize_t snd_info_text_entry_write(struct file *file,
|
||||||
/* don't handle too large text inputs */
|
/* don't handle too large text inputs */
|
||||||
if (next > 16 * 1024)
|
if (next > 16 * 1024)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&entry->access);
|
guard(mutex)(&entry->access);
|
||||||
buf = data->wbuffer;
|
buf = data->wbuffer;
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
||||||
if (!buf) {
|
if (!buf)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (next > buf->len) {
|
if (next > buf->len) {
|
||||||
char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
|
char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
|
||||||
if (!nbuf) {
|
if (!nbuf)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
kvfree(buf->buffer);
|
kvfree(buf->buffer);
|
||||||
buf->buffer = nbuf;
|
buf->buffer = nbuf;
|
||||||
buf->len = PAGE_ALIGN(next);
|
buf->len = PAGE_ALIGN(next);
|
||||||
}
|
}
|
||||||
if (copy_from_user(buf->buffer + pos, buffer, count)) {
|
if (copy_from_user(buf->buffer + pos, buffer, count))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
buf->size = next;
|
buf->size = next;
|
||||||
error:
|
|
||||||
mutex_unlock(&entry->access);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*offset = next;
|
*offset = next;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -369,10 +350,10 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
|
||||||
struct snd_info_private_data *data;
|
struct snd_info_private_data *data;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
mutex_lock(&info_mutex);
|
guard(mutex)(&info_mutex);
|
||||||
err = alloc_info_private(entry, &data);
|
err = alloc_info_private(entry, &data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlock;
|
return err;
|
||||||
|
|
||||||
data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
|
data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
|
||||||
if (!data->rbuffer) {
|
if (!data->rbuffer) {
|
||||||
|
@ -386,15 +367,12 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
|
||||||
err = single_open(file, snd_info_seq_show, data);
|
err = single_open(file, snd_info_seq_show, data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(data->rbuffer);
|
kfree(data->rbuffer);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
module_put(entry->module);
|
module_put(entry->module);
|
||||||
unlock:
|
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +527,7 @@ int snd_info_card_register(struct snd_card *card)
|
||||||
*/
|
*/
|
||||||
void snd_info_card_id_change(struct snd_card *card)
|
void snd_info_card_id_change(struct snd_card *card)
|
||||||
{
|
{
|
||||||
mutex_lock(&info_mutex);
|
guard(mutex)(&info_mutex);
|
||||||
if (card->proc_root_link) {
|
if (card->proc_root_link) {
|
||||||
proc_remove(card->proc_root_link);
|
proc_remove(card->proc_root_link);
|
||||||
card->proc_root_link = NULL;
|
card->proc_root_link = NULL;
|
||||||
|
@ -558,7 +536,6 @@ void snd_info_card_id_change(struct snd_card *card)
|
||||||
card->proc_root_link = proc_symlink(card->id,
|
card->proc_root_link = proc_symlink(card->id,
|
||||||
snd_proc_root->p,
|
snd_proc_root->p,
|
||||||
card->proc_root->name);
|
card->proc_root->name);
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -574,12 +551,11 @@ void snd_info_card_disconnect(struct snd_card *card)
|
||||||
if (card->proc_root)
|
if (card->proc_root)
|
||||||
proc_remove(card->proc_root->p);
|
proc_remove(card->proc_root->p);
|
||||||
|
|
||||||
mutex_lock(&info_mutex);
|
guard(mutex)(&info_mutex);
|
||||||
if (card->proc_root)
|
if (card->proc_root)
|
||||||
snd_info_clear_entries(card->proc_root);
|
snd_info_clear_entries(card->proc_root);
|
||||||
card->proc_root_link = NULL;
|
card->proc_root_link = NULL;
|
||||||
card->proc_root = NULL;
|
card->proc_root = NULL;
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -703,9 +679,8 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent,
|
||||||
entry->parent = parent;
|
entry->parent = parent;
|
||||||
entry->module = module;
|
entry->module = module;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
mutex_lock(&parent->access);
|
guard(mutex)(&parent->access);
|
||||||
list_add_tail(&entry->list, &parent->children);
|
list_add_tail(&entry->list, &parent->children);
|
||||||
mutex_unlock(&parent->access);
|
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -775,9 +750,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
|
||||||
return;
|
return;
|
||||||
if (entry->p) {
|
if (entry->p) {
|
||||||
proc_remove(entry->p);
|
proc_remove(entry->p);
|
||||||
mutex_lock(&info_mutex);
|
guard(mutex)(&info_mutex);
|
||||||
snd_info_clear_entries(entry);
|
snd_info_clear_entries(entry);
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free all children at first */
|
/* free all children at first */
|
||||||
|
@ -786,9 +760,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
|
||||||
|
|
||||||
p = entry->parent;
|
p = entry->parent;
|
||||||
if (p) {
|
if (p) {
|
||||||
mutex_lock(&p->access);
|
guard(mutex)(&p->access);
|
||||||
list_del(&entry->list);
|
list_del(&entry->list);
|
||||||
mutex_unlock(&p->access);
|
|
||||||
}
|
}
|
||||||
kfree(entry->name);
|
kfree(entry->name);
|
||||||
if (entry->private_free)
|
if (entry->private_free)
|
||||||
|
@ -804,15 +777,13 @@ static int __snd_info_register(struct snd_info_entry *entry)
|
||||||
if (snd_BUG_ON(!entry))
|
if (snd_BUG_ON(!entry))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
|
root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
|
||||||
mutex_lock(&info_mutex);
|
guard(mutex)(&info_mutex);
|
||||||
if (entry->p || !root)
|
if (entry->p || !root)
|
||||||
goto unlock;
|
return 0;
|
||||||
if (S_ISDIR(entry->mode)) {
|
if (S_ISDIR(entry->mode)) {
|
||||||
p = proc_mkdir_mode(entry->name, entry->mode, root);
|
p = proc_mkdir_mode(entry->name, entry->mode, root);
|
||||||
if (!p) {
|
if (!p)
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const struct proc_ops *ops;
|
const struct proc_ops *ops;
|
||||||
if (entry->content == SNDRV_INFO_CONTENT_DATA)
|
if (entry->content == SNDRV_INFO_CONTENT_DATA)
|
||||||
|
@ -821,15 +792,11 @@ static int __snd_info_register(struct snd_info_entry *entry)
|
||||||
ops = &snd_info_text_entry_ops;
|
ops = &snd_info_text_entry_ops;
|
||||||
p = proc_create_data(entry->name, entry->mode, root,
|
p = proc_create_data(entry->name, entry->mode, root,
|
||||||
ops, entry);
|
ops, entry);
|
||||||
if (!p) {
|
if (!p)
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
proc_set_size(p, entry->size);
|
proc_set_size(p, entry->size);
|
||||||
}
|
}
|
||||||
entry->p = p;
|
entry->p = p;
|
||||||
unlock:
|
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,20 +29,17 @@ int snd_oss_info_register(int dev, int num, char *string)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
|
if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
mutex_lock(&strings);
|
guard(mutex)(&strings);
|
||||||
if (string == NULL) {
|
if (string == NULL) {
|
||||||
x = snd_sndstat_strings[num][dev];
|
x = snd_sndstat_strings[num][dev];
|
||||||
kfree(x);
|
kfree(x);
|
||||||
x = NULL;
|
x = NULL;
|
||||||
} else {
|
} else {
|
||||||
x = kstrdup(string, GFP_KERNEL);
|
x = kstrdup(string, GFP_KERNEL);
|
||||||
if (x == NULL) {
|
if (x == NULL)
|
||||||
mutex_unlock(&strings);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
snd_sndstat_strings[num][dev] = x;
|
snd_sndstat_strings[num][dev] = x;
|
||||||
mutex_unlock(&strings);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_oss_info_register);
|
EXPORT_SYMBOL(snd_oss_info_register);
|
||||||
|
@ -53,7 +50,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
snd_iprintf(buf, "\n%s:", id);
|
snd_iprintf(buf, "\n%s:", id);
|
||||||
mutex_lock(&strings);
|
guard(mutex)(&strings);
|
||||||
for (idx = 0; idx < SNDRV_CARDS; idx++) {
|
for (idx = 0; idx < SNDRV_CARDS; idx++) {
|
||||||
str = snd_sndstat_strings[idx][dev];
|
str = snd_sndstat_strings[idx][dev];
|
||||||
if (str) {
|
if (str) {
|
||||||
|
@ -64,7 +61,6 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
|
||||||
snd_iprintf(buf, "%i: %s\n", idx, str);
|
snd_iprintf(buf, "%i: %s\n", idx, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&strings);
|
|
||||||
if (ok < 0)
|
if (ok < 0)
|
||||||
snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
|
snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
|
||||||
return ok;
|
return ok;
|
||||||
|
|
|
@ -284,30 +284,31 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
|
||||||
if (xid)
|
if (xid)
|
||||||
strscpy(card->id, xid, sizeof(card->id));
|
strscpy(card->id, xid, sizeof(card->id));
|
||||||
err = 0;
|
err = 0;
|
||||||
mutex_lock(&snd_card_mutex);
|
scoped_guard(mutex, &snd_card_mutex) {
|
||||||
if (idx < 0) /* first check the matching module-name slot */
|
if (idx < 0) /* first check the matching module-name slot */
|
||||||
idx = get_slot_from_bitmask(idx, module_slot_match, module);
|
idx = get_slot_from_bitmask(idx, module_slot_match, module);
|
||||||
if (idx < 0) /* if not matched, assign an empty slot */
|
if (idx < 0) /* if not matched, assign an empty slot */
|
||||||
idx = get_slot_from_bitmask(idx, check_empty_slot, module);
|
idx = get_slot_from_bitmask(idx, check_empty_slot, module);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
else if (idx < snd_ecards_limit) {
|
else if (idx < snd_ecards_limit) {
|
||||||
if (test_bit(idx, snd_cards_lock))
|
if (test_bit(idx, snd_cards_lock))
|
||||||
err = -EBUSY; /* invalid */
|
err = -EBUSY; /* invalid */
|
||||||
} else if (idx >= SNDRV_CARDS)
|
} else if (idx >= SNDRV_CARDS)
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
|
if (!err) {
|
||||||
|
set_bit(idx, snd_cards_lock); /* lock it */
|
||||||
|
if (idx >= snd_ecards_limit)
|
||||||
|
snd_ecards_limit = idx + 1; /* increase the limit */
|
||||||
|
}
|
||||||
|
}
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
|
dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
|
||||||
idx, snd_ecards_limit - 1, err);
|
idx, snd_ecards_limit - 1, err);
|
||||||
if (!card->managed)
|
if (!card->managed)
|
||||||
kfree(card); /* manually free here, as no destructor called */
|
kfree(card); /* manually free here, as no destructor called */
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
set_bit(idx, snd_cards_lock); /* lock it */
|
|
||||||
if (idx >= snd_ecards_limit)
|
|
||||||
snd_ecards_limit = idx + 1; /* increase the limit */
|
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
card->dev = parent;
|
card->dev = parent;
|
||||||
card->number = idx;
|
card->number = idx;
|
||||||
#ifdef MODULE
|
#ifdef MODULE
|
||||||
|
@ -386,11 +387,10 @@ struct snd_card *snd_card_ref(int idx)
|
||||||
{
|
{
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
|
|
||||||
mutex_lock(&snd_card_mutex);
|
guard(mutex)(&snd_card_mutex);
|
||||||
card = snd_cards[idx];
|
card = snd_cards[idx];
|
||||||
if (card)
|
if (card)
|
||||||
get_device(&card->card_dev);
|
get_device(&card->card_dev);
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_card_ref);
|
EXPORT_SYMBOL_GPL(snd_card_ref);
|
||||||
|
@ -398,12 +398,8 @@ EXPORT_SYMBOL_GPL(snd_card_ref);
|
||||||
/* return non-zero if a card is already locked */
|
/* return non-zero if a card is already locked */
|
||||||
int snd_card_locked(int card)
|
int snd_card_locked(int card)
|
||||||
{
|
{
|
||||||
int locked;
|
guard(mutex)(&snd_card_mutex);
|
||||||
|
return test_bit(card, snd_cards_lock);
|
||||||
mutex_lock(&snd_card_mutex);
|
|
||||||
locked = test_bit(card, snd_cards_lock);
|
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
return locked;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
|
static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
|
||||||
|
@ -427,15 +423,15 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct snd_monitor_file *df = NULL, *_df;
|
struct snd_monitor_file *df = NULL, *_df;
|
||||||
|
|
||||||
spin_lock(&shutdown_lock);
|
scoped_guard(spinlock, &shutdown_lock) {
|
||||||
list_for_each_entry(_df, &shutdown_files, shutdown_list) {
|
list_for_each_entry(_df, &shutdown_files, shutdown_list) {
|
||||||
if (_df->file == file) {
|
if (_df->file == file) {
|
||||||
df = _df;
|
df = _df;
|
||||||
list_del_init(&df->shutdown_list);
|
list_del_init(&df->shutdown_list);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&shutdown_lock);
|
|
||||||
|
|
||||||
if (likely(df)) {
|
if (likely(df)) {
|
||||||
if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
|
if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
|
||||||
|
@ -501,27 +497,24 @@ void snd_card_disconnect(struct snd_card *card)
|
||||||
if (!card)
|
if (!card)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock(&card->files_lock);
|
scoped_guard(spinlock, &card->files_lock) {
|
||||||
if (card->shutdown) {
|
if (card->shutdown)
|
||||||
spin_unlock(&card->files_lock);
|
return;
|
||||||
return;
|
card->shutdown = 1;
|
||||||
|
|
||||||
|
/* replace file->f_op with special dummy operations */
|
||||||
|
list_for_each_entry(mfile, &card->files_list, list) {
|
||||||
|
/* it's critical part, use endless loop */
|
||||||
|
/* we have no room to fail */
|
||||||
|
mfile->disconnected_f_op = mfile->file->f_op;
|
||||||
|
|
||||||
|
scoped_guard(spinlock, &shutdown_lock)
|
||||||
|
list_add(&mfile->shutdown_list, &shutdown_files);
|
||||||
|
|
||||||
|
mfile->file->f_op = &snd_shutdown_f_ops;
|
||||||
|
fops_get(mfile->file->f_op);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
card->shutdown = 1;
|
|
||||||
|
|
||||||
/* replace file->f_op with special dummy operations */
|
|
||||||
list_for_each_entry(mfile, &card->files_list, list) {
|
|
||||||
/* it's critical part, use endless loop */
|
|
||||||
/* we have no room to fail */
|
|
||||||
mfile->disconnected_f_op = mfile->file->f_op;
|
|
||||||
|
|
||||||
spin_lock(&shutdown_lock);
|
|
||||||
list_add(&mfile->shutdown_list, &shutdown_files);
|
|
||||||
spin_unlock(&shutdown_lock);
|
|
||||||
|
|
||||||
mfile->file->f_op = &snd_shutdown_f_ops;
|
|
||||||
fops_get(mfile->file->f_op);
|
|
||||||
}
|
|
||||||
spin_unlock(&card->files_lock);
|
|
||||||
|
|
||||||
/* notify all connected devices about disconnection */
|
/* notify all connected devices about disconnection */
|
||||||
/* at this point, they cannot respond to any calls except release() */
|
/* at this point, they cannot respond to any calls except release() */
|
||||||
|
@ -544,10 +537,10 @@ void snd_card_disconnect(struct snd_card *card)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disable fops (user space) operations for ALSA API */
|
/* disable fops (user space) operations for ALSA API */
|
||||||
mutex_lock(&snd_card_mutex);
|
scoped_guard(mutex, &snd_card_mutex) {
|
||||||
snd_cards[card->number] = NULL;
|
snd_cards[card->number] = NULL;
|
||||||
clear_bit(card->number, snd_cards_lock);
|
clear_bit(card->number, snd_cards_lock);
|
||||||
mutex_unlock(&snd_card_mutex);
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
wake_up(&card->power_sleep);
|
wake_up(&card->power_sleep);
|
||||||
|
@ -569,11 +562,10 @@ void snd_card_disconnect_sync(struct snd_card *card)
|
||||||
{
|
{
|
||||||
snd_card_disconnect(card);
|
snd_card_disconnect(card);
|
||||||
|
|
||||||
spin_lock_irq(&card->files_lock);
|
guard(spinlock_irq)(&card->files_lock);
|
||||||
wait_event_lock_irq(card->remove_sleep,
|
wait_event_lock_irq(card->remove_sleep,
|
||||||
list_empty(&card->files_list),
|
list_empty(&card->files_list),
|
||||||
card->files_lock);
|
card->files_lock);
|
||||||
spin_unlock_irq(&card->files_lock);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
|
EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
|
||||||
|
|
||||||
|
@ -767,9 +759,8 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
|
||||||
/* check if user specified own card->id */
|
/* check if user specified own card->id */
|
||||||
if (card->id[0] != '\0')
|
if (card->id[0] != '\0')
|
||||||
return;
|
return;
|
||||||
mutex_lock(&snd_card_mutex);
|
guard(mutex)(&snd_card_mutex);
|
||||||
snd_card_set_id_no_lock(card, nid, nid);
|
snd_card_set_id_no_lock(card, nid, nid);
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_card_set_id);
|
EXPORT_SYMBOL(snd_card_set_id);
|
||||||
|
|
||||||
|
@ -797,14 +788,11 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr,
|
||||||
}
|
}
|
||||||
memcpy(buf1, buf, copy);
|
memcpy(buf1, buf, copy);
|
||||||
buf1[copy] = '\0';
|
buf1[copy] = '\0';
|
||||||
mutex_lock(&snd_card_mutex);
|
guard(mutex)(&snd_card_mutex);
|
||||||
if (!card_id_ok(NULL, buf1)) {
|
if (!card_id_ok(NULL, buf1))
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
|
||||||
strcpy(card->id, buf1);
|
strcpy(card->id, buf1);
|
||||||
snd_info_card_id_change(card);
|
snd_info_card_id_change(card);
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -897,26 +885,27 @@ int snd_card_register(struct snd_card *card)
|
||||||
err = snd_device_register_all(card);
|
err = snd_device_register_all(card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
mutex_lock(&snd_card_mutex);
|
scoped_guard(mutex, &snd_card_mutex) {
|
||||||
if (snd_cards[card->number]) {
|
if (snd_cards[card->number]) {
|
||||||
/* already registered */
|
/* already registered */
|
||||||
mutex_unlock(&snd_card_mutex);
|
return snd_info_card_register(card); /* register pending info */
|
||||||
return snd_info_card_register(card); /* register pending info */
|
}
|
||||||
|
if (*card->id) {
|
||||||
|
/* make a unique id name from the given string */
|
||||||
|
char tmpid[sizeof(card->id)];
|
||||||
|
|
||||||
|
memcpy(tmpid, card->id, sizeof(card->id));
|
||||||
|
snd_card_set_id_no_lock(card, tmpid, tmpid);
|
||||||
|
} else {
|
||||||
|
/* create an id from either shortname or longname */
|
||||||
|
const char *src;
|
||||||
|
|
||||||
|
src = *card->shortname ? card->shortname : card->longname;
|
||||||
|
snd_card_set_id_no_lock(card, src,
|
||||||
|
retrieve_id_from_card_name(src));
|
||||||
|
}
|
||||||
|
snd_cards[card->number] = card;
|
||||||
}
|
}
|
||||||
if (*card->id) {
|
|
||||||
/* make a unique id name from the given string */
|
|
||||||
char tmpid[sizeof(card->id)];
|
|
||||||
memcpy(tmpid, card->id, sizeof(card->id));
|
|
||||||
snd_card_set_id_no_lock(card, tmpid, tmpid);
|
|
||||||
} else {
|
|
||||||
/* create an id from either shortname or longname */
|
|
||||||
const char *src;
|
|
||||||
src = *card->shortname ? card->shortname : card->longname;
|
|
||||||
snd_card_set_id_no_lock(card, src,
|
|
||||||
retrieve_id_from_card_name(src));
|
|
||||||
}
|
|
||||||
snd_cards[card->number] = card;
|
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
err = snd_info_card_register(card);
|
err = snd_info_card_register(card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -937,7 +926,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
|
|
||||||
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
|
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
|
||||||
mutex_lock(&snd_card_mutex);
|
guard(mutex)(&snd_card_mutex);
|
||||||
card = snd_cards[idx];
|
card = snd_cards[idx];
|
||||||
if (card) {
|
if (card) {
|
||||||
count++;
|
count++;
|
||||||
|
@ -949,7 +938,6 @@ static void snd_card_info_read(struct snd_info_entry *entry,
|
||||||
snd_iprintf(buffer, " %s\n",
|
snd_iprintf(buffer, " %s\n",
|
||||||
card->longname);
|
card->longname);
|
||||||
}
|
}
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
}
|
}
|
||||||
if (!count)
|
if (!count)
|
||||||
snd_iprintf(buffer, "--- no soundcards ---\n");
|
snd_iprintf(buffer, "--- no soundcards ---\n");
|
||||||
|
@ -962,13 +950,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
|
|
||||||
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
|
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
|
||||||
mutex_lock(&snd_card_mutex);
|
guard(mutex)(&snd_card_mutex);
|
||||||
card = snd_cards[idx];
|
card = snd_cards[idx];
|
||||||
if (card) {
|
if (card) {
|
||||||
count++;
|
count++;
|
||||||
snd_iprintf(buffer, "%s\n", card->longname);
|
snd_iprintf(buffer, "%s\n", card->longname);
|
||||||
}
|
}
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
}
|
}
|
||||||
if (!count) {
|
if (!count) {
|
||||||
snd_iprintf(buffer, "--- no soundcards ---\n");
|
snd_iprintf(buffer, "--- no soundcards ---\n");
|
||||||
|
@ -985,12 +972,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
|
|
||||||
for (idx = 0; idx < SNDRV_CARDS; idx++) {
|
for (idx = 0; idx < SNDRV_CARDS; idx++) {
|
||||||
mutex_lock(&snd_card_mutex);
|
guard(mutex)(&snd_card_mutex);
|
||||||
card = snd_cards[idx];
|
card = snd_cards[idx];
|
||||||
if (card)
|
if (card)
|
||||||
snd_iprintf(buffer, "%2i %s\n",
|
snd_iprintf(buffer, "%2i %s\n",
|
||||||
idx, card->module->name);
|
idx, card->module->name);
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1072,15 +1058,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
|
||||||
mfile->file = file;
|
mfile->file = file;
|
||||||
mfile->disconnected_f_op = NULL;
|
mfile->disconnected_f_op = NULL;
|
||||||
INIT_LIST_HEAD(&mfile->shutdown_list);
|
INIT_LIST_HEAD(&mfile->shutdown_list);
|
||||||
spin_lock(&card->files_lock);
|
guard(spinlock)(&card->files_lock);
|
||||||
if (card->shutdown) {
|
if (card->shutdown) {
|
||||||
spin_unlock(&card->files_lock);
|
|
||||||
kfree(mfile);
|
kfree(mfile);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
list_add(&mfile->list, &card->files_list);
|
list_add(&mfile->list, &card->files_list);
|
||||||
get_device(&card->card_dev);
|
get_device(&card->card_dev);
|
||||||
spin_unlock(&card->files_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_card_file_add);
|
EXPORT_SYMBOL(snd_card_file_add);
|
||||||
|
@ -1102,22 +1086,21 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
|
||||||
{
|
{
|
||||||
struct snd_monitor_file *mfile, *found = NULL;
|
struct snd_monitor_file *mfile, *found = NULL;
|
||||||
|
|
||||||
spin_lock(&card->files_lock);
|
scoped_guard(spinlock, &card->files_lock) {
|
||||||
list_for_each_entry(mfile, &card->files_list, list) {
|
list_for_each_entry(mfile, &card->files_list, list) {
|
||||||
if (mfile->file == file) {
|
if (mfile->file == file) {
|
||||||
list_del(&mfile->list);
|
list_del(&mfile->list);
|
||||||
spin_lock(&shutdown_lock);
|
scoped_guard(spinlock, &shutdown_lock)
|
||||||
list_del(&mfile->shutdown_list);
|
list_del(&mfile->shutdown_list);
|
||||||
spin_unlock(&shutdown_lock);
|
if (mfile->disconnected_f_op)
|
||||||
if (mfile->disconnected_f_op)
|
fops_put(mfile->disconnected_f_op);
|
||||||
fops_put(mfile->disconnected_f_op);
|
found = mfile;
|
||||||
found = mfile;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
if (list_empty(&card->files_list))
|
||||||
|
wake_up_all(&card->remove_sleep);
|
||||||
}
|
}
|
||||||
if (list_empty(&card->files_list))
|
|
||||||
wake_up_all(&card->remove_sleep);
|
|
||||||
spin_unlock(&card->files_lock);
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
dev_err(card->dev, "card file remove problem (%p)\n", file);
|
dev_err(card->dev, "card file remove problem (%p)\n", file);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
|
@ -42,11 +42,9 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
|
||||||
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
#ifdef CONFIG_SND_JACK_INPUT_DEV
|
||||||
struct snd_jack *jack = device->device_data;
|
struct snd_jack *jack = device->device_data;
|
||||||
|
|
||||||
mutex_lock(&jack->input_dev_lock);
|
guard(mutex)(&jack->input_dev_lock);
|
||||||
if (!jack->input_dev) {
|
if (!jack->input_dev)
|
||||||
mutex_unlock(&jack->input_dev_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* If the input device is registered with the input subsystem
|
/* If the input device is registered with the input subsystem
|
||||||
* then we need to use a different deallocator. */
|
* then we need to use a different deallocator. */
|
||||||
|
@ -55,7 +53,6 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
|
||||||
else
|
else
|
||||||
input_free_device(jack->input_dev);
|
input_free_device(jack->input_dev);
|
||||||
jack->input_dev = NULL;
|
jack->input_dev = NULL;
|
||||||
mutex_unlock(&jack->input_dev_lock);
|
|
||||||
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -92,11 +89,9 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||||
snprintf(jack->name, sizeof(jack->name), "%s %s",
|
snprintf(jack->name, sizeof(jack->name), "%s %s",
|
||||||
card->shortname, jack->id);
|
card->shortname, jack->id);
|
||||||
|
|
||||||
mutex_lock(&jack->input_dev_lock);
|
guard(mutex)(&jack->input_dev_lock);
|
||||||
if (!jack->input_dev) {
|
if (!jack->input_dev)
|
||||||
mutex_unlock(&jack->input_dev_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
jack->input_dev->name = jack->name;
|
jack->input_dev->name = jack->name;
|
||||||
|
|
||||||
|
@ -121,7 +116,6 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
jack->registered = 1;
|
jack->registered = 1;
|
||||||
|
|
||||||
mutex_unlock(&jack->input_dev_lock);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
#endif /* CONFIG_SND_JACK_INPUT_DEV */
|
||||||
|
@ -586,14 +580,9 @@ EXPORT_SYMBOL(snd_jack_new);
|
||||||
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
|
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
|
||||||
{
|
{
|
||||||
WARN_ON(jack->registered);
|
WARN_ON(jack->registered);
|
||||||
mutex_lock(&jack->input_dev_lock);
|
guard(mutex)(&jack->input_dev_lock);
|
||||||
if (!jack->input_dev) {
|
if (jack->input_dev)
|
||||||
mutex_unlock(&jack->input_dev_lock);
|
jack->input_dev->dev.parent = parent;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
jack->input_dev->dev.parent = parent;
|
|
||||||
mutex_unlock(&jack->input_dev_lock);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_jack_set_parent);
|
EXPORT_SYMBOL(snd_jack_set_parent);
|
||||||
|
|
||||||
|
|
|
@ -130,13 +130,12 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
|
||||||
|
|
||||||
if (mixer == NULL)
|
if (mixer == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
for (chn = 0; chn < 31; chn++) {
|
for (chn = 0; chn < 31; chn++) {
|
||||||
pslot = &mixer->slots[chn];
|
pslot = &mixer->slots[chn];
|
||||||
if (pslot->put_volume || pslot->put_recsrc)
|
if (pslot->put_volume || pslot->put_recsrc)
|
||||||
result |= 1 << chn;
|
result |= 1 << chn;
|
||||||
}
|
}
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,13 +147,12 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
|
||||||
|
|
||||||
if (mixer == NULL)
|
if (mixer == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
for (chn = 0; chn < 31; chn++) {
|
for (chn = 0; chn < 31; chn++) {
|
||||||
pslot = &mixer->slots[chn];
|
pslot = &mixer->slots[chn];
|
||||||
if (pslot->put_volume && pslot->stereo)
|
if (pslot->put_volume && pslot->stereo)
|
||||||
result |= 1 << chn;
|
result |= 1 << chn;
|
||||||
}
|
}
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +163,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
|
||||||
|
|
||||||
if (mixer == NULL)
|
if (mixer == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
|
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
|
||||||
result = mixer->mask_recsrc;
|
result = mixer->mask_recsrc;
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,7 +175,6 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
|
||||||
result |= 1 << chn;
|
result |= 1 << chn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,12 +185,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
|
||||||
|
|
||||||
if (mixer == NULL)
|
if (mixer == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
|
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
result = mixer->get_recsrc(fmixer, &index);
|
result = mixer->get_recsrc(fmixer, &index);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto unlock;
|
return result;
|
||||||
result = 1 << index;
|
result = 1 << index;
|
||||||
} else {
|
} else {
|
||||||
struct snd_mixer_oss_slot *pslot;
|
struct snd_mixer_oss_slot *pslot;
|
||||||
|
@ -209,8 +206,6 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mixer->oss_recsrc = result;
|
mixer->oss_recsrc = result;
|
||||||
unlock:
|
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +219,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
|
||||||
|
|
||||||
if (mixer == NULL)
|
if (mixer == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
|
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
|
||||||
if (recsrc & ~mixer->oss_recsrc)
|
if (recsrc & ~mixer->oss_recsrc)
|
||||||
recsrc &= ~mixer->oss_recsrc;
|
recsrc &= ~mixer->oss_recsrc;
|
||||||
|
@ -250,7 +245,6 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +256,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
|
||||||
|
|
||||||
if (mixer == NULL || slot > 30)
|
if (mixer == NULL || slot > 30)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
pslot = &mixer->slots[slot];
|
pslot = &mixer->slots[slot];
|
||||||
left = pslot->volume[0];
|
left = pslot->volume[0];
|
||||||
right = pslot->volume[1];
|
right = pslot->volume[1];
|
||||||
|
@ -270,21 +264,15 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
|
||||||
result = pslot->get_volume(fmixer, pslot, &left, &right);
|
result = pslot->get_volume(fmixer, pslot, &left, &right);
|
||||||
if (!pslot->stereo)
|
if (!pslot->stereo)
|
||||||
right = left;
|
right = left;
|
||||||
if (snd_BUG_ON(left < 0 || left > 100)) {
|
if (snd_BUG_ON(left < 0 || left > 100))
|
||||||
result = -EIO;
|
return -EIO;
|
||||||
goto unlock;
|
if (snd_BUG_ON(right < 0 || right > 100))
|
||||||
}
|
return -EIO;
|
||||||
if (snd_BUG_ON(right < 0 || right > 100)) {
|
|
||||||
result = -EIO;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
pslot->volume[0] = left;
|
pslot->volume[0] = left;
|
||||||
pslot->volume[1] = right;
|
pslot->volume[1] = right;
|
||||||
result = (left & 0xff) | ((right & 0xff) << 8);
|
result = (left & 0xff) | ((right & 0xff) << 8);
|
||||||
}
|
}
|
||||||
unlock:
|
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +285,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
|
||||||
|
|
||||||
if (mixer == NULL || slot > 30)
|
if (mixer == NULL || slot > 30)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
pslot = &mixer->slots[slot];
|
pslot = &mixer->slots[slot];
|
||||||
if (left > 100)
|
if (left > 100)
|
||||||
left = 100;
|
left = 100;
|
||||||
|
@ -308,12 +296,10 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
|
||||||
if (pslot->put_volume)
|
if (pslot->put_volume)
|
||||||
result = pslot->put_volume(fmixer, pslot, left, right);
|
result = pslot->put_volume(fmixer, pslot, left, right);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto unlock;
|
return result;
|
||||||
pslot->volume[0] = left;
|
pslot->volume[0] = left;
|
||||||
pslot->volume[1] = right;
|
pslot->volume[1] = right;
|
||||||
result = (left & 0xff) | ((right & 0xff) << 8);
|
result = (left & 0xff) | ((right & 0xff) << 8);
|
||||||
unlock:
|
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,37 +518,31 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
||||||
unsigned int numid,
|
unsigned int numid,
|
||||||
int *left, int *right)
|
int *left, int *right)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
struct snd_ctl_elem_value *uctl;
|
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_card *card = fmixer->card;
|
struct snd_card *card = fmixer->card;
|
||||||
|
|
||||||
if (numid == ID_UNKNOWN)
|
if (numid == ID_UNKNOWN)
|
||||||
return;
|
return;
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||||
if (!kctl) {
|
if (!kctl)
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL)
|
if (uinfo == NULL || uctl == NULL)
|
||||||
goto __unalloc;
|
return;
|
||||||
if (kctl->info(kctl, uinfo))
|
if (kctl->info(kctl, uinfo))
|
||||||
goto __unalloc;
|
return;
|
||||||
if (kctl->get(kctl, uctl))
|
if (kctl->get(kctl, uctl))
|
||||||
goto __unalloc;
|
return;
|
||||||
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
|
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
|
||||||
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
|
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
|
||||||
goto __unalloc;
|
return;
|
||||||
*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
|
*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
|
||||||
if (uinfo->count > 1)
|
if (uinfo->count > 1)
|
||||||
*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
|
*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
|
||||||
__unalloc:
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
kfree(uctl);
|
|
||||||
kfree(uinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
|
@ -571,27 +551,25 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
int *left, int *right,
|
int *left, int *right,
|
||||||
int route)
|
int route)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
struct snd_ctl_elem_value *uctl;
|
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_card *card = fmixer->card;
|
struct snd_card *card = fmixer->card;
|
||||||
|
|
||||||
if (numid == ID_UNKNOWN)
|
if (numid == ID_UNKNOWN)
|
||||||
return;
|
return;
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||||
if (!kctl) {
|
if (!kctl)
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL)
|
if (uinfo == NULL || uctl == NULL)
|
||||||
goto __unalloc;
|
return;
|
||||||
if (kctl->info(kctl, uinfo))
|
if (kctl->info(kctl, uinfo))
|
||||||
goto __unalloc;
|
return;
|
||||||
if (kctl->get(kctl, uctl))
|
if (kctl->get(kctl, uctl))
|
||||||
goto __unalloc;
|
return;
|
||||||
if (!uctl->value.integer.value[0]) {
|
if (!uctl->value.integer.value[0]) {
|
||||||
*left = 0;
|
*left = 0;
|
||||||
if (uinfo->count == 1)
|
if (uinfo->count == 1)
|
||||||
|
@ -599,10 +577,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
}
|
}
|
||||||
if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
|
if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
|
||||||
*right = 0;
|
*right = 0;
|
||||||
__unalloc:
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
kfree(uctl);
|
|
||||||
kfree(uinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
|
static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
|
||||||
|
@ -636,41 +610,35 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
||||||
unsigned int numid,
|
unsigned int numid,
|
||||||
int left, int right)
|
int left, int right)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
struct snd_ctl_elem_value *uctl;
|
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_card *card = fmixer->card;
|
struct snd_card *card = fmixer->card;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (numid == ID_UNKNOWN)
|
if (numid == ID_UNKNOWN)
|
||||||
return;
|
return;
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||||
if (!kctl) {
|
if (!kctl)
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL)
|
if (uinfo == NULL || uctl == NULL)
|
||||||
goto __unalloc;
|
return;
|
||||||
if (kctl->info(kctl, uinfo))
|
if (kctl->info(kctl, uinfo))
|
||||||
goto __unalloc;
|
return;
|
||||||
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
|
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
|
||||||
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
|
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
|
||||||
goto __unalloc;
|
return;
|
||||||
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
|
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
|
||||||
if (uinfo->count > 1)
|
if (uinfo->count > 1)
|
||||||
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
|
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
|
||||||
res = kctl->put(kctl, uctl);
|
res = kctl->put(kctl, uctl);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto __unalloc;
|
return;
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
||||||
__unalloc:
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
kfree(uctl);
|
|
||||||
kfree(uinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
|
@ -679,26 +647,24 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
int left, int right,
|
int left, int right,
|
||||||
int route)
|
int route)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
struct snd_ctl_elem_value *uctl;
|
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_card *card = fmixer->card;
|
struct snd_card *card = fmixer->card;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (numid == ID_UNKNOWN)
|
if (numid == ID_UNKNOWN)
|
||||||
return;
|
return;
|
||||||
down_read(&card->controls_rwsem);
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||||
if (!kctl) {
|
if (!kctl)
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL)
|
if (uinfo == NULL || uctl == NULL)
|
||||||
goto __unalloc;
|
return;
|
||||||
if (kctl->info(kctl, uinfo))
|
if (kctl->info(kctl, uinfo))
|
||||||
goto __unalloc;
|
return;
|
||||||
if (uinfo->count > 1) {
|
if (uinfo->count > 1) {
|
||||||
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
|
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
|
||||||
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
|
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
|
||||||
|
@ -711,13 +677,9 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
}
|
}
|
||||||
res = kctl->put(kctl, uctl);
|
res = kctl->put(kctl, uctl);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto __unalloc;
|
return;
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
||||||
__unalloc:
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
kfree(uctl);
|
|
||||||
kfree(uinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
|
static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
|
||||||
|
@ -822,28 +784,24 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_mixer_oss_slot *pslot;
|
struct snd_mixer_oss_slot *pslot;
|
||||||
struct slot *slot;
|
struct slot *slot;
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
struct snd_ctl_elem_value *uctl;
|
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
|
||||||
int err, idx;
|
int err, idx;
|
||||||
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL) {
|
if (uinfo == NULL || uctl == NULL)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto __free_only;
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
}
|
|
||||||
down_read(&card->controls_rwsem);
|
|
||||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||||
if (! kctl) {
|
if (!kctl)
|
||||||
err = -ENOENT;
|
return -ENOENT;
|
||||||
goto __unlock;
|
|
||||||
}
|
|
||||||
err = kctl->info(kctl, uinfo);
|
err = kctl->info(kctl, uinfo);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto __unlock;
|
return err;
|
||||||
err = kctl->get(kctl, uctl);
|
err = kctl->get(kctl, uctl);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto __unlock;
|
return err;
|
||||||
for (idx = 0; idx < 32; idx++) {
|
for (idx = 0; idx < 32; idx++) {
|
||||||
if (!(mixer->mask_recsrc & (1 << idx)))
|
if (!(mixer->mask_recsrc & (1 << idx)))
|
||||||
continue;
|
continue;
|
||||||
|
@ -858,13 +816,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = 0;
|
return 0;
|
||||||
__unlock:
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
__free_only:
|
|
||||||
kfree(uctl);
|
|
||||||
kfree(uinfo);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
|
static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
|
||||||
|
@ -874,26 +826,22 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
struct snd_mixer_oss_slot *pslot;
|
struct snd_mixer_oss_slot *pslot;
|
||||||
struct slot *slot = NULL;
|
struct slot *slot = NULL;
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
struct snd_ctl_elem_value *uctl;
|
struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL) {
|
if (uinfo == NULL || uctl == NULL)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto __free_only;
|
guard(rwsem_read)(&card->controls_rwsem);
|
||||||
}
|
|
||||||
down_read(&card->controls_rwsem);
|
|
||||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||||
if (! kctl) {
|
if (!kctl)
|
||||||
err = -ENOENT;
|
return -ENOENT;
|
||||||
goto __unlock;
|
|
||||||
}
|
|
||||||
err = kctl->info(kctl, uinfo);
|
err = kctl->info(kctl, uinfo);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto __unlock;
|
return err;
|
||||||
for (idx = 0; idx < 32; idx++) {
|
for (idx = 0; idx < 32; idx++) {
|
||||||
if (!(mixer->mask_recsrc & (1 << idx)))
|
if (!(mixer->mask_recsrc & (1 << idx)))
|
||||||
continue;
|
continue;
|
||||||
|
@ -907,20 +855,14 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
break;
|
break;
|
||||||
slot = NULL;
|
slot = NULL;
|
||||||
}
|
}
|
||||||
if (! slot)
|
if (!slot)
|
||||||
goto __unlock;
|
return 0;
|
||||||
for (idx = 0; idx < uinfo->count; idx++)
|
for (idx = 0; idx < uinfo->count; idx++)
|
||||||
uctl->value.enumerated.item[idx] = slot->capture_item;
|
uctl->value.enumerated.item[idx] = slot->capture_item;
|
||||||
err = kctl->put(kctl, uctl);
|
err = kctl->put(kctl, uctl);
|
||||||
if (err > 0)
|
if (err > 0)
|
||||||
snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
||||||
err = 0;
|
return 0;
|
||||||
__unlock:
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
__free_only:
|
|
||||||
kfree(uctl);
|
|
||||||
kfree(uinfo);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct snd_mixer_oss_assign_table {
|
struct snd_mixer_oss_assign_table {
|
||||||
|
@ -931,34 +873,26 @@ struct snd_mixer_oss_assign_table {
|
||||||
|
|
||||||
static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
|
static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_info *info;
|
struct snd_ctl_elem_info *info __free(kfree) = NULL;
|
||||||
struct snd_kcontrol *kcontrol;
|
struct snd_kcontrol *kcontrol;
|
||||||
struct snd_card *card = mixer->card;
|
struct snd_card *card = mixer->card;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
scoped_guard(rwsem_read, &card->controls_rwsem) {
|
||||||
kcontrol = snd_mixer_oss_test_id(mixer, name, index);
|
kcontrol = snd_mixer_oss_test_id(mixer, name, index);
|
||||||
if (kcontrol == NULL) {
|
if (kcontrol == NULL)
|
||||||
up_read(&card->controls_rwsem);
|
return 0;
|
||||||
return 0;
|
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||||
|
if (!info)
|
||||||
|
return -ENOMEM;
|
||||||
|
err = kcontrol->info(kcontrol, info);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
slot->numid[item] = kcontrol->id.numid;
|
||||||
}
|
}
|
||||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
|
||||||
if (! info) {
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
err = kcontrol->info(kcontrol, info);
|
|
||||||
if (err < 0) {
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
kfree(info);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
slot->numid[item] = kcontrol->id.numid;
|
|
||||||
up_read(&card->controls_rwsem);
|
|
||||||
if (info->count > slot->channels)
|
if (info->count > slot->channels)
|
||||||
slot->channels = info->count;
|
slot->channels = info->count;
|
||||||
slot->present |= 1 << item;
|
slot->present |= 1 << item;
|
||||||
kfree(info);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1068,24 +1002,19 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
|
||||||
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
|
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
|
||||||
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
|
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
|
||||||
return 0;
|
return 0;
|
||||||
down_read(&mixer->card->controls_rwsem);
|
guard(rwsem_read)(&mixer->card->controls_rwsem);
|
||||||
kctl = NULL;
|
kctl = NULL;
|
||||||
if (!ptr->index)
|
if (!ptr->index)
|
||||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||||
if (kctl) {
|
if (kctl) {
|
||||||
struct snd_ctl_elem_info *uinfo;
|
struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
|
||||||
|
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
if (! uinfo) {
|
if (!uinfo)
|
||||||
up_read(&mixer->card->controls_rwsem);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
if (kctl->info(kctl, uinfo)) {
|
if (kctl->info(kctl, uinfo))
|
||||||
up_read(&mixer->card->controls_rwsem);
|
|
||||||
kfree(uinfo);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
strcpy(str, ptr->name);
|
strcpy(str, ptr->name);
|
||||||
if (!strcmp(str, "Master"))
|
if (!strcmp(str, "Master"))
|
||||||
strcpy(str, "Mix");
|
strcpy(str, "Mix");
|
||||||
|
@ -1097,20 +1026,15 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
|
||||||
} else {
|
} else {
|
||||||
for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
|
for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
|
||||||
uinfo->value.enumerated.item = slot.capture_item;
|
uinfo->value.enumerated.item = slot.capture_item;
|
||||||
if (kctl->info(kctl, uinfo)) {
|
if (kctl->info(kctl, uinfo))
|
||||||
up_read(&mixer->card->controls_rwsem);
|
|
||||||
kfree(uinfo);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
if (!strcmp(uinfo->value.enumerated.name, str)) {
|
if (!strcmp(uinfo->value.enumerated.name, str)) {
|
||||||
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
|
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree(uinfo);
|
|
||||||
}
|
}
|
||||||
up_read(&mixer->card->controls_rwsem);
|
|
||||||
if (slot.present != 0) {
|
if (slot.present != 0) {
|
||||||
pslot = kmalloc(sizeof(slot), GFP_KERNEL);
|
pslot = kmalloc(sizeof(slot), GFP_KERNEL);
|
||||||
if (! pslot)
|
if (! pslot)
|
||||||
|
@ -1183,7 +1107,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
|
||||||
struct snd_mixer_oss *mixer = entry->private_data;
|
struct snd_mixer_oss *mixer = entry->private_data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mutex_lock(&mixer->reg_mutex);
|
guard(mutex)(&mixer->reg_mutex);
|
||||||
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
|
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
|
||||||
struct slot *p;
|
struct slot *p;
|
||||||
|
|
||||||
|
@ -1198,7 +1122,6 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
|
||||||
else
|
else
|
||||||
snd_iprintf(buffer, "\"\" 0\n");
|
snd_iprintf(buffer, "\"\" 0\n");
|
||||||
}
|
}
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
|
static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
|
||||||
|
@ -1225,9 +1148,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
|
||||||
cptr = snd_info_get_str(str, cptr, sizeof(str));
|
cptr = snd_info_get_str(str, cptr, sizeof(str));
|
||||||
if (! *str) {
|
if (! *str) {
|
||||||
/* remove the entry */
|
/* remove the entry */
|
||||||
mutex_lock(&mixer->reg_mutex);
|
scoped_guard(mutex, &mixer->reg_mutex)
|
||||||
mixer_slot_clear(&mixer->slots[ch]);
|
mixer_slot_clear(&mixer->slots[ch]);
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
|
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
|
||||||
|
@ -1236,28 +1158,27 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
|
||||||
pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
|
pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mutex_lock(&mixer->reg_mutex);
|
scoped_guard(mutex, &mixer->reg_mutex) {
|
||||||
slot = (struct slot *)mixer->slots[ch].private_data;
|
slot = (struct slot *)mixer->slots[ch].private_data;
|
||||||
if (slot && slot->assigned &&
|
if (slot && slot->assigned &&
|
||||||
slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
|
slot->assigned->index == idx && !strcmp(slot->assigned->name, str))
|
||||||
/* not changed */
|
/* not changed */
|
||||||
goto __unlock;
|
break;
|
||||||
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
|
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
|
||||||
if (!tbl)
|
if (!tbl)
|
||||||
goto __unlock;
|
break;
|
||||||
tbl->oss_id = ch;
|
tbl->oss_id = ch;
|
||||||
tbl->name = kstrdup(str, GFP_KERNEL);
|
tbl->name = kstrdup(str, GFP_KERNEL);
|
||||||
if (! tbl->name) {
|
if (!tbl->name) {
|
||||||
kfree(tbl);
|
kfree(tbl);
|
||||||
goto __unlock;
|
break;
|
||||||
|
}
|
||||||
|
tbl->index = idx;
|
||||||
|
if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
|
||||||
|
kfree(tbl->name);
|
||||||
|
kfree(tbl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tbl->index = idx;
|
|
||||||
if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
|
|
||||||
kfree(tbl->name);
|
|
||||||
kfree(tbl);
|
|
||||||
}
|
|
||||||
__unlock:
|
|
||||||
mutex_unlock(&mixer->reg_mutex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
|
||||||
snd_pcm_hw_param_t var, unsigned int best,
|
snd_pcm_hw_param_t var, unsigned int best,
|
||||||
int *dir)
|
int *dir)
|
||||||
{
|
{
|
||||||
struct snd_pcm_hw_params *save = NULL;
|
struct snd_pcm_hw_params *save __free(kfree) = NULL;
|
||||||
int v;
|
int v;
|
||||||
unsigned int saved_min;
|
unsigned int saved_min;
|
||||||
int last = 0;
|
int last = 0;
|
||||||
|
@ -404,38 +404,30 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
|
||||||
saved_min = min;
|
saved_min = min;
|
||||||
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
|
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
|
||||||
if (min >= 0) {
|
if (min >= 0) {
|
||||||
struct snd_pcm_hw_params *params1;
|
struct snd_pcm_hw_params *params1 __free(kfree) = NULL;
|
||||||
if (max < 0)
|
if (max < 0)
|
||||||
goto _end;
|
goto _end;
|
||||||
if ((unsigned int)min == saved_min && mindir == valdir)
|
if ((unsigned int)min == saved_min && mindir == valdir)
|
||||||
goto _end;
|
goto _end;
|
||||||
params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
|
params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
|
||||||
if (params1 == NULL) {
|
if (params1 == NULL)
|
||||||
kfree(save);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
*params1 = *save;
|
*params1 = *save;
|
||||||
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
|
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
|
||||||
if (max < 0) {
|
if (max < 0)
|
||||||
kfree(params1);
|
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
|
||||||
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
|
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
|
||||||
*params = *params1;
|
*params = *params1;
|
||||||
last = 1;
|
last = 1;
|
||||||
}
|
}
|
||||||
kfree(params1);
|
|
||||||
} else {
|
} else {
|
||||||
*params = *save;
|
*params = *save;
|
||||||
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
|
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
|
||||||
if (max < 0) {
|
if (max < 0)
|
||||||
kfree(save);
|
|
||||||
return max;
|
return max;
|
||||||
}
|
|
||||||
last = 1;
|
last = 1;
|
||||||
}
|
}
|
||||||
_end:
|
_end:
|
||||||
kfree(save);
|
|
||||||
if (last)
|
if (last)
|
||||||
v = snd_pcm_hw_param_last(pcm, params, var, dir);
|
v = snd_pcm_hw_param_last(pcm, params, var, dir);
|
||||||
else
|
else
|
||||||
|
@ -789,7 +781,7 @@ static int choose_rate(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params, unsigned int best_rate)
|
struct snd_pcm_hw_params *params, unsigned int best_rate)
|
||||||
{
|
{
|
||||||
const struct snd_interval *it;
|
const struct snd_interval *it;
|
||||||
struct snd_pcm_hw_params *save;
|
struct snd_pcm_hw_params *save __free(kfree) = NULL;
|
||||||
unsigned int rate, prev;
|
unsigned int rate, prev;
|
||||||
|
|
||||||
save = kmalloc(sizeof(*save), GFP_KERNEL);
|
save = kmalloc(sizeof(*save), GFP_KERNEL);
|
||||||
|
@ -808,10 +800,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
|
||||||
ret = snd_pcm_hw_param_set(substream, params,
|
ret = snd_pcm_hw_param_set(substream, params,
|
||||||
SNDRV_PCM_HW_PARAM_RATE,
|
SNDRV_PCM_HW_PARAM_RATE,
|
||||||
rate, 0);
|
rate, 0);
|
||||||
if (ret == (int)rate) {
|
if (ret == (int)rate)
|
||||||
kfree(save);
|
|
||||||
return rate;
|
return rate;
|
||||||
}
|
|
||||||
*params = *save;
|
*params = *save;
|
||||||
}
|
}
|
||||||
prev = rate;
|
prev = rate;
|
||||||
|
@ -821,7 +811,6 @@ static int choose_rate(struct snd_pcm_substream *substream,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not found, use the nearest rate */
|
/* not found, use the nearest rate */
|
||||||
kfree(save);
|
|
||||||
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
|
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1634,9 +1623,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
|
||||||
break;
|
break;
|
||||||
result = 0;
|
result = 0;
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream)
|
||||||
state = runtime->state;
|
state = runtime->state;
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (state != SNDRV_PCM_STATE_RUNNING) {
|
if (state != SNDRV_PCM_STATE_RUNNING) {
|
||||||
set_current_state(TASK_RUNNING);
|
set_current_state(TASK_RUNNING);
|
||||||
break;
|
break;
|
||||||
|
@ -1847,7 +1835,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
int err;
|
int err;
|
||||||
int direct;
|
int direct;
|
||||||
struct snd_pcm_hw_params *params;
|
struct snd_pcm_hw_params *params __free(kfree) = NULL;
|
||||||
unsigned int formats = 0;
|
unsigned int formats = 0;
|
||||||
const struct snd_mask *format_mask;
|
const struct snd_mask *format_mask;
|
||||||
int fmt;
|
int fmt;
|
||||||
|
@ -1873,7 +1861,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||||
_snd_pcm_hw_params_any(params);
|
_snd_pcm_hw_params_any(params);
|
||||||
err = snd_pcm_hw_refine(substream, params);
|
err = snd_pcm_hw_refine(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||||
for (fmt = 0; fmt < 32; ++fmt) {
|
for (fmt = 0; fmt < 32; ++fmt) {
|
||||||
if (snd_mask_test(format_mask, fmt)) {
|
if (snd_mask_test(format_mask, fmt)) {
|
||||||
|
@ -1883,9 +1871,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
return formats;
|
||||||
kfree(params);
|
|
||||||
return err < 0 ? err : formats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
|
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
|
||||||
|
@ -2347,7 +2333,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
|
||||||
{
|
{
|
||||||
struct snd_pcm_oss_setup *setup;
|
struct snd_pcm_oss_setup *setup;
|
||||||
|
|
||||||
mutex_lock(&pcm->streams[stream].oss.setup_mutex);
|
guard(mutex)(&pcm->streams[stream].oss.setup_mutex);
|
||||||
do {
|
do {
|
||||||
for (setup = pcm->streams[stream].oss.setup_list; setup;
|
for (setup = pcm->streams[stream].oss.setup_list; setup;
|
||||||
setup = setup->next) {
|
setup = setup->next) {
|
||||||
|
@ -2358,7 +2344,6 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
|
||||||
out:
|
out:
|
||||||
if (setup)
|
if (setup)
|
||||||
*rsetup = *setup;
|
*rsetup = *setup;
|
||||||
mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
|
static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
|
||||||
|
@ -2853,23 +2838,23 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
|
||||||
if (psubstream != NULL) {
|
if (psubstream != NULL) {
|
||||||
struct snd_pcm_runtime *runtime = psubstream->runtime;
|
struct snd_pcm_runtime *runtime = psubstream->runtime;
|
||||||
poll_wait(file, &runtime->sleep, wait);
|
poll_wait(file, &runtime->sleep, wait);
|
||||||
snd_pcm_stream_lock_irq(psubstream);
|
scoped_guard(pcm_stream_lock_irq, psubstream) {
|
||||||
if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
|
if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
|
||||||
(runtime->state != SNDRV_PCM_STATE_RUNNING ||
|
(runtime->state != SNDRV_PCM_STATE_RUNNING ||
|
||||||
snd_pcm_oss_playback_ready(psubstream)))
|
snd_pcm_oss_playback_ready(psubstream)))
|
||||||
mask |= EPOLLOUT | EPOLLWRNORM;
|
mask |= EPOLLOUT | EPOLLWRNORM;
|
||||||
snd_pcm_stream_unlock_irq(psubstream);
|
}
|
||||||
}
|
}
|
||||||
if (csubstream != NULL) {
|
if (csubstream != NULL) {
|
||||||
struct snd_pcm_runtime *runtime = csubstream->runtime;
|
struct snd_pcm_runtime *runtime = csubstream->runtime;
|
||||||
snd_pcm_state_t ostate;
|
snd_pcm_state_t ostate;
|
||||||
poll_wait(file, &runtime->sleep, wait);
|
poll_wait(file, &runtime->sleep, wait);
|
||||||
snd_pcm_stream_lock_irq(csubstream);
|
scoped_guard(pcm_stream_lock_irq, csubstream) {
|
||||||
ostate = runtime->state;
|
ostate = runtime->state;
|
||||||
if (ostate != SNDRV_PCM_STATE_RUNNING ||
|
if (ostate != SNDRV_PCM_STATE_RUNNING ||
|
||||||
snd_pcm_oss_capture_ready(csubstream))
|
snd_pcm_oss_capture_ready(csubstream))
|
||||||
mask |= EPOLLIN | EPOLLRDNORM;
|
mask |= EPOLLIN | EPOLLRDNORM;
|
||||||
snd_pcm_stream_unlock_irq(csubstream);
|
}
|
||||||
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
|
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
|
||||||
struct snd_pcm_oss_file ofile;
|
struct snd_pcm_oss_file ofile;
|
||||||
memset(&ofile, 0, sizeof(ofile));
|
memset(&ofile, 0, sizeof(ofile));
|
||||||
|
@ -2964,7 +2949,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
|
||||||
{
|
{
|
||||||
struct snd_pcm_str *pstr = entry->private_data;
|
struct snd_pcm_str *pstr = entry->private_data;
|
||||||
struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
|
struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
|
||||||
mutex_lock(&pstr->oss.setup_mutex);
|
guard(mutex)(&pstr->oss.setup_mutex);
|
||||||
while (setup) {
|
while (setup) {
|
||||||
snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
|
snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
|
||||||
setup->task_name,
|
setup->task_name,
|
||||||
|
@ -2978,7 +2963,6 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
|
||||||
setup->nosilence ? " no-silence" : "");
|
setup->nosilence ? " no-silence" : "");
|
||||||
setup = setup->next;
|
setup = setup->next;
|
||||||
}
|
}
|
||||||
mutex_unlock(&pstr->oss.setup_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
|
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
|
||||||
|
@ -3004,12 +2988,11 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
|
||||||
struct snd_pcm_oss_setup *setup, *setup1, template;
|
struct snd_pcm_oss_setup *setup, *setup1, template;
|
||||||
|
|
||||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||||
mutex_lock(&pstr->oss.setup_mutex);
|
guard(mutex)(&pstr->oss.setup_mutex);
|
||||||
memset(&template, 0, sizeof(template));
|
memset(&template, 0, sizeof(template));
|
||||||
ptr = snd_info_get_str(task_name, line, sizeof(task_name));
|
ptr = snd_info_get_str(task_name, line, sizeof(task_name));
|
||||||
if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
|
if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
|
||||||
snd_pcm_oss_proc_free_setup_list(pstr);
|
snd_pcm_oss_proc_free_setup_list(pstr);
|
||||||
mutex_unlock(&pstr->oss.setup_mutex);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
|
for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
|
||||||
|
@ -3049,7 +3032,6 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
|
||||||
setup = kmalloc(sizeof(*setup), GFP_KERNEL);
|
setup = kmalloc(sizeof(*setup), GFP_KERNEL);
|
||||||
if (! setup) {
|
if (! setup) {
|
||||||
buffer->error = -ENOMEM;
|
buffer->error = -ENOMEM;
|
||||||
mutex_unlock(&pstr->oss.setup_mutex);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pstr->oss.setup_list == NULL)
|
if (pstr->oss.setup_list == NULL)
|
||||||
|
@ -3063,12 +3045,10 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
|
||||||
if (! template.task_name) {
|
if (! template.task_name) {
|
||||||
kfree(setup);
|
kfree(setup);
|
||||||
buffer->error = -ENOMEM;
|
buffer->error = -ENOMEM;
|
||||||
mutex_unlock(&pstr->oss.setup_mutex);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*setup = template;
|
*setup = template;
|
||||||
mutex_unlock(&pstr->oss.setup_mutex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
sound/core/pcm.c
100
sound/core/pcm.c
|
@ -91,9 +91,8 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
||||||
|
|
||||||
if (get_user(device, (int __user *)arg))
|
if (get_user(device, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
scoped_guard(mutex, ®ister_mutex)
|
||||||
device = snd_pcm_next(card, device);
|
device = snd_pcm_next(card, device);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
if (put_user(device, (int __user *)arg))
|
if (put_user(device, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -106,7 +105,6 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
||||||
struct snd_pcm *pcm;
|
struct snd_pcm *pcm;
|
||||||
struct snd_pcm_str *pstr;
|
struct snd_pcm_str *pstr;
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
int err;
|
|
||||||
|
|
||||||
info = (struct snd_pcm_info __user *)arg;
|
info = (struct snd_pcm_info __user *)arg;
|
||||||
if (get_user(device, &info->device))
|
if (get_user(device, &info->device))
|
||||||
|
@ -118,35 +116,23 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
||||||
stream = array_index_nospec(stream, 2);
|
stream = array_index_nospec(stream, 2);
|
||||||
if (get_user(subdevice, &info->subdevice))
|
if (get_user(subdevice, &info->subdevice))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
pcm = snd_pcm_get(card, device);
|
pcm = snd_pcm_get(card, device);
|
||||||
if (pcm == NULL) {
|
if (pcm == NULL)
|
||||||
err = -ENXIO;
|
return -ENXIO;
|
||||||
goto _error;
|
|
||||||
}
|
|
||||||
pstr = &pcm->streams[stream];
|
pstr = &pcm->streams[stream];
|
||||||
if (pstr->substream_count == 0) {
|
if (pstr->substream_count == 0)
|
||||||
err = -ENOENT;
|
return -ENOENT;
|
||||||
goto _error;
|
if (subdevice >= pstr->substream_count)
|
||||||
}
|
return -ENXIO;
|
||||||
if (subdevice >= pstr->substream_count) {
|
|
||||||
err = -ENXIO;
|
|
||||||
goto _error;
|
|
||||||
}
|
|
||||||
for (substream = pstr->substream; substream;
|
for (substream = pstr->substream; substream;
|
||||||
substream = substream->next)
|
substream = substream->next)
|
||||||
if (substream->number == (int)subdevice)
|
if (substream->number == (int)subdevice)
|
||||||
break;
|
break;
|
||||||
if (substream == NULL) {
|
if (substream == NULL)
|
||||||
err = -ENXIO;
|
return -ENXIO;
|
||||||
goto _error;
|
guard(mutex)(&pcm->open_mutex);
|
||||||
}
|
return snd_pcm_info_user(substream, info);
|
||||||
mutex_lock(&pcm->open_mutex);
|
|
||||||
err = snd_pcm_info_user(substream, info);
|
|
||||||
mutex_unlock(&pcm->open_mutex);
|
|
||||||
_error:
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
|
case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
|
||||||
{
|
{
|
||||||
|
@ -225,9 +211,11 @@ static const char * const snd_pcm_format_names[] = {
|
||||||
*/
|
*/
|
||||||
const char *snd_pcm_format_name(snd_pcm_format_t format)
|
const char *snd_pcm_format_name(snd_pcm_format_t format)
|
||||||
{
|
{
|
||||||
if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
|
unsigned int format_num = (__force unsigned int)format;
|
||||||
|
|
||||||
|
if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num])
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
return snd_pcm_format_names[(__force unsigned int)format];
|
return snd_pcm_format_names[format_num];
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
|
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
|
||||||
|
|
||||||
|
@ -340,7 +328,7 @@ static const char *snd_pcm_oss_format_name(int format)
|
||||||
static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
|
static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
|
||||||
struct snd_info_buffer *buffer)
|
struct snd_info_buffer *buffer)
|
||||||
{
|
{
|
||||||
struct snd_pcm_info *info;
|
struct snd_pcm_info *info __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (! substream)
|
if (! substream)
|
||||||
|
@ -353,7 +341,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
|
||||||
err = snd_pcm_info(substream, info);
|
err = snd_pcm_info(substream, info);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_iprintf(buffer, "error %d\n", err);
|
snd_iprintf(buffer, "error %d\n", err);
|
||||||
kfree(info);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snd_iprintf(buffer, "card: %d\n", info->card);
|
snd_iprintf(buffer, "card: %d\n", info->card);
|
||||||
|
@ -367,7 +354,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
|
||||||
snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
|
snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
|
||||||
snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
|
snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
|
||||||
snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
|
snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
|
||||||
kfree(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
|
static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
|
||||||
|
@ -389,15 +375,15 @@ static void snd_pcm_substream_proc_hw_params_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;
|
||||||
|
|
||||||
mutex_lock(&substream->pcm->open_mutex);
|
guard(mutex)(&substream->pcm->open_mutex);
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (!runtime) {
|
if (!runtime) {
|
||||||
snd_iprintf(buffer, "closed\n");
|
snd_iprintf(buffer, "closed\n");
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
||||||
snd_iprintf(buffer, "no setup\n");
|
snd_iprintf(buffer, "no setup\n");
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
|
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
|
||||||
snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
|
snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
|
||||||
|
@ -416,8 +402,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
|
||||||
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
|
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
unlock:
|
|
||||||
mutex_unlock(&substream->pcm->open_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
|
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
|
||||||
|
@ -426,15 +410,15 @@ static void snd_pcm_substream_proc_sw_params_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;
|
||||||
|
|
||||||
mutex_lock(&substream->pcm->open_mutex);
|
guard(mutex)(&substream->pcm->open_mutex);
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (!runtime) {
|
if (!runtime) {
|
||||||
snd_iprintf(buffer, "closed\n");
|
snd_iprintf(buffer, "closed\n");
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
||||||
snd_iprintf(buffer, "no setup\n");
|
snd_iprintf(buffer, "no setup\n");
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
|
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
|
||||||
snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
|
snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
|
||||||
|
@ -444,8 +428,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
|
||||||
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
|
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
|
||||||
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
|
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
|
||||||
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
|
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
|
||||||
unlock:
|
|
||||||
mutex_unlock(&substream->pcm->open_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
|
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
|
||||||
|
@ -456,17 +438,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
|
||||||
struct snd_pcm_status64 status;
|
struct snd_pcm_status64 status;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
mutex_lock(&substream->pcm->open_mutex);
|
guard(mutex)(&substream->pcm->open_mutex);
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (!runtime) {
|
if (!runtime) {
|
||||||
snd_iprintf(buffer, "closed\n");
|
snd_iprintf(buffer, "closed\n");
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
memset(&status, 0, sizeof(status));
|
memset(&status, 0, sizeof(status));
|
||||||
err = snd_pcm_status64(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;
|
return;
|
||||||
}
|
}
|
||||||
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));
|
||||||
|
@ -480,8 +462,6 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
|
||||||
snd_iprintf(buffer, "-----\n");
|
snd_iprintf(buffer, "-----\n");
|
||||||
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
|
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
|
||||||
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
|
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
|
||||||
unlock:
|
|
||||||
mutex_unlock(&substream->pcm->open_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
||||||
|
@ -1009,9 +989,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
||||||
kfree(runtime->hw_constraints.rules);
|
kfree(runtime->hw_constraints.rules);
|
||||||
/* Avoid concurrent access to runtime via PCM timer interface */
|
/* Avoid concurrent access to runtime via PCM timer interface */
|
||||||
if (substream->timer) {
|
if (substream->timer) {
|
||||||
spin_lock_irq(&substream->timer->lock);
|
scoped_guard(spinlock_irq, &substream->timer->lock)
|
||||||
substream->runtime = NULL;
|
substream->runtime = NULL;
|
||||||
spin_unlock_irq(&substream->timer->lock);
|
|
||||||
} else {
|
} else {
|
||||||
substream->runtime = NULL;
|
substream->runtime = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1068,10 +1047,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
pcm = device->device_data;
|
pcm = device->device_data;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
err = snd_pcm_add(pcm);
|
err = snd_pcm_add(pcm);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
return err;
|
||||||
for (cidx = 0; cidx < 2; cidx++) {
|
for (cidx = 0; cidx < 2; cidx++) {
|
||||||
int devtype = -1;
|
int devtype = -1;
|
||||||
if (pcm->streams[cidx].substream == NULL)
|
if (pcm->streams[cidx].substream == NULL)
|
||||||
|
@ -1090,7 +1069,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
pcm->streams[cidx].dev);
|
pcm->streams[cidx].dev);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
list_del_init(&pcm->list);
|
list_del_init(&pcm->list);
|
||||||
goto unlock;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
||||||
|
@ -1098,9 +1077,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
pcm_call_notify(pcm, n_register);
|
pcm_call_notify(pcm, n_register);
|
||||||
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,8 +1086,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
int cidx;
|
int cidx;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
mutex_lock(&pcm->open_mutex);
|
guard(mutex)(&pcm->open_mutex);
|
||||||
wake_up(&pcm->open_wait);
|
wake_up(&pcm->open_wait);
|
||||||
list_del_init(&pcm->list);
|
list_del_init(&pcm->list);
|
||||||
|
|
||||||
|
@ -1138,8 +1114,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
||||||
snd_unregister_device(pcm->streams[cidx].dev);
|
snd_unregister_device(pcm->streams[cidx].dev);
|
||||||
free_chmap(&pcm->streams[cidx]);
|
free_chmap(&pcm->streams[cidx]);
|
||||||
}
|
}
|
||||||
mutex_unlock(&pcm->open_mutex);
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,7 +1138,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
|
||||||
!notify->n_unregister ||
|
!notify->n_unregister ||
|
||||||
!notify->n_disconnect))
|
!notify->n_disconnect))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
if (nfree) {
|
if (nfree) {
|
||||||
list_del(¬ify->list);
|
list_del(¬ify->list);
|
||||||
list_for_each_entry(pcm, &snd_pcm_devices, list)
|
list_for_each_entry(pcm, &snd_pcm_devices, list)
|
||||||
|
@ -1174,7 +1148,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
|
||||||
list_for_each_entry(pcm, &snd_pcm_devices, list)
|
list_for_each_entry(pcm, &snd_pcm_devices, list)
|
||||||
notify->n_register(pcm);
|
notify->n_register(pcm);
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_pcm_notify);
|
EXPORT_SYMBOL(snd_pcm_notify);
|
||||||
|
@ -1190,7 +1163,7 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
|
||||||
{
|
{
|
||||||
struct snd_pcm *pcm;
|
struct snd_pcm *pcm;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
||||||
snd_iprintf(buffer, "%02i-%02i: %s : %s",
|
snd_iprintf(buffer, "%02i-%02i: %s : %s",
|
||||||
pcm->card->number, pcm->device, pcm->id, pcm->name);
|
pcm->card->number, pcm->device, pcm->id, pcm->name);
|
||||||
|
@ -1202,7 +1175,6 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
|
||||||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
|
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
|
||||||
snd_iprintf(buffer, "\n");
|
snd_iprintf(buffer, "\n");
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_info_entry *snd_pcm_proc_entry;
|
static struct snd_info_entry *snd_pcm_proc_entry;
|
||||||
|
|
|
@ -235,7 +235,7 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
|
||||||
int refine,
|
int refine,
|
||||||
struct snd_pcm_hw_params32 __user *data32)
|
struct snd_pcm_hw_params32 __user *data32)
|
||||||
{
|
{
|
||||||
struct snd_pcm_hw_params *data;
|
struct snd_pcm_hw_params *data __free(kfree) = NULL;
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -248,34 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* only fifo_size (RO from userspace) is different, so just copy all */
|
/* only fifo_size (RO from userspace) is different, so just copy all */
|
||||||
if (copy_from_user(data, data32, sizeof(*data32))) {
|
if (copy_from_user(data, data32, sizeof(*data32)))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refine) {
|
if (refine) {
|
||||||
err = snd_pcm_hw_refine(substream, data);
|
err = snd_pcm_hw_refine(substream, data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
err = fixup_unreferenced_params(substream, data);
|
err = fixup_unreferenced_params(substream, data);
|
||||||
} else {
|
} else {
|
||||||
err = snd_pcm_hw_params(substream, data);
|
err = snd_pcm_hw_params(substream, data);
|
||||||
}
|
}
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
if (copy_to_user(data32, data, sizeof(*data32)) ||
|
if (copy_to_user(data32, data, sizeof(*data32)) ||
|
||||||
put_user(data->fifo_size, &data32->fifo_size)) {
|
put_user(data->fifo_size, &data32->fifo_size))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! refine) {
|
if (! refine) {
|
||||||
unsigned int new_boundary = recalculate_boundary(runtime);
|
unsigned int new_boundary = recalculate_boundary(runtime);
|
||||||
if (new_boundary)
|
if (new_boundary)
|
||||||
runtime->boundary = new_boundary;
|
runtime->boundary = new_boundary;
|
||||||
}
|
}
|
||||||
error:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +332,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
|
||||||
compat_caddr_t buf;
|
compat_caddr_t buf;
|
||||||
compat_caddr_t __user *bufptr;
|
compat_caddr_t __user *bufptr;
|
||||||
u32 frames;
|
u32 frames;
|
||||||
void __user **bufs;
|
void __user **bufs __free(kfree) = NULL;
|
||||||
int err, ch, i;
|
int err, ch, i;
|
||||||
|
|
||||||
if (! substream->runtime)
|
if (! substream->runtime)
|
||||||
|
@ -360,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
for (i = 0; i < ch; i++) {
|
for (i = 0; i < ch; i++) {
|
||||||
u32 ptr;
|
u32 ptr;
|
||||||
if (get_user(ptr, bufptr)) {
|
if (get_user(ptr, bufptr))
|
||||||
kfree(bufs);
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
|
||||||
bufs[i] = compat_ptr(ptr);
|
bufs[i] = compat_ptr(ptr);
|
||||||
bufptr++;
|
bufptr++;
|
||||||
}
|
}
|
||||||
|
@ -373,9 +365,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
|
||||||
err = snd_pcm_lib_readv(substream, bufs, frames);
|
err = snd_pcm_lib_readv(substream, bufs, frames);
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
if (put_user(err, &data32->result))
|
if (put_user(err, &data32->result))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
kfree(bufs);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,22 +432,22 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
|
||||||
boundary = recalculate_boundary(runtime);
|
boundary = recalculate_boundary(runtime);
|
||||||
if (!boundary)
|
if (!boundary)
|
||||||
boundary = 0x7fffffff;
|
boundary = 0x7fffffff;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
/* FIXME: we should consider the boundary for the sync from app */
|
/* FIXME: we should consider the boundary for the sync from app */
|
||||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
||||||
control->appl_ptr = scontrol.appl_ptr;
|
control->appl_ptr = scontrol.appl_ptr;
|
||||||
else
|
else
|
||||||
scontrol.appl_ptr = control->appl_ptr % boundary;
|
scontrol.appl_ptr = control->appl_ptr % boundary;
|
||||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
||||||
control->avail_min = scontrol.avail_min;
|
control->avail_min = scontrol.avail_min;
|
||||||
else
|
else
|
||||||
scontrol.avail_min = control->avail_min;
|
scontrol.avail_min = control->avail_min;
|
||||||
sstatus.state = status->state;
|
sstatus.state = status->state;
|
||||||
sstatus.hw_ptr = status->hw_ptr % boundary;
|
sstatus.hw_ptr = status->hw_ptr % boundary;
|
||||||
sstatus.tstamp = status->tstamp;
|
sstatus.tstamp = status->tstamp;
|
||||||
sstatus.suspended_state = status->suspended_state;
|
sstatus.suspended_state = status->suspended_state;
|
||||||
sstatus.audio_tstamp = status->audio_tstamp;
|
sstatus.audio_tstamp = status->audio_tstamp;
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
}
|
||||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
||||||
if (put_user(sstatus.state, &src->s.status.state) ||
|
if (put_user(sstatus.state, &src->s.status.state) ||
|
||||||
|
@ -519,26 +510,24 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
||||||
err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
|
err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
return err;
|
||||||
return err;
|
} else {
|
||||||
|
sync_cp->appl_ptr = control->appl_ptr;
|
||||||
}
|
}
|
||||||
} else {
|
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
||||||
sync_cp->appl_ptr = control->appl_ptr;
|
control->avail_min = sync_cp->avail_min;
|
||||||
|
else
|
||||||
|
sync_cp->avail_min = control->avail_min;
|
||||||
|
sync_ptr.s.status.state = status->state;
|
||||||
|
sync_ptr.s.status.hw_ptr = status->hw_ptr;
|
||||||
|
sync_ptr.s.status.tstamp = status->tstamp;
|
||||||
|
sync_ptr.s.status.suspended_state = status->suspended_state;
|
||||||
|
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
|
||||||
}
|
}
|
||||||
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
|
||||||
control->avail_min = sync_cp->avail_min;
|
|
||||||
else
|
|
||||||
sync_cp->avail_min = control->avail_min;
|
|
||||||
sync_ptr.s.status.state = status->state;
|
|
||||||
sync_ptr.s.status.hw_ptr = status->hw_ptr;
|
|
||||||
sync_ptr.s.status.tstamp = status->tstamp;
|
|
||||||
sync_ptr.s.status.suspended_state = status->suspended_state;
|
|
||||||
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
|
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
|
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
||||||
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
|
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
|
||||||
|
|
|
@ -1744,8 +1744,8 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
unsigned long flags;
|
|
||||||
snd_pcm_stream_lock_irqsave(substream, flags);
|
guard(pcm_stream_lock_irqsave)(substream);
|
||||||
if (snd_pcm_running(substream) &&
|
if (snd_pcm_running(substream) &&
|
||||||
snd_pcm_update_hw_ptr(substream) >= 0)
|
snd_pcm_update_hw_ptr(substream) >= 0)
|
||||||
runtime->status->hw_ptr %= runtime->buffer_size;
|
runtime->status->hw_ptr %= runtime->buffer_size;
|
||||||
|
@ -1753,7 +1753,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
|
||||||
runtime->status->hw_ptr = 0;
|
runtime->status->hw_ptr = 0;
|
||||||
runtime->hw_ptr_wrap = 0;
|
runtime->hw_ptr_wrap = 0;
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1899,14 +1898,11 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
|
||||||
*/
|
*/
|
||||||
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
|
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!substream))
|
if (snd_BUG_ON(!substream))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irqsave(substream, flags);
|
guard(pcm_stream_lock_irqsave)(substream);
|
||||||
snd_pcm_period_elapsed_under_stream_lock(substream);
|
snd_pcm_period_elapsed_under_stream_lock(substream);
|
||||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_pcm_period_elapsed);
|
EXPORT_SYMBOL(snd_pcm_period_elapsed);
|
||||||
|
|
||||||
|
|
|
@ -38,17 +38,15 @@ static void __update_allocated_size(struct snd_card *card, ssize_t bytes)
|
||||||
|
|
||||||
static void update_allocated_size(struct snd_card *card, ssize_t bytes)
|
static void update_allocated_size(struct snd_card *card, ssize_t bytes)
|
||||||
{
|
{
|
||||||
mutex_lock(&card->memory_mutex);
|
guard(mutex)(&card->memory_mutex);
|
||||||
__update_allocated_size(card, bytes);
|
__update_allocated_size(card, bytes);
|
||||||
mutex_unlock(&card->memory_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decrease_allocated_size(struct snd_card *card, size_t bytes)
|
static void decrease_allocated_size(struct snd_card *card, size_t bytes)
|
||||||
{
|
{
|
||||||
mutex_lock(&card->memory_mutex);
|
guard(mutex)(&card->memory_mutex);
|
||||||
WARN_ON(card->total_pcm_alloc_bytes < bytes);
|
WARN_ON(card->total_pcm_alloc_bytes < bytes);
|
||||||
__update_allocated_size(card, -(ssize_t)bytes);
|
__update_allocated_size(card, -(ssize_t)bytes);
|
||||||
mutex_unlock(&card->memory_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
|
static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
|
||||||
|
@ -58,14 +56,12 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* check and reserve the requested size */
|
/* check and reserve the requested size */
|
||||||
mutex_lock(&card->memory_mutex);
|
scoped_guard(mutex, &card->memory_mutex) {
|
||||||
if (max_alloc_per_card &&
|
if (max_alloc_per_card &&
|
||||||
card->total_pcm_alloc_bytes + size > max_alloc_per_card) {
|
card->total_pcm_alloc_bytes + size > max_alloc_per_card)
|
||||||
mutex_unlock(&card->memory_mutex);
|
return -ENOMEM;
|
||||||
return -ENOMEM;
|
__update_allocated_size(card, size);
|
||||||
}
|
}
|
||||||
__update_allocated_size(card, size);
|
|
||||||
mutex_unlock(&card->memory_mutex);
|
|
||||||
|
|
||||||
if (str == SNDRV_PCM_STREAM_PLAYBACK)
|
if (str == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
dir = DMA_TO_DEVICE;
|
dir = DMA_TO_DEVICE;
|
||||||
|
@ -191,20 +187,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
|
||||||
size_t size;
|
size_t size;
|
||||||
struct snd_dma_buffer new_dmab;
|
struct snd_dma_buffer new_dmab;
|
||||||
|
|
||||||
mutex_lock(&substream->pcm->open_mutex);
|
guard(mutex)(&substream->pcm->open_mutex);
|
||||||
if (substream->runtime) {
|
if (substream->runtime) {
|
||||||
buffer->error = -EBUSY;
|
buffer->error = -EBUSY;
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
if (!snd_info_get_line(buffer, line, sizeof(line))) {
|
if (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||||
snd_info_get_str(str, line, sizeof(str));
|
snd_info_get_str(str, line, sizeof(str));
|
||||||
size = simple_strtoul(str, NULL, 10) * 1024;
|
size = simple_strtoul(str, NULL, 10) * 1024;
|
||||||
if ((size != 0 && size < 8192) || size > substream->dma_max) {
|
if ((size != 0 && size < 8192) || size > substream->dma_max) {
|
||||||
buffer->error = -EINVAL;
|
buffer->error = -EINVAL;
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
if (substream->dma_buffer.bytes == size)
|
if (substream->dma_buffer.bytes == size)
|
||||||
goto unlock;
|
return;
|
||||||
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) {
|
||||||
|
@ -218,7 +214,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
|
||||||
substream->pcm->card->number, substream->pcm->device,
|
substream->pcm->card->number, substream->pcm->device,
|
||||||
substream->stream ? 'c' : 'p', substream->number,
|
substream->stream ? 'c' : 'p', substream->number,
|
||||||
substream->pcm->name, size);
|
substream->pcm->name, size);
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
substream->buffer_bytes_max = size;
|
substream->buffer_bytes_max = size;
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,8 +226,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
|
||||||
} else {
|
} else {
|
||||||
buffer->error = -EINVAL;
|
buffer->error = -EINVAL;
|
||||||
}
|
}
|
||||||
unlock:
|
|
||||||
mutex_unlock(&substream->pcm->open_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void preallocate_info_init(struct snd_pcm_substream *substream)
|
static inline void preallocate_info_init(struct snd_pcm_substream *substream)
|
||||||
|
|
|
@ -236,7 +236,7 @@ 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)
|
||||||
{
|
{
|
||||||
struct snd_pcm_info *info;
|
struct snd_pcm_info *info __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||||
|
@ -247,7 +247,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
|
||||||
if (copy_to_user(_info, info, sizeof(*info)))
|
if (copy_to_user(_info, info, sizeof(*info)))
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
}
|
}
|
||||||
kfree(info);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +358,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_constraints *constrs =
|
struct snd_pcm_hw_constraints *constrs =
|
||||||
&substream->runtime->hw_constraints;
|
&substream->runtime->hw_constraints;
|
||||||
unsigned int k;
|
unsigned int k;
|
||||||
unsigned int *rstamps;
|
unsigned int *rstamps __free(kfree) = NULL;
|
||||||
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
|
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
|
||||||
unsigned int stamp;
|
unsigned int stamp;
|
||||||
struct snd_pcm_hw_rule *r;
|
struct snd_pcm_hw_rule *r;
|
||||||
|
@ -435,10 +434,8 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
changed = r->func(params, r);
|
changed = r->func(params, r);
|
||||||
if (changed < 0) {
|
if (changed < 0)
|
||||||
err = changed;
|
return changed;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When the parameter is changed, notify it to the caller
|
* When the parameter is changed, notify it to the caller
|
||||||
|
@ -469,8 +466,6 @@ retry:
|
||||||
if (again)
|
if (again)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(rstamps);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,26 +571,24 @@ EXPORT_SYMBOL(snd_pcm_hw_refine);
|
||||||
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
|
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params __user * _params)
|
struct snd_pcm_hw_params __user * _params)
|
||||||
{
|
{
|
||||||
struct snd_pcm_hw_params *params;
|
struct snd_pcm_hw_params *params __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
params = memdup_user(_params, sizeof(*params));
|
params = memdup_user(_params, sizeof(*params));
|
||||||
if (IS_ERR(params))
|
if (IS_ERR(params))
|
||||||
return PTR_ERR(params);
|
return PTR_ERR(no_free_ptr(params));
|
||||||
|
|
||||||
err = snd_pcm_hw_refine(substream, params);
|
err = snd_pcm_hw_refine(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto end;
|
return err;
|
||||||
|
|
||||||
err = fixup_unreferenced_params(substream, params);
|
err = fixup_unreferenced_params(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto end;
|
return err;
|
||||||
|
|
||||||
if (copy_to_user(_params, params, sizeof(*params)))
|
if (copy_to_user(_params, params, sizeof(*params)))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
end:
|
return 0;
|
||||||
kfree(params);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int period_to_usecs(struct snd_pcm_runtime *runtime)
|
static int period_to_usecs(struct snd_pcm_runtime *runtime)
|
||||||
|
@ -616,10 +609,9 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
|
||||||
static void snd_pcm_set_state(struct snd_pcm_substream *substream,
|
static void snd_pcm_set_state(struct snd_pcm_substream *substream,
|
||||||
snd_pcm_state_t state)
|
snd_pcm_state_t state)
|
||||||
{
|
{
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
|
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
|
||||||
__snd_pcm_set_state(substream->runtime, state);
|
__snd_pcm_set_state(substream->runtime, state);
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
|
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
|
||||||
|
@ -745,20 +737,20 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
err = snd_pcm_buffer_access_lock(runtime);
|
err = snd_pcm_buffer_access_lock(runtime);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
switch (runtime->state) {
|
switch (runtime->state) {
|
||||||
case SNDRV_PCM_STATE_OPEN:
|
case SNDRV_PCM_STATE_OPEN:
|
||||||
case SNDRV_PCM_STATE_SETUP:
|
case SNDRV_PCM_STATE_SETUP:
|
||||||
case SNDRV_PCM_STATE_PREPARED:
|
case SNDRV_PCM_STATE_PREPARED:
|
||||||
if (!is_oss_stream(substream) &&
|
if (!is_oss_stream(substream) &&
|
||||||
atomic_read(&substream->mmap_count))
|
atomic_read(&substream->mmap_count))
|
||||||
|
err = -EBADFD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
err = -EBADFD;
|
err = -EBADFD;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
err = -EBADFD;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
|
@ -869,21 +861,19 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
|
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params __user * _params)
|
struct snd_pcm_hw_params __user * _params)
|
||||||
{
|
{
|
||||||
struct snd_pcm_hw_params *params;
|
struct snd_pcm_hw_params *params __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
params = memdup_user(_params, sizeof(*params));
|
params = memdup_user(_params, sizeof(*params));
|
||||||
if (IS_ERR(params))
|
if (IS_ERR(params))
|
||||||
return PTR_ERR(params);
|
return PTR_ERR(no_free_ptr(params));
|
||||||
|
|
||||||
err = snd_pcm_hw_params(substream, params);
|
err = snd_pcm_hw_params(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto end;
|
return err;
|
||||||
|
|
||||||
if (copy_to_user(_params, params, sizeof(*params)))
|
if (copy_to_user(_params, params, sizeof(*params)))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
end:
|
|
||||||
kfree(params);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,18 +900,18 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||||
result = snd_pcm_buffer_access_lock(runtime);
|
result = snd_pcm_buffer_access_lock(runtime);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
return result;
|
return result;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
switch (runtime->state) {
|
switch (runtime->state) {
|
||||||
case SNDRV_PCM_STATE_SETUP:
|
case SNDRV_PCM_STATE_SETUP:
|
||||||
case SNDRV_PCM_STATE_PREPARED:
|
case SNDRV_PCM_STATE_PREPARED:
|
||||||
if (atomic_read(&substream->mmap_count))
|
if (atomic_read(&substream->mmap_count))
|
||||||
|
result = -EBADFD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
result = -EBADFD;
|
result = -EBADFD;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
result = -EBADFD;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (result)
|
if (result)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
result = do_hw_free(substream);
|
result = do_hw_free(substream);
|
||||||
|
@ -941,12 +931,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
|
||||||
if (PCM_RUNTIME_CHECK(substream))
|
if (PCM_RUNTIME_CHECK(substream))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
if (runtime->state == SNDRV_PCM_STATE_OPEN)
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
return -EBADFD;
|
||||||
return -EBADFD;
|
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
|
|
||||||
if (params->tstamp_mode < 0 ||
|
if (params->tstamp_mode < 0 ||
|
||||||
params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
|
params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
|
||||||
|
@ -966,24 +954,24 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = 0;
|
err = 0;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
runtime->tstamp_mode = params->tstamp_mode;
|
runtime->tstamp_mode = params->tstamp_mode;
|
||||||
if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
|
if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
|
||||||
runtime->tstamp_type = params->tstamp_type;
|
runtime->tstamp_type = params->tstamp_type;
|
||||||
runtime->period_step = params->period_step;
|
runtime->period_step = params->period_step;
|
||||||
runtime->control->avail_min = params->avail_min;
|
runtime->control->avail_min = params->avail_min;
|
||||||
runtime->start_threshold = params->start_threshold;
|
runtime->start_threshold = params->start_threshold;
|
||||||
runtime->stop_threshold = params->stop_threshold;
|
runtime->stop_threshold = params->stop_threshold;
|
||||||
runtime->silence_threshold = params->silence_threshold;
|
runtime->silence_threshold = params->silence_threshold;
|
||||||
runtime->silence_size = params->silence_size;
|
runtime->silence_size = params->silence_size;
|
||||||
params->boundary = runtime->boundary;
|
params->boundary = runtime->boundary;
|
||||||
if (snd_pcm_running(substream)) {
|
if (snd_pcm_running(substream)) {
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||||
runtime->silence_size > 0)
|
runtime->silence_size > 0)
|
||||||
snd_pcm_playback_silence(substream, ULONG_MAX);
|
snd_pcm_playback_silence(substream, ULONG_MAX);
|
||||||
err = snd_pcm_update_state(substream, runtime);
|
err = snd_pcm_update_state(substream, runtime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,7 +1005,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
|
|
||||||
snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
|
snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
|
||||||
&runtime->audio_tstamp_config);
|
&runtime->audio_tstamp_config);
|
||||||
|
@ -1038,7 +1026,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
|
||||||
status->state = runtime->state;
|
status->state = runtime->state;
|
||||||
status->suspended_state = runtime->suspended_state;
|
status->suspended_state = runtime->suspended_state;
|
||||||
if (status->state == SNDRV_PCM_STATE_OPEN)
|
if (status->state == SNDRV_PCM_STATE_OPEN)
|
||||||
goto _end;
|
return 0;
|
||||||
status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
|
status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
|
||||||
status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
|
status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
|
||||||
if (snd_pcm_running(substream)) {
|
if (snd_pcm_running(substream)) {
|
||||||
|
@ -1083,8 +1071,6 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
|
||||||
status->overrange = runtime->overrange;
|
status->overrange = runtime->overrange;
|
||||||
runtime->avail_max = 0;
|
runtime->avail_max = 0;
|
||||||
runtime->overrange = 0;
|
runtime->overrange = 0;
|
||||||
_end:
|
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,12 +1155,10 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
|
||||||
|
|
||||||
channel = info->channel;
|
channel = info->channel;
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
if (runtime->state == SNDRV_PCM_STATE_OPEN)
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
return -EBADFD;
|
||||||
return -EBADFD;
|
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (channel >= runtime->channels)
|
if (channel >= runtime->channels)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
memset(info, 0, sizeof(*info));
|
memset(info, 0, sizeof(*info));
|
||||||
|
@ -1395,12 +1379,8 @@ static int snd_pcm_action_lock_irq(const struct action_ops *ops,
|
||||||
struct snd_pcm_substream *substream,
|
struct snd_pcm_substream *substream,
|
||||||
snd_pcm_state_t state)
|
snd_pcm_state_t state)
|
||||||
{
|
{
|
||||||
int res;
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
|
return snd_pcm_action(ops, substream, state);
|
||||||
snd_pcm_stream_lock_irq(substream);
|
|
||||||
res = snd_pcm_action(ops, substream, state);
|
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1412,17 +1392,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
/* Guarantee the group members won't change during non-atomic action */
|
/* Guarantee the group members won't change during non-atomic action */
|
||||||
down_read(&snd_pcm_link_rwsem);
|
guard(rwsem_read)(&snd_pcm_link_rwsem);
|
||||||
res = snd_pcm_buffer_access_lock(substream->runtime);
|
res = snd_pcm_buffer_access_lock(substream->runtime);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto unlock;
|
return res;
|
||||||
if (snd_pcm_stream_linked(substream))
|
if (snd_pcm_stream_linked(substream))
|
||||||
res = snd_pcm_action_group(ops, substream, state, false);
|
res = snd_pcm_action_group(ops, substream, state, false);
|
||||||
else
|
else
|
||||||
res = snd_pcm_action_single(ops, substream, state);
|
res = snd_pcm_action_single(ops, substream, state);
|
||||||
snd_pcm_buffer_access_unlock(substream->runtime);
|
snd_pcm_buffer_access_unlock(substream->runtime);
|
||||||
unlock:
|
|
||||||
up_read(&snd_pcm_link_rwsem);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1592,12 +1570,9 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
|
||||||
*/
|
*/
|
||||||
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
|
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(pcm_stream_lock_irqsave)(substream);
|
||||||
|
|
||||||
snd_pcm_stream_lock_irqsave(substream, flags);
|
|
||||||
if (substream->runtime && snd_pcm_running(substream))
|
if (substream->runtime && snd_pcm_running(substream))
|
||||||
__snd_pcm_xrun(substream);
|
__snd_pcm_xrun(substream);
|
||||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
|
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
|
||||||
|
@ -1749,14 +1724,9 @@ static const struct action_ops snd_pcm_action_suspend = {
|
||||||
*/
|
*/
|
||||||
static int snd_pcm_suspend(struct snd_pcm_substream *substream)
|
static int snd_pcm_suspend(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
int err;
|
guard(pcm_stream_lock_irqsave)(substream);
|
||||||
unsigned long flags;
|
return snd_pcm_action(&snd_pcm_action_suspend, substream,
|
||||||
|
ACTION_ARG_IGNORE);
|
||||||
snd_pcm_stream_lock_irqsave(substream, flags);
|
|
||||||
err = snd_pcm_action(&snd_pcm_action_suspend, substream,
|
|
||||||
ACTION_ARG_IGNORE);
|
|
||||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1872,22 +1842,17 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
|
||||||
static int snd_pcm_xrun(struct snd_pcm_substream *substream)
|
static int snd_pcm_xrun(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
int result;
|
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
switch (runtime->state) {
|
switch (runtime->state) {
|
||||||
case SNDRV_PCM_STATE_XRUN:
|
case SNDRV_PCM_STATE_XRUN:
|
||||||
result = 0; /* already there */
|
return 0; /* already there */
|
||||||
break;
|
|
||||||
case SNDRV_PCM_STATE_RUNNING:
|
case SNDRV_PCM_STATE_RUNNING:
|
||||||
__snd_pcm_xrun(substream);
|
__snd_pcm_xrun(substream);
|
||||||
result = 0;
|
return 0;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
result = -EBADFD;
|
return -EBADFD;
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1916,13 +1881,12 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
|
||||||
int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
|
int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
runtime->hw_ptr_base = 0;
|
runtime->hw_ptr_base = 0;
|
||||||
runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
|
runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
|
||||||
runtime->status->hw_ptr % runtime->period_size;
|
runtime->status->hw_ptr % runtime->period_size;
|
||||||
runtime->silence_start = runtime->status->hw_ptr;
|
runtime->silence_start = runtime->status->hw_ptr;
|
||||||
runtime->silence_filled = 0;
|
runtime->silence_filled = 0;
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1930,12 +1894,11 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
|
||||||
snd_pcm_state_t state)
|
snd_pcm_state_t state)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
runtime->control->appl_ptr = runtime->status->hw_ptr;
|
runtime->control->appl_ptr = runtime->status->hw_ptr;
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||||
runtime->silence_size > 0)
|
runtime->silence_size > 0)
|
||||||
snd_pcm_playback_silence(substream, ULONG_MAX);
|
snd_pcm_playback_silence(substream, ULONG_MAX);
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct action_ops snd_pcm_action_reset = {
|
static const struct action_ops snd_pcm_action_reset = {
|
||||||
|
@ -2011,16 +1974,16 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
|
||||||
else
|
else
|
||||||
f_flags = substream->f_flags;
|
f_flags = substream->f_flags;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
switch (substream->runtime->state) {
|
switch (substream->runtime->state) {
|
||||||
case SNDRV_PCM_STATE_PAUSED:
|
case SNDRV_PCM_STATE_PAUSED:
|
||||||
snd_pcm_pause(substream, false);
|
snd_pcm_pause(substream, false);
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case SNDRV_PCM_STATE_SUSPENDED:
|
case SNDRV_PCM_STATE_SUSPENDED:
|
||||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
|
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
|
|
||||||
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
|
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
|
||||||
substream,
|
substream,
|
||||||
|
@ -2237,14 +2200,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
|
||||||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
|
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
/* resume pause */
|
/* resume pause */
|
||||||
if (runtime->state == SNDRV_PCM_STATE_PAUSED)
|
if (runtime->state == SNDRV_PCM_STATE_PAUSED)
|
||||||
snd_pcm_pause(substream, false);
|
snd_pcm_pause(substream, false);
|
||||||
|
|
||||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
|
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
|
||||||
/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
|
/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2273,53 +2235,44 @@ static bool is_pcm_file(struct file *file)
|
||||||
*/
|
*/
|
||||||
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
||||||
{
|
{
|
||||||
int res = 0;
|
|
||||||
struct snd_pcm_file *pcm_file;
|
struct snd_pcm_file *pcm_file;
|
||||||
struct snd_pcm_substream *substream1;
|
struct snd_pcm_substream *substream1;
|
||||||
struct snd_pcm_group *group, *target_group;
|
struct snd_pcm_group *group __free(kfree) = NULL;
|
||||||
|
struct snd_pcm_group *target_group;
|
||||||
bool nonatomic = substream->pcm->nonatomic;
|
bool nonatomic = substream->pcm->nonatomic;
|
||||||
struct fd f = fdget(fd);
|
CLASS(fd, f)(fd);
|
||||||
|
|
||||||
if (!f.file)
|
if (!f.file)
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
if (!is_pcm_file(f.file)) {
|
if (!is_pcm_file(f.file))
|
||||||
res = -EBADFD;
|
return -EBADFD;
|
||||||
goto _badf;
|
|
||||||
}
|
|
||||||
pcm_file = f.file->private_data;
|
pcm_file = f.file->private_data;
|
||||||
substream1 = pcm_file->substream;
|
substream1 = pcm_file->substream;
|
||||||
|
|
||||||
if (substream == substream1) {
|
if (substream == substream1)
|
||||||
res = -EINVAL;
|
return -EINVAL;
|
||||||
goto _badf;
|
|
||||||
}
|
|
||||||
|
|
||||||
group = kzalloc(sizeof(*group), GFP_KERNEL);
|
group = kzalloc(sizeof(*group), GFP_KERNEL);
|
||||||
if (!group) {
|
if (!group)
|
||||||
res = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto _nolock;
|
|
||||||
}
|
|
||||||
snd_pcm_group_init(group);
|
snd_pcm_group_init(group);
|
||||||
|
|
||||||
down_write(&snd_pcm_link_rwsem);
|
guard(rwsem_write)(&snd_pcm_link_rwsem);
|
||||||
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN ||
|
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN ||
|
||||||
substream->runtime->state != substream1->runtime->state ||
|
substream->runtime->state != substream1->runtime->state ||
|
||||||
substream->pcm->nonatomic != substream1->pcm->nonatomic) {
|
substream->pcm->nonatomic != substream1->pcm->nonatomic)
|
||||||
res = -EBADFD;
|
return -EBADFD;
|
||||||
goto _end;
|
if (snd_pcm_stream_linked(substream1))
|
||||||
}
|
return -EALREADY;
|
||||||
if (snd_pcm_stream_linked(substream1)) {
|
|
||||||
res = -EALREADY;
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
if (!snd_pcm_stream_linked(substream)) {
|
if (!snd_pcm_stream_linked(substream)) {
|
||||||
snd_pcm_group_assign(substream, group);
|
snd_pcm_group_assign(substream, group);
|
||||||
group = NULL; /* assigned, don't free this one below */
|
group = NULL; /* assigned, don't free this one below */
|
||||||
|
}
|
||||||
|
target_group = substream->group;
|
||||||
}
|
}
|
||||||
target_group = substream->group;
|
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
|
|
||||||
snd_pcm_group_lock_irq(target_group, nonatomic);
|
snd_pcm_group_lock_irq(target_group, nonatomic);
|
||||||
snd_pcm_stream_lock_nested(substream1);
|
snd_pcm_stream_lock_nested(substream1);
|
||||||
|
@ -2327,13 +2280,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
||||||
refcount_inc(&target_group->refs);
|
refcount_inc(&target_group->refs);
|
||||||
snd_pcm_stream_unlock(substream1);
|
snd_pcm_stream_unlock(substream1);
|
||||||
snd_pcm_group_unlock_irq(target_group, nonatomic);
|
snd_pcm_group_unlock_irq(target_group, nonatomic);
|
||||||
_end:
|
return 0;
|
||||||
up_write(&snd_pcm_link_rwsem);
|
|
||||||
_nolock:
|
|
||||||
kfree(group);
|
|
||||||
_badf:
|
|
||||||
fdput(f);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relink_to_local(struct snd_pcm_substream *substream)
|
static void relink_to_local(struct snd_pcm_substream *substream)
|
||||||
|
@ -2348,14 +2295,11 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
|
||||||
struct snd_pcm_group *group;
|
struct snd_pcm_group *group;
|
||||||
bool nonatomic = substream->pcm->nonatomic;
|
bool nonatomic = substream->pcm->nonatomic;
|
||||||
bool do_free = false;
|
bool do_free = false;
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
down_write(&snd_pcm_link_rwsem);
|
guard(rwsem_write)(&snd_pcm_link_rwsem);
|
||||||
|
|
||||||
if (!snd_pcm_stream_linked(substream)) {
|
if (!snd_pcm_stream_linked(substream))
|
||||||
res = -EALREADY;
|
return -EALREADY;
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
|
|
||||||
group = substream->group;
|
group = substream->group;
|
||||||
snd_pcm_group_lock_irq(group, nonatomic);
|
snd_pcm_group_lock_irq(group, nonatomic);
|
||||||
|
@ -2374,10 +2318,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
|
||||||
snd_pcm_group_unlock_irq(group, nonatomic);
|
snd_pcm_group_unlock_irq(group, nonatomic);
|
||||||
if (do_free)
|
if (do_free)
|
||||||
kfree(group);
|
kfree(group);
|
||||||
|
return 0;
|
||||||
_end:
|
|
||||||
up_write(&snd_pcm_link_rwsem);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2950,10 +2891,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
|
||||||
/* block until the device gets woken up as it may touch the hardware */
|
/* block until the device gets woken up as it may touch the hardware */
|
||||||
snd_power_wait(pcm->card);
|
snd_power_wait(pcm->card);
|
||||||
|
|
||||||
mutex_lock(&pcm->open_mutex);
|
scoped_guard(mutex, &pcm->open_mutex) {
|
||||||
snd_pcm_release_substream(substream);
|
snd_pcm_release_substream(substream);
|
||||||
kfree(pcm_file);
|
kfree(pcm_file);
|
||||||
mutex_unlock(&pcm->open_mutex);
|
}
|
||||||
wake_up(&pcm->open_wait);
|
wake_up(&pcm->open_wait);
|
||||||
module_put(pcm->card->module);
|
module_put(pcm->card->module);
|
||||||
snd_card_file_remove(pcm->card, file);
|
snd_card_file_remove(pcm->card, file);
|
||||||
|
@ -3037,12 +2978,12 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
|
||||||
if (frames == 0)
|
if (frames == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
ret = do_pcm_hwsync(substream);
|
ret = do_pcm_hwsync(substream);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = rewind_appl_ptr(substream, frames,
|
ret = rewind_appl_ptr(substream, frames,
|
||||||
snd_pcm_hw_avail(substream));
|
snd_pcm_hw_avail(substream));
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
}
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3056,12 +2997,12 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
|
||||||
if (frames == 0)
|
if (frames == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
ret = do_pcm_hwsync(substream);
|
ret = do_pcm_hwsync(substream);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = forward_appl_ptr(substream, frames,
|
ret = forward_appl_ptr(substream, frames,
|
||||||
snd_pcm_avail(substream));
|
snd_pcm_avail(substream));
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
}
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3072,11 +3013,11 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
err = do_pcm_hwsync(substream);
|
err = do_pcm_hwsync(substream);
|
||||||
if (delay && !err)
|
if (delay && !err)
|
||||||
*delay = snd_pcm_calc_delay(substream);
|
*delay = snd_pcm_calc_delay(substream);
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
}
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -3108,27 +3049,25 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
||||||
err = pcm_lib_apply_appl_ptr(substream,
|
err = pcm_lib_apply_appl_ptr(substream,
|
||||||
sync_ptr.c.control.appl_ptr);
|
sync_ptr.c.control.appl_ptr);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
return err;
|
||||||
return err;
|
} else {
|
||||||
|
sync_ptr.c.control.appl_ptr = control->appl_ptr;
|
||||||
}
|
}
|
||||||
} else {
|
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
||||||
sync_ptr.c.control.appl_ptr = control->appl_ptr;
|
control->avail_min = sync_ptr.c.control.avail_min;
|
||||||
|
else
|
||||||
|
sync_ptr.c.control.avail_min = control->avail_min;
|
||||||
|
sync_ptr.s.status.state = status->state;
|
||||||
|
sync_ptr.s.status.hw_ptr = status->hw_ptr;
|
||||||
|
sync_ptr.s.status.tstamp = status->tstamp;
|
||||||
|
sync_ptr.s.status.suspended_state = status->suspended_state;
|
||||||
|
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
|
||||||
}
|
}
|
||||||
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
|
||||||
control->avail_min = sync_ptr.c.control.avail_min;
|
|
||||||
else
|
|
||||||
sync_ptr.c.control.avail_min = control->avail_min;
|
|
||||||
sync_ptr.s.status.state = status->state;
|
|
||||||
sync_ptr.s.status.hw_ptr = status->hw_ptr;
|
|
||||||
sync_ptr.s.status.tstamp = status->tstamp;
|
|
||||||
sync_ptr.s.status.suspended_state = status->suspended_state;
|
|
||||||
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
|
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
|
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
||||||
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
|
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
|
||||||
|
@ -3206,27 +3145,25 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
|
||||||
boundary = recalculate_boundary(runtime);
|
boundary = recalculate_boundary(runtime);
|
||||||
if (! boundary)
|
if (! boundary)
|
||||||
boundary = 0x7fffffff;
|
boundary = 0x7fffffff;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||||
/* FIXME: we should consider the boundary for the sync from app */
|
/* FIXME: we should consider the boundary for the sync from app */
|
||||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
||||||
err = pcm_lib_apply_appl_ptr(substream,
|
err = pcm_lib_apply_appl_ptr(substream,
|
||||||
scontrol.appl_ptr);
|
scontrol.appl_ptr);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
return err;
|
||||||
return err;
|
} else
|
||||||
}
|
scontrol.appl_ptr = control->appl_ptr % boundary;
|
||||||
} else
|
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
||||||
scontrol.appl_ptr = control->appl_ptr % boundary;
|
control->avail_min = scontrol.avail_min;
|
||||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
else
|
||||||
control->avail_min = scontrol.avail_min;
|
scontrol.avail_min = control->avail_min;
|
||||||
else
|
sstatus.state = status->state;
|
||||||
scontrol.avail_min = control->avail_min;
|
sstatus.hw_ptr = status->hw_ptr % boundary;
|
||||||
sstatus.state = status->state;
|
sstatus.tstamp = status->tstamp;
|
||||||
sstatus.hw_ptr = status->hw_ptr % boundary;
|
sstatus.suspended_state = status->suspended_state;
|
||||||
sstatus.tstamp = status->tstamp;
|
sstatus.audio_tstamp = status->audio_tstamp;
|
||||||
sstatus.suspended_state = status->suspended_state;
|
}
|
||||||
sstatus.audio_tstamp = status->audio_tstamp;
|
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
||||||
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
|
||||||
if (put_user(sstatus.state, &src->s.status.state) ||
|
if (put_user(sstatus.state, &src->s.status.state) ||
|
||||||
|
@ -3284,7 +3221,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
|
||||||
{
|
{
|
||||||
struct snd_xfern xfern;
|
struct snd_xfern xfern;
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
void *bufs;
|
void *bufs __free(kfree) = NULL;
|
||||||
snd_pcm_sframes_t result;
|
snd_pcm_sframes_t result;
|
||||||
|
|
||||||
if (runtime->state == SNDRV_PCM_STATE_OPEN)
|
if (runtime->state == SNDRV_PCM_STATE_OPEN)
|
||||||
|
@ -3298,12 +3235,11 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
|
||||||
|
|
||||||
bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
|
bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
|
||||||
if (IS_ERR(bufs))
|
if (IS_ERR(bufs))
|
||||||
return PTR_ERR(bufs);
|
return PTR_ERR(no_free_ptr(bufs));
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
|
result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
|
||||||
else
|
else
|
||||||
result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
|
result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
|
||||||
kfree(bufs);
|
|
||||||
if (put_user(result, &_xfern->result))
|
if (put_user(result, &_xfern->result))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return result < 0 ? result : 0;
|
return result < 0 ? result : 0;
|
||||||
|
@ -3571,7 +3507,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
snd_pcm_sframes_t result;
|
snd_pcm_sframes_t result;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
void __user **bufs;
|
void __user **bufs __free(kfree) = NULL;
|
||||||
snd_pcm_uframes_t frames;
|
snd_pcm_uframes_t frames;
|
||||||
const struct iovec *iov = iter_iov(to);
|
const struct iovec *iov = iter_iov(to);
|
||||||
|
|
||||||
|
@ -3600,7 +3536,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
|
||||||
result = snd_pcm_lib_readv(substream, bufs, frames);
|
result = snd_pcm_lib_readv(substream, bufs, frames);
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
result = frames_to_bytes(runtime, result);
|
result = frames_to_bytes(runtime, result);
|
||||||
kfree(bufs);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3611,7 +3546,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
snd_pcm_sframes_t result;
|
snd_pcm_sframes_t result;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
void __user **bufs;
|
void __user **bufs __free(kfree) = NULL;
|
||||||
snd_pcm_uframes_t frames;
|
snd_pcm_uframes_t frames;
|
||||||
const struct iovec *iov = iter_iov(from);
|
const struct iovec *iov = iter_iov(from);
|
||||||
|
|
||||||
|
@ -3639,7 +3574,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
|
||||||
result = snd_pcm_lib_writev(substream, bufs, frames);
|
result = snd_pcm_lib_writev(substream, bufs, frames);
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
result = frames_to_bytes(runtime, result);
|
result = frames_to_bytes(runtime, result);
|
||||||
kfree(bufs);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3668,7 +3602,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
|
||||||
poll_wait(file, &runtime->sleep, wait);
|
poll_wait(file, &runtime->sleep, wait);
|
||||||
|
|
||||||
mask = 0;
|
mask = 0;
|
||||||
snd_pcm_stream_lock_irq(substream);
|
guard(pcm_stream_lock_irq)(substream);
|
||||||
avail = snd_pcm_avail(substream);
|
avail = snd_pcm_avail(substream);
|
||||||
switch (runtime->state) {
|
switch (runtime->state) {
|
||||||
case SNDRV_PCM_STATE_RUNNING:
|
case SNDRV_PCM_STATE_RUNNING:
|
||||||
|
@ -3688,7 +3622,6 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
|
||||||
mask = ok | EPOLLERR;
|
mask = ok | EPOLLERR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snd_pcm_stream_unlock_irq(substream);
|
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4081,8 +4014,8 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara
|
||||||
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
|
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params_old __user * _oparams)
|
struct snd_pcm_hw_params_old __user * _oparams)
|
||||||
{
|
{
|
||||||
struct snd_pcm_hw_params *params;
|
struct snd_pcm_hw_params *params __free(kfree) = NULL;
|
||||||
struct snd_pcm_hw_params_old *oparams = NULL;
|
struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
params = kmalloc(sizeof(*params), GFP_KERNEL);
|
params = kmalloc(sizeof(*params), GFP_KERNEL);
|
||||||
|
@ -4090,34 +4023,28 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
oparams = memdup_user(_oparams, sizeof(*oparams));
|
oparams = memdup_user(_oparams, sizeof(*oparams));
|
||||||
if (IS_ERR(oparams)) {
|
if (IS_ERR(oparams))
|
||||||
err = PTR_ERR(oparams);
|
return PTR_ERR(no_free_ptr(oparams));
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
snd_pcm_hw_convert_from_old_params(params, oparams);
|
snd_pcm_hw_convert_from_old_params(params, oparams);
|
||||||
err = snd_pcm_hw_refine(substream, params);
|
err = snd_pcm_hw_refine(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_old;
|
return err;
|
||||||
|
|
||||||
err = fixup_unreferenced_params(substream, params);
|
err = fixup_unreferenced_params(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_old;
|
return err;
|
||||||
|
|
||||||
snd_pcm_hw_convert_to_old_params(oparams, params);
|
snd_pcm_hw_convert_to_old_params(oparams, params);
|
||||||
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
|
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
out_old:
|
return 0;
|
||||||
kfree(oparams);
|
|
||||||
out:
|
|
||||||
kfree(params);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
|
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params_old __user * _oparams)
|
struct snd_pcm_hw_params_old __user * _oparams)
|
||||||
{
|
{
|
||||||
struct snd_pcm_hw_params *params;
|
struct snd_pcm_hw_params *params __free(kfree) = NULL;
|
||||||
struct snd_pcm_hw_params_old *oparams = NULL;
|
struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
params = kmalloc(sizeof(*params), GFP_KERNEL);
|
params = kmalloc(sizeof(*params), GFP_KERNEL);
|
||||||
|
@ -4125,24 +4052,18 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
oparams = memdup_user(_oparams, sizeof(*oparams));
|
oparams = memdup_user(_oparams, sizeof(*oparams));
|
||||||
if (IS_ERR(oparams)) {
|
if (IS_ERR(oparams))
|
||||||
err = PTR_ERR(oparams);
|
return PTR_ERR(no_free_ptr(oparams));
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_hw_convert_from_old_params(params, oparams);
|
snd_pcm_hw_convert_from_old_params(params, oparams);
|
||||||
err = snd_pcm_hw_params(substream, params);
|
err = snd_pcm_hw_params(substream, params);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_old;
|
return err;
|
||||||
|
|
||||||
snd_pcm_hw_convert_to_old_params(oparams, params);
|
snd_pcm_hw_convert_to_old_params(oparams, params);
|
||||||
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
|
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
out_old:
|
return 0;
|
||||||
kfree(oparams);
|
|
||||||
out:
|
|
||||||
kfree(params);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_SUPPORT_OLD_API */
|
#endif /* CONFIG_SND_SUPPORT_OLD_API */
|
||||||
|
|
||||||
|
|
|
@ -105,13 +105,8 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime)
|
||||||
|
|
||||||
static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
|
static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
bool ready;
|
return __snd_rawmidi_ready(substream->runtime);
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
|
||||||
ready = __snd_rawmidi_ready(substream->runtime);
|
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
return ready;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
|
static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
|
||||||
|
@ -238,12 +233,9 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
|
||||||
static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream,
|
static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream,
|
||||||
bool is_input)
|
bool is_input)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
|
||||||
if (substream->opened && substream->runtime)
|
if (substream->opened && substream->runtime)
|
||||||
__reset_runtime_ptrs(substream->runtime, is_input);
|
__reset_runtime_ptrs(substream->runtime, is_input);
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
|
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
|
||||||
|
@ -260,33 +252,29 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
|
||||||
long timeout;
|
long timeout;
|
||||||
struct snd_rawmidi_runtime *runtime;
|
struct snd_rawmidi_runtime *runtime;
|
||||||
|
|
||||||
spin_lock_irq(&substream->lock);
|
scoped_guard(spinlock_irq, &substream->lock) {
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (!substream->opened || !runtime || !runtime->buffer) {
|
if (!substream->opened || !runtime || !runtime->buffer)
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
} else {
|
|
||||||
snd_rawmidi_buffer_ref(runtime);
|
snd_rawmidi_buffer_ref(runtime);
|
||||||
runtime->drain = 1;
|
runtime->drain = 1;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
timeout = wait_event_interruptible_timeout(runtime->sleep,
|
timeout = wait_event_interruptible_timeout(runtime->sleep,
|
||||||
(runtime->avail >= runtime->buffer_size),
|
(runtime->avail >= runtime->buffer_size),
|
||||||
10*HZ);
|
10*HZ);
|
||||||
|
|
||||||
spin_lock_irq(&substream->lock);
|
scoped_guard(spinlock_irq, &substream->lock) {
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
err = -ERESTARTSYS;
|
err = -ERESTARTSYS;
|
||||||
if (runtime->avail < runtime->buffer_size && !timeout) {
|
if (runtime->avail < runtime->buffer_size && !timeout) {
|
||||||
rmidi_warn(substream->rmidi,
|
rmidi_warn(substream->rmidi,
|
||||||
"rawmidi drain error (avail = %li, buffer_size = %li)\n",
|
"rawmidi drain error (avail = %li, buffer_size = %li)\n",
|
||||||
(long)runtime->avail, (long)runtime->buffer_size);
|
(long)runtime->avail, (long)runtime->buffer_size);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
|
}
|
||||||
|
runtime->drain = 0;
|
||||||
}
|
}
|
||||||
runtime->drain = 0;
|
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
|
|
||||||
if (err != -ERESTARTSYS) {
|
if (err != -ERESTARTSYS) {
|
||||||
/* we need wait a while to make sure that Tx FIFOs are empty */
|
/* we need wait a while to make sure that Tx FIFOs are empty */
|
||||||
|
@ -297,9 +285,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
|
||||||
snd_rawmidi_drop_output(substream);
|
snd_rawmidi_drop_output(substream);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(&substream->lock);
|
scoped_guard(spinlock_irq, &substream->lock)
|
||||||
snd_rawmidi_buffer_unref(runtime);
|
snd_rawmidi_buffer_unref(runtime);
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -363,14 +350,13 @@ static int open_substream(struct snd_rawmidi *rmidi,
|
||||||
snd_rawmidi_runtime_free(substream);
|
snd_rawmidi_runtime_free(substream);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
spin_lock_irq(&substream->lock);
|
guard(spinlock_irq)(&substream->lock);
|
||||||
substream->opened = 1;
|
substream->opened = 1;
|
||||||
substream->active_sensing = 0;
|
substream->active_sensing = 0;
|
||||||
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
|
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
|
||||||
substream->append = 1;
|
substream->append = 1;
|
||||||
substream->pid = get_pid(task_pid(current));
|
substream->pid = get_pid(task_pid(current));
|
||||||
rmidi->streams[substream->stream].substream_opened++;
|
rmidi->streams[substream->stream].substream_opened++;
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
}
|
}
|
||||||
substream->use_count++;
|
substream->use_count++;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -433,9 +419,8 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
|
||||||
if (!try_module_get(rmidi->card->module))
|
if (!try_module_get(rmidi->card->module))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
mutex_lock(&rmidi->open_mutex);
|
guard(mutex)(&rmidi->open_mutex);
|
||||||
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
|
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
|
||||||
mutex_unlock(&rmidi->open_mutex);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
module_put(rmidi->card->module);
|
module_put(rmidi->card->module);
|
||||||
return err;
|
return err;
|
||||||
|
@ -568,10 +553,10 @@ static void close_substream(struct snd_rawmidi *rmidi,
|
||||||
}
|
}
|
||||||
snd_rawmidi_buffer_ref_sync(substream);
|
snd_rawmidi_buffer_ref_sync(substream);
|
||||||
}
|
}
|
||||||
spin_lock_irq(&substream->lock);
|
scoped_guard(spinlock_irq, &substream->lock) {
|
||||||
substream->opened = 0;
|
substream->opened = 0;
|
||||||
substream->append = 0;
|
substream->append = 0;
|
||||||
spin_unlock_irq(&substream->lock);
|
}
|
||||||
substream->ops->close(substream);
|
substream->ops->close(substream);
|
||||||
if (substream->runtime->private_free)
|
if (substream->runtime->private_free)
|
||||||
substream->runtime->private_free(substream);
|
substream->runtime->private_free(substream);
|
||||||
|
@ -586,7 +571,7 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
|
||||||
struct snd_rawmidi *rmidi;
|
struct snd_rawmidi *rmidi;
|
||||||
|
|
||||||
rmidi = rfile->rmidi;
|
rmidi = rfile->rmidi;
|
||||||
mutex_lock(&rmidi->open_mutex);
|
guard(mutex)(&rmidi->open_mutex);
|
||||||
if (rfile->input) {
|
if (rfile->input) {
|
||||||
close_substream(rmidi, rfile->input, 1);
|
close_substream(rmidi, rfile->input, 1);
|
||||||
rfile->input = NULL;
|
rfile->input = NULL;
|
||||||
|
@ -596,7 +581,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
|
||||||
rfile->output = NULL;
|
rfile->output = NULL;
|
||||||
}
|
}
|
||||||
rfile->rmidi = NULL;
|
rfile->rmidi = NULL;
|
||||||
mutex_unlock(&rmidi->open_mutex);
|
|
||||||
wake_up(&rmidi->open_wait);
|
wake_up(&rmidi->open_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,12 +679,8 @@ static int __snd_rawmidi_info_select(struct snd_card *card,
|
||||||
|
|
||||||
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
|
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
|
||||||
{
|
{
|
||||||
int ret;
|
guard(mutex)(®ister_mutex);
|
||||||
|
return __snd_rawmidi_info_select(card, info);
|
||||||
mutex_lock(®ister_mutex);
|
|
||||||
ret = __snd_rawmidi_info_select(card, info);
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_info_select);
|
EXPORT_SYMBOL(snd_rawmidi_info_select);
|
||||||
|
|
||||||
|
@ -744,9 +724,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
|
||||||
newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
|
newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
|
||||||
if (!newbuf)
|
if (!newbuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spin_lock_irq(&substream->lock);
|
guard(spinlock_irq)(&substream->lock);
|
||||||
if (runtime->buffer_ref) {
|
if (runtime->buffer_ref) {
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
kvfree(newbuf);
|
kvfree(newbuf);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
@ -754,7 +733,6 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
|
||||||
runtime->buffer = newbuf;
|
runtime->buffer = newbuf;
|
||||||
runtime->buffer_size = params->buffer_size;
|
runtime->buffer_size = params->buffer_size;
|
||||||
__reset_runtime_ptrs(runtime, is_input);
|
__reset_runtime_ptrs(runtime, is_input);
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
kvfree(oldbuf);
|
kvfree(oldbuf);
|
||||||
}
|
}
|
||||||
runtime->avail_min = params->avail_min;
|
runtime->avail_min = params->avail_min;
|
||||||
|
@ -767,15 +745,12 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_rawmidi_drain_output(substream);
|
snd_rawmidi_drain_output(substream);
|
||||||
mutex_lock(&substream->rmidi->open_mutex);
|
guard(mutex)(&substream->rmidi->open_mutex);
|
||||||
if (substream->append && substream->use_count > 1)
|
if (substream->append && substream->use_count > 1)
|
||||||
err = -EBUSY;
|
return -EBUSY;
|
||||||
else
|
err = resize_runtime_buffer(substream, params, false);
|
||||||
err = resize_runtime_buffer(substream, params, false);
|
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
substream->active_sensing = !params->no_active_sensing;
|
substream->active_sensing = !params->no_active_sensing;
|
||||||
mutex_unlock(&substream->rmidi->open_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_output_params);
|
EXPORT_SYMBOL(snd_rawmidi_output_params);
|
||||||
|
@ -788,7 +763,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_rawmidi_drain_input(substream);
|
snd_rawmidi_drain_input(substream);
|
||||||
mutex_lock(&substream->rmidi->open_mutex);
|
guard(mutex)(&substream->rmidi->open_mutex);
|
||||||
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
|
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
|
else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
|
||||||
|
@ -802,7 +777,6 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
|
||||||
substream->framing = framing;
|
substream->framing = framing;
|
||||||
substream->clock_type = clock_type;
|
substream->clock_type = clock_type;
|
||||||
}
|
}
|
||||||
mutex_unlock(&substream->rmidi->open_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_input_params);
|
EXPORT_SYMBOL(snd_rawmidi_input_params);
|
||||||
|
@ -814,9 +788,8 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
|
||||||
|
|
||||||
memset(status, 0, sizeof(*status));
|
memset(status, 0, sizeof(*status));
|
||||||
status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
|
status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
|
||||||
spin_lock_irq(&substream->lock);
|
guard(spinlock_irq)(&substream->lock);
|
||||||
status->avail = runtime->avail;
|
status->avail = runtime->avail;
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,11 +800,10 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
|
||||||
|
|
||||||
memset(status, 0, sizeof(*status));
|
memset(status, 0, sizeof(*status));
|
||||||
status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
|
status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
|
||||||
spin_lock_irq(&substream->lock);
|
guard(spinlock_irq)(&substream->lock);
|
||||||
status->avail = runtime->avail;
|
status->avail = runtime->avail;
|
||||||
status->xruns = runtime->xruns;
|
status->xruns = runtime->xruns;
|
||||||
runtime->xruns = 0;
|
runtime->xruns = 0;
|
||||||
spin_unlock_irq(&substream->lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,19 +997,19 @@ static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
|
if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
|
||||||
device = SNDRV_RAWMIDI_DEVICES - 1;
|
device = SNDRV_RAWMIDI_DEVICES - 1;
|
||||||
mutex_lock(®ister_mutex);
|
scoped_guard(mutex, ®ister_mutex) {
|
||||||
device = device < 0 ? 0 : device + 1;
|
device = device < 0 ? 0 : device + 1;
|
||||||
for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
|
for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
|
||||||
rmidi = snd_rawmidi_search(card, device);
|
rmidi = snd_rawmidi_search(card, device);
|
||||||
if (!rmidi)
|
if (!rmidi)
|
||||||
continue;
|
continue;
|
||||||
is_ump = rawmidi_is_ump(rmidi);
|
is_ump = rawmidi_is_ump(rmidi);
|
||||||
if (find_ump == is_ump)
|
if (find_ump == is_ump)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (device == SNDRV_RAWMIDI_DEVICES)
|
||||||
|
device = -1;
|
||||||
}
|
}
|
||||||
if (device == SNDRV_RAWMIDI_DEVICES)
|
|
||||||
device = -1;
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
if (put_user(device, argp))
|
if (put_user(device, argp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1050,18 +1022,16 @@ static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd,
|
||||||
{
|
{
|
||||||
struct snd_ump_endpoint_info __user *info = argp;
|
struct snd_ump_endpoint_info __user *info = argp;
|
||||||
struct snd_rawmidi *rmidi;
|
struct snd_rawmidi *rmidi;
|
||||||
int device, ret;
|
int device;
|
||||||
|
|
||||||
if (get_user(device, &info->device))
|
if (get_user(device, &info->device))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
rmidi = snd_rawmidi_search(card, device);
|
rmidi = snd_rawmidi_search(card, device);
|
||||||
if (rmidi && rmidi->ops && rmidi->ops->ioctl)
|
if (rmidi && rmidi->ops && rmidi->ops->ioctl)
|
||||||
ret = rmidi->ops->ioctl(rmidi, cmd, argp);
|
return rmidi->ops->ioctl(rmidi, cmd, argp);
|
||||||
else
|
else
|
||||||
ret = -ENXIO;
|
return -ENXIO;
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1168,27 +1138,23 @@ static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substr
|
||||||
int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
|
int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
|
||||||
const unsigned char *buffer, int count)
|
const unsigned char *buffer, int count)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct timespec64 ts64 = get_framing_tstamp(substream);
|
struct timespec64 ts64 = get_framing_tstamp(substream);
|
||||||
int result = 0, count1;
|
int result = 0, count1;
|
||||||
struct snd_rawmidi_runtime *runtime;
|
struct snd_rawmidi_runtime *runtime;
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
if (!substream->opened) {
|
if (!substream->opened)
|
||||||
result = -EBADFD;
|
return -EBADFD;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (!runtime || !runtime->buffer) {
|
if (!runtime || !runtime->buffer) {
|
||||||
rmidi_dbg(substream->rmidi,
|
rmidi_dbg(substream->rmidi,
|
||||||
"snd_rawmidi_receive: input is not active!!!\n");
|
"snd_rawmidi_receive: input is not active!!!\n");
|
||||||
result = -EINVAL;
|
return -EINVAL;
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count = get_aligned_size(runtime, count);
|
count = get_aligned_size(runtime, count);
|
||||||
if (!count)
|
if (!count)
|
||||||
goto unlock;
|
return result;
|
||||||
|
|
||||||
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
|
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
|
||||||
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
|
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
|
||||||
|
@ -1211,7 +1177,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
|
||||||
count1 = runtime->buffer_size - runtime->avail;
|
count1 = runtime->buffer_size - runtime->avail;
|
||||||
count1 = get_aligned_size(runtime, count1);
|
count1 = get_aligned_size(runtime, count1);
|
||||||
if (!count1)
|
if (!count1)
|
||||||
goto unlock;
|
return result;
|
||||||
memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
|
memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
|
||||||
runtime->hw_ptr += count1;
|
runtime->hw_ptr += count1;
|
||||||
runtime->hw_ptr %= runtime->buffer_size;
|
runtime->hw_ptr %= runtime->buffer_size;
|
||||||
|
@ -1239,8 +1205,6 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
|
||||||
else if (__snd_rawmidi_ready(runtime))
|
else if (__snd_rawmidi_ready(runtime))
|
||||||
wake_up(&runtime->sleep);
|
wake_up(&runtime->sleep);
|
||||||
}
|
}
|
||||||
unlock:
|
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_receive);
|
EXPORT_SYMBOL(snd_rawmidi_receive);
|
||||||
|
@ -1362,20 +1326,15 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
|
||||||
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
|
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_rawmidi_runtime *runtime;
|
struct snd_rawmidi_runtime *runtime;
|
||||||
int result;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (!substream->opened || !runtime || !runtime->buffer) {
|
if (!substream->opened || !runtime || !runtime->buffer) {
|
||||||
rmidi_dbg(substream->rmidi,
|
rmidi_dbg(substream->rmidi,
|
||||||
"snd_rawmidi_transmit_empty: output is not active!!!\n");
|
"snd_rawmidi_transmit_empty: output is not active!!!\n");
|
||||||
result = 1;
|
return 1;
|
||||||
} else {
|
|
||||||
result = runtime->avail >= runtime->buffer_size;
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
return (runtime->avail >= runtime->buffer_size);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
|
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
|
||||||
|
|
||||||
|
@ -1449,16 +1408,10 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
|
||||||
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
|
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
|
||||||
unsigned char *buffer, int count)
|
unsigned char *buffer, int count)
|
||||||
{
|
{
|
||||||
int result;
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
|
||||||
if (!substream->opened || !substream->runtime)
|
if (!substream->opened || !substream->runtime)
|
||||||
result = -EBADFD;
|
return -EBADFD;
|
||||||
else
|
return __snd_rawmidi_transmit_peek(substream, buffer, count);
|
||||||
result = __snd_rawmidi_transmit_peek(substream, buffer, count);
|
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
|
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
|
||||||
|
|
||||||
|
@ -1505,16 +1458,10 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
|
||||||
*/
|
*/
|
||||||
int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
|
int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
|
||||||
{
|
{
|
||||||
int result;
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
|
||||||
if (!substream->opened || !substream->runtime)
|
if (!substream->opened || !substream->runtime)
|
||||||
result = -EBADFD;
|
return -EBADFD;
|
||||||
else
|
return __snd_rawmidi_transmit_ack(substream, count);
|
||||||
result = __snd_rawmidi_transmit_ack(substream, count);
|
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
|
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
|
||||||
|
|
||||||
|
@ -1531,21 +1478,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
|
||||||
int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
|
int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
|
||||||
unsigned char *buffer, int count)
|
unsigned char *buffer, int count)
|
||||||
{
|
{
|
||||||
int result;
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
|
||||||
if (!substream->opened)
|
if (!substream->opened)
|
||||||
result = -EBADFD;
|
return -EBADFD;
|
||||||
else {
|
count = __snd_rawmidi_transmit_peek(substream, buffer, count);
|
||||||
count = __snd_rawmidi_transmit_peek(substream, buffer, count);
|
if (count <= 0)
|
||||||
if (count <= 0)
|
return count;
|
||||||
result = count;
|
return __snd_rawmidi_transmit_ack(substream, count);
|
||||||
else
|
|
||||||
result = __snd_rawmidi_transmit_ack(substream, count);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_transmit);
|
EXPORT_SYMBOL(snd_rawmidi_transmit);
|
||||||
|
|
||||||
|
@ -1558,17 +1497,15 @@ EXPORT_SYMBOL(snd_rawmidi_transmit);
|
||||||
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
|
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_rawmidi_runtime *runtime;
|
struct snd_rawmidi_runtime *runtime;
|
||||||
unsigned long flags;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&substream->lock, flags);
|
guard(spinlock_irqsave)(&substream->lock);
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
if (substream->opened && runtime &&
|
if (substream->opened && runtime &&
|
||||||
runtime->avail < runtime->buffer_size) {
|
runtime->avail < runtime->buffer_size) {
|
||||||
count = runtime->buffer_size - runtime->avail;
|
count = runtime->buffer_size - runtime->avail;
|
||||||
__snd_rawmidi_transmit_ack(substream, count);
|
__snd_rawmidi_transmit_ack(substream, count);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&substream->lock, flags);
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_rawmidi_proceed);
|
EXPORT_SYMBOL(snd_rawmidi_proceed);
|
||||||
|
@ -1772,7 +1709,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
|
||||||
rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
|
rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
|
||||||
if (rmidi->ops && rmidi->ops->proc_read)
|
if (rmidi->ops && rmidi->ops->proc_read)
|
||||||
rmidi->ops->proc_read(entry, buffer);
|
rmidi->ops->proc_read(entry, buffer);
|
||||||
mutex_lock(&rmidi->open_mutex);
|
guard(mutex)(&rmidi->open_mutex);
|
||||||
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
|
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
|
||||||
list_for_each_entry(substream,
|
list_for_each_entry(substream,
|
||||||
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
|
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
|
||||||
|
@ -1787,10 +1724,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
|
||||||
" Owner PID : %d\n",
|
" Owner PID : %d\n",
|
||||||
pid_vnr(substream->pid));
|
pid_vnr(substream->pid));
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
spin_lock_irq(&substream->lock);
|
scoped_guard(spinlock_irq, &substream->lock) {
|
||||||
buffer_size = runtime->buffer_size;
|
buffer_size = runtime->buffer_size;
|
||||||
avail = runtime->avail;
|
avail = runtime->avail;
|
||||||
spin_unlock_irq(&substream->lock);
|
}
|
||||||
snd_iprintf(buffer,
|
snd_iprintf(buffer,
|
||||||
" Mode : %s\n"
|
" Mode : %s\n"
|
||||||
" Buffer size : %lu\n"
|
" Buffer size : %lu\n"
|
||||||
|
@ -1814,11 +1751,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
|
||||||
" Owner PID : %d\n",
|
" Owner PID : %d\n",
|
||||||
pid_vnr(substream->pid));
|
pid_vnr(substream->pid));
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
spin_lock_irq(&substream->lock);
|
scoped_guard(spinlock_irq, &substream->lock) {
|
||||||
buffer_size = runtime->buffer_size;
|
buffer_size = runtime->buffer_size;
|
||||||
avail = runtime->avail;
|
avail = runtime->avail;
|
||||||
xruns = runtime->xruns;
|
xruns = runtime->xruns;
|
||||||
spin_unlock_irq(&substream->lock);
|
}
|
||||||
snd_iprintf(buffer,
|
snd_iprintf(buffer,
|
||||||
" Buffer size : %lu\n"
|
" Buffer size : %lu\n"
|
||||||
" Avail : %lu\n"
|
" Avail : %lu\n"
|
||||||
|
@ -1835,7 +1772,6 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&rmidi->open_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2024,12 +1960,12 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
|
||||||
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
|
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
err = 0;
|
err = 0;
|
||||||
mutex_lock(®ister_mutex);
|
scoped_guard(mutex, ®ister_mutex) {
|
||||||
if (snd_rawmidi_search(rmidi->card, rmidi->device))
|
if (snd_rawmidi_search(rmidi->card, rmidi->device))
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
else
|
else
|
||||||
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
|
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
|
||||||
mutex_unlock(®ister_mutex);
|
}
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -2102,9 +2038,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
|
||||||
error_unregister:
|
error_unregister:
|
||||||
snd_unregister_device(rmidi->dev);
|
snd_unregister_device(rmidi->dev);
|
||||||
error:
|
error:
|
||||||
mutex_lock(®ister_mutex);
|
scoped_guard(mutex, ®ister_mutex)
|
||||||
list_del(&rmidi->list);
|
list_del(&rmidi->list);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2113,8 +2048,8 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
|
||||||
struct snd_rawmidi *rmidi = device->device_data;
|
struct snd_rawmidi *rmidi = device->device_data;
|
||||||
int dir;
|
int dir;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
mutex_lock(&rmidi->open_mutex);
|
guard(mutex)(&rmidi->open_mutex);
|
||||||
wake_up(&rmidi->open_wait);
|
wake_up(&rmidi->open_wait);
|
||||||
list_del_init(&rmidi->list);
|
list_del_init(&rmidi->list);
|
||||||
for (dir = 0; dir < 2; dir++) {
|
for (dir = 0; dir < 2; dir++) {
|
||||||
|
@ -2140,8 +2075,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_OSSEMUL */
|
#endif /* CONFIG_SND_OSSEMUL */
|
||||||
snd_unregister_device(rmidi->dev);
|
snd_unregister_device(rmidi->dev);
|
||||||
mutex_unlock(&rmidi->open_mutex);
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,6 @@ config SND_SEQ_UMP
|
||||||
among legacy and UMP clients.
|
among legacy and UMP clients.
|
||||||
|
|
||||||
config SND_SEQ_UMP_CLIENT
|
config SND_SEQ_UMP_CLIENT
|
||||||
tristate
|
|
||||||
def_tristate SND_UMP
|
def_tristate SND_UMP
|
||||||
|
|
||||||
endif # SND_SEQUENCER
|
endif # SND_SEQUENCER
|
||||||
|
|
|
@ -163,6 +163,6 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
|
||||||
|
|
||||||
|
|
||||||
/* misc. functions for proc interface */
|
/* misc. functions for proc interface */
|
||||||
char *enabled_str(int bool);
|
char *enabled_str(bool b);
|
||||||
|
|
||||||
#endif /* __SEQ_OSS_DEVICE_H */
|
#endif /* __SEQ_OSS_DEVICE_H */
|
||||||
|
|
|
@ -63,20 +63,18 @@ int __init
|
||||||
snd_seq_oss_create_client(void)
|
snd_seq_oss_create_client(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct snd_seq_port_info *port;
|
struct snd_seq_port_info *port __free(kfree) = NULL;
|
||||||
struct snd_seq_port_callback port_callback;
|
struct snd_seq_port_callback port_callback;
|
||||||
|
|
||||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||||
if (!port) {
|
if (!port)
|
||||||
rc = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create ALSA client */
|
/* create ALSA client */
|
||||||
rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
|
rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
|
||||||
"OSS sequencer");
|
"OSS sequencer");
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto __error;
|
return rc;
|
||||||
|
|
||||||
system_client = rc;
|
system_client = rc;
|
||||||
|
|
||||||
|
@ -104,14 +102,11 @@ snd_seq_oss_create_client(void)
|
||||||
subs.dest.port = system_port;
|
subs.dest.port = system_port;
|
||||||
call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
|
call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
|
||||||
}
|
}
|
||||||
rc = 0;
|
|
||||||
|
|
||||||
/* look up midi devices */
|
/* look up midi devices */
|
||||||
schedule_work(&async_lookup_work);
|
schedule_work(&async_lookup_work);
|
||||||
|
|
||||||
__error:
|
return 0;
|
||||||
kfree(port);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -455,9 +450,9 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp)
|
||||||
* misc. functions for proc interface
|
* misc. functions for proc interface
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
enabled_str(int bool)
|
enabled_str(bool b)
|
||||||
{
|
{
|
||||||
return bool ? "enabled" : "disabled";
|
return b ? "enabled" : "disabled";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
|
|
@ -64,16 +64,13 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
|
||||||
int
|
int
|
||||||
snd_seq_oss_midi_lookup_ports(int client)
|
snd_seq_oss_midi_lookup_ports(int client)
|
||||||
{
|
{
|
||||||
struct snd_seq_client_info *clinfo;
|
struct snd_seq_client_info *clinfo __free(kfree) = NULL;
|
||||||
struct snd_seq_port_info *pinfo;
|
struct snd_seq_port_info *pinfo __free(kfree) = NULL;
|
||||||
|
|
||||||
clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
|
clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
|
||||||
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
|
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
|
||||||
if (! clinfo || ! pinfo) {
|
if (!clinfo || !pinfo)
|
||||||
kfree(clinfo);
|
|
||||||
kfree(pinfo);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
clinfo->client = -1;
|
clinfo->client = -1;
|
||||||
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
|
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
|
||||||
if (clinfo->client == client)
|
if (clinfo->client == client)
|
||||||
|
@ -83,8 +80,6 @@ snd_seq_oss_midi_lookup_ports(int client)
|
||||||
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
|
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
|
||||||
snd_seq_oss_midi_check_new_port(pinfo);
|
snd_seq_oss_midi_check_new_port(pinfo);
|
||||||
}
|
}
|
||||||
kfree(clinfo);
|
|
||||||
kfree(pinfo);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,8 @@ struct snd_seq_port_info32 {
|
||||||
static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd,
|
static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd,
|
||||||
struct snd_seq_port_info32 __user *data32)
|
struct snd_seq_port_info32 __user *data32)
|
||||||
{
|
{
|
||||||
int err = -EFAULT;
|
struct snd_seq_port_info *data __free(kfree) = NULL;
|
||||||
struct snd_seq_port_info *data;
|
int err;
|
||||||
|
|
||||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
@ -41,20 +41,18 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned
|
||||||
if (copy_from_user(data, data32, sizeof(*data32)) ||
|
if (copy_from_user(data, data32, sizeof(*data32)) ||
|
||||||
get_user(data->flags, &data32->flags) ||
|
get_user(data->flags, &data32->flags) ||
|
||||||
get_user(data->time_queue, &data32->time_queue))
|
get_user(data->time_queue, &data32->time_queue))
|
||||||
goto error;
|
return -EFAULT;
|
||||||
data->kernel = NULL;
|
data->kernel = NULL;
|
||||||
|
|
||||||
err = snd_seq_kernel_client_ctl(client->number, cmd, data);
|
err = snd_seq_kernel_client_ctl(client->number, cmd, data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return err;
|
||||||
|
|
||||||
if (copy_to_user(data32, data, sizeof(*data32)) ||
|
if (copy_to_user(data32, data, sizeof(*data32)) ||
|
||||||
put_user(data->flags, &data32->flags) ||
|
put_user(data->flags, &data32->flags) ||
|
||||||
put_user(data->time_queue, &data32->time_queue))
|
put_user(data->time_queue, &data32->time_queue))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
error:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,12 +88,11 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f)
|
||||||
atomic_set(&f->overflow, 0);
|
atomic_set(&f->overflow, 0);
|
||||||
|
|
||||||
snd_use_lock_sync(&f->use_lock);
|
snd_use_lock_sync(&f->use_lock);
|
||||||
spin_lock_irq(&f->lock);
|
guard(spinlock_irq)(&f->lock);
|
||||||
/* drain the fifo */
|
/* drain the fifo */
|
||||||
while ((cell = fifo_cell_out(f)) != NULL) {
|
while ((cell = fifo_cell_out(f)) != NULL) {
|
||||||
snd_seq_cell_free(cell);
|
snd_seq_cell_free(cell);
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&f->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,7 +101,6 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
|
||||||
struct snd_seq_event *event)
|
struct snd_seq_event *event)
|
||||||
{
|
{
|
||||||
struct snd_seq_event_cell *cell;
|
struct snd_seq_event_cell *cell;
|
||||||
unsigned long flags;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (snd_BUG_ON(!f))
|
if (snd_BUG_ON(!f))
|
||||||
|
@ -118,15 +116,15 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* append new cells to fifo */
|
/* append new cells to fifo */
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
scoped_guard(spinlock_irqsave, &f->lock) {
|
||||||
if (f->tail != NULL)
|
if (f->tail != NULL)
|
||||||
f->tail->next = cell;
|
f->tail->next = cell;
|
||||||
f->tail = cell;
|
f->tail = cell;
|
||||||
if (f->head == NULL)
|
if (f->head == NULL)
|
||||||
f->head = cell;
|
f->head = cell;
|
||||||
cell->next = NULL;
|
cell->next = NULL;
|
||||||
f->cells++;
|
f->cells++;
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
}
|
||||||
|
|
||||||
/* wakeup client */
|
/* wakeup client */
|
||||||
if (waitqueue_active(&f->input_sleep))
|
if (waitqueue_active(&f->input_sleep))
|
||||||
|
@ -199,16 +197,13 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
|
||||||
void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
|
void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
|
||||||
struct snd_seq_event_cell *cell)
|
struct snd_seq_event_cell *cell)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (cell) {
|
if (cell) {
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
guard(spinlock_irqsave)(&f->lock);
|
||||||
cell->next = f->head;
|
cell->next = f->head;
|
||||||
f->head = cell;
|
f->head = cell;
|
||||||
if (!f->tail)
|
if (!f->tail)
|
||||||
f->tail = cell;
|
f->tail = cell;
|
||||||
f->cells++;
|
f->cells++;
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,17 +234,17 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(&f->lock);
|
scoped_guard(spinlock_irq, &f->lock) {
|
||||||
/* remember old pool */
|
/* remember old pool */
|
||||||
oldpool = f->pool;
|
oldpool = f->pool;
|
||||||
oldhead = f->head;
|
oldhead = f->head;
|
||||||
/* exchange pools */
|
/* exchange pools */
|
||||||
f->pool = newpool;
|
f->pool = newpool;
|
||||||
f->head = NULL;
|
f->head = NULL;
|
||||||
f->tail = NULL;
|
f->tail = NULL;
|
||||||
f->cells = 0;
|
f->cells = 0;
|
||||||
/* NOTE: overflow flag is not cleared */
|
/* NOTE: overflow flag is not cleared */
|
||||||
spin_unlock_irq(&f->lock);
|
}
|
||||||
|
|
||||||
/* close the old pool and wait until all users are gone */
|
/* close the old pool and wait until all users are gone */
|
||||||
snd_seq_pool_mark_closing(oldpool);
|
snd_seq_pool_mark_closing(oldpool);
|
||||||
|
@ -268,16 +263,14 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
|
||||||
/* get the number of unused cells safely */
|
/* get the number of unused cells safely */
|
||||||
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
|
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int cells;
|
int cells;
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
snd_use_lock_use(&f->use_lock);
|
snd_use_lock_use(&f->use_lock);
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
scoped_guard(spinlock_irqsave, &f->lock)
|
||||||
cells = snd_seq_unused_cells(f->pool);
|
cells = snd_seq_unused_cells(f->pool);
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
snd_use_lock_free(&f->use_lock);
|
snd_use_lock_free(&f->use_lock);
|
||||||
return cells;
|
return cells;
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,6 @@ static inline void free_cell(struct snd_seq_pool *pool,
|
||||||
|
|
||||||
void snd_seq_cell_free(struct snd_seq_event_cell * cell)
|
void snd_seq_cell_free(struct snd_seq_event_cell * cell)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_seq_pool *pool;
|
struct snd_seq_pool *pool;
|
||||||
|
|
||||||
if (snd_BUG_ON(!cell))
|
if (snd_BUG_ON(!cell))
|
||||||
|
@ -241,7 +240,7 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
|
||||||
if (snd_BUG_ON(!pool))
|
if (snd_BUG_ON(!pool))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock_irqsave(&pool->lock, flags);
|
guard(spinlock_irqsave)(&pool->lock);
|
||||||
free_cell(pool, cell);
|
free_cell(pool, cell);
|
||||||
if (snd_seq_ev_is_variable(&cell->event)) {
|
if (snd_seq_ev_is_variable(&cell->event)) {
|
||||||
if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
|
if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
|
||||||
|
@ -259,7 +258,6 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
|
||||||
if (snd_seq_output_ok(pool))
|
if (snd_seq_output_ok(pool))
|
||||||
wake_up(&pool->output_sleep);
|
wake_up(&pool->output_sleep);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&pool->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,9 +447,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* add new cells to the free cell list */
|
/* add new cells to the free cell list */
|
||||||
spin_lock_irq(&pool->lock);
|
guard(spinlock_irq)(&pool->lock);
|
||||||
if (pool->ptr) {
|
if (pool->ptr) {
|
||||||
spin_unlock_irq(&pool->lock);
|
|
||||||
kvfree(cellptr);
|
kvfree(cellptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -470,20 +467,16 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
|
||||||
/* init statistics */
|
/* init statistics */
|
||||||
pool->max_used = 0;
|
pool->max_used = 0;
|
||||||
pool->total_elements = pool->size;
|
pool->total_elements = pool->size;
|
||||||
spin_unlock_irq(&pool->lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* refuse the further insertion to the pool */
|
/* refuse the further insertion to the pool */
|
||||||
void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
|
void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!pool))
|
if (snd_BUG_ON(!pool))
|
||||||
return;
|
return;
|
||||||
spin_lock_irqsave(&pool->lock, flags);
|
guard(spinlock_irqsave)(&pool->lock);
|
||||||
pool->closing = 1;
|
pool->closing = 1;
|
||||||
spin_unlock_irqrestore(&pool->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove events */
|
/* remove events */
|
||||||
|
@ -502,18 +495,17 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
|
||||||
schedule_timeout_uninterruptible(1);
|
schedule_timeout_uninterruptible(1);
|
||||||
|
|
||||||
/* release all resources */
|
/* release all resources */
|
||||||
spin_lock_irq(&pool->lock);
|
scoped_guard(spinlock_irq, &pool->lock) {
|
||||||
ptr = pool->ptr;
|
ptr = pool->ptr;
|
||||||
pool->ptr = NULL;
|
pool->ptr = NULL;
|
||||||
pool->free = NULL;
|
pool->free = NULL;
|
||||||
pool->total_elements = 0;
|
pool->total_elements = 0;
|
||||||
spin_unlock_irq(&pool->lock);
|
}
|
||||||
|
|
||||||
kvfree(ptr);
|
kvfree(ptr);
|
||||||
|
|
||||||
spin_lock_irq(&pool->lock);
|
guard(spinlock_irq)(&pool->lock);
|
||||||
pool->closing = 0;
|
pool->closing = 0;
|
||||||
spin_unlock_irq(&pool->lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,12 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* callback for snd_seq_dump_var_event(), bridging to dump_midi() */
|
||||||
|
static int __dump_midi(void *ptr, void *buf, int count)
|
||||||
|
{
|
||||||
|
return dump_midi(ptr, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
static int event_process_midi(struct snd_seq_event *ev, int direct,
|
static int event_process_midi(struct snd_seq_event *ev, int direct,
|
||||||
void *private_data, int atomic, int hop)
|
void *private_data, int atomic, int hop)
|
||||||
{
|
{
|
||||||
|
@ -132,7 +138,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
|
||||||
pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
|
pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
|
snd_seq_dump_var_event(ev, __dump_midi, substream);
|
||||||
snd_midi_event_reset_decode(msynth->parser);
|
snd_midi_event_reset_decode(msynth->parser);
|
||||||
} else {
|
} else {
|
||||||
if (msynth->parser == NULL)
|
if (msynth->parser == NULL)
|
||||||
|
@ -264,8 +270,8 @@ snd_seq_midisynth_probe(struct device *_dev)
|
||||||
struct snd_seq_device *dev = to_seq_dev(_dev);
|
struct snd_seq_device *dev = to_seq_dev(_dev);
|
||||||
struct seq_midisynth_client *client;
|
struct seq_midisynth_client *client;
|
||||||
struct seq_midisynth *msynth, *ms;
|
struct seq_midisynth *msynth, *ms;
|
||||||
struct snd_seq_port_info *port;
|
struct snd_seq_port_info *port __free(kfree) = NULL;
|
||||||
struct snd_rawmidi_info *info;
|
struct snd_rawmidi_info *info __free(kfree) = NULL;
|
||||||
struct snd_rawmidi *rmidi = dev->private_data;
|
struct snd_rawmidi *rmidi = dev->private_data;
|
||||||
int newclient = 0;
|
int newclient = 0;
|
||||||
unsigned int p, ports;
|
unsigned int p, ports;
|
||||||
|
@ -291,31 +297,24 @@ snd_seq_midisynth_probe(struct device *_dev)
|
||||||
ports = output_count;
|
ports = output_count;
|
||||||
if (ports < input_count)
|
if (ports < input_count)
|
||||||
ports = input_count;
|
ports = input_count;
|
||||||
if (ports == 0) {
|
if (ports == 0)
|
||||||
kfree(info);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
|
||||||
if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
|
if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
|
||||||
ports = 256 / SNDRV_RAWMIDI_DEVICES;
|
ports = 256 / SNDRV_RAWMIDI_DEVICES;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
client = synths[card->number];
|
client = synths[card->number];
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
newclient = 1;
|
newclient = 1;
|
||||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||||
if (client == NULL) {
|
if (client == NULL)
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
kfree(info);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
client->seq_client =
|
client->seq_client =
|
||||||
snd_seq_create_kernel_client(
|
snd_seq_create_kernel_client(
|
||||||
card, 0, "%s", card->shortname[0] ?
|
card, 0, "%s", card->shortname[0] ?
|
||||||
(const char *)card->shortname : "External MIDI");
|
(const char *)card->shortname : "External MIDI");
|
||||||
if (client->seq_client < 0) {
|
if (client->seq_client < 0) {
|
||||||
kfree(client);
|
kfree(client);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
kfree(info);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,9 +395,6 @@ snd_seq_midisynth_probe(struct device *_dev)
|
||||||
client->num_ports++;
|
client->num_ports++;
|
||||||
if (newclient)
|
if (newclient)
|
||||||
synths[card->number] = client;
|
synths[card->number] = client;
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
kfree(info);
|
|
||||||
kfree(port);
|
|
||||||
return 0; /* success */
|
return 0; /* success */
|
||||||
|
|
||||||
__nomem:
|
__nomem:
|
||||||
|
@ -411,9 +407,6 @@ snd_seq_midisynth_probe(struct device *_dev)
|
||||||
snd_seq_delete_kernel_client(client->seq_client);
|
snd_seq_delete_kernel_client(client->seq_client);
|
||||||
kfree(client);
|
kfree(client);
|
||||||
}
|
}
|
||||||
kfree(info);
|
|
||||||
kfree(port);
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,12 +420,10 @@ snd_seq_midisynth_remove(struct device *_dev)
|
||||||
struct snd_card *card = dev->card;
|
struct snd_card *card = dev->card;
|
||||||
int device = dev->device, p, ports;
|
int device = dev->device, p, ports;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
client = synths[card->number];
|
client = synths[card->number];
|
||||||
if (client == NULL || client->ports[device] == NULL) {
|
if (client == NULL || client->ports[device] == NULL)
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
|
||||||
ports = client->ports_per_device[device];
|
ports = client->ports_per_device[device];
|
||||||
client->ports_per_device[device] = 0;
|
client->ports_per_device[device] = 0;
|
||||||
msynth = client->ports[device];
|
msynth = client->ports[device];
|
||||||
|
@ -446,7 +437,6 @@ snd_seq_midisynth_remove(struct device *_dev)
|
||||||
synths[card->number] = NULL;
|
synths[card->number] = NULL;
|
||||||
kfree(client);
|
kfree(client);
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,21 +144,15 @@ static inline void reset_encode(struct snd_midi_event *dev)
|
||||||
|
|
||||||
void snd_midi_event_reset_encode(struct snd_midi_event *dev)
|
void snd_midi_event_reset_encode(struct snd_midi_event *dev)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&dev->lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
|
||||||
reset_encode(dev);
|
reset_encode(dev);
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_midi_event_reset_encode);
|
EXPORT_SYMBOL(snd_midi_event_reset_encode);
|
||||||
|
|
||||||
void snd_midi_event_reset_decode(struct snd_midi_event *dev)
|
void snd_midi_event_reset_decode(struct snd_midi_event *dev)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&dev->lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
|
||||||
dev->lastcmd = 0xff;
|
dev->lastcmd = 0xff;
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_midi_event_reset_decode);
|
EXPORT_SYMBOL(snd_midi_event_reset_decode);
|
||||||
|
|
||||||
|
@ -177,7 +171,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
|
||||||
struct snd_seq_event *ev)
|
struct snd_seq_event *ev)
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (c >= MIDI_CMD_COMMON_CLOCK) {
|
if (c >= MIDI_CMD_COMMON_CLOCK) {
|
||||||
/* real-time event */
|
/* real-time event */
|
||||||
|
@ -187,7 +180,7 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
|
||||||
return ev->type != SNDRV_SEQ_EVENT_NONE;
|
return ev->type != SNDRV_SEQ_EVENT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
guard(spinlock_irqsave)(&dev->lock);
|
||||||
if ((c & 0x80) &&
|
if ((c & 0x80) &&
|
||||||
(c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
|
(c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
|
||||||
/* new command */
|
/* new command */
|
||||||
|
@ -236,7 +229,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_midi_event_encode_byte);
|
EXPORT_SYMBOL(snd_midi_event_encode_byte);
|
||||||
|
|
|
@ -48,17 +48,15 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
|
||||||
|
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
read_lock(&client->ports_lock);
|
guard(read_lock)(&client->ports_lock);
|
||||||
list_for_each_entry(port, &client->ports_list_head, list) {
|
list_for_each_entry(port, &client->ports_list_head, list) {
|
||||||
if (port->addr.port == num) {
|
if (port->addr.port == num) {
|
||||||
if (port->closing)
|
if (port->closing)
|
||||||
break; /* deleting now */
|
break; /* deleting now */
|
||||||
snd_use_lock_use(&port->use_lock);
|
snd_use_lock_use(&port->use_lock);
|
||||||
read_unlock(&client->ports_lock);
|
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_unlock(&client->ports_lock);
|
|
||||||
return NULL; /* not found */
|
return NULL; /* not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +71,7 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
|
||||||
|
|
||||||
num = pinfo->addr.port;
|
num = pinfo->addr.port;
|
||||||
found = NULL;
|
found = NULL;
|
||||||
read_lock(&client->ports_lock);
|
guard(read_lock)(&client->ports_lock);
|
||||||
list_for_each_entry(port, &client->ports_list_head, list) {
|
list_for_each_entry(port, &client->ports_list_head, list) {
|
||||||
if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
|
if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
|
||||||
!check_inactive)
|
!check_inactive)
|
||||||
|
@ -93,7 +91,6 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
|
||||||
else
|
else
|
||||||
snd_use_lock_use(&found->use_lock);
|
snd_use_lock_use(&found->use_lock);
|
||||||
}
|
}
|
||||||
read_unlock(&client->ports_lock);
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,13 +142,12 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
|
||||||
snd_use_lock_use(&new_port->use_lock);
|
snd_use_lock_use(&new_port->use_lock);
|
||||||
|
|
||||||
num = max(port, 0);
|
num = max(port, 0);
|
||||||
mutex_lock(&client->ports_mutex);
|
guard(mutex)(&client->ports_mutex);
|
||||||
write_lock_irq(&client->ports_lock);
|
guard(write_lock_irq)(&client->ports_lock);
|
||||||
list_for_each_entry(p, &client->ports_list_head, list) {
|
list_for_each_entry(p, &client->ports_list_head, list) {
|
||||||
if (p->addr.port == port) {
|
if (p->addr.port == port) {
|
||||||
kfree(new_port);
|
kfree(new_port);
|
||||||
num = -EBUSY;
|
return -EBUSY;
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
if (p->addr.port > num)
|
if (p->addr.port > num)
|
||||||
break;
|
break;
|
||||||
|
@ -164,9 +160,6 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
|
||||||
new_port->addr.port = num; /* store the port number in the port */
|
new_port->addr.port = num; /* store the port number in the port */
|
||||||
sprintf(new_port->name, "port-%d", num);
|
sprintf(new_port->name, "port-%d", num);
|
||||||
*port_ret = new_port;
|
*port_ret = new_port;
|
||||||
unlock:
|
|
||||||
write_unlock_irq(&client->ports_lock);
|
|
||||||
mutex_unlock(&client->ports_mutex);
|
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
@ -281,19 +274,18 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
|
||||||
{
|
{
|
||||||
struct snd_seq_client_port *found = NULL, *p;
|
struct snd_seq_client_port *found = NULL, *p;
|
||||||
|
|
||||||
mutex_lock(&client->ports_mutex);
|
scoped_guard(mutex, &client->ports_mutex) {
|
||||||
write_lock_irq(&client->ports_lock);
|
guard(write_lock_irq)(&client->ports_lock);
|
||||||
list_for_each_entry(p, &client->ports_list_head, list) {
|
list_for_each_entry(p, &client->ports_list_head, list) {
|
||||||
if (p->addr.port == port) {
|
if (p->addr.port == port) {
|
||||||
/* ok found. delete from the list at first */
|
/* ok found. delete from the list at first */
|
||||||
list_del(&p->list);
|
list_del(&p->list);
|
||||||
client->num_ports--;
|
client->num_ports--;
|
||||||
found = p;
|
found = p;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_unlock_irq(&client->ports_lock);
|
|
||||||
mutex_unlock(&client->ports_mutex);
|
|
||||||
if (found)
|
if (found)
|
||||||
return port_delete(client, found);
|
return port_delete(client, found);
|
||||||
else
|
else
|
||||||
|
@ -309,16 +301,16 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
|
||||||
/* move the port list to deleted_list, and
|
/* move the port list to deleted_list, and
|
||||||
* clear the port list in the client data.
|
* clear the port list in the client data.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&client->ports_mutex);
|
guard(mutex)(&client->ports_mutex);
|
||||||
write_lock_irq(&client->ports_lock);
|
scoped_guard(write_lock_irq, &client->ports_lock) {
|
||||||
if (! list_empty(&client->ports_list_head)) {
|
if (!list_empty(&client->ports_list_head)) {
|
||||||
list_add(&deleted_list, &client->ports_list_head);
|
list_add(&deleted_list, &client->ports_list_head);
|
||||||
list_del_init(&client->ports_list_head);
|
list_del_init(&client->ports_list_head);
|
||||||
} else {
|
} else {
|
||||||
INIT_LIST_HEAD(&deleted_list);
|
INIT_LIST_HEAD(&deleted_list);
|
||||||
|
}
|
||||||
|
client->num_ports = 0;
|
||||||
}
|
}
|
||||||
client->num_ports = 0;
|
|
||||||
write_unlock_irq(&client->ports_lock);
|
|
||||||
|
|
||||||
/* remove each port in deleted_list */
|
/* remove each port in deleted_list */
|
||||||
list_for_each_entry_safe(port, tmp, &deleted_list, list) {
|
list_for_each_entry_safe(port, tmp, &deleted_list, list) {
|
||||||
|
@ -326,7 +318,6 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
|
||||||
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
|
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
|
||||||
port_delete(client, port);
|
port_delete(client, port);
|
||||||
}
|
}
|
||||||
mutex_unlock(&client->ports_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,42 +497,37 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
grp = is_src ? &port->c_src : &port->c_dest;
|
grp = is_src ? &port->c_src : &port->c_dest;
|
||||||
err = -EBUSY;
|
guard(rwsem_write)(&grp->list_mutex);
|
||||||
down_write(&grp->list_mutex);
|
|
||||||
if (exclusive) {
|
if (exclusive) {
|
||||||
if (!list_empty(&grp->list_head))
|
if (!list_empty(&grp->list_head))
|
||||||
goto __error;
|
return -EBUSY;
|
||||||
} else {
|
} else {
|
||||||
if (grp->exclusive)
|
if (grp->exclusive)
|
||||||
goto __error;
|
return -EBUSY;
|
||||||
/* check whether already exists */
|
/* check whether already exists */
|
||||||
list_for_each(p, &grp->list_head) {
|
list_for_each(p, &grp->list_head) {
|
||||||
s = get_subscriber(p, is_src);
|
s = get_subscriber(p, is_src);
|
||||||
if (match_subs_info(&subs->info, &s->info))
|
if (match_subs_info(&subs->info, &s->info))
|
||||||
goto __error;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = subscribe_port(client, port, grp, &subs->info, ack);
|
err = subscribe_port(client, port, grp, &subs->info, ack);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
grp->exclusive = 0;
|
grp->exclusive = 0;
|
||||||
goto __error;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add to list */
|
/* add to list */
|
||||||
write_lock_irq(&grp->list_lock);
|
guard(write_lock_irq)(&grp->list_lock);
|
||||||
if (is_src)
|
if (is_src)
|
||||||
list_add_tail(&subs->src_list, &grp->list_head);
|
list_add_tail(&subs->src_list, &grp->list_head);
|
||||||
else
|
else
|
||||||
list_add_tail(&subs->dest_list, &grp->list_head);
|
list_add_tail(&subs->dest_list, &grp->list_head);
|
||||||
grp->exclusive = exclusive;
|
grp->exclusive = exclusive;
|
||||||
atomic_inc(&subs->ref_count);
|
atomic_inc(&subs->ref_count);
|
||||||
write_unlock_irq(&grp->list_lock);
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
__error:
|
return 0;
|
||||||
up_write(&grp->list_mutex);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called with grp->list_mutex held */
|
/* called with grp->list_mutex held */
|
||||||
|
@ -556,12 +542,12 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
|
||||||
|
|
||||||
grp = is_src ? &port->c_src : &port->c_dest;
|
grp = is_src ? &port->c_src : &port->c_dest;
|
||||||
list = is_src ? &subs->src_list : &subs->dest_list;
|
list = is_src ? &subs->src_list : &subs->dest_list;
|
||||||
write_lock_irq(&grp->list_lock);
|
scoped_guard(write_lock_irq, &grp->list_lock) {
|
||||||
empty = list_empty(list);
|
empty = list_empty(list);
|
||||||
if (!empty)
|
if (!empty)
|
||||||
list_del_init(list);
|
list_del_init(list);
|
||||||
grp->exclusive = 0;
|
grp->exclusive = 0;
|
||||||
write_unlock_irq(&grp->list_lock);
|
}
|
||||||
|
|
||||||
if (!empty)
|
if (!empty)
|
||||||
unsubscribe_port(client, port, grp, &subs->info, ack);
|
unsubscribe_port(client, port, grp, &subs->info, ack);
|
||||||
|
@ -575,9 +561,8 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
|
||||||
struct snd_seq_port_subs_info *grp;
|
struct snd_seq_port_subs_info *grp;
|
||||||
|
|
||||||
grp = is_src ? &port->c_src : &port->c_dest;
|
grp = is_src ? &port->c_src : &port->c_dest;
|
||||||
down_write(&grp->list_mutex);
|
guard(rwsem_write)(&grp->list_mutex);
|
||||||
__delete_and_unsubscribe_port(client, port, subs, is_src, ack);
|
__delete_and_unsubscribe_port(client, port, subs, is_src, ack);
|
||||||
up_write(&grp->list_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* connect two ports */
|
/* connect two ports */
|
||||||
|
@ -639,18 +624,18 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
|
||||||
/* always start from deleting the dest port for avoiding concurrent
|
/* always start from deleting the dest port for avoiding concurrent
|
||||||
* deletions
|
* deletions
|
||||||
*/
|
*/
|
||||||
down_write(&dest->list_mutex);
|
scoped_guard(rwsem_write, &dest->list_mutex) {
|
||||||
/* look for the connection */
|
/* look for the connection */
|
||||||
list_for_each_entry(subs, &dest->list_head, dest_list) {
|
list_for_each_entry(subs, &dest->list_head, dest_list) {
|
||||||
if (match_subs_info(info, &subs->info)) {
|
if (match_subs_info(info, &subs->info)) {
|
||||||
__delete_and_unsubscribe_port(dest_client, dest_port,
|
__delete_and_unsubscribe_port(dest_client, dest_port,
|
||||||
subs, false,
|
subs, false,
|
||||||
connector->number != dest_client->number);
|
connector->number != dest_client->number);
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
up_write(&dest->list_mutex);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -669,7 +654,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
|
||||||
struct snd_seq_subscribers *s;
|
struct snd_seq_subscribers *s;
|
||||||
int err = -ENOENT;
|
int err = -ENOENT;
|
||||||
|
|
||||||
down_read(&src_grp->list_mutex);
|
guard(rwsem_read)(&src_grp->list_mutex);
|
||||||
list_for_each_entry(s, &src_grp->list_head, src_list) {
|
list_for_each_entry(s, &src_grp->list_head, src_list) {
|
||||||
if (addr_match(dest_addr, &s->info.dest)) {
|
if (addr_match(dest_addr, &s->info.dest)) {
|
||||||
*subs = s->info;
|
*subs = s->info;
|
||||||
|
@ -677,7 +662,6 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
up_read(&src_grp->list_mutex);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||||
struct snd_seq_event_cell * cell)
|
struct snd_seq_event_cell * cell)
|
||||||
{
|
{
|
||||||
struct snd_seq_event_cell *cur, *prev;
|
struct snd_seq_event_cell *cur, *prev;
|
||||||
unsigned long flags;
|
|
||||||
int count;
|
int count;
|
||||||
int prior;
|
int prior;
|
||||||
|
|
||||||
|
@ -142,7 +141,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||||
/* check flags */
|
/* check flags */
|
||||||
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
|
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
|
||||||
|
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
guard(spinlock_irqsave)(&f->lock);
|
||||||
|
|
||||||
/* check if this element needs to inserted at the end (ie. ordered
|
/* check if this element needs to inserted at the end (ie. ordered
|
||||||
data is inserted) This will be very likeley if a sequencer
|
data is inserted) This will be very likeley if a sequencer
|
||||||
|
@ -154,7 +153,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||||
f->tail = cell;
|
f->tail = cell;
|
||||||
cell->next = NULL;
|
cell->next = NULL;
|
||||||
f->cells++;
|
f->cells++;
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +177,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||||
prev = cur;
|
prev = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
if (! --count) {
|
if (! --count) {
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
|
pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +192,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||||
if (cur == NULL) /* reached end of the list */
|
if (cur == NULL) /* reached end of the list */
|
||||||
f->tail = cell;
|
f->tail = cell;
|
||||||
f->cells++;
|
f->cells++;
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,14 +209,13 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
|
||||||
void *current_time)
|
void *current_time)
|
||||||
{
|
{
|
||||||
struct snd_seq_event_cell *cell;
|
struct snd_seq_event_cell *cell;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
|
pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
|
||||||
|
|
||||||
|
guard(spinlock_irqsave)(&f->lock);
|
||||||
cell = f->head;
|
cell = f->head;
|
||||||
if (cell && current_time && !event_is_ready(&cell->event, current_time))
|
if (cell && current_time && !event_is_ready(&cell->event, current_time))
|
||||||
cell = NULL;
|
cell = NULL;
|
||||||
|
@ -235,7 +230,6 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
|
||||||
f->cells--;
|
f->cells--;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,73 +243,43 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
|
||||||
return f->cells;
|
return f->cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int prioq_match(struct snd_seq_event_cell *cell,
|
/* remove cells matching with the condition */
|
||||||
int client, int timestamp)
|
static void prioq_remove_cells(struct snd_seq_prioq *f,
|
||||||
{
|
bool (*match)(struct snd_seq_event_cell *cell,
|
||||||
if (cell->event.source.client == client ||
|
void *arg),
|
||||||
cell->event.dest.client == client)
|
void *arg)
|
||||||
return 1;
|
|
||||||
if (!timestamp)
|
|
||||||
return 0;
|
|
||||||
switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
|
|
||||||
case SNDRV_SEQ_TIME_STAMP_TICK:
|
|
||||||
if (cell->event.time.tick)
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
case SNDRV_SEQ_TIME_STAMP_REAL:
|
|
||||||
if (cell->event.time.time.tv_sec ||
|
|
||||||
cell->event.time.time.tv_nsec)
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove cells for left client */
|
|
||||||
void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
|
|
||||||
{
|
{
|
||||||
register struct snd_seq_event_cell *cell, *next;
|
register struct snd_seq_event_cell *cell, *next;
|
||||||
unsigned long flags;
|
|
||||||
struct snd_seq_event_cell *prev = NULL;
|
struct snd_seq_event_cell *prev = NULL;
|
||||||
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
|
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
|
||||||
|
|
||||||
/* collect all removed cells */
|
/* collect all removed cells */
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
scoped_guard(spinlock_irqsave, &f->lock) {
|
||||||
cell = f->head;
|
for (cell = f->head; cell; cell = next) {
|
||||||
while (cell) {
|
next = cell->next;
|
||||||
next = cell->next;
|
if (!match(cell, arg)) {
|
||||||
if (prioq_match(cell, client, timestamp)) {
|
prev = cell;
|
||||||
/* remove cell from prioq */
|
continue;
|
||||||
if (cell == f->head) {
|
|
||||||
f->head = cell->next;
|
|
||||||
} else {
|
|
||||||
prev->next = cell->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove cell from prioq */
|
||||||
|
if (cell == f->head)
|
||||||
|
f->head = cell->next;
|
||||||
|
else
|
||||||
|
prev->next = cell->next;
|
||||||
if (cell == f->tail)
|
if (cell == f->tail)
|
||||||
f->tail = cell->next;
|
f->tail = cell->next;
|
||||||
f->cells--;
|
f->cells--;
|
||||||
|
|
||||||
/* add cell to free list */
|
/* add cell to free list */
|
||||||
cell->next = NULL;
|
cell->next = NULL;
|
||||||
if (freefirst == NULL) {
|
if (freefirst == NULL)
|
||||||
freefirst = cell;
|
freefirst = cell;
|
||||||
} else {
|
else
|
||||||
freeprev->next = cell;
|
freeprev->next = cell;
|
||||||
}
|
|
||||||
freeprev = cell;
|
freeprev = cell;
|
||||||
} else {
|
|
||||||
#if 0
|
|
||||||
pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
|
|
||||||
"client = %i\n",
|
|
||||||
cell->event.type,
|
|
||||||
cell->event.source.client,
|
|
||||||
cell->event.dest.client,
|
|
||||||
client);
|
|
||||||
#endif
|
|
||||||
prev = cell;
|
|
||||||
}
|
}
|
||||||
cell = next;
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
|
|
||||||
/* remove selected cells */
|
/* remove selected cells */
|
||||||
while (freefirst) {
|
while (freefirst) {
|
||||||
|
@ -325,22 +289,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prioq_remove_match(struct snd_seq_remove_events *info,
|
struct prioq_match_arg {
|
||||||
struct snd_seq_event *ev)
|
int client;
|
||||||
|
int timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool prioq_match(struct snd_seq_event_cell *cell, void *arg)
|
||||||
{
|
{
|
||||||
|
struct prioq_match_arg *v = arg;
|
||||||
|
|
||||||
|
if (cell->event.source.client == v->client ||
|
||||||
|
cell->event.dest.client == v->client)
|
||||||
|
return true;
|
||||||
|
if (!v->timestamp)
|
||||||
|
return false;
|
||||||
|
switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
|
||||||
|
case SNDRV_SEQ_TIME_STAMP_TICK:
|
||||||
|
if (cell->event.time.tick)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SNDRV_SEQ_TIME_STAMP_REAL:
|
||||||
|
if (cell->event.time.time.tv_sec ||
|
||||||
|
cell->event.time.time.tv_nsec)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove cells for left client */
|
||||||
|
void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp)
|
||||||
|
{
|
||||||
|
struct prioq_match_arg arg = { client, timestamp };
|
||||||
|
|
||||||
|
return prioq_remove_cells(f, prioq_match, &arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct prioq_remove_match_arg {
|
||||||
|
int client;
|
||||||
|
struct snd_seq_remove_events *info;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool prioq_remove_match(struct snd_seq_event_cell *cell, void *arg)
|
||||||
|
{
|
||||||
|
struct prioq_remove_match_arg *v = arg;
|
||||||
|
struct snd_seq_event *ev = &cell->event;
|
||||||
|
struct snd_seq_remove_events *info = v->info;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
if (ev->source.client != v->client)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
|
||||||
if (ev->dest.client != info->dest.client ||
|
if (ev->dest.client != info->dest.client ||
|
||||||
ev->dest.port != info->dest.port)
|
ev->dest.port != info->dest.port)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
|
||||||
if (! snd_seq_ev_is_channel_type(ev))
|
if (! snd_seq_ev_is_channel_type(ev))
|
||||||
return 0;
|
return false;
|
||||||
/* data.note.channel and data.control.channel are identical */
|
/* data.note.channel and data.control.channel are identical */
|
||||||
if (ev->data.note.channel != info->channel)
|
if (ev->data.note.channel != info->channel)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
|
||||||
|
@ -348,7 +358,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
|
||||||
else
|
else
|
||||||
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
|
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
|
||||||
if (!res)
|
if (!res)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
|
||||||
|
@ -356,81 +366,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
|
||||||
else
|
else
|
||||||
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
|
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
|
||||||
if (res)
|
if (res)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
|
||||||
if (ev->type != info->type)
|
if (ev->type != info->type)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
|
||||||
/* Do not remove off events */
|
/* Do not remove off events */
|
||||||
switch (ev->type) {
|
switch (ev->type) {
|
||||||
case SNDRV_SEQ_EVENT_NOTEOFF:
|
case SNDRV_SEQ_EVENT_NOTEOFF:
|
||||||
/* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
|
/* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
|
||||||
return 0;
|
return false;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
|
if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
|
||||||
if (info->tag != ev->tag)
|
if (info->tag != ev->tag)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove cells matching remove criteria */
|
/* remove cells matching remove criteria */
|
||||||
void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
|
void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
|
||||||
struct snd_seq_remove_events *info)
|
struct snd_seq_remove_events *info)
|
||||||
{
|
{
|
||||||
struct snd_seq_event_cell *cell, *next;
|
struct prioq_remove_match_arg arg = { client, info };
|
||||||
unsigned long flags;
|
|
||||||
struct snd_seq_event_cell *prev = NULL;
|
|
||||||
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
|
|
||||||
|
|
||||||
/* collect all removed cells */
|
return prioq_remove_cells(f, prioq_remove_match, &arg);
|
||||||
spin_lock_irqsave(&f->lock, flags);
|
|
||||||
cell = f->head;
|
|
||||||
|
|
||||||
while (cell) {
|
|
||||||
next = cell->next;
|
|
||||||
if (cell->event.source.client == client &&
|
|
||||||
prioq_remove_match(info, &cell->event)) {
|
|
||||||
|
|
||||||
/* remove cell from prioq */
|
|
||||||
if (cell == f->head) {
|
|
||||||
f->head = cell->next;
|
|
||||||
} else {
|
|
||||||
prev->next = cell->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell == f->tail)
|
|
||||||
f->tail = cell->next;
|
|
||||||
f->cells--;
|
|
||||||
|
|
||||||
/* add cell to free list */
|
|
||||||
cell->next = NULL;
|
|
||||||
if (freefirst == NULL) {
|
|
||||||
freefirst = cell;
|
|
||||||
} else {
|
|
||||||
freeprev->next = cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
freeprev = cell;
|
|
||||||
} else {
|
|
||||||
prev = cell;
|
|
||||||
}
|
|
||||||
cell = next;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&f->lock, flags);
|
|
||||||
|
|
||||||
/* remove selected cells */
|
|
||||||
while (freefirst) {
|
|
||||||
freenext = freefirst->next;
|
|
||||||
snd_seq_cell_free(freefirst);
|
|
||||||
freefirst = freenext;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,43 +50,35 @@ int snd_seq_queue_get_cur_queues(void)
|
||||||
static int queue_list_add(struct snd_seq_queue *q)
|
static int queue_list_add(struct snd_seq_queue *q)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&queue_list_lock, flags);
|
guard(spinlock_irqsave)(&queue_list_lock);
|
||||||
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
|
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
|
||||||
if (! queue_list[i]) {
|
if (! queue_list[i]) {
|
||||||
queue_list[i] = q;
|
queue_list[i] = q;
|
||||||
q->queue = i;
|
q->queue = i;
|
||||||
num_queues++;
|
num_queues++;
|
||||||
spin_unlock_irqrestore(&queue_list_lock, flags);
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&queue_list_lock, flags);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_seq_queue *queue_list_remove(int id, int client)
|
static struct snd_seq_queue *queue_list_remove(int id, int client)
|
||||||
{
|
{
|
||||||
struct snd_seq_queue *q;
|
struct snd_seq_queue *q;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&queue_list_lock, flags);
|
guard(spinlock_irqsave)(&queue_list_lock);
|
||||||
q = queue_list[id];
|
q = queue_list[id];
|
||||||
if (q) {
|
if (q) {
|
||||||
spin_lock(&q->owner_lock);
|
guard(spinlock)(&q->owner_lock);
|
||||||
if (q->owner == client) {
|
if (q->owner == client) {
|
||||||
/* found */
|
/* found */
|
||||||
q->klocked = 1;
|
q->klocked = 1;
|
||||||
spin_unlock(&q->owner_lock);
|
|
||||||
queue_list[id] = NULL;
|
queue_list[id] = NULL;
|
||||||
num_queues--;
|
num_queues--;
|
||||||
spin_unlock_irqrestore(&queue_list_lock, flags);
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
spin_unlock(&q->owner_lock);
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&queue_list_lock, flags);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,15 +195,13 @@ int snd_seq_queue_delete(int client, int queueid)
|
||||||
struct snd_seq_queue *queueptr(int queueid)
|
struct snd_seq_queue *queueptr(int queueid)
|
||||||
{
|
{
|
||||||
struct snd_seq_queue *q;
|
struct snd_seq_queue *q;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
|
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
|
||||||
return NULL;
|
return NULL;
|
||||||
spin_lock_irqsave(&queue_list_lock, flags);
|
guard(spinlock_irqsave)(&queue_list_lock);
|
||||||
q = queue_list[queueid];
|
q = queue_list[queueid];
|
||||||
if (q)
|
if (q)
|
||||||
snd_use_lock_use(&q->use_lock);
|
snd_use_lock_use(&q->use_lock);
|
||||||
spin_unlock_irqrestore(&queue_list_lock, flags);
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +229,6 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
|
||||||
|
|
||||||
void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_seq_event_cell *cell;
|
struct snd_seq_event_cell *cell;
|
||||||
snd_seq_tick_time_t cur_tick;
|
snd_seq_tick_time_t cur_tick;
|
||||||
snd_seq_real_time_t cur_time;
|
snd_seq_real_time_t cur_time;
|
||||||
|
@ -249,14 +238,13 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* make this function non-reentrant */
|
/* make this function non-reentrant */
|
||||||
spin_lock_irqsave(&q->check_lock, flags);
|
scoped_guard(spinlock_irqsave, &q->check_lock) {
|
||||||
if (q->check_blocked) {
|
if (q->check_blocked) {
|
||||||
q->check_again = 1;
|
q->check_again = 1;
|
||||||
spin_unlock_irqrestore(&q->check_lock, flags);
|
return; /* other thread is already checking queues */
|
||||||
return; /* other thread is already checking queues */
|
}
|
||||||
|
q->check_blocked = 1;
|
||||||
}
|
}
|
||||||
q->check_blocked = 1;
|
|
||||||
spin_unlock_irqrestore(&q->check_lock, flags);
|
|
||||||
|
|
||||||
__again:
|
__again:
|
||||||
/* Process tick queue... */
|
/* Process tick queue... */
|
||||||
|
@ -283,16 +271,14 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* free lock */
|
/* free lock */
|
||||||
spin_lock_irqsave(&q->check_lock, flags);
|
scoped_guard(spinlock_irqsave, &q->check_lock) {
|
||||||
if (q->check_again) {
|
if (q->check_again) {
|
||||||
q->check_again = 0;
|
q->check_again = 0;
|
||||||
if (processed < MAX_CELL_PROCESSES_IN_QUEUE) {
|
if (processed < MAX_CELL_PROCESSES_IN_QUEUE)
|
||||||
spin_unlock_irqrestore(&q->check_lock, flags);
|
goto __again;
|
||||||
goto __again;
|
|
||||||
}
|
}
|
||||||
|
q->check_blocked = 0;
|
||||||
}
|
}
|
||||||
q->check_blocked = 0;
|
|
||||||
spin_unlock_irqrestore(&q->check_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -361,25 +347,20 @@ static inline int check_access(struct snd_seq_queue *q, int client)
|
||||||
*/
|
*/
|
||||||
static int queue_access_lock(struct snd_seq_queue *q, int client)
|
static int queue_access_lock(struct snd_seq_queue *q, int client)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int access_ok;
|
int access_ok;
|
||||||
|
|
||||||
spin_lock_irqsave(&q->owner_lock, flags);
|
guard(spinlock_irqsave)(&q->owner_lock);
|
||||||
access_ok = check_access(q, client);
|
access_ok = check_access(q, client);
|
||||||
if (access_ok)
|
if (access_ok)
|
||||||
q->klocked = 1;
|
q->klocked = 1;
|
||||||
spin_unlock_irqrestore(&q->owner_lock, flags);
|
|
||||||
return access_ok;
|
return access_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unlock the queue */
|
/* unlock the queue */
|
||||||
static inline void queue_access_unlock(struct snd_seq_queue *q)
|
static inline void queue_access_unlock(struct snd_seq_queue *q)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&q->owner_lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&q->owner_lock, flags);
|
|
||||||
q->klocked = 0;
|
q->klocked = 0;
|
||||||
spin_unlock_irqrestore(&q->owner_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exported - only checking permission */
|
/* exported - only checking permission */
|
||||||
|
@ -387,13 +368,11 @@ int snd_seq_queue_check_access(int queueid, int client)
|
||||||
{
|
{
|
||||||
struct snd_seq_queue *q = queueptr(queueid);
|
struct snd_seq_queue *q = queueptr(queueid);
|
||||||
int access_ok;
|
int access_ok;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (! q)
|
if (! q)
|
||||||
return 0;
|
return 0;
|
||||||
spin_lock_irqsave(&q->owner_lock, flags);
|
scoped_guard(spinlock_irqsave, &q->owner_lock)
|
||||||
access_ok = check_access(q, client);
|
access_ok = check_access(q, client);
|
||||||
spin_unlock_irqrestore(&q->owner_lock, flags);
|
|
||||||
queuefree(q);
|
queuefree(q);
|
||||||
return access_ok;
|
return access_ok;
|
||||||
}
|
}
|
||||||
|
@ -406,7 +385,6 @@ int snd_seq_queue_check_access(int queueid, int client)
|
||||||
int snd_seq_queue_set_owner(int queueid, int client, int locked)
|
int snd_seq_queue_set_owner(int queueid, int client, int locked)
|
||||||
{
|
{
|
||||||
struct snd_seq_queue *q = queueptr(queueid);
|
struct snd_seq_queue *q = queueptr(queueid);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (q == NULL)
|
if (q == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -416,10 +394,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&q->owner_lock, flags);
|
scoped_guard(spinlock_irqsave, &q->owner_lock) {
|
||||||
q->locked = locked ? 1 : 0;
|
q->locked = locked ? 1 : 0;
|
||||||
q->owner = client;
|
q->owner = client;
|
||||||
spin_unlock_irqrestore(&q->owner_lock, flags);
|
}
|
||||||
queue_access_unlock(q);
|
queue_access_unlock(q);
|
||||||
queuefree(q);
|
queuefree(q);
|
||||||
|
|
||||||
|
@ -750,10 +728,10 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
|
||||||
else
|
else
|
||||||
bpm = 0;
|
bpm = 0;
|
||||||
|
|
||||||
spin_lock_irq(&q->owner_lock);
|
scoped_guard(spinlock_irq, &q->owner_lock) {
|
||||||
locked = q->locked;
|
locked = q->locked;
|
||||||
owner = q->owner;
|
owner = q->owner;
|
||||||
spin_unlock_irq(&q->owner_lock);
|
}
|
||||||
|
|
||||||
snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
|
snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
|
||||||
snd_iprintf(buffer, "owned by client : %d\n", owner);
|
snd_iprintf(buffer, "owned by client : %d\n", owner);
|
||||||
|
|
|
@ -75,9 +75,7 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
|
||||||
|
|
||||||
void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
|
void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
/* setup defaults */
|
/* setup defaults */
|
||||||
tmr->ppq = 96; /* 96 PPQ */
|
tmr->ppq = 96; /* 96 PPQ */
|
||||||
tmr->tempo = 500000; /* 120 BPM */
|
tmr->tempo = 500000; /* 120 BPM */
|
||||||
|
@ -93,7 +91,6 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
|
||||||
tmr->preferred_resolution = seq_default_timer_resolution;
|
tmr->preferred_resolution = seq_default_timer_resolution;
|
||||||
|
|
||||||
tmr->skew = tmr->skew_base = SKEW_BASE;
|
tmr->skew = tmr->skew_base = SKEW_BASE;
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void seq_timer_reset(struct snd_seq_timer *tmr)
|
static void seq_timer_reset(struct snd_seq_timer *tmr)
|
||||||
|
@ -108,11 +105,8 @@ static void seq_timer_reset(struct snd_seq_timer *tmr)
|
||||||
|
|
||||||
void snd_seq_timer_reset(struct snd_seq_timer *tmr)
|
void snd_seq_timer_reset(struct snd_seq_timer *tmr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
seq_timer_reset(tmr);
|
seq_timer_reset(tmr);
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,7 +115,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
|
||||||
unsigned long resolution,
|
unsigned long resolution,
|
||||||
unsigned long ticks)
|
unsigned long ticks)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct snd_seq_queue *q = timeri->callback_data;
|
struct snd_seq_queue *q = timeri->callback_data;
|
||||||
struct snd_seq_timer *tmr;
|
struct snd_seq_timer *tmr;
|
||||||
|
|
||||||
|
@ -130,30 +123,28 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
|
||||||
tmr = q->timer;
|
tmr = q->timer;
|
||||||
if (tmr == NULL)
|
if (tmr == NULL)
|
||||||
return;
|
return;
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
if (!tmr->running) {
|
scoped_guard(spinlock_irqsave, &tmr->lock) {
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
if (!tmr->running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
resolution *= ticks;
|
||||||
|
if (tmr->skew != tmr->skew_base) {
|
||||||
|
/* FIXME: assuming skew_base = 0x10000 */
|
||||||
|
resolution = (resolution >> 16) * tmr->skew +
|
||||||
|
(((resolution & 0xffff) * tmr->skew) >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update timer */
|
||||||
|
snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
|
||||||
|
|
||||||
|
/* calculate current tick */
|
||||||
|
snd_seq_timer_update_tick(&tmr->tick, resolution);
|
||||||
|
|
||||||
|
/* register actual time of this timer update */
|
||||||
|
ktime_get_ts64(&tmr->last_update);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolution *= ticks;
|
|
||||||
if (tmr->skew != tmr->skew_base) {
|
|
||||||
/* FIXME: assuming skew_base = 0x10000 */
|
|
||||||
resolution = (resolution >> 16) * tmr->skew +
|
|
||||||
(((resolution & 0xffff) * tmr->skew) >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update timer */
|
|
||||||
snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
|
|
||||||
|
|
||||||
/* calculate current tick */
|
|
||||||
snd_seq_timer_update_tick(&tmr->tick, resolution);
|
|
||||||
|
|
||||||
/* register actual time of this timer update */
|
|
||||||
ktime_get_ts64(&tmr->last_update);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
|
|
||||||
/* check queues and dispatch events */
|
/* check queues and dispatch events */
|
||||||
snd_seq_check_queue(q, 1, 0);
|
snd_seq_check_queue(q, 1, 0);
|
||||||
}
|
}
|
||||||
|
@ -161,18 +152,15 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
|
||||||
/* set current tempo */
|
/* set current tempo */
|
||||||
int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
|
int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!tmr))
|
if (snd_BUG_ON(!tmr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (tempo <= 0)
|
if (tempo <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
if ((unsigned int)tempo != tmr->tempo) {
|
if ((unsigned int)tempo != tmr->tempo) {
|
||||||
tmr->tempo = tempo;
|
tmr->tempo = tempo;
|
||||||
snd_seq_timer_set_tick_resolution(tmr);
|
snd_seq_timer_set_tick_resolution(tmr);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,17 +168,15 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
|
||||||
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
|
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
|
||||||
{
|
{
|
||||||
int changed;
|
int changed;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!tmr))
|
if (snd_BUG_ON(!tmr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (tempo <= 0 || ppq <= 0)
|
if (tempo <= 0 || ppq <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
if (tmr->running && (ppq != tmr->ppq)) {
|
if (tmr->running && (ppq != tmr->ppq)) {
|
||||||
/* refuse to change ppq on running timers */
|
/* refuse to change ppq on running timers */
|
||||||
/* because it will upset the song position (ticks) */
|
/* because it will upset the song position (ticks) */
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
|
pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +185,6 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
|
||||||
tmr->ppq = ppq;
|
tmr->ppq = ppq;
|
||||||
if (changed)
|
if (changed)
|
||||||
snd_seq_timer_set_tick_resolution(tmr);
|
snd_seq_timer_set_tick_resolution(tmr);
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,15 +192,12 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
|
||||||
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
|
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
|
||||||
snd_seq_tick_time_t position)
|
snd_seq_tick_time_t position)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!tmr))
|
if (snd_BUG_ON(!tmr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
tmr->tick.cur_tick = position;
|
tmr->tick.cur_tick = position;
|
||||||
tmr->tick.fraction = 0;
|
tmr->tick.fraction = 0;
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,15 +205,12 @@ int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
|
||||||
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
|
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
|
||||||
snd_seq_real_time_t position)
|
snd_seq_real_time_t position)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!tmr))
|
if (snd_BUG_ON(!tmr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
snd_seq_sanity_real_time(&position);
|
snd_seq_sanity_real_time(&position);
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
tmr->cur_time = position;
|
tmr->cur_time = position;
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,8 +218,6 @@ int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
|
||||||
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
|
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
|
||||||
unsigned int base)
|
unsigned int base)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (snd_BUG_ON(!tmr))
|
if (snd_BUG_ON(!tmr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -249,9 +226,8 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
|
||||||
pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
|
pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
tmr->skew = skew;
|
tmr->skew = skew;
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,12 +272,12 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
|
||||||
snd_timer_instance_free(t);
|
snd_timer_instance_free(t);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
spin_lock_irq(&tmr->lock);
|
scoped_guard(spinlock_irq, &tmr->lock) {
|
||||||
if (tmr->timeri)
|
if (tmr->timeri)
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
else
|
else
|
||||||
tmr->timeri = t;
|
tmr->timeri = t;
|
||||||
spin_unlock_irq(&tmr->lock);
|
}
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_timer_close(t);
|
snd_timer_close(t);
|
||||||
snd_timer_instance_free(t);
|
snd_timer_instance_free(t);
|
||||||
|
@ -318,10 +294,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
|
||||||
tmr = q->timer;
|
tmr = q->timer;
|
||||||
if (snd_BUG_ON(!tmr))
|
if (snd_BUG_ON(!tmr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
spin_lock_irq(&tmr->lock);
|
scoped_guard(spinlock_irq, &tmr->lock) {
|
||||||
t = tmr->timeri;
|
t = tmr->timeri;
|
||||||
tmr->timeri = NULL;
|
tmr->timeri = NULL;
|
||||||
spin_unlock_irq(&tmr->lock);
|
}
|
||||||
if (t) {
|
if (t) {
|
||||||
snd_timer_close(t);
|
snd_timer_close(t);
|
||||||
snd_timer_instance_free(t);
|
snd_timer_instance_free(t);
|
||||||
|
@ -342,13 +318,8 @@ static int seq_timer_stop(struct snd_seq_timer *tmr)
|
||||||
|
|
||||||
int snd_seq_timer_stop(struct snd_seq_timer *tmr)
|
int snd_seq_timer_stop(struct snd_seq_timer *tmr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
int err;
|
return seq_timer_stop(tmr);
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
err = seq_timer_stop(tmr);
|
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int initialize_timer(struct snd_seq_timer *tmr)
|
static int initialize_timer(struct snd_seq_timer *tmr)
|
||||||
|
@ -398,13 +369,8 @@ static int seq_timer_start(struct snd_seq_timer *tmr)
|
||||||
|
|
||||||
int snd_seq_timer_start(struct snd_seq_timer *tmr)
|
int snd_seq_timer_start(struct snd_seq_timer *tmr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
int err;
|
return seq_timer_start(tmr);
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
err = seq_timer_start(tmr);
|
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int seq_timer_continue(struct snd_seq_timer *tmr)
|
static int seq_timer_continue(struct snd_seq_timer *tmr)
|
||||||
|
@ -426,13 +392,8 @@ static int seq_timer_continue(struct snd_seq_timer *tmr)
|
||||||
|
|
||||||
int snd_seq_timer_continue(struct snd_seq_timer *tmr)
|
int snd_seq_timer_continue(struct snd_seq_timer *tmr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
int err;
|
return seq_timer_continue(tmr);
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
err = seq_timer_continue(tmr);
|
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return current 'real' time. use timeofday() to get better granularity. */
|
/* return current 'real' time. use timeofday() to get better granularity. */
|
||||||
|
@ -440,9 +401,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
|
||||||
bool adjust_ktime)
|
bool adjust_ktime)
|
||||||
{
|
{
|
||||||
snd_seq_real_time_t cur_time;
|
snd_seq_real_time_t cur_time;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
cur_time = tmr->cur_time;
|
cur_time = tmr->cur_time;
|
||||||
if (adjust_ktime && tmr->running) {
|
if (adjust_ktime && tmr->running) {
|
||||||
struct timespec64 tm;
|
struct timespec64 tm;
|
||||||
|
@ -453,7 +413,6 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
|
||||||
cur_time.tv_sec += tm.tv_sec;
|
cur_time.tv_sec += tm.tv_sec;
|
||||||
snd_seq_sanity_real_time(&cur_time);
|
snd_seq_sanity_real_time(&cur_time);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return cur_time;
|
return cur_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,13 +420,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
|
||||||
high PPQ values) */
|
high PPQ values) */
|
||||||
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
|
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
|
||||||
{
|
{
|
||||||
snd_seq_tick_time_t cur_tick;
|
guard(spinlock_irqsave)(&tmr->lock);
|
||||||
unsigned long flags;
|
return tmr->tick.cur_tick;
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
|
||||||
cur_tick = tmr->tick.cur_tick;
|
|
||||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
|
||||||
return cur_tick;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -486,19 +440,18 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
|
||||||
q = queueptr(idx);
|
q = queueptr(idx);
|
||||||
if (q == NULL)
|
if (q == NULL)
|
||||||
continue;
|
continue;
|
||||||
mutex_lock(&q->timer_mutex);
|
scoped_guard(mutex, &q->timer_mutex) {
|
||||||
tmr = q->timer;
|
tmr = q->timer;
|
||||||
if (!tmr)
|
if (!tmr)
|
||||||
goto unlock;
|
break;
|
||||||
ti = tmr->timeri;
|
ti = tmr->timeri;
|
||||||
if (!ti)
|
if (!ti)
|
||||||
goto unlock;
|
break;
|
||||||
snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
|
snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
|
||||||
resolution = snd_timer_resolution(ti) * tmr->ticks;
|
resolution = snd_timer_resolution(ti) * tmr->ticks;
|
||||||
snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
|
snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
|
||||||
snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
|
snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
|
||||||
unlock:
|
}
|
||||||
mutex_unlock(&q->timer_mutex);
|
|
||||||
queuefree(q);
|
queuefree(q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,21 +115,19 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
|
||||||
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
|
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
|
||||||
{
|
{
|
||||||
struct snd_ump_endpoint *ump = client->ump;
|
struct snd_ump_endpoint *ump = client->ump;
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
mutex_lock(&ump->open_mutex);
|
guard(mutex)(&ump->open_mutex);
|
||||||
if (dir == STR_OUT && !client->opened[dir]) {
|
if (dir == STR_OUT && !client->opened[dir]) {
|
||||||
err = snd_rawmidi_kernel_open(&ump->core, 0,
|
err = snd_rawmidi_kernel_open(&ump->core, 0,
|
||||||
SNDRV_RAWMIDI_LFLG_OUTPUT |
|
SNDRV_RAWMIDI_LFLG_OUTPUT |
|
||||||
SNDRV_RAWMIDI_LFLG_APPEND,
|
SNDRV_RAWMIDI_LFLG_APPEND,
|
||||||
&client->out_rfile);
|
&client->out_rfile);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlock;
|
return err;
|
||||||
}
|
}
|
||||||
client->opened[dir]++;
|
client->opened[dir]++;
|
||||||
unlock:
|
return 0;
|
||||||
mutex_unlock(&ump->open_mutex);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close the rawmidi */
|
/* close the rawmidi */
|
||||||
|
@ -137,11 +135,10 @@ static int seq_ump_client_close(struct seq_ump_client *client, int dir)
|
||||||
{
|
{
|
||||||
struct snd_ump_endpoint *ump = client->ump;
|
struct snd_ump_endpoint *ump = client->ump;
|
||||||
|
|
||||||
mutex_lock(&ump->open_mutex);
|
guard(mutex)(&ump->open_mutex);
|
||||||
if (!--client->opened[dir])
|
if (!--client->opened[dir])
|
||||||
if (dir == STR_OUT)
|
if (dir == STR_OUT)
|
||||||
snd_rawmidi_kernel_release(&client->out_rfile);
|
snd_rawmidi_kernel_release(&client->out_rfile);
|
||||||
mutex_unlock(&ump->open_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,15 +214,12 @@ static void fill_port_info(struct snd_seq_port_info *port,
|
||||||
static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
|
static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
|
||||||
{
|
{
|
||||||
struct seq_ump_group *group = &client->groups[group_index];
|
struct seq_ump_group *group = &client->groups[group_index];
|
||||||
struct snd_seq_port_info *port;
|
struct snd_seq_port_info *port __free(kfree) = NULL;
|
||||||
struct snd_seq_port_callback pcallbacks;
|
struct snd_seq_port_callback pcallbacks;
|
||||||
int err;
|
|
||||||
|
|
||||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||||
if (!port) {
|
if (!port)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
fill_port_info(port, client, group);
|
fill_port_info(port, client, group);
|
||||||
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
|
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
|
||||||
|
@ -238,24 +232,22 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
|
||||||
pcallbacks.unuse = seq_ump_unuse;
|
pcallbacks.unuse = seq_ump_unuse;
|
||||||
pcallbacks.event_input = seq_ump_process_event;
|
pcallbacks.event_input = seq_ump_process_event;
|
||||||
port->kernel = &pcallbacks;
|
port->kernel = &pcallbacks;
|
||||||
err = snd_seq_kernel_client_ctl(client->seq_client,
|
return snd_seq_kernel_client_ctl(client->seq_client,
|
||||||
SNDRV_SEQ_IOCTL_CREATE_PORT,
|
SNDRV_SEQ_IOCTL_CREATE_PORT,
|
||||||
port);
|
port);
|
||||||
error:
|
|
||||||
kfree(port);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update the sequencer ports; called from notify_fb_change callback */
|
/* update the sequencer ports; called from notify_fb_change callback */
|
||||||
static void update_port_infos(struct seq_ump_client *client)
|
static void update_port_infos(struct seq_ump_client *client)
|
||||||
{
|
{
|
||||||
struct snd_seq_port_info *old, *new;
|
struct snd_seq_port_info *old __free(kfree) = NULL;
|
||||||
|
struct snd_seq_port_info *new __free(kfree) = NULL;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
old = kzalloc(sizeof(*old), GFP_KERNEL);
|
old = kzalloc(sizeof(*old), GFP_KERNEL);
|
||||||
new = kzalloc(sizeof(*new), GFP_KERNEL);
|
new = kzalloc(sizeof(*new), GFP_KERNEL);
|
||||||
if (!old || !new)
|
if (!old || !new)
|
||||||
goto error;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
|
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
|
||||||
old->addr.client = client->seq_client;
|
old->addr.client = client->seq_client;
|
||||||
|
@ -264,7 +256,7 @@ static void update_port_infos(struct seq_ump_client *client)
|
||||||
SNDRV_SEQ_IOCTL_GET_PORT_INFO,
|
SNDRV_SEQ_IOCTL_GET_PORT_INFO,
|
||||||
old);
|
old);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return;
|
||||||
fill_port_info(new, client, &client->groups[i]);
|
fill_port_info(new, client, &client->groups[i]);
|
||||||
if (old->capability == new->capability &&
|
if (old->capability == new->capability &&
|
||||||
!strcmp(old->name, new->name))
|
!strcmp(old->name, new->name))
|
||||||
|
@ -273,13 +265,10 @@ static void update_port_infos(struct seq_ump_client *client)
|
||||||
SNDRV_SEQ_IOCTL_SET_PORT_INFO,
|
SNDRV_SEQ_IOCTL_SET_PORT_INFO,
|
||||||
new);
|
new);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
return;
|
||||||
/* notify to system port */
|
/* notify to system port */
|
||||||
snd_seq_system_client_ev_port_change(client->seq_client, i);
|
snd_seq_system_client_ev_port_change(client->seq_client, i);
|
||||||
}
|
}
|
||||||
error:
|
|
||||||
kfree(new);
|
|
||||||
kfree(old);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update dir_bits and active flag for all groups in the client */
|
/* update dir_bits and active flag for all groups in the client */
|
||||||
|
@ -334,7 +323,7 @@ static void update_group_attrs(struct seq_ump_client *client)
|
||||||
/* create a UMP Endpoint port */
|
/* create a UMP Endpoint port */
|
||||||
static int create_ump_endpoint_port(struct seq_ump_client *client)
|
static int create_ump_endpoint_port(struct seq_ump_client *client)
|
||||||
{
|
{
|
||||||
struct snd_seq_port_info *port;
|
struct snd_seq_port_info *port __free(kfree) = NULL;
|
||||||
struct snd_seq_port_callback pcallbacks;
|
struct snd_seq_port_callback pcallbacks;
|
||||||
unsigned int rawmidi_info = client->ump->core.info_flags;
|
unsigned int rawmidi_info = client->ump->core.info_flags;
|
||||||
int err;
|
int err;
|
||||||
|
@ -383,7 +372,6 @@ static int create_ump_endpoint_port(struct seq_ump_client *client)
|
||||||
err = snd_seq_kernel_client_ctl(client->seq_client,
|
err = snd_seq_kernel_client_ctl(client->seq_client,
|
||||||
SNDRV_SEQ_IOCTL_CREATE_PORT,
|
SNDRV_SEQ_IOCTL_CREATE_PORT,
|
||||||
port);
|
port);
|
||||||
kfree(port);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,13 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
|
||||||
/*
|
/*
|
||||||
* decode input event and put to read buffer of each opened file
|
* decode input event and put to read buffer of each opened file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */
|
||||||
|
static int dump_to_rawmidi(void *ptr, void *buf, int count)
|
||||||
|
{
|
||||||
|
return snd_rawmidi_receive(ptr, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
|
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
|
||||||
struct snd_seq_event *ev,
|
struct snd_seq_event *ev,
|
||||||
bool atomic)
|
bool atomic)
|
||||||
|
@ -80,7 +87,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
|
||||||
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
|
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
|
||||||
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
|
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
|
||||||
continue;
|
continue;
|
||||||
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream);
|
snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
|
||||||
snd_midi_event_reset_decode(vmidi->parser);
|
snd_midi_event_reset_decode(vmidi->parser);
|
||||||
} else {
|
} else {
|
||||||
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
|
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
|
||||||
|
@ -192,11 +199,10 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
|
||||||
vmidi->client = rdev->client;
|
vmidi->client = rdev->client;
|
||||||
vmidi->port = rdev->port;
|
vmidi->port = rdev->port;
|
||||||
runtime->private_data = vmidi;
|
runtime->private_data = vmidi;
|
||||||
down_write(&rdev->filelist_sem);
|
scoped_guard(rwsem_write, &rdev->filelist_sem) {
|
||||||
write_lock_irq(&rdev->filelist_lock);
|
guard(write_lock_irq)(&rdev->filelist_lock);
|
||||||
list_add_tail(&vmidi->list, &rdev->filelist);
|
list_add_tail(&vmidi->list, &rdev->filelist);
|
||||||
write_unlock_irq(&rdev->filelist_lock);
|
}
|
||||||
up_write(&rdev->filelist_sem);
|
|
||||||
vmidi->rdev = rdev;
|
vmidi->rdev = rdev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -236,11 +242,10 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
|
||||||
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
|
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
|
||||||
struct snd_virmidi *vmidi = substream->runtime->private_data;
|
struct snd_virmidi *vmidi = substream->runtime->private_data;
|
||||||
|
|
||||||
down_write(&rdev->filelist_sem);
|
scoped_guard(rwsem_write, &rdev->filelist_sem) {
|
||||||
write_lock_irq(&rdev->filelist_lock);
|
guard(write_lock_irq)(&rdev->filelist_lock);
|
||||||
list_del(&vmidi->list);
|
list_del(&vmidi->list);
|
||||||
write_unlock_irq(&rdev->filelist_lock);
|
}
|
||||||
up_write(&rdev->filelist_sem);
|
|
||||||
snd_midi_event_free(vmidi->parser);
|
snd_midi_event_free(vmidi->parser);
|
||||||
substream->runtime->private_data = NULL;
|
substream->runtime->private_data = NULL;
|
||||||
kfree(vmidi);
|
kfree(vmidi);
|
||||||
|
@ -356,26 +361,22 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
|
||||||
{
|
{
|
||||||
int client;
|
int client;
|
||||||
struct snd_seq_port_callback pcallbacks;
|
struct snd_seq_port_callback pcallbacks;
|
||||||
struct snd_seq_port_info *pinfo;
|
struct snd_seq_port_info *pinfo __free(kfree) = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (rdev->client >= 0)
|
if (rdev->client >= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
|
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
|
||||||
if (!pinfo) {
|
if (!pinfo)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = snd_seq_create_kernel_client(rdev->card, rdev->device,
|
client = snd_seq_create_kernel_client(rdev->card, rdev->device,
|
||||||
"%s %d-%d", rdev->rmidi->name,
|
"%s %d-%d", rdev->rmidi->name,
|
||||||
rdev->card->number,
|
rdev->card->number,
|
||||||
rdev->device);
|
rdev->device);
|
||||||
if (client < 0) {
|
if (client < 0)
|
||||||
err = client;
|
return client;
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
rdev->client = client;
|
rdev->client = client;
|
||||||
|
|
||||||
/* create a port */
|
/* create a port */
|
||||||
|
@ -403,15 +404,11 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_seq_delete_kernel_client(client);
|
snd_seq_delete_kernel_client(client);
|
||||||
rdev->client = -1;
|
rdev->client = -1;
|
||||||
goto __error;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdev->port = pinfo->addr.port;
|
rdev->port = pinfo->addr.port;
|
||||||
err = 0; /* success */
|
return 0; /* success */
|
||||||
|
|
||||||
__error:
|
|
||||||
kfree(pinfo);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
|
||||||
sdrv->argsize == sdev->argsize;
|
sdrv->argsize == sdev->argsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bus_type snd_seq_bus_type = {
|
static const struct bus_type snd_seq_bus_type = {
|
||||||
.name = "snd_seq",
|
.name = "snd_seq",
|
||||||
.match = snd_seq_bus_match,
|
.match = snd_seq_bus_match,
|
||||||
};
|
};
|
||||||
|
|
|
@ -103,7 +103,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
|
||||||
|
|
||||||
if (minor >= ARRAY_SIZE(snd_minors))
|
if (minor >= ARRAY_SIZE(snd_minors))
|
||||||
return NULL;
|
return NULL;
|
||||||
mutex_lock(&sound_mutex);
|
guard(mutex)(&sound_mutex);
|
||||||
mreg = snd_minors[minor];
|
mreg = snd_minors[minor];
|
||||||
if (mreg && mreg->type == type) {
|
if (mreg && mreg->type == type) {
|
||||||
private_data = mreg->private_data;
|
private_data = mreg->private_data;
|
||||||
|
@ -111,7 +111,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
|
||||||
get_device(&mreg->card_ptr->card_dev);
|
get_device(&mreg->card_ptr->card_dev);
|
||||||
} else
|
} else
|
||||||
private_data = NULL;
|
private_data = NULL;
|
||||||
mutex_unlock(&sound_mutex);
|
|
||||||
return private_data;
|
return private_data;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_lookup_minor_data);
|
EXPORT_SYMBOL(snd_lookup_minor_data);
|
||||||
|
@ -150,17 +149,15 @@ static int snd_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
if (minor >= ARRAY_SIZE(snd_minors))
|
if (minor >= ARRAY_SIZE(snd_minors))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
mutex_lock(&sound_mutex);
|
scoped_guard(mutex, &sound_mutex) {
|
||||||
mptr = snd_minors[minor];
|
mptr = snd_minors[minor];
|
||||||
if (mptr == NULL) {
|
if (mptr == NULL) {
|
||||||
mptr = autoload_device(minor);
|
mptr = autoload_device(minor);
|
||||||
if (!mptr) {
|
if (!mptr)
|
||||||
mutex_unlock(&sound_mutex);
|
return -ENODEV;
|
||||||
return -ENODEV;
|
|
||||||
}
|
}
|
||||||
|
new_fops = fops_get(mptr->f_ops);
|
||||||
}
|
}
|
||||||
new_fops = fops_get(mptr->f_ops);
|
|
||||||
mutex_unlock(&sound_mutex);
|
|
||||||
if (!new_fops)
|
if (!new_fops)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
replace_fops(file, new_fops);
|
replace_fops(file, new_fops);
|
||||||
|
@ -269,7 +266,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
|
||||||
preg->f_ops = f_ops;
|
preg->f_ops = f_ops;
|
||||||
preg->private_data = private_data;
|
preg->private_data = private_data;
|
||||||
preg->card_ptr = card;
|
preg->card_ptr = card;
|
||||||
mutex_lock(&sound_mutex);
|
guard(mutex)(&sound_mutex);
|
||||||
minor = snd_find_free_minor(type, card, dev);
|
minor = snd_find_free_minor(type, card, dev);
|
||||||
if (minor < 0) {
|
if (minor < 0) {
|
||||||
err = minor;
|
err = minor;
|
||||||
|
@ -284,7 +281,6 @@ int snd_register_device(int type, struct snd_card *card, int dev,
|
||||||
|
|
||||||
snd_minors[minor] = preg;
|
snd_minors[minor] = preg;
|
||||||
error:
|
error:
|
||||||
mutex_unlock(&sound_mutex);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
kfree(preg);
|
kfree(preg);
|
||||||
return err;
|
return err;
|
||||||
|
@ -305,7 +301,7 @@ int snd_unregister_device(struct device *dev)
|
||||||
int minor;
|
int minor;
|
||||||
struct snd_minor *preg;
|
struct snd_minor *preg;
|
||||||
|
|
||||||
mutex_lock(&sound_mutex);
|
guard(mutex)(&sound_mutex);
|
||||||
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
|
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
|
||||||
preg = snd_minors[minor];
|
preg = snd_minors[minor];
|
||||||
if (preg && preg->dev == dev) {
|
if (preg && preg->dev == dev) {
|
||||||
|
@ -315,7 +311,6 @@ int snd_unregister_device(struct device *dev)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&sound_mutex);
|
|
||||||
if (minor >= ARRAY_SIZE(snd_minors))
|
if (minor >= ARRAY_SIZE(snd_minors))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -355,7 +350,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
|
||||||
int minor;
|
int minor;
|
||||||
struct snd_minor *mptr;
|
struct snd_minor *mptr;
|
||||||
|
|
||||||
mutex_lock(&sound_mutex);
|
guard(mutex)(&sound_mutex);
|
||||||
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
|
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
|
||||||
mptr = snd_minors[minor];
|
mptr = snd_minors[minor];
|
||||||
if (!mptr)
|
if (!mptr)
|
||||||
|
@ -373,7 +368,6 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
|
||||||
snd_iprintf(buffer, "%3i: : %s\n", minor,
|
snd_iprintf(buffer, "%3i: : %s\n", minor,
|
||||||
snd_device_type_name(mptr->type));
|
snd_device_type_name(mptr->type));
|
||||||
}
|
}
|
||||||
mutex_unlock(&sound_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init snd_minor_info_init(void)
|
int __init snd_minor_info_init(void)
|
||||||
|
|
|
@ -0,0 +1,312 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Sound core KUnit test
|
||||||
|
* Author: Ivan Orlov <ivan.orlov0322@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kunit/test.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
|
||||||
|
#define SILENCE_BUFFER_MAX_FRAMES 260
|
||||||
|
#define SILENCE_BUFFER_SIZE (sizeof(u64) * SILENCE_BUFFER_MAX_FRAMES)
|
||||||
|
#define SILENCE(...) { __VA_ARGS__ }
|
||||||
|
#define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) { \
|
||||||
|
.format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits, \
|
||||||
|
.width = wd, .le = endianness, .sd = signd, .silence = silence_arr, \
|
||||||
|
.name = #fmt, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1)
|
||||||
|
#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1
|
||||||
|
|
||||||
|
#define VALID_NAME "ValidName"
|
||||||
|
#define NAME_W_SPEC_CHARS "In%v@1id name"
|
||||||
|
#define NAME_W_SPACE "Test name"
|
||||||
|
#define NAME_W_SPACE_REMOVED "Testname"
|
||||||
|
|
||||||
|
#define TEST_FIRST_COMPONENT "Component1"
|
||||||
|
#define TEST_SECOND_COMPONENT "Component2"
|
||||||
|
|
||||||
|
struct snd_format_test_data {
|
||||||
|
snd_pcm_format_t format;
|
||||||
|
int physical_bits;
|
||||||
|
int width;
|
||||||
|
int le;
|
||||||
|
int sd;
|
||||||
|
unsigned char silence[8];
|
||||||
|
unsigned char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct avail_test_data {
|
||||||
|
snd_pcm_uframes_t buffer_size;
|
||||||
|
snd_pcm_uframes_t hw_ptr;
|
||||||
|
snd_pcm_uframes_t appl_ptr;
|
||||||
|
snd_pcm_uframes_t expected_avail;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_format_test_data valid_fmt[] = {
|
||||||
|
DEFINE_FORMAT(S8, 8, 8, -1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U8, 8, 8, -1, 0, SILENCE(0x80)),
|
||||||
|
DEFINE_FORMAT(S16_LE, 16, 16, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S16_BE, 16, 16, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U16_LE, 16, 16, 1, 0, SILENCE(0x00, 0x80)),
|
||||||
|
DEFINE_FORMAT(U16_BE, 16, 16, 0, 0, SILENCE(0x80, 0x00)),
|
||||||
|
DEFINE_FORMAT(S24_LE, 32, 24, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S24_BE, 32, 24, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U24_LE, 32, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
|
||||||
|
DEFINE_FORMAT(U24_BE, 32, 24, 0, 0, SILENCE(0x00, 0x80, 0x00, 0x00)),
|
||||||
|
DEFINE_FORMAT(S32_LE, 32, 32, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S32_BE, 32, 32, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U32_LE, 32, 32, 1, 0, SILENCE(0x00, 0x00, 0x00, 0x80)),
|
||||||
|
DEFINE_FORMAT(U32_BE, 32, 32, 0, 0, SILENCE(0x80, 0x00, 0x00, 0x00)),
|
||||||
|
DEFINE_FORMAT(FLOAT_LE, 32, 32, 1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(FLOAT_BE, 32, 32, 0, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(FLOAT64_LE, 64, 64, 1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(FLOAT64_BE, 64, 64, 0, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(IEC958_SUBFRAME_LE, 32, 32, 1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(IEC958_SUBFRAME_BE, 32, 32, 0, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(MU_LAW, 8, 8, -1, -1, SILENCE(0x7f)),
|
||||||
|
DEFINE_FORMAT(A_LAW, 8, 8, -1, -1, SILENCE(0x55)),
|
||||||
|
DEFINE_FORMAT(IMA_ADPCM, 4, 4, -1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(G723_24, 3, 3, -1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(G723_40, 5, 5, -1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(DSD_U8, 8, 8, 1, 0, SILENCE(0x69)),
|
||||||
|
DEFINE_FORMAT(DSD_U16_LE, 16, 16, 1, 0, SILENCE(0x69, 0x69)),
|
||||||
|
DEFINE_FORMAT(DSD_U32_LE, 32, 32, 1, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
|
||||||
|
DEFINE_FORMAT(DSD_U16_BE, 16, 16, 0, 0, SILENCE(0x69, 0x69)),
|
||||||
|
DEFINE_FORMAT(DSD_U32_BE, 32, 32, 0, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
|
||||||
|
DEFINE_FORMAT(S20_LE, 32, 20, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S20_BE, 32, 20, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U20_LE, 32, 20, 1, 0, SILENCE(0x00, 0x00, 0x08, 0x00)),
|
||||||
|
DEFINE_FORMAT(U20_BE, 32, 20, 0, 0, SILENCE(0x00, 0x08, 0x00, 0x00)),
|
||||||
|
DEFINE_FORMAT(S24_3LE, 24, 24, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S24_3BE, 24, 24, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U24_3LE, 24, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
|
||||||
|
DEFINE_FORMAT(U24_3BE, 24, 24, 0, 0, SILENCE(0x80, 0x00, 0x00)),
|
||||||
|
DEFINE_FORMAT(S20_3LE, 24, 20, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S20_3BE, 24, 20, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U20_3LE, 24, 20, 1, 0, SILENCE(0x00, 0x00, 0x08)),
|
||||||
|
DEFINE_FORMAT(U20_3BE, 24, 20, 0, 0, SILENCE(0x08, 0x00, 0x00)),
|
||||||
|
DEFINE_FORMAT(S18_3LE, 24, 18, 1, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(S18_3BE, 24, 18, 0, 1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(U18_3LE, 24, 18, 1, 0, SILENCE(0x00, 0x00, 0x02)),
|
||||||
|
DEFINE_FORMAT(U18_3BE, 24, 18, 0, 0, SILENCE(0x02, 0x00, 0x00)),
|
||||||
|
DEFINE_FORMAT(G723_24_1B, 8, 3, -1, -1, SILENCE()),
|
||||||
|
DEFINE_FORMAT(G723_40_1B, 8, 5, -1, -1, SILENCE()),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_phys_format_size(struct kunit *test)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(valid_fmt[i].format),
|
||||||
|
valid_fmt[i].physical_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_1), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_2), -EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_format_width(struct kunit *test)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(valid_fmt[i].format),
|
||||||
|
valid_fmt[i].width);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_format_signed(struct kunit *test)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_signed(valid_fmt[i].format),
|
||||||
|
valid_fmt[i].sd < 0 ? -EINVAL : valid_fmt[i].sd);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_unsigned(valid_fmt[i].format),
|
||||||
|
valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_format_endianness(struct kunit *test)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(valid_fmt[i].format),
|
||||||
|
valid_fmt[i].le < 0 ? -EINVAL : valid_fmt[i].le);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(valid_fmt[i].format),
|
||||||
|
valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_1), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_2), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_1), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_2), -EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data,
|
||||||
|
u8 *buffer, size_t samples_count)
|
||||||
|
{
|
||||||
|
size_t sample_bytes = data->physical_bits >> 3;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
KUNIT_ASSERT_EQ(test, snd_pcm_format_set_silence(data->format, buffer, samples_count), 0);
|
||||||
|
for (i = 0; i < samples_count * sample_bytes; i++)
|
||||||
|
KUNIT_EXPECT_EQ(test, buffer[i], data->silence[i % sample_bytes]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_format_fill_silence(struct kunit *test)
|
||||||
|
{
|
||||||
|
u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES };
|
||||||
|
u8 *buffer;
|
||||||
|
u32 i, j;
|
||||||
|
|
||||||
|
buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(buf_samples); i++) {
|
||||||
|
for (j = 0; j < ARRAY_SIZE(valid_fmt); j++)
|
||||||
|
_test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT_1, buffer, 20), -EINVAL);
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size)
|
||||||
|
{
|
||||||
|
snd_pcm_uframes_t boundary = buffer_size;
|
||||||
|
|
||||||
|
while (boundary * 2 <= 0x7fffffffUL - buffer_size)
|
||||||
|
boundary *= 2;
|
||||||
|
return boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct avail_test_data p_avail_data[] = {
|
||||||
|
/* buf_size + hw_ptr < appl_ptr => avail = buf_size + hw_ptr - appl_ptr + boundary */
|
||||||
|
{ 128, 1000, 1129, 1073741824UL - 1 },
|
||||||
|
/*
|
||||||
|
* buf_size + hw_ptr - appl_ptr >= boundary =>
|
||||||
|
* => avail = buf_size + hw_ptr - appl_ptr - boundary
|
||||||
|
*/
|
||||||
|
{ 128, 1073741824UL, 10, 118 },
|
||||||
|
/* standard case: avail = buf_size + hw_ptr - appl_ptr */
|
||||||
|
{ 128, 1000, 1001, 127 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_playback_avail(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
|
||||||
|
r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) {
|
||||||
|
r->buffer_size = p_avail_data[i].buffer_size;
|
||||||
|
r->boundary = calculate_boundary(r->buffer_size);
|
||||||
|
r->status->hw_ptr = p_avail_data[i].hw_ptr;
|
||||||
|
r->control->appl_ptr = p_avail_data[i].appl_ptr;
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_playback_avail(r), p_avail_data[i].expected_avail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct avail_test_data c_avail_data[] = {
|
||||||
|
/* hw_ptr - appl_ptr < 0 => avail = hw_ptr - appl_ptr + boundary */
|
||||||
|
{ 128, 1000, 1001, 1073741824UL - 1 },
|
||||||
|
/* standard case: avail = hw_ptr - appl_ptr */
|
||||||
|
{ 128, 1001, 1000, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_capture_avail(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
|
||||||
|
r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) {
|
||||||
|
r->buffer_size = c_avail_data[i].buffer_size;
|
||||||
|
r->boundary = calculate_boundary(r->buffer_size);
|
||||||
|
r->status->hw_ptr = c_avail_data[i].hw_ptr;
|
||||||
|
r->control->appl_ptr = c_avail_data[i].appl_ptr;
|
||||||
|
KUNIT_EXPECT_EQ(test, snd_pcm_capture_avail(r), c_avail_data[i].expected_avail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_card_set_id(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
|
||||||
|
|
||||||
|
snd_card_set_id(card, VALID_NAME);
|
||||||
|
KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME);
|
||||||
|
|
||||||
|
/* clear the first id character so we can set it again */
|
||||||
|
card->id[0] = '\0';
|
||||||
|
snd_card_set_id(card, NAME_W_SPEC_CHARS);
|
||||||
|
KUNIT_EXPECT_STRNEQ(test, card->id, NAME_W_SPEC_CHARS);
|
||||||
|
|
||||||
|
card->id[0] = '\0';
|
||||||
|
snd_card_set_id(card, NAME_W_SPACE);
|
||||||
|
kunit_info(test, "%s", card->id);
|
||||||
|
KUNIT_EXPECT_STREQ(test, card->id, NAME_W_SPACE_REMOVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_pcm_format_name(struct kunit *test)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
|
||||||
|
name = snd_pcm_format_name(valid_fmt[i].format);
|
||||||
|
KUNIT_ASSERT_NOT_NULL_MSG(test, name, "Don't have name for %s", valid_fmt[i].name);
|
||||||
|
KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_1), "Unknown");
|
||||||
|
KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_2), "Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_card_add_component(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
|
||||||
|
|
||||||
|
snd_component_add(card, TEST_FIRST_COMPONENT);
|
||||||
|
KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT);
|
||||||
|
|
||||||
|
snd_component_add(card, TEST_SECOND_COMPONENT);
|
||||||
|
KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT " " TEST_SECOND_COMPONENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kunit_case sound_utils_cases[] = {
|
||||||
|
KUNIT_CASE(test_phys_format_size),
|
||||||
|
KUNIT_CASE(test_format_width),
|
||||||
|
KUNIT_CASE(test_format_endianness),
|
||||||
|
KUNIT_CASE(test_format_signed),
|
||||||
|
KUNIT_CASE(test_format_fill_silence),
|
||||||
|
KUNIT_CASE(test_playback_avail),
|
||||||
|
KUNIT_CASE(test_capture_avail),
|
||||||
|
KUNIT_CASE(test_card_set_id),
|
||||||
|
KUNIT_CASE(test_pcm_format_name),
|
||||||
|
KUNIT_CASE(test_card_add_component),
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kunit_suite sound_utils_suite = {
|
||||||
|
.name = "sound-core-test",
|
||||||
|
.test_cases = sound_utils_cases,
|
||||||
|
};
|
||||||
|
|
||||||
|
kunit_test_suite(sound_utils_suite);
|
||||||
|
MODULE_AUTHOR("Ivan Orlov");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -29,7 +29,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
|
||||||
|
|
||||||
if (minor >= ARRAY_SIZE(snd_oss_minors))
|
if (minor >= ARRAY_SIZE(snd_oss_minors))
|
||||||
return NULL;
|
return NULL;
|
||||||
mutex_lock(&sound_oss_mutex);
|
guard(mutex)(&sound_oss_mutex);
|
||||||
mreg = snd_oss_minors[minor];
|
mreg = snd_oss_minors[minor];
|
||||||
if (mreg && mreg->type == type) {
|
if (mreg && mreg->type == type) {
|
||||||
private_data = mreg->private_data;
|
private_data = mreg->private_data;
|
||||||
|
@ -37,7 +37,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
|
||||||
get_device(&mreg->card_ptr->card_dev);
|
get_device(&mreg->card_ptr->card_dev);
|
||||||
} else
|
} else
|
||||||
private_data = NULL;
|
private_data = NULL;
|
||||||
mutex_unlock(&sound_oss_mutex);
|
|
||||||
return private_data;
|
return private_data;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_lookup_oss_minor_data);
|
EXPORT_SYMBOL(snd_lookup_oss_minor_data);
|
||||||
|
@ -106,7 +105,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
||||||
preg->f_ops = f_ops;
|
preg->f_ops = f_ops;
|
||||||
preg->private_data = private_data;
|
preg->private_data = private_data;
|
||||||
preg->card_ptr = card;
|
preg->card_ptr = card;
|
||||||
mutex_lock(&sound_oss_mutex);
|
guard(mutex)(&sound_oss_mutex);
|
||||||
snd_oss_minors[minor] = preg;
|
snd_oss_minors[minor] = preg;
|
||||||
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
|
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
|
||||||
switch (minor_unit) {
|
switch (minor_unit) {
|
||||||
|
@ -130,7 +129,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
||||||
goto __end;
|
goto __end;
|
||||||
snd_oss_minors[track2] = preg;
|
snd_oss_minors[track2] = preg;
|
||||||
}
|
}
|
||||||
mutex_unlock(&sound_oss_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
__end:
|
__end:
|
||||||
|
@ -139,7 +137,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
||||||
if (register1 >= 0)
|
if (register1 >= 0)
|
||||||
unregister_sound_special(register1);
|
unregister_sound_special(register1);
|
||||||
snd_oss_minors[minor] = NULL;
|
snd_oss_minors[minor] = NULL;
|
||||||
mutex_unlock(&sound_oss_mutex);
|
|
||||||
kfree(preg);
|
kfree(preg);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
@ -156,12 +153,10 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
|
||||||
return 0;
|
return 0;
|
||||||
if (minor < 0)
|
if (minor < 0)
|
||||||
return minor;
|
return minor;
|
||||||
mutex_lock(&sound_oss_mutex);
|
guard(mutex)(&sound_oss_mutex);
|
||||||
mptr = snd_oss_minors[minor];
|
mptr = snd_oss_minors[minor];
|
||||||
if (mptr == NULL) {
|
if (mptr == NULL)
|
||||||
mutex_unlock(&sound_oss_mutex);
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
|
||||||
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
|
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
|
||||||
case SNDRV_MINOR_OSS_PCM:
|
case SNDRV_MINOR_OSS_PCM:
|
||||||
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
|
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
|
||||||
|
@ -176,7 +171,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
|
||||||
if (track2 >= 0)
|
if (track2 >= 0)
|
||||||
snd_oss_minors[track2] = NULL;
|
snd_oss_minors[track2] = NULL;
|
||||||
snd_oss_minors[minor] = NULL;
|
snd_oss_minors[minor] = NULL;
|
||||||
mutex_unlock(&sound_oss_mutex);
|
|
||||||
|
|
||||||
/* call unregister_sound_special() outside sound_oss_mutex;
|
/* call unregister_sound_special() outside sound_oss_mutex;
|
||||||
* otherwise may deadlock, as it can trigger the release of a card
|
* otherwise may deadlock, as it can trigger the release of a card
|
||||||
|
@ -220,7 +214,7 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
|
||||||
int minor;
|
int minor;
|
||||||
struct snd_minor *mptr;
|
struct snd_minor *mptr;
|
||||||
|
|
||||||
mutex_lock(&sound_oss_mutex);
|
guard(mutex)(&sound_oss_mutex);
|
||||||
for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
|
for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
|
||||||
mptr = snd_oss_minors[minor];
|
mptr = snd_oss_minors[minor];
|
||||||
if (!mptr)
|
if (!mptr)
|
||||||
|
@ -233,7 +227,6 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
|
||||||
snd_iprintf(buffer, "%3i: : %s\n", minor,
|
snd_iprintf(buffer, "%3i: : %s\n", minor,
|
||||||
snd_oss_device_type_name(mptr->type));
|
snd_oss_device_type_name(mptr->type));
|
||||||
}
|
}
|
||||||
mutex_unlock(&sound_oss_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -224,14 +224,12 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
list_move_tail(&slave->open_list, &master->slave_list_head);
|
list_move_tail(&slave->open_list, &master->slave_list_head);
|
||||||
master->timer->num_instances++;
|
master->timer->num_instances++;
|
||||||
spin_lock_irq(&slave_active_lock);
|
guard(spinlock_irq)(&slave_active_lock);
|
||||||
spin_lock(&master->timer->lock);
|
guard(spinlock)(&master->timer->lock);
|
||||||
slave->master = master;
|
slave->master = master;
|
||||||
slave->timer = master->timer;
|
slave->timer = master->timer;
|
||||||
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
|
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
|
||||||
list_add_tail(&slave->active_list, &master->slave_active_head);
|
list_add_tail(&slave->active_list, &master->slave_active_head);
|
||||||
spin_unlock(&master->timer->lock);
|
|
||||||
spin_unlock_irq(&slave_active_lock);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,6 +380,25 @@ list_added:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_timer_open);
|
EXPORT_SYMBOL(snd_timer_open);
|
||||||
|
|
||||||
|
/* remove slave links, called from snd_timer_close_locked() below */
|
||||||
|
static void remove_slave_links(struct snd_timer_instance *timeri,
|
||||||
|
struct snd_timer *timer)
|
||||||
|
{
|
||||||
|
struct snd_timer_instance *slave, *tmp;
|
||||||
|
|
||||||
|
guard(spinlock_irq)(&slave_active_lock);
|
||||||
|
guard(spinlock)(&timer->lock);
|
||||||
|
timeri->timer = NULL;
|
||||||
|
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) {
|
||||||
|
list_move_tail(&slave->open_list, &snd_timer_slave_list);
|
||||||
|
timer->num_instances--;
|
||||||
|
slave->master = NULL;
|
||||||
|
slave->timer = NULL;
|
||||||
|
list_del_init(&slave->ack_list);
|
||||||
|
list_del_init(&slave->active_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close a timer instance
|
* close a timer instance
|
||||||
* call this with register_mutex down.
|
* call this with register_mutex down.
|
||||||
|
@ -390,12 +407,10 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
|
||||||
struct device **card_devp_to_put)
|
struct device **card_devp_to_put)
|
||||||
{
|
{
|
||||||
struct snd_timer *timer = timeri->timer;
|
struct snd_timer *timer = timeri->timer;
|
||||||
struct snd_timer_instance *slave, *tmp;
|
|
||||||
|
|
||||||
if (timer) {
|
if (timer) {
|
||||||
spin_lock_irq(&timer->lock);
|
guard(spinlock)(&timer->lock);
|
||||||
timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
|
timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
|
||||||
spin_unlock_irq(&timer->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list_empty(&timeri->open_list)) {
|
if (!list_empty(&timeri->open_list)) {
|
||||||
|
@ -418,21 +433,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&timer->lock);
|
spin_unlock_irq(&timer->lock);
|
||||||
|
|
||||||
/* remove slave links */
|
remove_slave_links(timeri, timer);
|
||||||
spin_lock_irq(&slave_active_lock);
|
|
||||||
spin_lock(&timer->lock);
|
|
||||||
timeri->timer = NULL;
|
|
||||||
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
|
|
||||||
open_list) {
|
|
||||||
list_move_tail(&slave->open_list, &snd_timer_slave_list);
|
|
||||||
timer->num_instances--;
|
|
||||||
slave->master = NULL;
|
|
||||||
slave->timer = NULL;
|
|
||||||
list_del_init(&slave->ack_list);
|
|
||||||
list_del_init(&slave->active_list);
|
|
||||||
}
|
|
||||||
spin_unlock(&timer->lock);
|
|
||||||
spin_unlock_irq(&slave_active_lock);
|
|
||||||
|
|
||||||
/* slave doesn't need to release timer resources below */
|
/* slave doesn't need to release timer resources below */
|
||||||
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
|
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
|
||||||
|
@ -459,9 +460,8 @@ void snd_timer_close(struct snd_timer_instance *timeri)
|
||||||
if (snd_BUG_ON(!timeri))
|
if (snd_BUG_ON(!timeri))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
scoped_guard(mutex, ®ister_mutex)
|
||||||
snd_timer_close_locked(timeri, &card_dev_to_put);
|
snd_timer_close_locked(timeri, &card_dev_to_put);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
/* put_device() is called after unlock for avoiding deadlock */
|
/* put_device() is called after unlock for avoiding deadlock */
|
||||||
if (card_dev_to_put)
|
if (card_dev_to_put)
|
||||||
put_device(card_dev_to_put);
|
put_device(card_dev_to_put);
|
||||||
|
@ -480,15 +480,13 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
|
||||||
{
|
{
|
||||||
struct snd_timer * timer;
|
struct snd_timer * timer;
|
||||||
unsigned long ret = 0;
|
unsigned long ret = 0;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (timeri == NULL)
|
if (timeri == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
timer = timeri->timer;
|
timer = timeri->timer;
|
||||||
if (timer) {
|
if (timer) {
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
ret = snd_timer_hw_resolution(timer);
|
ret = snd_timer_hw_resolution(timer);
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -532,26 +530,19 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
|
||||||
{
|
{
|
||||||
struct snd_timer *timer;
|
struct snd_timer *timer;
|
||||||
int result;
|
int result;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
timer = timeri->timer;
|
timer = timeri->timer;
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
|
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
|
||||||
result = -EINVAL;
|
return -EINVAL;
|
||||||
goto unlock;
|
if (timer->card && timer->card->shutdown)
|
||||||
}
|
return -ENODEV;
|
||||||
if (timer->card && timer->card->shutdown) {
|
|
||||||
result = -ENODEV;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
|
if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
|
||||||
SNDRV_TIMER_IFLG_START)) {
|
SNDRV_TIMER_IFLG_START))
|
||||||
result = -EBUSY;
|
return -EBUSY;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start)
|
if (start)
|
||||||
timeri->ticks = timeri->cticks = ticks;
|
timeri->ticks = timeri->cticks = ticks;
|
||||||
|
@ -577,8 +568,6 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
|
||||||
}
|
}
|
||||||
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
|
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
|
||||||
SNDRV_TIMER_EVENT_CONTINUE);
|
SNDRV_TIMER_EVENT_CONTINUE);
|
||||||
unlock:
|
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,53 +575,38 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
|
||||||
static int snd_timer_start_slave(struct snd_timer_instance *timeri,
|
static int snd_timer_start_slave(struct snd_timer_instance *timeri,
|
||||||
bool start)
|
bool start)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&slave_active_lock);
|
||||||
int err;
|
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
|
||||||
|
return -EINVAL;
|
||||||
spin_lock_irqsave(&slave_active_lock, flags);
|
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING)
|
||||||
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
|
return -EBUSY;
|
||||||
err = -EINVAL;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
|
|
||||||
err = -EBUSY;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
|
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
|
||||||
if (timeri->master && timeri->timer) {
|
if (timeri->master && timeri->timer) {
|
||||||
spin_lock(&timeri->timer->lock);
|
guard(spinlock)(&timeri->timer->lock);
|
||||||
list_add_tail(&timeri->active_list,
|
list_add_tail(&timeri->active_list,
|
||||||
&timeri->master->slave_active_head);
|
&timeri->master->slave_active_head);
|
||||||
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
|
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
|
||||||
SNDRV_TIMER_EVENT_CONTINUE);
|
SNDRV_TIMER_EVENT_CONTINUE);
|
||||||
spin_unlock(&timeri->timer->lock);
|
|
||||||
}
|
}
|
||||||
err = 1; /* delayed start */
|
return 1; /* delayed start */
|
||||||
unlock:
|
|
||||||
spin_unlock_irqrestore(&slave_active_lock, flags);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stop/pause a master timer */
|
/* stop/pause a master timer */
|
||||||
static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
|
static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
|
||||||
{
|
{
|
||||||
struct snd_timer *timer;
|
struct snd_timer *timer;
|
||||||
int result = 0;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
timer = timeri->timer;
|
timer = timeri->timer;
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
list_del_init(&timeri->ack_list);
|
list_del_init(&timeri->ack_list);
|
||||||
list_del_init(&timeri->active_list);
|
list_del_init(&timeri->active_list);
|
||||||
if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
|
if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
|
||||||
SNDRV_TIMER_IFLG_START))) {
|
SNDRV_TIMER_IFLG_START)))
|
||||||
result = -EBUSY;
|
return -EBUSY;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (timer->card && timer->card->shutdown)
|
if (timer->card && timer->card->shutdown)
|
||||||
goto unlock;
|
return 0;
|
||||||
if (stop) {
|
if (stop) {
|
||||||
timeri->cticks = timeri->ticks;
|
timeri->cticks = timeri->ticks;
|
||||||
timeri->pticks = 0;
|
timeri->pticks = 0;
|
||||||
|
@ -656,30 +630,25 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
|
||||||
timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
|
timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
|
||||||
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
|
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
|
||||||
SNDRV_TIMER_EVENT_PAUSE);
|
SNDRV_TIMER_EVENT_PAUSE);
|
||||||
unlock:
|
return 0;
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stop/pause a slave timer */
|
/* stop/pause a slave timer */
|
||||||
static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
|
static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
bool running;
|
bool running;
|
||||||
|
|
||||||
spin_lock_irqsave(&slave_active_lock, flags);
|
guard(spinlock_irqsave)(&slave_active_lock);
|
||||||
running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
|
running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
|
||||||
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
|
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
|
||||||
if (timeri->timer) {
|
if (timeri->timer) {
|
||||||
spin_lock(&timeri->timer->lock);
|
guard(spinlock)(&timeri->timer->lock);
|
||||||
list_del_init(&timeri->ack_list);
|
list_del_init(&timeri->ack_list);
|
||||||
list_del_init(&timeri->active_list);
|
list_del_init(&timeri->active_list);
|
||||||
if (running)
|
if (running)
|
||||||
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
|
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
|
||||||
SNDRV_TIMER_EVENT_PAUSE);
|
SNDRV_TIMER_EVENT_PAUSE);
|
||||||
spin_unlock(&timeri->timer->lock);
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&slave_active_lock, flags);
|
|
||||||
return running ? 0 : -EBUSY;
|
return running ? 0 : -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,12 +773,9 @@ static void snd_timer_process_callbacks(struct snd_timer *timer,
|
||||||
static void snd_timer_clear_callbacks(struct snd_timer *timer,
|
static void snd_timer_clear_callbacks(struct snd_timer *timer,
|
||||||
struct list_head *head)
|
struct list_head *head)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
|
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
|
||||||
while (!list_empty(head))
|
while (!list_empty(head))
|
||||||
list_del_init(head->next);
|
list_del_init(head->next);
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -819,16 +785,14 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
|
||||||
static void snd_timer_work(struct work_struct *work)
|
static void snd_timer_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
|
struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (timer->card && timer->card->shutdown) {
|
if (timer->card && timer->card->shutdown) {
|
||||||
snd_timer_clear_callbacks(timer, &timer->sack_list_head);
|
snd_timer_clear_callbacks(timer, &timer->sack_list_head);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
snd_timer_process_callbacks(timer, &timer->sack_list_head);
|
snd_timer_process_callbacks(timer, &timer->sack_list_head);
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -842,8 +806,6 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
||||||
struct snd_timer_instance *ti, *ts, *tmp;
|
struct snd_timer_instance *ti, *ts, *tmp;
|
||||||
unsigned long resolution;
|
unsigned long resolution;
|
||||||
struct list_head *ack_list_head;
|
struct list_head *ack_list_head;
|
||||||
unsigned long flags;
|
|
||||||
bool use_work = false;
|
|
||||||
|
|
||||||
if (timer == NULL)
|
if (timer == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -853,7 +815,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
|
|
||||||
/* remember the current resolution */
|
/* remember the current resolution */
|
||||||
resolution = snd_timer_hw_resolution(timer);
|
resolution = snd_timer_hw_resolution(timer);
|
||||||
|
@ -919,10 +881,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
||||||
snd_timer_process_callbacks(timer, &timer->ack_list_head);
|
snd_timer_process_callbacks(timer, &timer->ack_list_head);
|
||||||
|
|
||||||
/* do we have any slow callbacks? */
|
/* do we have any slow callbacks? */
|
||||||
use_work = !list_empty(&timer->sack_list_head);
|
if (!list_empty(&timer->sack_list_head))
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
|
|
||||||
if (use_work)
|
|
||||||
queue_work(system_highpri_wq, &timer->task_work);
|
queue_work(system_highpri_wq, &timer->task_work);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_timer_interrupt);
|
EXPORT_SYMBOL(snd_timer_interrupt);
|
||||||
|
@ -988,7 +947,7 @@ static int snd_timer_free(struct snd_timer *timer)
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
if (! list_empty(&timer->open_list_head)) {
|
if (! list_empty(&timer->open_list_head)) {
|
||||||
struct list_head *p, *n;
|
struct list_head *p, *n;
|
||||||
struct snd_timer_instance *ti;
|
struct snd_timer_instance *ti;
|
||||||
|
@ -1000,7 +959,6 @@ static int snd_timer_free(struct snd_timer *timer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list_del(&timer->device_list);
|
list_del(&timer->device_list);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
|
|
||||||
if (timer->private_free)
|
if (timer->private_free)
|
||||||
timer->private_free(timer);
|
timer->private_free(timer);
|
||||||
|
@ -1025,7 +983,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
||||||
!timer->hw.resolution && timer->hw.c_resolution == NULL)
|
!timer->hw.resolution && timer->hw.c_resolution == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
list_for_each_entry(timer1, &snd_timer_list, device_list) {
|
list_for_each_entry(timer1, &snd_timer_list, device_list) {
|
||||||
if (timer1->tmr_class > timer->tmr_class)
|
if (timer1->tmr_class > timer->tmr_class)
|
||||||
break;
|
break;
|
||||||
|
@ -1046,11 +1004,9 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
||||||
if (timer1->tmr_subdevice < timer->tmr_subdevice)
|
if (timer1->tmr_subdevice < timer->tmr_subdevice)
|
||||||
continue;
|
continue;
|
||||||
/* conflicts.. */
|
/* conflicts.. */
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
list_add_tail(&timer->device_list, &timer1->device_list);
|
list_add_tail(&timer->device_list, &timer1->device_list);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,20 +1015,18 @@ static int snd_timer_dev_disconnect(struct snd_device *device)
|
||||||
struct snd_timer *timer = device->device_data;
|
struct snd_timer *timer = device->device_data;
|
||||||
struct snd_timer_instance *ti;
|
struct snd_timer_instance *ti;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
list_del_init(&timer->device_list);
|
list_del_init(&timer->device_list);
|
||||||
/* wake up pending sleepers */
|
/* wake up pending sleepers */
|
||||||
list_for_each_entry(ti, &timer->open_list_head, open_list) {
|
list_for_each_entry(ti, &timer->open_list_head, open_list) {
|
||||||
if (ti->disconnect)
|
if (ti->disconnect)
|
||||||
ti->disconnect(ti);
|
ti->disconnect(ti);
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
|
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
unsigned long resolution = 0;
|
unsigned long resolution = 0;
|
||||||
struct snd_timer_instance *ti, *ts;
|
struct snd_timer_instance *ti, *ts;
|
||||||
|
|
||||||
|
@ -1083,7 +1037,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
|
||||||
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
|
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
|
||||||
event > SNDRV_TIMER_EVENT_MRESUME))
|
event > SNDRV_TIMER_EVENT_MRESUME))
|
||||||
return;
|
return;
|
||||||
spin_lock_irqsave(&timer->lock, flags);
|
guard(spinlock_irqsave)(&timer->lock);
|
||||||
if (event == SNDRV_TIMER_EVENT_MSTART ||
|
if (event == SNDRV_TIMER_EVENT_MSTART ||
|
||||||
event == SNDRV_TIMER_EVENT_MCONTINUE ||
|
event == SNDRV_TIMER_EVENT_MCONTINUE ||
|
||||||
event == SNDRV_TIMER_EVENT_MRESUME)
|
event == SNDRV_TIMER_EVENT_MRESUME)
|
||||||
|
@ -1095,7 +1049,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
|
||||||
if (ts->ccallback)
|
if (ts->ccallback)
|
||||||
ts->ccallback(ts, event, tstamp, resolution);
|
ts->ccallback(ts, event, tstamp, resolution);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&timer->lock, flags);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(snd_timer_notify);
|
EXPORT_SYMBOL(snd_timer_notify);
|
||||||
|
|
||||||
|
@ -1248,7 +1201,7 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
|
||||||
struct snd_timer_instance *ti;
|
struct snd_timer_instance *ti;
|
||||||
unsigned long resolution;
|
unsigned long resolution;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
||||||
if (timer->card && timer->card->shutdown)
|
if (timer->card && timer->card->shutdown)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1270,9 +1223,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
|
||||||
timer->tmr_device, timer->tmr_subdevice);
|
timer->tmr_device, timer->tmr_subdevice);
|
||||||
}
|
}
|
||||||
snd_iprintf(buffer, "%s :", timer->name);
|
snd_iprintf(buffer, "%s :", timer->name);
|
||||||
spin_lock_irq(&timer->lock);
|
scoped_guard(spinlock_irq, &timer->lock)
|
||||||
resolution = snd_timer_hw_resolution(timer);
|
resolution = snd_timer_hw_resolution(timer);
|
||||||
spin_unlock_irq(&timer->lock);
|
|
||||||
if (resolution)
|
if (resolution)
|
||||||
snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
|
snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
|
||||||
resolution / 1000,
|
resolution / 1000,
|
||||||
|
@ -1288,7 +1240,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
|
||||||
SNDRV_TIMER_IFLG_RUNNING))
|
SNDRV_TIMER_IFLG_RUNNING))
|
||||||
? "running" : "stopped");
|
? "running" : "stopped");
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_info_entry *snd_timer_proc_entry;
|
static struct snd_info_entry *snd_timer_proc_entry;
|
||||||
|
@ -1329,7 +1280,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
|
||||||
struct snd_timer_read *r;
|
struct snd_timer_read *r;
|
||||||
int prev;
|
int prev;
|
||||||
|
|
||||||
spin_lock(&tu->qlock);
|
guard(spinlock)(&tu->qlock);
|
||||||
if (tu->qused > 0) {
|
if (tu->qused > 0) {
|
||||||
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
|
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
|
||||||
r = &tu->queue[prev];
|
r = &tu->queue[prev];
|
||||||
|
@ -1348,7 +1299,6 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
|
||||||
tu->qused++;
|
tu->qused++;
|
||||||
}
|
}
|
||||||
__wake:
|
__wake:
|
||||||
spin_unlock(&tu->qlock);
|
|
||||||
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
|
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
|
||||||
wake_up(&tu->qchange_sleep);
|
wake_up(&tu->qchange_sleep);
|
||||||
}
|
}
|
||||||
|
@ -1372,7 +1322,6 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
|
||||||
{
|
{
|
||||||
struct snd_timer_user *tu = timeri->callback_data;
|
struct snd_timer_user *tu = timeri->callback_data;
|
||||||
struct snd_timer_tread64 r1;
|
struct snd_timer_tread64 r1;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (event >= SNDRV_TIMER_EVENT_START &&
|
if (event >= SNDRV_TIMER_EVENT_START &&
|
||||||
event <= SNDRV_TIMER_EVENT_PAUSE)
|
event <= SNDRV_TIMER_EVENT_PAUSE)
|
||||||
|
@ -1384,9 +1333,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
|
||||||
r1.tstamp_sec = tstamp->tv_sec;
|
r1.tstamp_sec = tstamp->tv_sec;
|
||||||
r1.tstamp_nsec = tstamp->tv_nsec;
|
r1.tstamp_nsec = tstamp->tv_nsec;
|
||||||
r1.val = resolution;
|
r1.val = resolution;
|
||||||
spin_lock_irqsave(&tu->qlock, flags);
|
scoped_guard(spinlock_irqsave, &tu->qlock)
|
||||||
snd_timer_user_append_to_tqueue(tu, &r1);
|
snd_timer_user_append_to_tqueue(tu, &r1);
|
||||||
spin_unlock_irqrestore(&tu->qlock, flags);
|
|
||||||
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
|
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
|
||||||
wake_up(&tu->qchange_sleep);
|
wake_up(&tu->qchange_sleep);
|
||||||
}
|
}
|
||||||
|
@ -1410,51 +1358,48 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
|
||||||
|
|
||||||
memset(&r1, 0, sizeof(r1));
|
memset(&r1, 0, sizeof(r1));
|
||||||
memset(&tstamp, 0, sizeof(tstamp));
|
memset(&tstamp, 0, sizeof(tstamp));
|
||||||
spin_lock(&tu->qlock);
|
scoped_guard(spinlock, &tu->qlock) {
|
||||||
if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
|
if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
|
||||||
(1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
|
(1 << SNDRV_TIMER_EVENT_TICK))) == 0)
|
||||||
spin_unlock(&tu->qlock);
|
return;
|
||||||
return;
|
if (tu->last_resolution != resolution || ticks > 0) {
|
||||||
}
|
if (timer_tstamp_monotonic)
|
||||||
if (tu->last_resolution != resolution || ticks > 0) {
|
ktime_get_ts64(&tstamp);
|
||||||
if (timer_tstamp_monotonic)
|
else
|
||||||
ktime_get_ts64(&tstamp);
|
ktime_get_real_ts64(&tstamp);
|
||||||
else
|
}
|
||||||
ktime_get_real_ts64(&tstamp);
|
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
|
||||||
}
|
tu->last_resolution != resolution) {
|
||||||
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
|
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
|
||||||
tu->last_resolution != resolution) {
|
r1.tstamp_sec = tstamp.tv_sec;
|
||||||
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
|
r1.tstamp_nsec = tstamp.tv_nsec;
|
||||||
|
r1.val = resolution;
|
||||||
|
snd_timer_user_append_to_tqueue(tu, &r1);
|
||||||
|
tu->last_resolution = resolution;
|
||||||
|
append++;
|
||||||
|
}
|
||||||
|
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
|
||||||
|
break;
|
||||||
|
if (ticks == 0)
|
||||||
|
break;
|
||||||
|
if (tu->qused > 0) {
|
||||||
|
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
|
||||||
|
r = &tu->tqueue[prev];
|
||||||
|
if (r->event == SNDRV_TIMER_EVENT_TICK) {
|
||||||
|
r->tstamp_sec = tstamp.tv_sec;
|
||||||
|
r->tstamp_nsec = tstamp.tv_nsec;
|
||||||
|
r->val += ticks;
|
||||||
|
append++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r1.event = SNDRV_TIMER_EVENT_TICK;
|
||||||
r1.tstamp_sec = tstamp.tv_sec;
|
r1.tstamp_sec = tstamp.tv_sec;
|
||||||
r1.tstamp_nsec = tstamp.tv_nsec;
|
r1.tstamp_nsec = tstamp.tv_nsec;
|
||||||
r1.val = resolution;
|
r1.val = ticks;
|
||||||
snd_timer_user_append_to_tqueue(tu, &r1);
|
snd_timer_user_append_to_tqueue(tu, &r1);
|
||||||
tu->last_resolution = resolution;
|
|
||||||
append++;
|
append++;
|
||||||
}
|
}
|
||||||
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
|
|
||||||
goto __wake;
|
|
||||||
if (ticks == 0)
|
|
||||||
goto __wake;
|
|
||||||
if (tu->qused > 0) {
|
|
||||||
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
|
|
||||||
r = &tu->tqueue[prev];
|
|
||||||
if (r->event == SNDRV_TIMER_EVENT_TICK) {
|
|
||||||
r->tstamp_sec = tstamp.tv_sec;
|
|
||||||
r->tstamp_nsec = tstamp.tv_nsec;
|
|
||||||
r->val += ticks;
|
|
||||||
append++;
|
|
||||||
goto __wake;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r1.event = SNDRV_TIMER_EVENT_TICK;
|
|
||||||
r1.tstamp_sec = tstamp.tv_sec;
|
|
||||||
r1.tstamp_nsec = tstamp.tv_nsec;
|
|
||||||
r1.val = ticks;
|
|
||||||
snd_timer_user_append_to_tqueue(tu, &r1);
|
|
||||||
append++;
|
|
||||||
__wake:
|
|
||||||
spin_unlock(&tu->qlock);
|
|
||||||
if (append == 0)
|
if (append == 0)
|
||||||
return;
|
return;
|
||||||
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
|
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
|
||||||
|
@ -1476,14 +1421,13 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(&tu->qlock);
|
guard(spinlock_irq)(&tu->qlock);
|
||||||
kfree(tu->queue);
|
kfree(tu->queue);
|
||||||
kfree(tu->tqueue);
|
kfree(tu->tqueue);
|
||||||
tu->queue_size = size;
|
tu->queue_size = size;
|
||||||
tu->queue = queue;
|
tu->queue = queue;
|
||||||
tu->tqueue = tqueue;
|
tu->tqueue = tqueue;
|
||||||
tu->qhead = tu->qtail = tu->qused = 0;
|
tu->qhead = tu->qtail = tu->qused = 0;
|
||||||
spin_unlock_irq(&tu->qlock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1519,12 +1463,12 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
|
||||||
if (file->private_data) {
|
if (file->private_data) {
|
||||||
tu = file->private_data;
|
tu = file->private_data;
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
mutex_lock(&tu->ioctl_lock);
|
scoped_guard(mutex, &tu->ioctl_lock) {
|
||||||
if (tu->timeri) {
|
if (tu->timeri) {
|
||||||
snd_timer_close(tu->timeri);
|
snd_timer_close(tu->timeri);
|
||||||
snd_timer_instance_free(tu->timeri);
|
snd_timer_instance_free(tu->timeri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&tu->ioctl_lock);
|
|
||||||
snd_fasync_free(tu->fasync);
|
snd_fasync_free(tu->fasync);
|
||||||
kfree(tu->queue);
|
kfree(tu->queue);
|
||||||
kfree(tu->tqueue);
|
kfree(tu->tqueue);
|
||||||
|
@ -1559,7 +1503,7 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
|
||||||
|
|
||||||
if (copy_from_user(&id, _tid, sizeof(id)))
|
if (copy_from_user(&id, _tid, sizeof(id)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
if (id.dev_class < 0) { /* first item */
|
if (id.dev_class < 0) { /* first item */
|
||||||
if (list_empty(&snd_timer_list))
|
if (list_empty(&snd_timer_list))
|
||||||
snd_timer_user_zero_id(&id);
|
snd_timer_user_zero_id(&id);
|
||||||
|
@ -1636,7 +1580,6 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
|
||||||
snd_timer_user_zero_id(&id);
|
snd_timer_user_zero_id(&id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
if (copy_to_user(_tid, &id, sizeof(*_tid)))
|
if (copy_to_user(_tid, &id, sizeof(*_tid)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1645,70 +1588,54 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
|
||||||
static int snd_timer_user_ginfo(struct file *file,
|
static int snd_timer_user_ginfo(struct file *file,
|
||||||
struct snd_timer_ginfo __user *_ginfo)
|
struct snd_timer_ginfo __user *_ginfo)
|
||||||
{
|
{
|
||||||
struct snd_timer_ginfo *ginfo;
|
struct snd_timer_ginfo *ginfo __free(kfree) = NULL;
|
||||||
struct snd_timer_id tid;
|
struct snd_timer_id tid;
|
||||||
struct snd_timer *t;
|
struct snd_timer *t;
|
||||||
struct list_head *p;
|
struct list_head *p;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
ginfo = memdup_user(_ginfo, sizeof(*ginfo));
|
ginfo = memdup_user(_ginfo, sizeof(*ginfo));
|
||||||
if (IS_ERR(ginfo))
|
if (IS_ERR(ginfo))
|
||||||
return PTR_ERR(ginfo);
|
return PTR_ERR(no_free_ptr(ginfo));
|
||||||
|
|
||||||
tid = ginfo->tid;
|
tid = ginfo->tid;
|
||||||
memset(ginfo, 0, sizeof(*ginfo));
|
memset(ginfo, 0, sizeof(*ginfo));
|
||||||
ginfo->tid = tid;
|
ginfo->tid = tid;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
t = snd_timer_find(&tid);
|
t = snd_timer_find(&tid);
|
||||||
if (t != NULL) {
|
if (!t)
|
||||||
ginfo->card = t->card ? t->card->number : -1;
|
return -ENODEV;
|
||||||
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
|
ginfo->card = t->card ? t->card->number : -1;
|
||||||
ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
|
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
|
||||||
strscpy(ginfo->id, t->id, sizeof(ginfo->id));
|
ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
|
||||||
strscpy(ginfo->name, t->name, sizeof(ginfo->name));
|
strscpy(ginfo->id, t->id, sizeof(ginfo->id));
|
||||||
spin_lock_irq(&t->lock);
|
strscpy(ginfo->name, t->name, sizeof(ginfo->name));
|
||||||
|
scoped_guard(spinlock_irq, &t->lock)
|
||||||
ginfo->resolution = snd_timer_hw_resolution(t);
|
ginfo->resolution = snd_timer_hw_resolution(t);
|
||||||
spin_unlock_irq(&t->lock);
|
if (t->hw.resolution_min > 0) {
|
||||||
if (t->hw.resolution_min > 0) {
|
ginfo->resolution_min = t->hw.resolution_min;
|
||||||
ginfo->resolution_min = t->hw.resolution_min;
|
ginfo->resolution_max = t->hw.resolution_max;
|
||||||
ginfo->resolution_max = t->hw.resolution_max;
|
|
||||||
}
|
|
||||||
list_for_each(p, &t->open_list_head) {
|
|
||||||
ginfo->clients++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = -ENODEV;
|
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
list_for_each(p, &t->open_list_head) {
|
||||||
if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
|
ginfo->clients++;
|
||||||
err = -EFAULT;
|
}
|
||||||
kfree(ginfo);
|
if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
|
||||||
return err;
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int timer_set_gparams(struct snd_timer_gparams *gparams)
|
static int timer_set_gparams(struct snd_timer_gparams *gparams)
|
||||||
{
|
{
|
||||||
struct snd_timer *t;
|
struct snd_timer *t;
|
||||||
int err;
|
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
t = snd_timer_find(&gparams->tid);
|
t = snd_timer_find(&gparams->tid);
|
||||||
if (!t) {
|
if (!t)
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto _error;
|
if (!list_empty(&t->open_list_head))
|
||||||
}
|
return -EBUSY;
|
||||||
if (!list_empty(&t->open_list_head)) {
|
if (!t->hw.set_period)
|
||||||
err = -EBUSY;
|
return -ENOSYS;
|
||||||
goto _error;
|
return t->hw.set_period(t, gparams->period_num, gparams->period_den);
|
||||||
}
|
|
||||||
if (!t->hw.set_period) {
|
|
||||||
err = -ENOSYS;
|
|
||||||
goto _error;
|
|
||||||
}
|
|
||||||
err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
|
|
||||||
_error:
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_timer_user_gparams(struct file *file,
|
static int snd_timer_user_gparams(struct file *file,
|
||||||
|
@ -1734,10 +1661,10 @@ static int snd_timer_user_gstatus(struct file *file,
|
||||||
tid = gstatus.tid;
|
tid = gstatus.tid;
|
||||||
memset(&gstatus, 0, sizeof(gstatus));
|
memset(&gstatus, 0, sizeof(gstatus));
|
||||||
gstatus.tid = tid;
|
gstatus.tid = tid;
|
||||||
mutex_lock(®ister_mutex);
|
guard(mutex)(®ister_mutex);
|
||||||
t = snd_timer_find(&tid);
|
t = snd_timer_find(&tid);
|
||||||
if (t != NULL) {
|
if (t != NULL) {
|
||||||
spin_lock_irq(&t->lock);
|
guard(spinlock_irq)(&t->lock);
|
||||||
gstatus.resolution = snd_timer_hw_resolution(t);
|
gstatus.resolution = snd_timer_hw_resolution(t);
|
||||||
if (t->hw.precise_resolution) {
|
if (t->hw.precise_resolution) {
|
||||||
t->hw.precise_resolution(t, &gstatus.resolution_num,
|
t->hw.precise_resolution(t, &gstatus.resolution_num,
|
||||||
|
@ -1746,11 +1673,9 @@ static int snd_timer_user_gstatus(struct file *file,
|
||||||
gstatus.resolution_num = gstatus.resolution;
|
gstatus.resolution_num = gstatus.resolution;
|
||||||
gstatus.resolution_den = 1000000000uL;
|
gstatus.resolution_den = 1000000000uL;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&t->lock);
|
|
||||||
} else {
|
} else {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
|
if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
return err;
|
return err;
|
||||||
|
@ -1804,9 +1729,8 @@ static int snd_timer_user_info(struct file *file,
|
||||||
struct snd_timer_info __user *_info)
|
struct snd_timer_info __user *_info)
|
||||||
{
|
{
|
||||||
struct snd_timer_user *tu;
|
struct snd_timer_user *tu;
|
||||||
struct snd_timer_info *info;
|
struct snd_timer_info *info __free(kfree) = NULL;
|
||||||
struct snd_timer *t;
|
struct snd_timer *t;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
tu = file->private_data;
|
tu = file->private_data;
|
||||||
if (!tu->timeri)
|
if (!tu->timeri)
|
||||||
|
@ -1823,13 +1747,11 @@ static int snd_timer_user_info(struct file *file,
|
||||||
info->flags |= SNDRV_TIMER_FLG_SLAVE;
|
info->flags |= SNDRV_TIMER_FLG_SLAVE;
|
||||||
strscpy(info->id, t->id, sizeof(info->id));
|
strscpy(info->id, t->id, sizeof(info->id));
|
||||||
strscpy(info->name, t->name, sizeof(info->name));
|
strscpy(info->name, t->name, sizeof(info->name));
|
||||||
spin_lock_irq(&t->lock);
|
scoped_guard(spinlock_irq, &t->lock)
|
||||||
info->resolution = snd_timer_hw_resolution(t);
|
info->resolution = snd_timer_hw_resolution(t);
|
||||||
spin_unlock_irq(&t->lock);
|
|
||||||
if (copy_to_user(_info, info, sizeof(*_info)))
|
if (copy_to_user(_info, info, sizeof(*_info)))
|
||||||
err = -EFAULT;
|
return -EFAULT;
|
||||||
kfree(info);
|
return 0;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_timer_user_params(struct file *file,
|
static int snd_timer_user_params(struct file *file,
|
||||||
|
@ -1887,45 +1809,47 @@ static int snd_timer_user_params(struct file *file,
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
snd_timer_stop(tu->timeri);
|
snd_timer_stop(tu->timeri);
|
||||||
spin_lock_irq(&t->lock);
|
scoped_guard(spinlock_irq, &t->lock) {
|
||||||
tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
|
tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
|
||||||
SNDRV_TIMER_IFLG_EXCLUSIVE|
|
SNDRV_TIMER_IFLG_EXCLUSIVE|
|
||||||
SNDRV_TIMER_IFLG_EARLY_EVENT);
|
SNDRV_TIMER_IFLG_EARLY_EVENT);
|
||||||
if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
|
if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
|
||||||
tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
|
tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
|
||||||
if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
|
if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
|
||||||
tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
|
tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
|
||||||
if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
|
if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
|
||||||
tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
|
tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
|
||||||
spin_unlock_irq(&t->lock);
|
}
|
||||||
if (params.queue_size > 0 &&
|
if (params.queue_size > 0 &&
|
||||||
(unsigned int)tu->queue_size != params.queue_size) {
|
(unsigned int)tu->queue_size != params.queue_size) {
|
||||||
err = realloc_user_queue(tu, params.queue_size);
|
err = realloc_user_queue(tu, params.queue_size);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
spin_lock_irq(&tu->qlock);
|
scoped_guard(spinlock_irq, &tu->qlock) {
|
||||||
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_tread64 tread;
|
struct snd_timer_tread64 tread;
|
||||||
memset(&tread, 0, sizeof(tread));
|
|
||||||
tread.event = SNDRV_TIMER_EVENT_EARLY;
|
memset(&tread, 0, sizeof(tread));
|
||||||
tread.tstamp_sec = 0;
|
tread.event = SNDRV_TIMER_EVENT_EARLY;
|
||||||
tread.tstamp_nsec = 0;
|
tread.tstamp_sec = 0;
|
||||||
tread.val = 0;
|
tread.tstamp_nsec = 0;
|
||||||
snd_timer_user_append_to_tqueue(tu, &tread);
|
tread.val = 0;
|
||||||
} else {
|
snd_timer_user_append_to_tqueue(tu, &tread);
|
||||||
struct snd_timer_read *r = &tu->queue[0];
|
} else {
|
||||||
r->resolution = 0;
|
struct snd_timer_read *r = &tu->queue[0];
|
||||||
r->ticks = 0;
|
|
||||||
tu->qused++;
|
r->resolution = 0;
|
||||||
tu->qtail++;
|
r->ticks = 0;
|
||||||
|
tu->qused++;
|
||||||
|
tu->qtail++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
tu->filter = params.filter;
|
||||||
|
tu->ticks = params.ticks;
|
||||||
}
|
}
|
||||||
tu->filter = params.filter;
|
|
||||||
tu->ticks = params.ticks;
|
|
||||||
spin_unlock_irq(&tu->qlock);
|
|
||||||
err = 0;
|
err = 0;
|
||||||
_end:
|
_end:
|
||||||
if (copy_to_user(_params, ¶ms, sizeof(params)))
|
if (copy_to_user(_params, ¶ms, sizeof(params)))
|
||||||
|
@ -1948,9 +1872,8 @@ static int snd_timer_user_status32(struct file *file,
|
||||||
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;
|
||||||
spin_lock_irq(&tu->qlock);
|
scoped_guard(spinlock_irq, &tu->qlock)
|
||||||
status.queue = tu->qused;
|
status.queue = tu->qused;
|
||||||
spin_unlock_irq(&tu->qlock);
|
|
||||||
if (copy_to_user(_status, &status, sizeof(status)))
|
if (copy_to_user(_status, &status, sizeof(status)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1971,9 +1894,8 @@ static int snd_timer_user_status64(struct file *file,
|
||||||
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;
|
||||||
spin_lock_irq(&tu->qlock);
|
scoped_guard(spinlock_irq, &tu->qlock)
|
||||||
status.queue = tu->qused;
|
status.queue = tu->qused;
|
||||||
spin_unlock_irq(&tu->qlock);
|
|
||||||
if (copy_to_user(_status, &status, sizeof(status)))
|
if (copy_to_user(_status, &status, sizeof(status)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2131,12 +2053,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
struct snd_timer_user *tu = file->private_data;
|
struct snd_timer_user *tu = file->private_data;
|
||||||
long ret;
|
|
||||||
|
|
||||||
mutex_lock(&tu->ioctl_lock);
|
guard(mutex)(&tu->ioctl_lock);
|
||||||
ret = __snd_timer_user_ioctl(file, cmd, arg, false);
|
return __snd_timer_user_ioctl(file, cmd, arg, false);
|
||||||
mutex_unlock(&tu->ioctl_lock);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_timer_user_fasync(int fd, struct file * file, int on)
|
static int snd_timer_user_fasync(int fd, struct file * file, int on)
|
||||||
|
@ -2263,12 +2182,11 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
|
||||||
poll_wait(file, &tu->qchange_sleep, wait);
|
poll_wait(file, &tu->qchange_sleep, wait);
|
||||||
|
|
||||||
mask = 0;
|
mask = 0;
|
||||||
spin_lock_irq(&tu->qlock);
|
guard(spinlock_irq)(&tu->qlock);
|
||||||
if (tu->qused)
|
if (tu->qused)
|
||||||
mask |= EPOLLIN | EPOLLRDNORM;
|
mask |= EPOLLIN | EPOLLRDNORM;
|
||||||
if (tu->disconnected)
|
if (tu->disconnected)
|
||||||
mask |= EPOLLERR;
|
mask |= EPOLLERR;
|
||||||
spin_unlock_irq(&tu->qlock);
|
|
||||||
|
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue