sound updates for 6.5-rc1

Lots of changes as usual, but the only significant stuff in ALSA core
 part is the MIDI 2.0 support, while ASoC core kept receiving the code
 refactoring.  The majority of changes are seen rather in device
 drivers, and quite a few new drivers can be found there.
 
 Here we go, some highlights:
 
 ALSA and ASoC Core:
 - Support of MIDI 2.0 devices: rawmidi and sequencer API have been
   extended for the support of the new UMP (Universal MIDI Packet)
   protocol, USB audio driver got the USB MIDI 2.0 interface support
 - Continued refactoring around ASoC DAI links and the ordering of
   trigger callbacks
 - PCM ABI extension for better drain support
 
 ASoC Drivers:
 - Conversions of many drivers to use maple tree based caches
 - Everlasting improvement works on ASoC Intel drivers
 - Compressed audio support for Qualcomm
 - Support for AMD SoundWire, Analog Devices SSM3515, Google Chameleon,
   Ingenic X1000, Intel systems with various CODECs, Loongson
   platforms, Maxim MAX98388, Mediatek MT8188, Nuvoton NAU8825C, NXP
   platforms with NAU8822, Qualcomm WSA884x, StarFive JH7110, Texas
   Instruments TAS2781
 
 HD-audio:
 - Quirks for HP and ASUS machines
 - CS35L41 HD-audio codec fixes
 - Loongson HD-audio support
 
 Misc:
 - A new virtual PCM test driver for kselftests
 - Continued refactoring and improvements on the legacy emu10k1 driver
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmScAA8OHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE8rGg/+MZtQVa/uPAS914pTaBbwr0JTmaZwnroCYAGZ
 VF708hXDoqdJMXkVyBxogpBGdydwCCEIPZ6TKslslIjxz1eojATN1BiAlYDSrTOL
 TYORARXJ+HLHK8/okCucIAl7A1CNxRHBUfSqgN7N6OWfYY/Rd8JL6mIuL8M0rPkT
 dAN219q/+GVMckiUVVSo78SRZL93S6TiQkcomeA3SoB3ycGCkaDD9Leb4vwr6iPa
 Yytcf/DWWD5plEEZFVzuyT1KTyi3HhcVZYF29QaoZaSkNIBwUJV7IObz+zJTs5BC
 /CgudWbQ/uhgiOucKNId+7sG04ehTJgKDRVZ6ArQt2p0aLC8KZKB+ytt9QHdCPlZ
 czQX86PjQ4DeivvTaoFvqjDfDFosSWkHWYxqA0fEEVd7p+6ZrhmZdmtidFxF5/Oq
 Dk0AFRwc71w4/OZU83lYv2BLXaqGVZ8ptmeEILaAJoxkpWwomHYW5nYFZ2Pnb8h3
 Yl9Q0f82uFNqfPcGJLSpqJ/Or9BVI2qQU75gHHXIe1GXUAaHkLLRPfpzQtGjkPap
 KC0+VMGEWy0y0mdytt0ecIkz2Dv/RvlahTr5jHEXSb3r93H6nRTTjxzyLvXHoPy0
 4iVf1g7VPL69V3vZ6AlkPdMo/yV7q/72bP0ZJ6CgVtdOZO4Q1N8ItwFt8FN0nAcu
 FeYq8pg=
 =GuXv
 -----END PGP SIGNATURE-----

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

Pull sound updates from Takashi Iwai:
 "Lots of changes as usual, but the only significant stuff in ALSA core
  part is the MIDI 2.0 support, while ASoC core kept receiving the code
  refactoring. The majority of changes are seen rather in device
  drivers, and quite a few new drivers can be found there.

  Here we go, some highlights:

  ALSA and ASoC Core:
   - Support of MIDI 2.0 devices: rawmidi and sequencer API have been
     extended for the support of the new UMP (Universal MIDI Packet)
     protocol, USB audio driver got the USB MIDI 2.0 interface support
   - Continued refactoring around ASoC DAI links and the ordering of
     trigger callbacks
   - PCM ABI extension for better drain support

  ASoC Drivers:
   - Conversions of many drivers to use maple tree based caches
   - Everlasting improvement works on ASoC Intel drivers
   - Compressed audio support for Qualcomm
   - Support for AMD SoundWire, Analog Devices SSM3515, Google
     Chameleon, Ingenic X1000, Intel systems with various CODECs,
     Loongson platforms, Maxim MAX98388, Mediatek MT8188, Nuvoton
     NAU8825C, NXP platforms with NAU8822, Qualcomm WSA884x, StarFive
     JH7110, Texas Instruments TAS2781

  HD-audio:
   - Quirks for HP and ASUS machines
   - CS35L41 HD-audio codec fixes
   - Loongson HD-audio support

  Misc:
   - A new virtual PCM test driver for kselftests
   - Continued refactoring and improvements on the legacy emu10k1
     driver"

* tag 'sound-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (556 commits)
  ALSA: hda/realtek: Enable mute/micmute LEDs and limit mic boost on EliteBook
  ASoC: hdmi-codec: fix channel info for compressed formats
  ALSA: pcm: fix ELD constraints for (E)AC3, DTS(-HD) and MLP formats
  ASoC: core: Always store of_node when getting DAI link component
  ASoC: tas2781: Fix error code in tas2781_load_calibration()
  ASoC: amd: update pm_runtime enable sequence
  ALSA: ump: Export MIDI1 / UMP conversion helpers
  ASoC: tas2781: fix Kconfig dependencies
  ASoC: amd: acp: remove acp poweroff function
  ASoC: amd: acp: clear pdm dma interrupt mask
  ASoC: codecs: max98090: Allow dsp_a mode
  ASoC: qcom: common: add default jack dapm pins
  ASoC: loongson: fix address space confusion
  ASoC: dt-bindings: microchip,sama7g5-pdmc: Simplify "microchip,mic-pos" constraints
  ASoC: tegra: Remove stale comments in AHUB
  ASoC: tegra: Use normal system sleep for ASRC
  ALSA: hda/realtek: Add quirks for ROG ALLY CS35l41 audio
  ASoC: fsl-asoc-card: Allow passing the number of slots in use
  ASoC: codecs: wsa884x: Add WSA884x family of speakers
  ASoC: dt-bindings: qcom,wsa8840: Add WSA884x family of speakers
  ...
This commit is contained in:
Linus Torvalds 2023-06-29 10:46:47 -07:00
commit f8824e151f
607 changed files with 33573 additions and 7110 deletions

View File

@ -0,0 +1,79 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/adi,max98388.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices MAX98388 Speaker Amplifier
maintainers:
- Ryan Lee <ryans.lee@analog.com>
description:
The MAX98388 is a mono Class-D speaker amplifier with I/V feedback.
The device provides a PCM interface for audio data and a standard
I2C interface for control data communication.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- adi,max98388
reg:
maxItems: 1
'#sound-dai-cells':
const: 0
adi,vmon-slot-no:
description: slot number of the voltage feedback monitor
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
default: 0
adi,imon-slot-no:
description: slot number of the current feedback monitor
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
default: 1
adi,interleave-mode:
description:
For cases where a single combined channel for the I/V feedback data
is not sufficient, the device can also be configured to share
a single data output channel on alternating frames.
In this configuration, the current and voltage data will be frame
interleaved on a single output channel.
type: boolean
reset-gpios:
maxItems: 1
required:
- compatible
- reg
- '#sound-dai-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
max98388: amplifier@39 {
compatible = "adi,max98388";
reg = <0x39>;
#sound-dai-cells = <0>;
adi,vmon-slot-no = <0>;
adi,imon-slot-no = <1>;
adi,interleave-mode;
reset-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
};
};

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/adi,ssm2518.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices SSM2518 audio amplifier
maintainers:
- Lars-Peter Clausen <lars@metafoo.de>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: adi,ssm2518
reg:
maxItems: 1
description: |
I2C address of the device. This will either be 0x34 (ADDR pin low)
or 0x35 (ADDR pin high)
gpios:
maxItems: 1
description: |
GPIO connected to the nSD pin. If the property is not present
it is assumed that the nSD pin is hardwired to always on.
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@34 {
compatible = "adi,ssm2518";
reg = <0x34>;
gpios = <&gpio 5 0>;
};
};

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/adi,ssm3515.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices SSM3515 Audio Amplifier
maintainers:
- Martin Povišer <povik+lin@cutebit.org>
description: |
SSM3515 is a mono Class-D audio amplifier with digital input.
https://www.analog.com/media/en/technical-documentation/data-sheets/SSM3515.pdf
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- adi,ssm3515
reg:
maxItems: 1
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@14 {
compatible = "adi,ssm3515";
reg = <0x14>;
#sound-dai-cells = <0>;
sound-name-prefix = "Left Tweeter";
};
};

View File

@ -24,7 +24,11 @@ properties:
connection's sink, the second being the connection's source.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
widgets:
description: User specified audio sound widgets.
description: |
User specified audio sound widgets.
Each entry is a pair of strings, the first being the type of
widget ("Microphone", "Line", "Headphone", "Speaker"), the
second being the machine specific name for the widget.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
convert-rate:
$ref: /schemas/sound/dai-params.yaml#/$defs/dai-sample-rate

View File

@ -62,7 +62,7 @@ patternProperties:
GPIO pin direction. Valid only when 'gpio-ctrl' is 1
0 = Output
1 = Input
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 1
default: 1
@ -71,7 +71,7 @@ patternProperties:
GPIO level. Valid only when 'gpio-ctrl' is 1 and 'gpio-dir' is 0
0 = Low
1 = High
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 1
default: 0
@ -80,7 +80,7 @@ patternProperties:
GPIO level. Valid only when 'gpio-ctrl' is 1 and 'gpio-dir' is 0
0 = CMOS
1 = Open Drain
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 1
default: 0
@ -90,7 +90,7 @@ patternProperties:
and 'gpio-dir' is 0
0 = Non-inverted, Active High
1 = Inverted, Active Low
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 1
default: 0
@ -114,7 +114,7 @@ patternProperties:
0 = High impedance input
1 = Pin acts as a GPIO, direction controlled by 'gpio-dir'
2-7 = Reserved
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
default: 0

View File

@ -44,6 +44,10 @@ properties:
VAHP-supply:
description: phandle to voltage regulator of headphone
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
@ -69,6 +73,13 @@ examples:
VA-supply = <&reg_audio>;
VAHP-supply = <&reg_audio>;
reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
/* assume audio-graph */
port {
cpu_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
};
...

View File

@ -1,112 +0,0 @@
Dialog Semiconductor DA7219 Audio Codec bindings
DA7219 is an audio codec with advanced accessory detect features.
======
Required properties:
- compatible : Should be "dlg,da7219"
- reg: Specifies the I2C slave address
- interrupts : IRQ line info for DA7219.
(See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
further information relating to interrupt properties)
- VDD-supply: VDD power supply for the device
- VDDMIC-supply: VDDMIC power supply for the device
- VDDIO-supply: VDDIO power supply for the device
(See Documentation/devicetree/bindings/regulator/regulator.txt for further
information relating to regulators)
Optional properties:
- interrupt-names : Name associated with interrupt line. Should be "wakeup" if
interrupt is to be used to wake system, otherwise "irq" should be used.
- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
- #clock-cells : Should be set to '<1>', two clock sources provided;
- clock-output-names : Names given for DAI clock outputs (WCLK & BCLK);
- clocks : phandle and clock specifier for codec MCLK.
- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
- dlg,micbias-lvl : Voltage (mV) for Mic Bias
[<1600>, <1800>, <2000>, <2200>, <2400>, <2600>]
- dlg,mic-amp-in-sel : Mic input source type
["diff", "se_p", "se_n"]
Deprecated properties:
- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
(LDO unavailable in production HW so property no longer required).
======
Child node - 'da7219_aad':
Optional properties:
- dlg,micbias-pulse-lvl : Mic bias higher voltage pulse level (mV).
[<2800>, <2900>]
- dlg,micbias-pulse-time : Mic bias higher voltage pulse duration (ms)
- dlg,btn-cfg : Periodic button press measurements for 4-pole jack (ms)
[<2>, <5>, <10>, <50>, <100>, <200>, <500>]
- dlg,mic-det-thr : Impedance threshold for mic detection measurement (Ohms)
[<200>, <500>, <750>, <1000>]
- dlg,jack-ins-deb : Debounce time for jack insertion (ms)
[<5>, <10>, <20>, <50>, <100>, <200>, <500>, <1000>]
- dlg,jack-det-rate: Jack type detection latency (3/4 pole)
["32ms_64ms", "64ms_128ms", "128ms_256ms", "256ms_512ms"]
- dlg,jack-rem-deb : Debounce time for jack removal (ms)
[<1>, <5>, <10>, <20>]
- dlg,a-d-btn-thr : Impedance threshold between buttons A and D
[0x0 - 0xFF]
- dlg,d-b-btn-thr : Impedance threshold between buttons D and B
[0x0 - 0xFF]
- dlg,b-c-btn-thr : Impedance threshold between buttons B and C
[0x0 - 0xFF]
- dlg,c-mic-btn-thr : Impedance threshold between button C and Mic
[0x0 - 0xFF]
- dlg,btn-avg : Number of 8-bit readings for averaged button measurement
[<1>, <2>, <4>, <8>]
- dlg,adc-1bit-rpt : Repeat count for 1-bit button measurement
[<1>, <2>, <4>, <8>]
======
Example:
codec: da7219@1a {
compatible = "dlg,da7219";
reg = <0x1a>;
interrupt-parent = <&gpio6>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
VDD-supply = <&reg_audio>;
VDDMIC-supply = <&reg_audio>;
VDDIO-supply = <&reg_audio>;
#clock-cells = <1>;
clock-output-names = "dai-wclk", "dai-bclk";
clocks = <&clks 201>;
clock-names = "mclk";
dlg,ldo-lvl = <1200>;
dlg,micbias-lvl = <2600>;
dlg,mic-amp-in-sel = "diff";
da7219_aad {
dlg,btn-cfg = <50>;
dlg,mic-det-thr = <500>;
dlg,jack-ins-deb = <20>;
dlg,jack-det-rate = "32ms_64ms";
dlg,jack-rem-deb = <1>;
dlg,a-d-btn-thr = <0xa>;
dlg,d-b-btn-thr = <0x16>;
dlg,b-c-btn-thr = <0x21>;
dlg,c-mic-btn-thr = <0x3E>;
dlg,btn-avg = <4>;
dlg,adc-1bit-rpt = <1>;
};
};

View File

@ -0,0 +1,237 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/dialog,da7219.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dialog Semiconductor DA7219 Audio Codec
maintainers:
- David Rau <David.Rau.opensource@dm.renesas.com>
description:
The DA7219 is an ultra low-power audio codec with
in-built advanced accessory detection (AAD) for mobile
computing and accessory applications, which supports
sample rates up to 96 kHz at 24-bit resolution.
properties:
compatible:
const: dlg,da7219
reg:
maxItems: 1
interrupts:
maxItems: 1
VDD-supply:
description:
VDD power supply for the device.
VDDMIC-supply:
description:
VDDMIC power supply for the device.
VDDIO-supply:
description:
VDDIO power supply for the device.
interrupt-names:
description:
Should be "wakeup" if interrupt is to be used to wake system,
otherwise "irq" should be used.
enum:
- wakeup
- irq
wakeup-source:
type: boolean
description:
Flag to indicate this device can wake system (suspend/resume).
"#clock-cells":
const: 1
clock-output-names:
minItems: 2
maxItems: 2
description:
Name given for DAI WCLK and BCLK outputs.
clocks:
maxItems: 1
description:
phandle and clock specifier for codec MCLK.
clock-names:
const: mclk
dlg,micbias-lvl:
enum: [1600, 1800, 2000, 2200, 2400, 2600]
description:
Voltage (mV) for Mic Bias.
$ref: /schemas/types.yaml#/definitions/uint32
dlg,mic-amp-in-sel:
enum: ["diff", "se_p", "se_n"]
description:
Mic input source type.
diff - Differential.
se_p - MIC_P.
Positive differential analog microphone input.
se_n - MIC_N.
Negative differential analog microphone input.
$ref: /schemas/types.yaml#/definitions/string
da7219_aad:
type: object
description:
Configuration of advanced accessory detection.
properties:
dlg,micbias-pulse-lvl:
enum: [2800, 2900]
description:
Mic bias higher voltage pulse level (mV).
$ref: /schemas/types.yaml#/definitions/uint32
dlg,micbias-pulse-time:
description:
Mic bias higher voltage pulse duration (ms).
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
dlg,btn-cfg:
enum: [2, 5, 10, 50, 100, 200, 500]
description:
Periodic button press measurements for 4-pole jack (ms).
$ref: /schemas/types.yaml#/definitions/uint32
dlg,mic-det-thr:
enum: [200, 500, 750, 1000]
description:
Impedance threshold for mic detection measurement (Ohms).
$ref: /schemas/types.yaml#/definitions/uint32
dlg,jack-ins-deb:
enum: [5, 10, 20, 50, 100, 200, 500, 1000]
description:
Debounce time for jack insertion (ms).
$ref: /schemas/types.yaml#/definitions/uint32
dlg,jack-ins-det-pty:
enum: ["low", "high"]
description:
Polarity for jack insertion detection.
$ref: /schemas/types.yaml#/definitions/string
dlg,jack-det-rate:
enum: ["32_64", "64_128", "128_256", "256_512"]
description:
Jack type (3/4 pole) detection latency (ms).
$ref: /schemas/types.yaml#/definitions/string
dlg,jack-rem-deb:
enum: [1, 5, 10, 20]
description:
Debounce time for jack removal (ms).
$ref: /schemas/types.yaml#/definitions/uint32
dlg,a-d-btn-thr:
description:
Impedance threshold between buttons A and D.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
dlg,d-b-btn-thr:
description:
Impedance threshold between buttons D and B.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
dlg,b-c-btn-thr:
description:
Impedance threshold between buttons B and C.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
dlg,c-mic-btn-thr:
description:
Impedance threshold between button C and Mic.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
dlg,btn-avg:
enum: [1, 2, 4, 8]
description:
Number of 8-bit readings for averaged button measurement.
$ref: /schemas/types.yaml#/definitions/uint32
dlg,adc-1bit-rpt:
enum: [1, 2, 4, 8]
description:
Repeat count for 1-bit button measurement.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- compatible
- reg
- interrupts
- VDD-supply
- VDDMIC-supply
- VDDIO-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec: da7219@1a {
compatible = "dlg,da7219";
reg = <0x1a>;
interrupt-parent = <&gpio6>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
VDD-supply = <&vdd_reg>;
VDDMIC-supply = <&vddmic_reg>;
VDDIO-supply = <&vddio_reg>;
#clock-cells = <1>;
clock-output-names = "da7219-dai-wclk", "da7219-dai-bclk";
clocks = <&clks 201>;
clock-names = "mclk";
dlg,micbias-lvl = <2600>;
dlg,mic-amp-in-sel = "diff";
da7219_aad {
dlg,btn-cfg = <50>;
dlg,mic-det-thr = <500>;
dlg,jack-ins-deb = <20>;
dlg,jack-ins-det-pty = "low";
dlg,jack-det-rate = "32_64";
dlg,jack-rem-deb = <1>;
dlg,a-d-btn-thr = <0xa>;
dlg,d-b-btn-thr = <0x16>;
dlg,b-c-btn-thr = <0x21>;
dlg,c-mic-btn-thr = <0x3E>;
dlg,btn-avg = <4>;
dlg,adc-1bit-rpt = <1>;
};
};
};

View File

@ -46,6 +46,8 @@ The compatible list for this generic sound card currently:
"fsl,imx-audio-wm8958"
"fsl,imx-audio-nau8822"
Required properties:
- compatible : Contains one of entries in the compatible list.

View File

@ -0,0 +1,31 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/google,chv3-codec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Google Chameleon v3 audio codec
maintainers:
- Paweł Anikiel <pan@semihalf.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: google,chv3-codec
"#sound-dai-cells":
const: 0
required:
- compatible
additionalProperties: false
examples:
- |
audio-codec {
compatible = "google,chv3-codec";
};

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/google,chv3-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Google Chameleon v3 I2S device
maintainers:
- Paweł Anikiel <pan@semihalf.com>
description: |
I2S device for the Google Chameleon v3. The device handles both RX
and TX using a producer/consumer ring buffer design.
properties:
compatible:
const: google,chv3-i2s
reg:
items:
- description: core registers
- description: irq registers
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2s@c0060300 {
compatible = "google,chv3-i2s";
reg = <0xc0060300 0x100>,
<0xc0060f00 0x10>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
};

View File

@ -74,7 +74,8 @@ patternProperties:
properties:
sound-dai:
maxItems: 1
minItems: 1
maxItems: 4
required:
- link-name

View File

@ -23,6 +23,7 @@ properties:
- ingenic,jz4760-i2s
- ingenic,jz4770-i2s
- ingenic,jz4780-i2s
- ingenic,x1000-i2s
- items:
- const: ingenic,jz4725b-i2s
- const: ingenic,jz4740-i2s

View File

@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/loongson,ls-audio-card.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Loongson 7axxx/2kxxx ASoC audio sound card driver
maintainers:
- Yingkun Meng <mengyingkun@loongson.cn>
description:
The binding describes the sound card present in loongson
7axxx/2kxxx platform. The sound card is an ASoC component
which uses Loongson I2S controller to transfer the audio data.
properties:
compatible:
const: loongson,ls-audio-card
model:
$ref: /schemas/types.yaml#/definitions/string
description: User specified audio sound card name
mclk-fs:
$ref: simple-card.yaml#/definitions/mclk-fs
cpu:
description: Holds subnode which indicates cpu dai.
type: object
additionalProperties: false
properties:
sound-dai:
maxItems: 1
required:
- sound-dai
codec:
description: Holds subnode which indicates codec dai.
type: object
additionalProperties: false
properties:
sound-dai:
maxItems: 1
required:
- sound-dai
required:
- compatible
- model
- mclk-fs
- cpu
- codec
additionalProperties: false
examples:
- |
sound {
compatible = "loongson,ls-audio-card";
model = "loongson-audio";
mclk-fs = <512>;
cpu {
sound-dai = <&i2s>;
};
codec {
sound-dai = <&es8323>;
};
};

View File

@ -29,6 +29,10 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the mediatek topckgen controller
mediatek,infracfg:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the mediatek infracfg controller
power-domains:
maxItems: 1
@ -52,6 +56,11 @@ properties:
- description: mux for i2si1_mck
- description: mux for i2si2_mck
- description: audio 26m clock
- description: audio pll1 divide 4
- description: audio pll2 divide 4
- description: clock divider for iec
- description: mux for a2sys clock
- description: mux for aud_iec
clock-names:
items:
@ -63,16 +72,21 @@ properties:
- const: apll12_div2
- const: apll12_div3
- const: apll12_div9
- const: a1sys_hp_sel
- const: aud_intbus_sel
- const: audio_h_sel
- const: audio_local_bus_sel
- const: dptx_m_sel
- const: i2so1_m_sel
- const: i2so2_m_sel
- const: i2si1_m_sel
- const: i2si2_m_sel
- const: top_a1sys_hp
- const: top_aud_intbus
- const: top_audio_h
- const: top_audio_local_bus
- const: top_dptx
- const: top_i2so1
- const: top_i2so2
- const: top_i2si1
- const: top_i2si2
- const: adsp_audio_26m
- const: apll1_d4
- const: apll2_d4
- const: apll12_div4
- const: top_a2sys
- const: top_aud_iec
mediatek,etdm-in1-cowork-source:
$ref: /schemas/types.yaml#/definitions/uint32
@ -144,6 +158,7 @@ required:
- resets
- reset-names
- mediatek,topckgen
- mediatek,infracfg
- power-domains
- clocks
- clock-names
@ -162,6 +177,7 @@ examples:
resets = <&watchdog 14>;
reset-names = "audiosys";
mediatek,topckgen = <&topckgen>;
mediatek,infracfg = <&infracfg_ao>;
power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
mediatek,etdm-in2-cowork-source = <2>;
mediatek,etdm-out2-cowork-source = <0>;
@ -184,7 +200,12 @@ examples:
<&topckgen 78>, //CLK_TOP_I2SO2
<&topckgen 79>, //CLK_TOP_I2SI1
<&topckgen 80>, //CLK_TOP_I2SI2
<&adsp_audio26m 0>; //CLK_AUDIODSP_AUDIO26M
<&adsp_audio26m 0>, //CLK_AUDIODSP_AUDIO26M
<&topckgen 132>, //CLK_TOP_APLL1_D4
<&topckgen 133>, //CLK_TOP_APLL2_D4
<&topckgen 183>, //CLK_TOP_APLL12_CK_DIV4
<&topckgen 84>, //CLK_TOP_A2SYS
<&topckgen 82>; //CLK_TOP_AUD_IEC>;
clock-names = "clk26m",
"apll1",
"apll2",
@ -193,16 +214,21 @@ examples:
"apll12_div2",
"apll12_div3",
"apll12_div9",
"a1sys_hp_sel",
"aud_intbus_sel",
"audio_h_sel",
"audio_local_bus_sel",
"dptx_m_sel",
"i2so1_m_sel",
"i2so2_m_sel",
"i2si1_m_sel",
"i2si2_m_sel",
"adsp_audio_26m";
"top_a1sys_hp",
"top_aud_intbus",
"top_audio_h",
"top_audio_local_bus",
"top_dptx",
"top_i2so1",
"top_i2so2",
"top_i2si1",
"top_i2si2",
"adsp_audio_26m",
"apll1_d4",
"apll2_d4",
"apll12_div4",
"top_a2sys",
"top_aud_iec";
};
...

View File

@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
const: mediatek,mt8188-mt6359-evb
enum:
- mediatek,mt8188-mt6359-evb
- mediatek,mt8188-nau8825
model:
$ref: /schemas/types.yaml#/definitions/string
@ -42,7 +44,6 @@ patternProperties:
we are going to update parameters in this node.
items:
enum:
- ADDA_BE
- DPTX_BE
- ETDM1_IN_BE
- ETDM2_IN_BE
@ -62,11 +63,28 @@ patternProperties:
required:
- sound-dai
dai-format:
description: audio format.
items:
enum:
- i2s
- right_j
- left_j
- dsp_a
- dsp_b
mediatek,clk-provider:
$ref: /schemas/types.yaml#/definitions/string
description: Indicates dai-link clock master.
items:
enum:
- cpu
- codec
additionalProperties: false
required:
- link-name
- codec
additionalProperties: false
@ -87,7 +105,8 @@ examples:
"AIN1", "Headset Mic";
dai-link-0 {
link-name = "ETDM3_OUT_BE";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&hdmi0>;
};

View File

@ -56,13 +56,9 @@ properties:
items:
items:
- description: value for DS line
enum: [0, 1]
- description: value for sampling edge
anyOf:
- enum:
- [0, 0]
- [0, 1]
- [1, 0]
- [1, 1]
enum: [0, 1]
minItems: 1
maxItems: 4
uniqueItems: true

View File

@ -1,24 +0,0 @@
Nuvoton NAU8315 Mono Class-D Amplifier
Required properties:
- compatible : "nuvoton,nau8315"
"nuvoton,nau8318"
Optional properties:
- enable-gpios : GPIO specifier for the chip's device enable input(EN) pin.
If this option is not specified then driver does not manage
the pin state (e.g. chip is always on).
Example:
#include <dt-bindings/gpio/gpio.h>
nau8315 {
compatible = "nuvoton,nau8315";
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
};
nau8318 {
compatible = "nuvoton,nau8318";
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
};

View File

@ -1,16 +0,0 @@
NAU85L40 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "nuvoton,nau8540"
- reg : the I2C address of the device.
Example:
codec: nau8540@1c {
compatible = "nuvoton,nau8540";
reg = <0x1c>;
};

View File

@ -1,17 +0,0 @@
NAU8810/NAU8812/NAU8814 audio CODEC
This device supports I2C only.
Required properties:
- compatible : One of "nuvoton,nau8810" or "nuvoton,nau8812" or
"nuvoton,nau8814"
- reg : the I2C address of the device.
Example:
codec: nau8810@1a {
compatible = "nuvoton,nau8810";
reg = <0x1a>;
};

View File

@ -1,88 +0,0 @@
Nuvoton NAU8824 audio codec
This device supports I2C only.
Required properties:
- compatible : Must be "nuvoton,nau8824"
- reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1).
Optional properties:
- nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
- nuvoton,vref-impedance: VREF Impedance selection
0 - Open
1 - 25 kOhm
2 - 125 kOhm
3 - 2.5 kOhm
- nuvoton,micbias-voltage: Micbias voltage level.
0 - VDDA
1 - VDDA
2 - VDDA * 1.1
3 - VDDA * 1.2
4 - VDDA * 1.3
5 - VDDA * 1.4
6 - VDDA * 1.53
7 - VDDA * 1.53
- nuvoton,sar-threshold-num: Number of buttons supported
- nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as
SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R)
where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance.
Refer datasheet section 10.2 for more information about threshold calculation.
- nuvoton,sar-hysteresis: Button impedance measurement hysteresis.
- nuvoton,sar-voltage: Reference voltage for button impedance measurement.
0 - VDDA
1 - VDDA
2 - VDDA * 1.1
3 - VDDA * 1.2
4 - VDDA * 1.3
5 - VDDA * 1.4
6 - VDDA * 1.53
7 - VDDA * 1.53
- nuvoton,sar-compare-time: SAR compare time
0 - 500 ns
1 - 1 us
2 - 2 us
3 - 4 us
- nuvoton,sar-sampling-time: SAR sampling time
0 - 2 us
1 - 4 us
2 - 8 us
3 - 16 us
- nuvoton,short-key-debounce: Button short key press debounce time.
0 - 30 ms
1 - 50 ms
2 - 100 ms
- nuvoton,jack-eject-debounce: Jack ejection debounce time.
0 - 0 ms
1 - 1 ms
2 - 10 ms
Example:
headset: nau8824@1a {
compatible = "nuvoton,nau8824";
reg = <0x1a>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
nuvoton,vref-impedance = <2>;
nuvoton,micbias-voltage = <6>;
// Setup 4 buttons impedance according to Android specification
nuvoton,sar-threshold-num = <4>;
nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
nuvoton,sar-hysteresis = <0>;
nuvoton,sar-voltage = <6>;
nuvoton,sar-compare-time = <1>;
nuvoton,sar-sampling-time = <1>;
nuvoton,short-key-debounce = <0>;
nuvoton,jack-eject-debounce = <1>;
};

View File

@ -1,111 +0,0 @@
Nuvoton NAU8825 audio codec
This device supports I2C only.
Required properties:
- compatible : Must be "nuvoton,nau8825"
- reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1).
Optional properties:
- nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
- nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
otherwise pin in high impedance state.
- nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
- nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
- nuvoton,vref-impedance: VREF Impedance selection
0 - Open
1 - 25 kOhm
2 - 125 kOhm
3 - 2.5 kOhm
- nuvoton,micbias-voltage: Micbias voltage level.
0 - VDDA
1 - VDDA
2 - VDDA * 1.1
3 - VDDA * 1.2
4 - VDDA * 1.3
5 - VDDA * 1.4
6 - VDDA * 1.53
7 - VDDA * 1.53
- nuvoton,sar-threshold-num: Number of buttons supported
- nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as
SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R)
where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance.
Refer datasheet section 10.2 for more information about threshold calculation.
- nuvoton,sar-hysteresis: Button impedance measurement hysteresis.
- nuvoton,sar-voltage: Reference voltage for button impedance measurement.
0 - VDDA
1 - VDDA
2 - VDDA * 1.1
3 - VDDA * 1.2
4 - VDDA * 1.3
5 - VDDA * 1.4
6 - VDDA * 1.53
7 - VDDA * 1.53
- nuvoton,sar-compare-time: SAR compare time
0 - 500 ns
1 - 1 us
2 - 2 us
3 - 4 us
- nuvoton,sar-sampling-time: SAR sampling time
0 - 2 us
1 - 4 us
2 - 8 us
3 - 16 us
- nuvoton,short-key-debounce: Button short key press debounce time.
0 - 30 ms
1 - 50 ms
2 - 100 ms
3 - 30 ms
- nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- nuvoton,crosstalk-enable: make crosstalk function enable if set.
- nuvoton,adcout-drive-strong: make the drive strength of ADCOUT IO PIN strong if set.
Otherwise, the drive keeps normal strength.
- nuvoton,adc-delay-ms: Delay (in ms) to make input path stable and avoid pop noise. The
default value is 125 and range between 125 to 500 ms.
- clocks: list of phandle and clock specifier pairs according to common clock bindings for the
clocks described in clock-names
- clock-names: should include "mclk" for the MCLK master clock
Example:
headset: nau8825@1a {
compatible = "nuvoton,nau8825";
reg = <0x1a>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
nuvoton,jkdet-enable;
nuvoton,jkdet-pull-enable;
nuvoton,jkdet-pull-up;
nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
nuvoton,vref-impedance = <2>;
nuvoton,micbias-voltage = <6>;
// Setup 4 buttons impedance according to Android specification
nuvoton,sar-threshold-num = <4>;
nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
nuvoton,sar-hysteresis = <1>;
nuvoton,sar-voltage = <0>;
nuvoton,sar-compare-time = <0>;
nuvoton,sar-sampling-time = <0>;
nuvoton,short-key-debounce = <2>;
nuvoton,jack-insert-debounce = <7>;
nuvoton,jack-eject-debounce = <7>;
nuvoton,crosstalk-enable;
clock-names = "mclk";
clocks = <&tegra_pmc TEGRA_PMC_CLK_OUT_2>;
};

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nuvoton,nau8315.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NAU8315/NAU8318 Mono Class-D Amplifier
maintainers:
- David Lin <CTLIN0@nuvoton.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- nuvoton,nau8315
- nuvoton,nau8318
'#sound-dai-cells':
const: 0
enable-gpios:
maxItems: 1
description:
GPIO specifier for the chip's device enable input(EN) pin.
If this option is not specified then driver does not manage
the pin state (e.g. chip is always on).
required:
- compatible
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
codec {
compatible = "nuvoton,nau8315";
#sound-dai-cells = <0>;
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
};

View File

@ -0,0 +1,40 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nuvoton,nau8540.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Nuvoton Technology Corporation NAU85L40 Audio CODEC
maintainers:
- John Hsu <KCHSU0@nuvoton.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: nuvoton,nau8540
reg:
maxItems: 1
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1c {
compatible = "nuvoton,nau8540";
reg = <0x1c>;
};
};

View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nuvoton,nau8810.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NAU8810/NAU8812/NAU8814 audio CODEC
maintainers:
- David Lin <CTLIN0@nuvoton.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- nuvoton,nau8810
- nuvoton,nau8812
- nuvoton,nau8814
reg:
maxItems: 1
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
#sound-dai-cells = <0>;
compatible = "nuvoton,nau8810";
reg = <0x1a>;
};
};

View File

@ -0,0 +1,182 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nuvoton,nau8824.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NAU8824 audio CODEC
maintainers:
- John Hsu <KCHSU0@nuvoton.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- nuvoton,nau8824
reg:
maxItems: 1
'#sound-dai-cells':
const: 0
interrupts:
maxItems: 1
nuvoton,jkdet-polarity:
$ref: /schemas/types.yaml#/definitions/uint32
description:
JKDET pin polarity.
enum:
- 0 # active high
- 1 # active low
default: 1
nuvoton,vref-impedance:
$ref: /schemas/types.yaml#/definitions/uint32
description:
VREF Impedance selection.
enum:
- 0 # Open
- 1 # 25 kOhm
- 2 # 125 kOhm
- 3 # 2.5 kOhm
default: 2
nuvoton,micbias-voltage:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Micbias voltage level.
enum:
- 0 # VDDA
- 1 # VDDA
- 2 # VDDA * 1.1
- 3 # VDDA * 1.2
- 4 # VDDA * 1.3
- 5 # VDDA * 1.4
- 6 # VDDA * 1.53
- 7 # VDDA * 1.53
default: 6
nuvoton,sar-threshold-num:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Number of buttons supported.
minimum: 1
maximum: 8
default: 4
nuvoton,sar-threshold:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Impedance threshold for each button. Array that contains up to 8 buttons
configuration. SAR value is calculated as
SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) where MICBIAS is
configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by
'nuvoton,sar-voltage', R - button impedance.
Refer datasheet section 10.2 for more information about threshold
calculation.
minItems: 1
maxItems: 8
items:
minimum: 0
maximum: 255
nuvoton,sar-hysteresis:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Button impedance measurement hysteresis.
default: 0
nuvoton,sar-voltage:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Reference voltage for button impedance measurement.
enum:
- 0 # VDDA
- 1 # VDDA
- 2 # VDDA * 1.1
- 3 # VDDA * 1.2
- 4 # VDDA * 1.3
- 5 # VDDA * 1.4
- 6 # VDDA * 1.53
- 7 # VDDA * 1.53
default: 6
nuvoton,sar-compare-time:
$ref: /schemas/types.yaml#/definitions/uint32
description:
SAR compare time.
enum:
- 0 # 500ns
- 1 # 1us
- 2 # 2us
- 3 # 4us
default: 1
nuvoton,sar-sampling-time:
$ref: /schemas/types.yaml#/definitions/uint32
description:
SAR sampling time.
enum:
- 0 # 2us
- 1 # 4us
- 2 # 8us
- 3 # 16us
default: 1
nuvoton,short-key-debounce:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Button short key press debounce time.
enum:
- 0 # 30 ms
- 1 # 50 ms
- 2 # 100 ms
default: 0
nuvoton,jack-eject-debounce:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Jack ejection debounce time.
enum:
- 0 # 0 ms
- 1 # 1 ms
- 2 # 10 ms
default: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
#sound-dai-cells = <0>;
compatible = "nuvoton,nau8824";
reg = <0x1a>;
interrupt-parent = <&gpio>;
interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
nuvoton,vref-impedance = <2>;
nuvoton,micbias-voltage = <6>;
nuvoton,sar-threshold-num = <4>;
// Setup 4 buttons impedance according to Android specification
nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
nuvoton,sar-hysteresis = <0>;
nuvoton,sar-voltage = <6>;
nuvoton,sar-compare-time = <1>;
nuvoton,sar-sampling-time = <1>;
nuvoton,short-key-debounce = <0>;
nuvoton,jack-eject-debounce = <1>;
};
};

View File

@ -0,0 +1,239 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nuvoton,nau8825.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NAU8825 audio CODEC
maintainers:
- John Hsu <KCHSU0@nuvoton.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- nuvoton,nau8825
reg:
maxItems: 1
interrupts:
maxItems: 1
nuvoton,jkdet-enable:
description:
Enable jack detection via JKDET pin.
type: boolean
nuvoton,jkdet-pull-enable:
description:
Enable JKDET pin pull.
If set - pin pull enabled, otherwise pin in high impedance state.
type: boolean
nuvoton,jkdet-pull-up:
description:
Pull-up JKDET pin.
If set then JKDET pin is pull up, otherwise pull down.
type: boolean
nuvoton,jkdet-polarity:
$ref: /schemas/types.yaml#/definitions/uint32
description:
JKDET pin polarity.
enum:
- 0 # active high
- 1 # active low
default: 1
nuvoton,vref-impedance:
$ref: /schemas/types.yaml#/definitions/uint32
description:
VREF Impedance selection.
enum:
- 0 # Open
- 1 # 25 kOhm
- 2 # 125 kOhm
- 3 # 2.5 kOhm
default: 2
nuvoton,micbias-voltage:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Micbias voltage level.
enum:
- 0 # VDDA
- 1 # VDDA
- 2 # VDDA * 1.1
- 3 # VDDA * 1.2
- 4 # VDDA * 1.3
- 5 # VDDA * 1.4
- 6 # VDDA * 1.53
- 7 # VDDA * 1.53
default: 6
nuvoton,sar-threshold-num:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Number of buttons supported.
minimum: 1
maximum: 4
default: 4
nuvoton,sar-threshold:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Impedance threshold for each button. Array that contains up to 8 buttons
configuration. SAR value is calculated as
SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) where MICBIAS is
configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by
'nuvoton,sar-voltage', R - button impedance.
Refer datasheet section 10.2 for more information about threshold
calculation.
minItems: 1
maxItems: 4
items:
minimum: 0
maximum: 255
nuvoton,sar-hysteresis:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Button impedance measurement hysteresis.
default: 0
nuvoton,sar-voltage:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Reference voltage for button impedance measurement.
enum:
- 0 # VDDA
- 1 # VDDA
- 2 # VDDA * 1.1
- 3 # VDDA * 1.2
- 4 # VDDA * 1.3
- 5 # VDDA * 1.4
- 6 # VDDA * 1.53
- 7 # VDDA * 1.53
default: 6
nuvoton,sar-compare-time:
$ref: /schemas/types.yaml#/definitions/uint32
description:
SAR compare time.
enum:
- 0 # 500 ns
- 1 # 1 us
- 2 # 2 us
- 3 # 4 us
default: 1
nuvoton,sar-sampling-time:
$ref: /schemas/types.yaml#/definitions/uint32
description:
SAR sampling time.
enum:
- 0 # 2 us
- 1 # 4 us
- 2 # 8 us
- 3 # 16 us
default: 1
nuvoton,short-key-debounce:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Button short key press debounce time.
enum:
- 0 # 30 ms
- 1 # 50 ms
- 2 # 100 ms
- 3 # 30 ms
default: 3
nuvoton,jack-insert-debounce:
$ref: /schemas/types.yaml#/definitions/uint32
description:
number from 0 to 7 that sets debounce time to 2^(n+2) ms.
maximum: 7
default: 7
nuvoton,jack-eject-debounce:
$ref: /schemas/types.yaml#/definitions/uint32
description:
number from 0 to 7 that sets debounce time to 2^(n+2) ms
maximum: 7
default: 0
nuvoton,crosstalk-enable:
description:
make crosstalk function enable if set.
type: boolean
nuvoton,adcout-drive-strong:
description:
make the drive strength of ADCOUT IO PIN strong if set.
Otherwise, the drive keeps normal strength.
type: boolean
nuvoton,adc-delay-ms:
description:
Delay (in ms) to make input path stable and avoid pop noise.
The default value is 125 and range between 125 to 500 ms.
minimum: 125
maximum: 500
default: 125
clocks:
maxItems: 1
clock-names:
items:
- const: mclk
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
#sound-dai-cells = <0>;
compatible = "nuvoton,nau8825";
reg = <0x1a>;
interrupt-parent = <&gpio>;
interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
nuvoton,jkdet-enable;
nuvoton,jkdet-pull-enable;
nuvoton,jkdet-pull-up;
nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
nuvoton,vref-impedance = <2>;
nuvoton,micbias-voltage = <6>;
// Setup 4 buttons impedance according to Android specification
nuvoton,sar-threshold-num = <4>;
nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
nuvoton,sar-hysteresis = <1>;
nuvoton,sar-voltage = <0>;
nuvoton,sar-compare-time = <0>;
nuvoton,sar-sampling-time = <0>;
nuvoton,short-key-debounce = <2>;
nuvoton,jack-insert-debounce = <7>;
nuvoton,jack-eject-debounce = <7>;
nuvoton,crosstalk-enable;
clock-names = "mclk";
clocks = <&tegra_pmc 1>;
};
};

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/nvidia,tegra-audio-common.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Common properties for NVIDIA Tegra audio complexes

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/qcom,q6apm-dai.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/qcom,q6apm-dai.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Audio Process Manager Digital Audio Interfaces

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-clocks.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-clocks.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm DSP LPASS Clock Controller

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-ports.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-ports.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm DSP LPASS(Low Power Audio SubSystem) Audio Ports

View File

@ -0,0 +1,66 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wsa8840.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm WSA8840/WSA8845/WSA8845H smart speaker amplifier
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description:
WSA884X is a family of Qualcomm Aqstic smart speaker amplifiers using
SoundWire digital audio interface.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: sdw20217020400
reg:
maxItems: 1
powerdown-gpios:
description: Powerdown/Shutdown line to use (pin SD_N)
maxItems: 1
'#sound-dai-cells':
const: 0
vdd-1p8-supply: true
vdd-io-supply: true
required:
- compatible
- reg
- powerdown-gpios
- '#sound-dai-cells'
- vdd-1p8-supply
- vdd-io-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
soundwire-controller {
#address-cells = <2>;
#size-cells = <0>;
speaker@0,1 {
compatible = "sdw20217020400";
reg = <0 1>;
pinctrl-names = "default";
pinctrl-0 = <&spkr_2_sd_n_active>;
powerdown-gpios = <&lpass_tlmm 18 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
sound-name-prefix = "SpkrRight";
vdd-1p8-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l3g_1p2>;
};
};

View File

@ -0,0 +1,40 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/realtek,rt1016.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Reaktek RT1016 Stereo Class D Audio Amplifier
maintainers:
- oder_chiou@realtek.com
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: realtek,rt1016
reg:
maxItems: 1
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
compatible = "realtek,rt1016";
reg = <0x1a>;
};
};

View File

@ -1,17 +0,0 @@
RT1016 Stereo Class D Audio Amplifier
This device supports I2C only.
Required properties:
- compatible : "realtek,rt1016".
- reg : The I2C address of the device.
Example:
rt1016: codec@1a {
compatible = "realtek,rt1016";
reg = <0x1a>;
};

View File

@ -36,7 +36,8 @@ properties:
const: i2sclk
resets:
maxItems: 1
items:
- description: Optional controller resets
dmas:
items:

View File

@ -1,20 +0,0 @@
SSM2518 audio amplifier
This device supports I2C only.
Required properties:
- compatible : Must be "adi,ssm2518"
- reg : the I2C address of the device. This will either be 0x34 (ADDR pin low)
or 0x35 (ADDR pin high)
Optional properties:
- gpios : GPIO connected to the nSD pin. If the property is not present it is
assumed that the nSD pin is hardwired to always on.
Example:
ssm2518: ssm2518@34 {
compatible = "adi,ssm2518";
reg = <0x34>;
gpios = <&gpio 5 0>;
};

View File

@ -61,6 +61,10 @@ properties:
description: Configure the I2S device as MCLK clock provider.
const: 0
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- "#sound-dai-cells"
@ -89,6 +93,13 @@ examples:
dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&i2s2_pins_a>;
/* assume audio-graph */
port {
codec_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
};
};
};
...

View File

@ -0,0 +1,98 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/starfive,jh7110-tdm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: StarFive JH7110 TDM Controller
description: |
The TDM Controller is a Time Division Multiplexed audio interface
integrated in StarFive JH7110 SoC, allowing up to 8 channels of
audio over a serial interface. The TDM controller can operate both
in master and slave mode.
maintainers:
- Walker Chen <walker.chen@starfivetech.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- starfive,jh7110-tdm
reg:
maxItems: 1
clocks:
items:
- description: TDM AHB Clock
- description: TDM APB Clock
- description: TDM Internal Clock
- description: TDM Clock
- description: Inner MCLK
- description: TDM External Clock
clock-names:
items:
- const: tdm_ahb
- const: tdm_apb
- const: tdm_internal
- const: tdm
- const: mclk_inner
- const: tdm_ext
resets:
items:
- description: tdm ahb reset line
- description: tdm apb reset line
- description: tdm core reset line
dmas:
items:
- description: RX DMA Channel
- description: TX DMA Channel
dma-names:
items:
- const: rx
- const: tx
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
- clocks
- clock-names
- resets
- dmas
- dma-names
- "#sound-dai-cells"
additionalProperties: false
examples:
- |
tdm@10090000 {
compatible = "starfive,jh7110-tdm";
reg = <0x10090000 0x1000>;
clocks = <&syscrg 184>,
<&syscrg 185>,
<&syscrg 186>,
<&syscrg 187>,
<&syscrg 17>,
<&tdm_ext>;
clock-names = "tdm_ahb", "tdm_apb",
"tdm_internal", "tdm",
"mclk_inner", "tdm_ext";
resets = <&syscrg 105>,
<&syscrg 107>,
<&syscrg 106>;
dmas = <&dma 20>, <&dma 21>;
dma-names = "rx","tx";
#sound-dai-cells = <0>;
};

View File

@ -2,8 +2,8 @@
# Copyright (C) 2019 Texas Instruments Incorporated
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/tas2562.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/tas2562.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TAS2562 Smart PA

View File

@ -2,8 +2,8 @@
# Copyright (C) 2019-20 Texas Instruments Incorporated
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/tas2770.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/tas2770.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TAS2770 Smart PA

View File

@ -2,8 +2,8 @@
# Copyright (C) 2020-2022 Texas Instruments Incorporated
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/tas27xx.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/tas27xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TAS2764/TAS2780 Smart PA

View File

@ -0,0 +1,74 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2022 - 2023 Texas Instruments Incorporated
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tas2781.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TAS2781 SmartAMP
maintainers:
- Shenghao Ding <shenghao-ding@ti.com>
description:
The TAS2781 is a mono, digital input Class-D audio amplifier
optimized for efficiently driving high peak power into small
loudspeakers. An integrated on-chip DSP supports Texas Instruments
Smart Amp speaker protection algorithm. The integrated speaker
voltage and current sense provides for real time
monitoring of loudspeaker behavior.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- ti,tas2781
reg:
description:
I2C address, in multiple tas2781s case, all the i2c address
aggreate as one Audio Device to support multiple audio slots.
maxItems: 8
minItems: 1
items:
minimum: 0x38
maximum: 0x3f
reset-gpios:
maxItems: 1
interrupts:
maxItems: 1
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
/* example with quad tas2781s, such as tablet or pad device */
#address-cells = <1>;
#size-cells = <0>;
quad_tas2781: tas2781@38 {
compatible = "ti,tas2781";
reg = <0x38>, /* Audio slot 0 */
<0x3a>, /* Audio slot 1 */
<0x39>, /* Audio slot 2 */
<0x3b>; /* Audio slot 3 */
#sound-dai-cells = <0>;
reset-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio1>;
interrupts = <15>;
};
};
...

View File

@ -0,0 +1,101 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2019 Texas Instruments Incorporated
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tlv320aic32x4.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TLV320AIC32x4 Stereo Audio codec
maintainers:
- Alexander Stein <alexander.stein@ew.tq-group.com>
description: |
The TLV320AIC32x4 audio codec can be accessed using I2C or SPI
properties:
compatible:
enum:
- ti,tas2505
- ti,tlv320aic32x4
- ti,tlv320aic32x6
reg:
maxItems: 1
clocks:
items:
- description: Master clock
clock-names:
items:
- const: mclk
av-supply:
description: Analog core power supply
dv-supply:
description: Digital core power supply
iov-supply:
description: Digital IO power supply
ldoin-supply:
description: LDO power supply
reset-gpios:
maxItems: 1
'#sound-dai-cells':
const: 0
aic32x4-gpio-func:
description: |
GPIO function configuration for pins MFP1-MFP5.
Types are defined in include/sound/tlv320aic32x4.h
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 5
maxItems: 5
required:
- compatible
- reg
- clocks
- clock-names
- iov-supply
allOf:
- $ref: dai-common.yaml#
- if:
not:
required:
- ldoin-supply
then:
required:
- av-supply
- dv-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
audio-codec@18 {
compatible = "ti,tlv320aic32x4";
reg = <0x18>;
iov-supply = <&reg_3v3>;
ldoin-supply = <&reg_3v3>;
clocks = <&clks 201>;
clock-names = "mclk";
aic32x4-gpio-func= <
0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */
0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
0x08 /* MFP5 AIC32X4_MFP5_GPIO_INPUT */
>;
};
};

View File

@ -61,6 +61,7 @@ properties:
GPIO specification for the active low RESET input.
gpio-reset:
$ref: /schemas/types.yaml#/definitions/uint32-matrix
maxItems: 1
description:
Deprecated, please use reset-gpios instead.

View File

@ -1,42 +0,0 @@
Texas Instruments - tlv320aic32x4 Codec module
The tlv320aic32x4 serial control bus communicates through I2C protocols
Required properties:
- compatible - "string" - One of:
"ti,tlv320aic32x4" TLV320AIC3204
"ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256
"ti,tas2505" TAS2505, TAS2521
- reg: I2C slave address
- *-supply: Required supply regulators are:
"iov" - digital IO power supply
"ldoin" - LDO power supply
"dv" - Digital core power supply
"av" - Analog core power supply
If you supply ldoin, dv and av are optional. Otherwise they are required
See regulator/regulator.txt for more information about the detailed binding
format.
Optional properties:
- reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
- clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
See clock/clock-bindings.txt for information about the detailed format.
- aic32x4-gpio-func - <array of 5 int>
- Types are defined in include/sound/tlv320aic32x4.h
Example:
codec: tlv320aic32x4@18 {
compatible = "ti,tlv320aic32x4";
reg = <0x18>;
clocks = <&clks 201>;
clock-names = "mclk";
aic32x4-gpio-func= <
0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */
0xff /* AIC32X4_MFPX_DEFAULT_VALUE */
0x08 /* MFP5 AIC32X4_MFP5_GPIO_INPUT */
>;
};

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/wlf,wm8903.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/sound/wlf,wm8903.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: WM8903 audio codec

View File

@ -227,7 +227,7 @@ PCM stream related controls
name='EMU10K1 PCM Volume',index 0-31
------------------------------------
Channel volume attenuation in range 0-0xffff. The maximum value (no
Channel volume attenuation in range 0-0x1fffd. The middle value (no
attenuation) is default. The channel mapping for three values is
as follows:
@ -240,30 +240,30 @@ name='EMU10K1 PCM Send Routing',index 0-31
This control specifies the destination - FX-bus accumulators. There are 24
values in this mapping:
* 0 - mono, A destination (FX-bus 0-63), default 0
* 1 - mono, B destination (FX-bus 0-63), default 1
* 2 - mono, C destination (FX-bus 0-63), default 2
* 3 - mono, D destination (FX-bus 0-63), default 3
* 4 - mono, E destination (FX-bus 0-63), default 0
* 5 - mono, F destination (FX-bus 0-63), default 0
* 6 - mono, G destination (FX-bus 0-63), default 0
* 7 - mono, H destination (FX-bus 0-63), default 0
* 8 - left, A destination (FX-bus 0-63), default 0
* 9 - left, B destination (FX-bus 0-63), default 1
* 0 - mono, A destination (FX-bus 0-63), default 0
* 1 - mono, B destination (FX-bus 0-63), default 1
* 2 - mono, C destination (FX-bus 0-63), default 2
* 3 - mono, D destination (FX-bus 0-63), default 3
* 4 - mono, E destination (FX-bus 0-63), default 4
* 5 - mono, F destination (FX-bus 0-63), default 5
* 6 - mono, G destination (FX-bus 0-63), default 6
* 7 - mono, H destination (FX-bus 0-63), default 7
* 8 - left, A destination (FX-bus 0-63), default 0
* 9 - left, B destination (FX-bus 0-63), default 1
* 10 - left, C destination (FX-bus 0-63), default 2
* 11 - left, D destination (FX-bus 0-63), default 3
* 12 - left, E destination (FX-bus 0-63), default 0
* 13 - left, F destination (FX-bus 0-63), default 0
* 14 - left, G destination (FX-bus 0-63), default 0
* 15 - left, H destination (FX-bus 0-63), default 0
* 12 - left, E destination (FX-bus 0-63), default 4
* 13 - left, F destination (FX-bus 0-63), default 5
* 14 - left, G destination (FX-bus 0-63), default 6
* 15 - left, H destination (FX-bus 0-63), default 7
* 16 - right, A destination (FX-bus 0-63), default 0
* 17 - right, B destination (FX-bus 0-63), default 1
* 18 - right, C destination (FX-bus 0-63), default 2
* 19 - right, D destination (FX-bus 0-63), default 3
* 20 - right, E destination (FX-bus 0-63), default 0
* 21 - right, F destination (FX-bus 0-63), default 0
* 22 - right, G destination (FX-bus 0-63), default 0
* 23 - right, H destination (FX-bus 0-63), default 0
* 20 - right, E destination (FX-bus 0-63), default 4
* 21 - right, F destination (FX-bus 0-63), default 5
* 22 - right, G destination (FX-bus 0-63), default 6
* 23 - right, H destination (FX-bus 0-63), default 7
Don't forget that it's illegal to assign a channel to the same FX-bus accumulator
more than once (it means 0=0 && 1=0 is an invalid combination).

View File

@ -17,3 +17,4 @@ Card-Specific Information
hdspm
serial-u16550
img-spdif-in
pcmtest

View File

@ -0,0 +1,120 @@
.. SPDX-License-Identifier: GPL-2.0
The Virtual PCM Test Driver
===========================
The Virtual PCM Test Driver emulates a generic PCM device, and can be used for
testing/fuzzing of the userspace ALSA applications, as well as for testing/fuzzing of
the PCM middle layer. Additionally, it can be used for simulating hard to reproduce
problems with PCM devices.
What can this driver do?
~~~~~~~~~~~~~~~~~~~~~~~~
At this moment the driver can do the following things:
* Simulate both capture and playback processes
* Generate random or pattern-based capturing data
* Inject delays into the playback and capturing processes
* Inject errors during the PCM callbacks
It supports up to 8 substreams and 4 channels. Also it supports both interleaved and
non-interleaved access modes.
Also, this driver can check the playback stream for containing the predefined pattern,
which is used in the corresponding selftest (alsa/pcmtest-test.sh) to check the PCM middle
layer data transferring functionality. Additionally, this driver redefines the default
RESET ioctl, and the selftest covers this PCM API functionality as well.
Configuration
-------------
The driver has several parameters besides the common ALSA module parameters:
* fill_mode (bool) - Buffer fill mode (see below)
* inject_delay (int)
* inject_hwpars_err (bool)
* inject_prepare_err (bool)
* inject_trigger_err (bool)
Capture Data Generation
-----------------------
The driver has two modes of data generation: the first (0 in the fill_mode parameter)
means random data generation, the second (1 in the fill_mode) - pattern-based
data generation. Let's look at the second mode.
First of all, you may want to specify the pattern for data generation. You can do it
by writing the pattern to the debugfs file. There are pattern buffer debugfs entries
for each channel, as well as entries which contain the pattern buffer length.
* /sys/kernel/debug/pcmtest/fill_pattern[0-3]
* /sys/kernel/debug/pcmtest/fill_pattern[0-3]_len
To set the pattern for the channel 0 you can execute the following command:
.. code-block:: bash
echo -n mycoolpattern > /sys/kernel/debug/pcmtest/fill_pattern0
Then, after every capture action performed on the 'pcmtest' device the buffer for the
channel 0 will contain 'mycoolpatternmycoolpatternmycoolpatternmy...'.
The pattern itself can be up to 4096 bytes long.
Delay injection
---------------
The driver has 'inject_delay' parameter, which has very self-descriptive name and
can be used for time delay/speedup simulations. The parameter has integer type, and
it means the delay added between module's internal timer ticks.
If the 'inject_delay' value is positive, the buffer will be filled slower, if it is
negative - faster. You can try it yourself by starting a recording in any
audiorecording application (like Audacity) and selecting the 'pcmtest' device as a
source.
This parameter can be also used for generating a huge amount of sound data in a very
short period of time (with the negative 'inject_delay' value).
Errors injection
----------------
This module can be used for injecting errors into the PCM communication process. This
action can help you to figure out how the userspace ALSA program behaves under unusual
circumstances.
For example, you can make all 'hw_params' PCM callback calls return EBUSY error by
writing '1' to the 'inject_hwpars_err' module parameter:
.. code-block:: bash
echo 1 > /sys/module/snd_pcmtest/parameters/inject_hwpars_err
Errors can be injected into the following PCM callbacks:
* hw_params (EBUSY)
* prepare (EINVAL)
* trigger (EINVAL)
Playback test
-------------
This driver can be also used for the playback functionality testing - every time you
write the playback data to the 'pcmtest' PCM device and close it, the driver checks the
buffer for containing the looped pattern (which is specified in the fill_pattern
debugfs file for each channel). If the playback buffer content represents the looped
pattern, 'pc_test' debugfs entry is set into '1'. Otherwise, the driver sets it to '0'.
ioctl redefinition test
-----------------------
The driver redefines the 'reset' ioctl, which is default for all PCM devices. To test
this functionality, we can trigger the reset ioctl and check the 'ioctl_test' debugfs
entry:
.. code-block:: bash
cat /sys/kernel/debug/pcmtest/ioctl_test
If the ioctl is triggered successfully, this file will contain '1', and '0' otherwise.

View File

@ -258,7 +258,7 @@ PCM stream related controls
``name='EMU10K1 PCM Volume',index 0-31``
----------------------------------------
Channel volume attenuation in range 0-0xffff. The maximum value (no
Channel volume attenuation in range 0-0x1fffd. The middle value (no
attenuation) is default. The channel mapping for three values is
as follows:

View File

@ -268,11 +268,12 @@ with setting of meta_data and signalling for next track ::
| |
| V
| +----------+
| | |
| |NEXT_TRACK|
| | |
| +----------+
| |
| compr_set_params() | |
| +-----------|NEXT_TRACK|
| | | |
| | +--+-------+
| | | |
| +--------------+ |
| |
| | compr_partial_drain()
| |

View File

@ -15,3 +15,4 @@ Designs and Implementations
oss-emulation
seq-oss
jack-injection
midi-2.0

View File

@ -0,0 +1,378 @@
=================
MIDI 2.0 on Linux
=================
General
=======
MIDI 2.0 is an extended protocol for providing higher resolutions and
more fine controls over the legacy MIDI 1.0. The fundamental changes
introduced for supporting MIDI 2.0 are:
- Support of Universal MIDI Packet (UMP)
- Support of MIDI 2.0 protocol messages
- Transparent conversions between UMP and legacy MIDI 1.0 byte stream
- MIDI-CI for property and profile configurations
UMP is a new container format to hold all MIDI protocol 1.0 and MIDI
2.0 protocol messages. Unlike the former byte stream, it's 32bit
aligned, and each message can be put in a single packet. UMP can send
the events up to 16 "UMP Groups", where each UMP Group contain up to
16 MIDI channels.
MIDI 2.0 protocol is an extended protocol to achieve the higher
resolution and more controls over the old MIDI 1.0 protocol.
MIDI-CI is a high-level protocol that can talk with the MIDI device
for the flexible profiles and configurations. It's represented in the
form of special SysEx.
For Linux implementations, the kernel supports the UMP transport and
the encoding/decoding of MIDI protocols on UMP, while MIDI-CI is
supported in user-space over the standard SysEx.
As of this writing, only USB MIDI device supports the UMP and Linux
2.0 natively. The UMP support itself is pretty generic, hence it
could be used by other transport layers, although it could be
implemented differently (e.g. as a ALSA sequencer client), too.
The access to UMP devices are provided in two ways: the access via
rawmidi device and the access via ALSA sequencer API.
ALSA sequencer API was extended to allow the payload of UMP packets.
It's allowed to connect freely between MIDI 1.0 and MIDI 2.0 sequencer
clients, and the events are converted transparently.
Kernel Configuration
====================
The following new configs are added for supporting MIDI 2.0:
`CONFIG_SND_UMP`, `CONFIG_SND_UMP_LEGACY_RAWMIDI`,
`CONFIG_SND_SEQ_UMP`, `CONFIG_SND_SEQ_UMP_CLIENT`, and
`CONFIG_SND_USB_AUDIO_MIDI_V2`. The first visible one is
`CONFIG_SND_USB_AUDIO_MIDI_V2`, and when you choose it (to set `=y`),
the core support for UMP (`CONFIG_SND_UMP`) and the sequencer binding
(`CONFIG_SND_SEQ_UMP_CLIENT`) will be automatically selected.
Additionally, `CONFIG_SND_UMP_LEGACY_RAWMIDI=y` will enable the
support for the legacy raw MIDI device for UMP Endpoints.
Rawmidi Device with USB MIDI 2.0
================================
When a device supports MIDI 2.0, the USB-audio driver probes and uses
the MIDI 2.0 interface (that is found always at the altset 1) as
default instead of the MIDI 1.0 interface (at altset 0). You can
switch back to the binding with the old MIDI 1.0 interface by passing
`midi2_enable=0` option to snd-usb-audio driver module, too.
The USB audio driver tries to query the UMP Endpoint and UMP Function
Block information that are provided since UMP v1.1, and builds up the
topology based on those information. When the device is older and
doesn't respond to the new UMP inquiries, the driver falls back and
builds the topology based on Group Terminal Block (GTB) information
from the USB descriptor. Some device might be screwed up by the
unexpected UMP command; in such a case, pass `midi2_probe=0` option to
snd-usb-audio driver for skipping the UMP v1.1 inquiries.
When the MIDI 2.0 device is probed, the kernel creates a rawmidi
device for each UMP Endpoint of the device. Its device name is
`/dev/snd/umpC*D*` and different from the standard rawmidi device name
`/dev/snd/midiC*D*` for MIDI 1.0, in order to avoid confusing the
legacy applications accessing mistakenly to UMP devices.
You can read and write UMP packet data directly from/to this UMP
rawmidi device. For example, reading via `hexdump` like below will
show the incoming UMP packets of the card 0 device 0 in the hex
format::
% hexdump -C /dev/snd/umpC0D0
00000000 01 07 b0 20 00 07 b0 20 64 3c 90 20 64 3c 80 20 |... ... d<. d<. |
Unlike the MIDI 1.0 byte stream, UMP is a 32bit packet, and the size
for reading or writing the device is also aligned to 32bit (which is 4
bytes).
The 32-bit words in the UMP packet payload are always in CPU native
endianness. Transport drivers are responsible to convert UMP words
from / to system endianness to required transport endianness / byte
order.
When `CONFIG_SND_UMP_LEGACY_RAWMIDI` is set, the driver creates
another standard raw MIDI device additionally as `/dev/snd/midiC*D*`.
This contains 16 substreams, and each substream corresponds to a
(0-based) UMP Group. Legacy applications can access to the specified
group via each substream in MIDI 1.0 byte stream format. With the
ALSA rawmidi API, you can open the arbitrary substream, while just
opening `/dev/snd/midiC*D*` will end up with opening the first
substream.
Each UMP Endpoint can provide the additional information, constructed
from the information inquired via UMP 1.1 Stream messages or USB MIDI
2.0 descriptors. And a UMP Endpoint may contain one or more UMP
Blocks, where UMP Block is an abstraction introduced in the ALSA UMP
implementations to represent the associations among UMP Groups. UMP
Block corresponds to Function Block in UMP 1.1 specification. When
UMP 1.1 Function Block information isn't available, it's filled
partially from Group Terminal Block (GTB) as defined in USB MIDI 2.0
specifications.
The information of UMP Endpoints and UMP Blocks are found in the proc
file `/proc/asound/card*/midi*`. For example::
% cat /proc/asound/card1/midi0
ProtoZOA MIDI
Type: UMP
EP Name: ProtoZOA
EP Product ID: ABCD12345678
UMP Version: 0x0000
Protocol Caps: 0x00000100
Protocol: 0x00000100
Num Blocks: 3
Block 0 (ProtoZOA Main)
Direction: bidirection
Active: Yes
Groups: 1-1
Is MIDI1: No
Block 1 (ProtoZOA Ext IN)
Direction: output
Active: Yes
Groups: 2-2
Is MIDI1: Yes (Low Speed)
....
Note that `Groups` field shown in the proc file above indicates the
1-based UMP Group numbers (from-to).
Those additional UMP Endpoint and UMP Block information can be
obtained via the new ioctls `SNDRV_UMP_IOCTL_ENDPOINT_INFO` and
`SNDRV_UMP_IOCTL_BLOCK_INFO`, respectively.
The rawmidi name and the UMP Endpoint name are usually identical, and
in the case of USB MIDI, it's taken from `iInterface` of the
corresponding USB MIDI interface descriptor. If it's not provided,
it's copied from `iProduct` of the USB device descriptor as a
fallback.
The Endpoint Product ID is a string field and supposed to be unique.
It's copied from `iSerialNumber` of the device for USB MIDI.
The protocol capabilities and the actual protocol bits are defined in
`asound.h`.
ALSA Sequencer with USB MIDI 2.0
================================
In addition to the rawmidi interfaces, ALSA sequencer interface
supports the new UMP MIDI 2.0 device, too. Now, each ALSA sequencer
client may set its MIDI version (0, 1 or 2) to declare itself being
either the legacy, UMP MIDI 1.0 or UMP MIDI 2.0 device, respectively.
The first, legacy client is the one that sends/receives the old
sequencer event as was. Meanwhile, UMP MIDI 1.0 and 2.0 clients send
and receive in the extended event record for UMP. The MIDI version is
seen in the new `midi_version` field of `snd_seq_client_info`.
A UMP packet can be sent/received in a sequencer event embedded by
specifying the new event flag bit `SNDRV_SEQ_EVENT_UMP`. When this
flag is set, the event has 16 byte (128 bit) data payload for holding
the UMP packet. Without the `SNDRV_SEQ_EVENT_UMP` bit flag, the event
is treated as a legacy event as it was (with max 12 byte data
payload).
With `SNDRV_SEQ_EVENT_UMP` flag set, the type field of a UMP sequencer
event is ignored (but it should be set to 0 as default).
The type of each client can be seen in `/proc/asound/seq/clients`.
For example::
% cat /proc/asound/seq/clients
Client info
cur clients : 3
....
Client 14 : "Midi Through" [Kernel Legacy]
Port 0 : "Midi Through Port-0" (RWe-)
Client 20 : "ProtoZOA" [Kernel UMP MIDI1]
UMP Endpoint: ProtoZOA
UMP Block 0: ProtoZOA Main [Active]
Groups: 1-1
UMP Block 1: ProtoZOA Ext IN [Active]
Groups: 2-2
UMP Block 2: ProtoZOA Ext OUT [Active]
Groups: 3-3
Port 0 : "MIDI 2.0" (RWeX) [In/Out]
Port 1 : "ProtoZOA Main" (RWeX) [In/Out]
Port 2 : "ProtoZOA Ext IN" (-We-) [Out]
Port 3 : "ProtoZOA Ext OUT" (R-e-) [In]
Here you can find two types of kernel clients, "Legacy" for client 14,
and "UMP MIDI1" for client 20, which is a USB MIDI 2.0 device.
A USB MIDI 2.0 client gives always the port 0 as "MIDI 2.0" and the
rest ports from 1 for each UMP Group (e.g. port 1 for Group 1).
In this example, the device has three active groups (Main, Ext IN and
Ext OUT), and those are exposed as sequencer ports from 1 to 3.
The "MIDI 2.0" port is for a UMP Endpoint, and its difference from
other UMP Group ports is that UMP Endpoint port sends the events from
the all ports on the device ("catch-all"), while each UMP Group port
sends only the events from the given UMP Group.
Also, UMP groupless messages (such as the UMP message type 0x0f) are
sent only to the UMP Endpoint port.
Note that, although each UMP sequencer client usually creates 16
ports, those ports that don't belong to any UMP Blocks (or belonging
to inactive UMP Blocks) are marked as inactive, and they don't appear
in the proc outputs. In the example above, the sequencer ports from 4
to 16 are present but not shown there.
The proc file above shows the UMP Block information, too. The same
entry (but with more detailed information) is found in the rawmidi
proc output.
When clients are connected between different MIDI versions, the events
are translated automatically depending on the client's version, not
only between the legacy and the UMP MIDI 1.0/2.0 types, but also
between UMP MIDI 1.0 and 2.0 types, too. For example, running
`aseqdump` program on the ProtoZOA Main port in the legacy mode will
give you the output like::
% aseqdump -p 20:1
Waiting for data. Press Ctrl+C to end.
Source Event Ch Data
20:1 Note on 0, note 60, velocity 100
20:1 Note off 0, note 60, velocity 100
20:1 Control change 0, controller 11, value 4
When you run `aseqdump` in MIDI 2.0 mode, it'll receive the high
precision data like::
% aseqdump -u 2 -p 20:1
Waiting for data. Press Ctrl+C to end.
Source Event Ch Data
20:1 Note on 0, note 60, velocity 0xc924, attr type = 0, data = 0x0
20:1 Note off 0, note 60, velocity 0xc924, attr type = 0, data = 0x0
20:1 Control change 0, controller 11, value 0x2000000
while the data is automatically converted by ALSA sequencer core.
Rawmidi API Extensions
======================
* The additional UMP Endpoint information can be obtained via the new
ioctl `SNDRV_UMP_IOCTL_ENDPOINT_INFO`. It contains the associated
card and device numbers, the bit flags, the protocols, the number of
UMP Blocks, the name string of the endpoint, etc.
The protocols are specified in two field, the protocol capabilities
and the current protocol. Both contain the bit flags specifying the
MIDI protocol version (`SNDRV_UMP_EP_INFO_PROTO_MIDI1` or
`SNDRV_UMP_EP_INFO_PROTO_MIDI2`) in the upper byte and the jitter
reduction timestamp (`SNDRV_UMP_EP_INFO_PROTO_JRTS_TX` and
`SNDRV_UMP_EP_INFO_PROTO_JRTS_RX`) in the lower byte.
A UMP Endpoint may contain up to 32 UMP Blocks, and the number of
the currently assigned blocks are shown in the Endpoint information.
* Each UMP Block information can be obtained via another new ioctl
`SNDRV_UMP_IOCTL_BLOCK_INFO`. The block ID number (0-based) has to
be passed for the block to query. The received data contains the
associated the direction of the block, the first associated group ID
(0-based) and the number of groups, the name string of the block,
etc.
The direction is either `SNDRV_UMP_DIR_INPUT`,
`SNDRV_UMP_DIR_OUTPUT` or `SNDRV_UMP_DIR_BIDIRECTION`.
* For the device supports UMP v1.1, the UMP MIDI protocol can be
switched via "Stream Configuration Request" message (UMP type 0x0f,
status 0x05). When UMP core receives such a message, it updates the
UMP EP info and the corresponding sequencer clients as well.
Control API Extensions
======================
* The new ioctl `SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE` is introduced for
querying the next UMP rawmidi device, while the existing ioctl
`SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE` queries only the legacy
rawmidi devices.
For setting the subdevice (substream number) to be opened, use the
ioctl `SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE` like the normal
rawmidi.
* Two new ioctls `SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO` and
`SNDRV_CTL_IOCTL_UMP_BLOCK_INFO` provide the UMP Endpoint and UMP
Block information of the specified UMP device via ALSA control API
without opening the actual (UMP) rawmidi device.
The `card` field is ignored upon inquiry, always tied with the card
of the control interface.
Sequencer API Extensions
========================
* `midi_version` field is added to `snd_seq_client_info` to indicate
the current MIDI version (either 0, 1 or 2) of each client.
When `midi_version` is 1 or 2, the alignment of read from a UMP
sequencer client is also changed from the former 28 bytes to 32
bytes for the extended payload. The alignment size for the write
isn't changed, but each event size may differ depending on the new
bit flag below.
* `SNDRV_SEQ_EVENT_UMP` flag bit is added for each sequencer event
flags. When this bit flag is set, the sequencer event is extended
to have a larger payload of 16 bytes instead of the legacy 12
bytes, and the event contains the UMP packet in the payload.
* The new sequencer port type bit (`SNDRV_SEQ_PORT_TYPE_MIDI_UMP`)
indicates the port being UMP-capable.
* The sequencer ports have new capability bits to indicate the
inactive ports (`SNDRV_SEQ_PORT_CAP_INACTIVE`) and the UMP Endpoint
port (`SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT`).
* The event conversion of ALSA sequencer clients can be suppressed the
new filter bit `SNDRV_SEQ_FILTER_NO_CONVERT` set to the client info.
For example, the kernel pass-through client (`snd-seq-dummy`) sets
this flag internally.
* The port information gained the new field `direction` to indicate
the direction of the port (either `SNDRV_SEQ_PORT_DIR_INPUT`,
`SNDRV_SEQ_PORT_DIR_OUTPUT` or `SNDRV_SEQ_PORT_DIR_BIDIRECTION`).
* Another additional field for the port information is `ump_group`
which specifies the associated UMP Group Number (1-based).
When it's non-zero, the UMP group field in the UMP packet updated
upon delivery to the specified group (corrected to be 0-based).
Each sequencer port is supposed to set this field if it's a port to
specific to a certain UMP group.
* Each client may set the additional event filter for UMP Groups in
`group_filter` bitmap. The filter consists of bitmap from 1-based
Group numbers. For example, when the bit 1 is set, messages from
Group 1 (i.e. the very first group) are filtered and not delivered.
The bit 0 is used for filtering UMP groupless messages.
* Two new ioctls are added for UMP-capable clients:
`SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO` and
`SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO`. They are used to get and set
either `snd_ump_endpoint_info` or `snd_ump_block_info` data
associated with the sequencer client. The USB MIDI driver provides
those information from the underlying UMP rawmidi, while a
user-space client may provide its own data via `*_SET` ioctl.
For an Endpoint data, pass 0 to the `type` field, while for a Block
data, pass the block number + 1 to the `type` field.
Setting the data for a kernel client shall result in an error.
* With UMP 1.1, Function Block information may be changed
dynamically. When the update of Function Block is received from the
device, ALSA sequencer core changes the corresponding sequencer port
name and attributes accordingly, and notifies the changes via the
announcement to the ALSA sequencer system port, similarly like the
normal port change notification.

View File

@ -17267,6 +17267,7 @@ F: sound/soc/codecs/wcd9335.*
F: sound/soc/codecs/wcd934x.c
F: sound/soc/codecs/wsa881x.c
F: sound/soc/codecs/wsa883x.c
F: sound/soc/codecs/wsa884x.c
F: sound/soc/qcom/
QCOM EMBEDDED USB DEBUGGER (EUD)
@ -20244,6 +20245,12 @@ F: Documentation/devicetree/bindings/power/starfive*
F: drivers/soc/starfive/jh71xx_pmu.c
F: include/dt-bindings/power/starfive,jh7110-pmu.h
STARFIVE JH7110 TDM DRIVER
M: Walker Chen <walker.chen@starfivetech.com>
S: Maintained
F: Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml
F: sound/soc/starfive/jh7110_tdm.c
STARFIVE SOC DRIVERS
M: Conor Dooley <conor@kernel.org>
S: Maintained
@ -22535,6 +22542,14 @@ L: linux-fsdevel@vger.kernel.org
S: Maintained
F: fs/vboxsf/*
VIRTUAL PCM TEST DRIVER
M: Ivan Orlov <ivan.orlov0322@gmail.com>
L: alsa-devel@alsa-project.org
S: Maintained
F: Documentation/sound/cards/pcmtest.rst
F: sound/drivers/pcmtest.c
F: tools/testing/selftests/alsa/test-pcmtest-driver.c
VIRTUAL SERIO DEVICE DRIVER
M: Stephen Chandler Paul <thatslyude@gmail.com>
S: Maintained

View File

@ -2059,10 +2059,10 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
goto out_fw;
}
cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
(le32_to_cpu(hdr->ver) >> 16) & 0xff,
(le32_to_cpu(hdr->ver) >> 8) & 0xff,
le32_to_cpu(hdr->ver) & 0xff);
cs_dsp_info(dsp, "%s: v%d.%d.%d\n", file,
(le32_to_cpu(hdr->ver) >> 16) & 0xff,
(le32_to_cpu(hdr->ver) >> 8) & 0xff,
le32_to_cpu(hdr->ver) & 0xff);
pos = le32_to_cpu(hdr->len);

View File

@ -131,6 +131,14 @@
#define RX_CODEC_DMA_RX_7 126
#define QUINARY_MI2S_RX 127
#define QUINARY_MI2S_TX 128
#define DISPLAY_PORT_RX_0 DISPLAY_PORT_RX
#define DISPLAY_PORT_RX_1 129
#define DISPLAY_PORT_RX_2 130
#define DISPLAY_PORT_RX_3 131
#define DISPLAY_PORT_RX_4 132
#define DISPLAY_PORT_RX_5 133
#define DISPLAY_PORT_RX_6 134
#define DISPLAY_PORT_RX_7 135
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2

View File

@ -158,6 +158,9 @@
#define PCI_VENDOR_ID_LOONGSON 0x0014
#define PCI_DEVICE_ID_LOONGSON_HDA 0x7a07
#define PCI_DEVICE_ID_LOONGSON_HDMI 0x7a37
#define PCI_VENDOR_ID_TTTECH 0x0357
#define PCI_DEVICE_ID_TTTECH_MC322 0x000a

View File

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* <linux/usb/midi-v2.h> -- USB MIDI 2.0 definitions.
*/
#ifndef __LINUX_USB_MIDI_V2_H
#define __LINUX_USB_MIDI_V2_H
#include <linux/types.h>
#include <linux/usb/midi.h>
/* A.1 MS Class-Specific Interface Descriptor Types */
#define USB_DT_CS_GR_TRM_BLOCK 0x26
/* A.1 MS Class-Specific Interface Descriptor Subtypes */
/* same as MIDI 1.0 */
/* A.2 MS Class-Specific Endpoint Descriptor Subtypes */
#define USB_MS_GENERAL_2_0 0x02
/* A.3 MS Class-Specific Group Terminal Block Descriptor Subtypes */
#define USB_MS_GR_TRM_BLOCK_UNDEFINED 0x00
#define USB_MS_GR_TRM_BLOCK_HEADER 0x01
#define USB_MS_GR_TRM_BLOCK 0x02
/* A.4 MS Interface Header MIDIStreaming Class Revision */
#define USB_MS_REV_MIDI_1_0 0x0100
#define USB_MS_REV_MIDI_2_0 0x0200
/* A.5 MS MIDI IN and OUT Jack Types */
/* same as MIDI 1.0 */
/* A.6 Group Terminal Block Types */
#define USB_MS_GR_TRM_BLOCK_TYPE_BIDIRECTIONAL 0x00
#define USB_MS_GR_TRM_BLOCK_TYPE_INPUT_ONLY 0x01
#define USB_MS_GR_TRM_BLOCK_TYPE_OUTPUT_ONLY 0x02
/* A.7 Group Terminal Default MIDI Protocol */
#define USB_MS_MIDI_PROTO_UNKNOWN 0x00 /* Unknown (Use MIDI-CI) */
#define USB_MS_MIDI_PROTO_1_0_64 0x01 /* MIDI 1.0, UMP up to 64bits */
#define USB_MS_MIDI_PROTO_1_0_64_JRTS 0x02 /* MIDI 1.0, UMP up to 64bits, Jitter Reduction Timestamps */
#define USB_MS_MIDI_PROTO_1_0_128 0x03 /* MIDI 1.0, UMP up to 128bits */
#define USB_MS_MIDI_PROTO_1_0_128_JRTS 0x04 /* MIDI 1.0, UMP up to 128bits, Jitter Reduction Timestamps */
#define USB_MS_MIDI_PROTO_2_0 0x11 /* MIDI 2.0 */
#define USB_MS_MIDI_PROTO_2_0_JRTS 0x12 /* MIDI 2.0, Jitter Reduction Timestamps */
/* 5.2.2.1 Class-Specific MS Interface Header Descriptor */
/* Same as MIDI 1.0, use struct usb_ms_header_descriptor */
/* 5.3.2 Class-Specific MIDI Streaming Data Endpoint Descriptor */
struct usb_ms20_endpoint_descriptor {
__u8 bLength; /* 4+n */
__u8 bDescriptorType; /* USB_DT_CS_ENDPOINT */
__u8 bDescriptorSubtype; /* USB_MS_GENERAL_2_0 */
__u8 bNumGrpTrmBlock; /* Number of Group Terminal Blocks: n */
__u8 baAssoGrpTrmBlkID[]; /* ID of the Group Terminal Blocks [n] */
} __packed;
#define USB_DT_MS20_ENDPOINT_SIZE(n) (4 + (n))
/* As above, but more useful for defining your own descriptors: */
#define DECLARE_USB_MS20_ENDPOINT_DESCRIPTOR(n) \
struct usb_ms20_endpoint_descriptor_##n { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubtype; \
__u8 bNumGrpTrmBlock; \
__u8 baAssoGrpTrmBlkID[n]; \
} __packed
/* 5.4.1 Class-Specific Group Terminal Block Header Descriptor */
struct usb_ms20_gr_trm_block_header_descriptor {
__u8 bLength; /* 5 */
__u8 bDescriptorType; /* USB_DT_CS_GR_TRM_BLOCK */
__u8 bDescriptorSubtype; /* USB_MS_GR_TRM_BLOCK_HEADER */
__le16 wTotalLength; /* Total number of bytes */
} __packed;
/* 5.4.2.1 Group Terminal Block Descriptor */
struct usb_ms20_gr_trm_block_descriptor {
__u8 bLength; /* 13 */
__u8 bDescriptorType; /* USB_DT_CS_GR_TRM_BLOCK */
__u8 bDescriptorSubtype; /* USB_MS_GR_TRM_BLOCK */
__u8 bGrpTrmBlkID; /* ID of this Group Terminal Block */
__u8 bGrpTrmBlkType; /* Group Terminal Block Type */
__u8 nGroupTrm; /* The first member Group Terminal in this block */
__u8 nNumGroupTrm; /* Number of member Group Terminals spanned */
__u8 iBlockItem; /* String ID of Block item */
__u8 bMIDIProtocol; /* Default MIDI protocol */
__le16 wMaxInputBandwidth; /* Max input bandwidth capability in 4kB/s */
__le16 wMaxOutputBandwidth; /* Max output bandwidth capability in 4kB/s */
} __packed;
#endif /* __LINUX_USB_MIDI_V2_H */

View File

@ -65,6 +65,10 @@
#define snd_seq_ev_is_abstime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_ABS)
#define snd_seq_ev_is_reltime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_REL)
/* check whether the given event is a UMP event */
#define snd_seq_ev_is_ump(ev) \
(IS_ENABLED(CONFIG_SND_SEQ_UMP) && ((ev)->flags & SNDRV_SEQ_EVENT_UMP))
/* queue sync port */
#define snd_seq_queue_sync_port(q) ((q) + 16)

View File

@ -98,7 +98,7 @@ struct snd_card {
struct device ctl_dev; /* control device */
unsigned int last_numid; /* last used numeric ID */
struct rw_semaphore controls_rwsem; /* controls list lock */
struct rw_semaphore controls_rwsem; /* controls lock (list and values) */
rwlock_t ctl_files_rwlock; /* ctl_files list lock */
int controls_count; /* count of all controls */
size_t user_ctl_alloc_size; // current memory allocation by user controls.
@ -232,7 +232,7 @@ static inline struct device *snd_card_get_device_link(struct snd_card *card)
extern int snd_major;
extern int snd_ecards_limit;
extern struct class *sound_class;
extern const struct class sound_class;
#ifdef CONFIG_SND_DEBUG
extern struct dentry *sound_debugfs_root;
#endif

View File

@ -223,6 +223,7 @@
#define CS35L56_MBOX_CMD_AUDIO_PLAY 0x0B000001
#define CS35L56_MBOX_CMD_AUDIO_PAUSE 0x0B000002
#define CS35L56_MBOX_CMD_AUDIO_REINIT 0x0B000003
#define CS35L56_MBOX_CMD_HIBERNATE_NOW 0x02000001
#define CS35L56_MBOX_CMD_WAKEUP 0x02000002
#define CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE 0x02000003

View File

@ -44,6 +44,11 @@ enum da7219_aad_jack_ins_deb {
DA7219_AAD_JACK_INS_DEB_1S,
};
enum da7219_aad_jack_ins_det_pty {
DA7219_AAD_JACK_INS_DET_PTY_LOW = 0,
DA7219_AAD_JACK_INS_DET_PTY_HIGH,
};
enum da7219_aad_jack_det_rate {
DA7219_AAD_JACK_DET_RATE_32_64MS = 0,
DA7219_AAD_JACK_DET_RATE_64_128MS,
@ -80,6 +85,7 @@ struct da7219_aad_pdata {
enum da7219_aad_btn_cfg btn_cfg;
enum da7219_aad_mic_det_thr mic_det_thr;
enum da7219_aad_jack_ins_deb jack_ins_deb;
enum da7219_aad_jack_ins_det_pty jack_ins_det_pty;
enum da7219_aad_jack_det_rate jack_det_rate;
enum da7219_aad_jack_rem_deb jack_rem_deb;

View File

@ -38,6 +38,35 @@
#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL))
// This is used to define hardware bit-fields (sub-registers) by combining
// the bit shift and count with the actual register address. The passed
// mask must represent a single run of adjacent bits.
// The non-concatenating (_NC) variant should be used directly only for
// sub-registers that do not follow the <register>_<field> naming pattern.
#define SUB_REG_NC(reg, field, mask) \
enum { \
field ## _MASK = mask, \
field = reg | \
(__builtin_ctz(mask) << 16) | \
(__builtin_popcount(mask) << 24), \
};
#define SUB_REG(reg, field, mask) SUB_REG_NC(reg, reg ## _ ## field, mask)
// Macros for manipulating values of bit-fields declared using the above macros.
// Best used with constant register addresses, as otherwise quite some code is
// generated. The actual register read/write functions handle combined addresses
// automatically, so use of these macros conveys no advantage when accessing a
// single sub-register at a time.
#define REG_SHIFT(r) (((r) >> 16) & 0x1f)
#define REG_SIZE(r) (((r) >> 24) & 0x1f)
#define REG_MASK0(r) ((1U << REG_SIZE(r)) - 1U)
#define REG_MASK(r) (REG_MASK0(r) << REG_SHIFT(r))
#define REG_VAL_GET(r, v) ((v & REG_MASK(r)) >> REG_SHIFT(r))
#define REG_VAL_PUT(r, v) ((v) << REG_SHIFT(r))
// List terminator for snd_emu10k1_ptr_write_multiple()
#define REGLIST_END ~0
// Audigy specify registers are prefixed with 'A_'
/************************************************************************************************/
@ -90,6 +119,10 @@
#define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */
#define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */
#define IPR_CHANNELLOOP 0x00000040 /* Channel (half) loop interrupt(s) pending */
/* The interrupt is triggered shortly after */
/* CCR_READADDRESS has crossed the boundary; */
/* due to the cache, this runs ahead of the */
/* actual playback position. */
#define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */
/* highest set channel in CLIPL, CLIPH, HLIPL, */
/* or HLIPH. When IPR is written with CL set, */
@ -148,12 +181,10 @@
#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */
#define WC 0x10 /* Wall Clock register */
#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */
#define WC_SAMPLECOUNTER 0x14060010
#define WC_CURRENTCHANNEL_MASK 0x0000003F /* Channel [0..63] currently being serviced */
SUB_REG(WC, SAMPLECOUNTER, 0x03FFFFC0) /* Sample periods elapsed since reset */
SUB_REG(WC, CURRENTCHANNEL, 0x0000003F) /* Channel [0..63] currently being serviced */
/* NOTE: Each channel takes 1/64th of a sample */
/* period to be serviced. */
#define WC_CURRENTCHANNEL 0x06000010
#define HCFG 0x14 /* Hardware config register */
/* NOTE: There is no reason to use the legacy */
@ -225,9 +256,8 @@
/* async audio source */
#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
/* NOTE: This should generally never be used. */
#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */
SUB_REG(HCFG, LOCKTANKCACHE, 0x00000004) /* 1 = Cancel bustmaster accesses to tankcache */
/* NOTE: This should generally never be used. */
#define HCFG_LOCKTANKCACHE 0x01020014
#define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */
/* NOTE: This is a 'cheap' way to implement a */
/* master mute function on the mute button, and */
@ -381,56 +411,49 @@
// distortion), the modulation engine sets the target registers, towards
// which the current registers "swerve" gradually.
// For the odd channel in a stereo pair, these registers are meaningless:
// CPF_STEREO, CPF_CURRENTPITCH, PTRX_PITCHTARGET, CCR_CACHEINVALIDSIZE,
// PSST_LOOPSTARTADDR, DSL_LOOPENDADDR, CCCA_CURRADDR
// The somewhat non-obviously still meaningful ones are:
// CPF_STOP, CPF_FRACADDRESS, CCR_READADDRESS (!),
// CCCA_INTERPROM, CCCA_8BITSELECT (!)
// (The envelope engine is ignored here, as stereo matters only for verbatim playback.)
#define CPF 0x00 /* Current pitch and fraction register */
#define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */
#define CPF_CURRENTPITCH 0x10100000
SUB_REG(CPF, CURRENTPITCH, 0xffff0000) /* Current pitch (linear, 0x4000 == unity pitch shift) */
#define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */
#define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */
SUB_REG(CPF, STOP, 0x00004000) /* 1 = Current pitch forced to 0 */
/* Can be set only while matching bit in SOLEx is 1 */
#define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */
#define PTRX 0x01 /* Pitch target and send A/B amounts register */
#define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */
#define PTRX_PITCHTARGET 0x10100001
#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */
#define PTRX_FXSENDAMOUNT_A 0x08080001
#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */
#define PTRX_FXSENDAMOUNT_B 0x08000001
SUB_REG(PTRX, PITCHTARGET, 0xffff0000) /* Pitch target of specified channel */
SUB_REG(PTRX, FXSENDAMOUNT_A, 0x0000ff00) /* Linear level of channel output sent to FX send bus A */
SUB_REG(PTRX, FXSENDAMOUNT_B, 0x000000ff) /* Linear level of channel output sent to FX send bus B */
// Note: the volumes are raw multpliers, so real 100% is impossible.
#define CVCF 0x02 /* Current volume and filter cutoff register */
#define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */
#define CVCF_CURRENTVOL 0x10100002
#define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */
#define CVCF_CURRENTFILTER 0x10000002
SUB_REG(CVCF, CURRENTVOL, 0xffff0000) /* Current linear volume of specified channel */
SUB_REG(CVCF, CURRENTFILTER, 0x0000ffff) /* Current filter cutoff frequency of specified channel */
#define VTFT 0x03 /* Volume target and filter cutoff target register */
#define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */
#define VTFT_VOLUMETARGET 0x10100003
#define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */
#define VTFT_FILTERTARGET 0x10000003
SUB_REG(VTFT, VOLUMETARGET, 0xffff0000) /* Volume target of specified channel */
SUB_REG(VTFT, FILTERTARGET, 0x0000ffff) /* Filter cutoff target of specified channel */
#define Z1 0x05 /* Filter delay memory 1 register */
#define Z2 0x04 /* Filter delay memory 2 register */
#define PSST 0x06 /* Send C amount and loop start address register */
#define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */
#define PSST_FXSENDAMOUNT_C 0x08180006
#define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */
#define PSST_LOOPSTARTADDR 0x18000006
SUB_REG(PSST, FXSENDAMOUNT_C, 0xff000000) /* Linear level of channel output sent to FX send bus C */
SUB_REG(PSST, LOOPSTARTADDR, 0x00ffffff) /* Loop start address of the specified channel */
#define DSL 0x07 /* Send D amount and loop end address register */
#define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */
#define DSL_FXSENDAMOUNT_D 0x08180007
#define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */
#define DSL_LOOPENDADDR 0x18000007
SUB_REG(DSL, FXSENDAMOUNT_D, 0xff000000) /* Linear level of channel output sent to FX send bus D */
SUB_REG(DSL, LOOPENDADDR, 0x00ffffff) /* Loop end address of the specified channel */
#define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */
#define CCCA_RESONANCE_MASK 0xf0000000 /* Lowpass filter resonance (Q) height */
#define CCCA_RESONANCE 0x041c0008
SUB_REG(CCCA, RESONANCE, 0xf0000000) /* Lowpass filter resonance (Q) height */
#define CCCA_INTERPROM_MASK 0x0e000000 /* Selects passband of interpolation ROM */
/* 1 == full band, 7 == lowpass */
/* ROM 0 is used when pitch shifting downward or less */
@ -447,27 +470,24 @@
#define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */
#define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */
/* 8-bit samples are unsigned, 16-bit ones signed */
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
#define CCCA_CURRADDR 0x18000008
SUB_REG(CCCA, CURRADDR, 0x00ffffff) /* Current address of the selected channel */
#define CCR 0x09 /* Cache control register */
#define CCR_CACHEINVALIDSIZE 0x07190009
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples before the read address */
SUB_REG(CCR, CACHEINVALIDSIZE, 0xfe000000) /* Number of invalid samples before the read address */
#define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */
#define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */
/* Auto-set from CPF_STEREO_MASK */
#define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */
/* Auto-set from CCCA_8BITSELECT */
#define CCR_READADDRESS 0x06100009
#define CCR_READADDRESS_MASK 0x003f0000 /* Next cached sample to play */
#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */
SUB_REG(CCR, READADDRESS, 0x003f0000) /* Next cached sample to play */
SUB_REG(CCR, LOOPINVALSIZE, 0x0000fe00) /* Number of invalid samples in cache prior to loop */
/* NOTE: This is valid only if CACHELOOPFLAG is set */
#define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */
#define CCR_CACHELOOPADDRHI 0x000000ff /* CLP_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */
SUB_REG(CCR, CACHELOOPADDRHI, 0x000000ff) /* CLP_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */
#define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
/* NOTE: This register is normally not used */
#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address low word */
SUB_REG(CLP, CACHELOOPADDR, 0x0000ffff) /* Cache loop address low word */
#define FXRT 0x0b /* Effects send routing register */
/* NOTE: It is illegal to assign the same routing to */
@ -537,20 +557,17 @@
#define IP_UNITY 0x0000e000 /* Unity pitch shift */
#define IFATN 0x19 /* Initial filter cutoff and attenuation register */
#define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */
SUB_REG(IFATN, FILTERCUTOFF, 0x0000ff00) /* Initial filter cutoff frequency in exponential units */
/* 6 most significant bits are semitones */
/* 2 least significant bits are fractions */
#define IFATN_FILTERCUTOFF 0x08080019
#define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */
#define IFATN_ATTENUATION 0x08000019
SUB_REG(IFATN, ATTENUATION, 0x000000ff) /* Initial attenuation in 0.375dB steps */
#define PEFE 0x1a /* Pitch envelope and filter envelope amount register */
#define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */
SUB_REG(PEFE, PITCHAMOUNT, 0x0000ff00) /* Pitch envlope amount */
/* Signed 2's complement, +/- one octave peak extremes */
#define PEFE_PITCHAMOUNT 0x0808001a
#define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */
SUB_REG(PEFE, FILTERAMOUNT, 0x000000ff) /* Filter envlope amount */
/* Signed 2's complement, +/- six octaves peak extremes */
#define PEFE_FILTERAMOUNT 0x0800001a
#define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */
#define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */
@ -577,24 +594,22 @@
/* 0x1f: not used */
#define CD0 0x20 /* Cache data 0 register */
#define CD1 0x21 /* Cache data 1 register */
#define CD2 0x22 /* Cache data 2 register */
#define CD3 0x23 /* Cache data 3 register */
#define CD4 0x24 /* Cache data 4 register */
#define CD5 0x25 /* Cache data 5 register */
#define CD6 0x26 /* Cache data 6 register */
#define CD7 0x27 /* Cache data 7 register */
#define CD8 0x28 /* Cache data 8 register */
#define CD9 0x29 /* Cache data 9 register */
#define CDA 0x2a /* Cache data A register */
#define CDB 0x2b /* Cache data B register */
#define CDC 0x2c /* Cache data C register */
#define CDD 0x2d /* Cache data D register */
#define CDE 0x2e /* Cache data E register */
#define CDF 0x2f /* Cache data F register */
/* 0x30-3f seem to be the same as 0x20-2f */
// 32 cache registers (== 128 bytes) per channel follow.
// In stereo mode, the two channels' caches are concatenated into one,
// and hold the interleaved frames.
// The cache holds 64 frames, so the upper half is not used in 8-bit mode.
// All registers mentioned below count in frames.
// The cache is a ring buffer; CCR_READADDRESS operates modulo 64.
// The cache is filled from (CCCA_CURRADDR - CCR_CACHEINVALIDSIZE)
// into (CCR_READADDRESS - CCR_CACHEINVALIDSIZE).
// The engine has a fetch threshold of 32 bytes, so it tries to keep
// CCR_CACHEINVALIDSIZE below 8 (16-bit stereo), 16 (16-bit mono,
// 8-bit stereo), or 32 (8-bit mono). The actual transfers are pretty
// unpredictable, especially if several voices are running.
// Frames are consumed at CCR_READADDRESS, which is incremented afterwards,
// along with CCCA_CURRADDR and CCR_CACHEINVALIDSIZE. This implies that the
// actual playback position always lags CCCA_CURRADDR by exactly 64 frames.
#define CD0 0x20 /* Cache data registers 0 .. 0x1f */
#define PTB 0x40 /* Page table base register */
#define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */
@ -695,6 +710,8 @@
#define ADCBS_BUFSIZE_57344 0x0000001e
#define ADCBS_BUFSIZE_65536 0x0000001f
// On Audigy, the FX send amounts are not applied instantly, but determine
// targets towards which the following registers swerve gradually.
#define A_CSBA 0x4c /* FX send B & A current amounts */
#define A_CSDC 0x4d /* FX send D & C current amounts */
#define A_CSFE 0x4e /* FX send F & E current amounts */
@ -755,6 +772,9 @@
#define CLIPL 0x5a /* Channel loop interrupt pending low register */
#define CLIPH 0x5b /* Channel loop interrupt pending high register */
// These cause CPF_STOP_MASK to be set shortly after CCCA_CURRADDR passes DSL_LOOPENDADDR.
// Subsequent changes to the address registers don't resume; clearing the bit here or in CPF does.
// The registers are NOT synchronized; the next serviced channel picks up immediately.
#define SOLEL 0x5c /* Stop on loop enable low register */
#define SOLEH 0x5d /* Stop on loop enable high register */
@ -793,22 +813,19 @@
#define SRCS_SPDIFRATE_96 0x00080000
#define MICIDX 0x63 /* Microphone recording buffer index register */
#define MICIDX_MASK 0x0000ffff /* 16-bit value */
#define MICIDX_IDX 0x10000063
SUB_REG(MICIDX, IDX, 0x0000ffff)
#define ADCIDX 0x64 /* ADC recording buffer index register */
#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */
#define ADCIDX_IDX 0x10000064
SUB_REG(ADCIDX, IDX, 0x0000ffff)
#define A_ADCIDX 0x63
#define A_ADCIDX_IDX 0x10000063
SUB_REG(A_ADCIDX, IDX, 0x0000ffff)
#define A_MICIDX 0x64
#define A_MICIDX_IDX 0x10000064
SUB_REG(A_MICIDX, IDX, 0x0000ffff)
#define FXIDX 0x65 /* FX recording buffer index register */
#define FXIDX_MASK 0x0000ffff /* 16-bit value */
#define FXIDX_IDX 0x10000065
SUB_REG(FXIDX, IDX, 0x0000ffff)
/* The 32-bit HLIEx and HLIPx registers all have one bit per channel control/status */
#define HLIEL 0x66 /* Channel half loop interrupt enable low register */
@ -852,8 +869,8 @@
#define A_SPDIF_44100 0x00000080
#define A_SPDIF_MUTED 0x000000c0
#define A_I2S_CAPTURE_RATE_MASK 0x00000e00 /* This sets the capture PCM rate, but it is */
#define A_I2S_CAPTURE_RATE 0x03090076 /* unclear if this sets the ADC rate as well. */
SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM rate, but it is */
/* unclear if this sets the ADC rate as well. */
#define A_I2S_CAPTURE_48000 0x0
#define A_I2S_CAPTURE_192000 0x1
#define A_I2S_CAPTURE_96000 0x2
@ -1093,6 +1110,9 @@
#define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */
#define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */
// The actual code disagrees about the bit width of the registers -
// the formula used is freq = 0x1770000 / (((X_HI << 5) | X_LO) + 1)
#define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */
#define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */
@ -1189,9 +1209,10 @@
* physical outputs of Hana, or outputs going to Alice2/Tina for capture -
* 16 x EMU_DST_ALICE2_EMU32_X (2x on rev2 boards). Which data is fed into
* a channel depends on the mixer control setting for each destination - see
* emumixer.c - snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
* the register arrays in emumixer.c.
*/
#define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */
/* This channel is delayed by one sample. */
#define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */
@ -1422,24 +1443,35 @@
/* 0x600 and 0x700 no used */
/* ------------------- CONSTANTS -------------------- */
extern const char * const snd_emu10k1_fxbus[32];
extern const char * const snd_emu10k1_sblive_ins[16];
extern const char * const snd_emu10k1_audigy_ins[16];
extern const char * const snd_emu10k1_sblive_outs[32];
extern const char * const snd_emu10k1_audigy_outs[32];
extern const s8 snd_emu10k1_sblive51_fxbus2_map[16];
/* ------------------- STRUCTURES -------------------- */
enum {
EMU10K1_UNUSED, // This must be zero
EMU10K1_EFX,
EMU10K1_EFX_IRQ,
EMU10K1_PCM,
EMU10K1_PCM_IRQ,
EMU10K1_SYNTH,
EMU10K1_MIDI
EMU10K1_NUM_TYPES
};
struct snd_emu10k1;
struct snd_emu10k1_voice {
int number;
unsigned int use: 1,
pcm: 1,
efx: 1,
synth: 1,
midi: 1;
unsigned char number;
unsigned char use;
unsigned char dirty;
unsigned char last;
void (*interrupt)(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice);
struct snd_emu10k1_pcm *epcm;
@ -1461,7 +1493,9 @@ struct snd_emu10k1_pcm {
struct snd_emu10k1_voice *extra;
unsigned short running;
unsigned short first_ptr;
snd_pcm_uframes_t resume_pos;
struct snd_util_memblk *memblk;
unsigned int pitch_target;
unsigned int start_addr;
unsigned int ccca_start_addr;
unsigned int capture_ipr; /* interrupt acknowledge mask */
@ -1479,6 +1513,8 @@ struct snd_emu10k1_pcm_mixer {
/* mono, left, right x 8 sends (4 on emu10k1) */
unsigned char send_routing[3][8];
unsigned char send_volume[3][8];
// 0x8000 is neutral. The mixer code rescales it to 0xffff to maintain
// backwards compatibility with user space.
unsigned short attn[3];
struct snd_emu10k1_pcm *epcm;
};
@ -1492,6 +1528,9 @@ struct snd_emu10k1_pcm_mixer {
#define snd_emu10k1_compose_audigy_fxrt2(route) \
((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 24))
#define snd_emu10k1_compose_audigy_sendamounts(vol) \
(((unsigned int)vol[4] << 24) | ((unsigned int)vol[5] << 16) | ((unsigned int)vol[6] << 8) | (unsigned int)vol[7])
struct snd_emu10k1_memblk {
struct snd_util_memblk mem;
/* private part */
@ -1510,9 +1549,9 @@ struct snd_emu10k1_fx8010_ctl {
unsigned int vcount;
unsigned int count; /* count of GPR (1..16) */
unsigned short gpr[32]; /* GPR number(s) */
unsigned int value[32];
unsigned int min; /* minimum range */
unsigned int max; /* maximum range */
int value[32];
int min; /* minimum range */
int max; /* maximum range */
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
struct snd_kcontrol *kcontrol;
};
@ -1600,35 +1639,43 @@ struct snd_emu_chip_details {
u32 device;
u32 subsystem;
unsigned char revision;
unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */
/* Redundant with emu10k2_chip being unset. */
unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */
unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */
/* Redundant with ca0108_chip being unset. */
unsigned char ca0108_chip; /* Audigy 2 Value */
unsigned char ca_cardbus_chip; /* Audigy 2 ZS Notebook */
unsigned char ca0151_chip; /* P16V */
unsigned char spk71; /* Has 7.1 speakers */
unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */
unsigned char spdif_bug; /* Has Spdif phasing bug */
unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */
unsigned char ecard; /* APS EEPROM */
unsigned char emu_model; /* EMU model type */
unsigned char spi_dac; /* SPI interface for DAC; requires ca0108_chip */
unsigned char i2c_adc; /* I2C interface for ADC; requires ca0108_chip */
unsigned char adc_1361t; /* Use Philips 1361T ADC */
unsigned char invert_shared_spdif; /* analog/digital switch inverted */
unsigned char emu_model; /* EMU model type */
unsigned int emu10k1_chip:1; /* Original SB Live. Not SB Live 24bit. */
/* Redundant with emu10k2_chip being unset. */
unsigned int emu10k2_chip:1; /* Audigy 1 or Audigy 2. */
unsigned int ca0102_chip:1; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */
/* Redundant with ca0108_chip being unset. */
unsigned int ca0108_chip:1; /* Audigy 2 Value */
unsigned int ca_cardbus_chip:1; /* Audigy 2 ZS Notebook */
unsigned int ca0151_chip:1; /* P16V */
unsigned int spk20:1; /* Stereo only */
unsigned int spk71:1; /* Has 7.1 speakers */
unsigned int no_adat:1; /* Has no ADAT, only SPDIF */
unsigned int sblive51:1; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */
unsigned int spdif_bug:1; /* Has Spdif phasing bug */
unsigned int ac97_chip:2; /* Has an AC97 chip: 1 = mandatory, 2 = optional */
unsigned int ecard:1; /* APS EEPROM */
unsigned int spi_dac:1; /* SPI interface for DAC; requires ca0108_chip */
unsigned int i2c_adc:1; /* I2C interface for ADC; requires ca0108_chip */
unsigned int adc_1361t:1; /* Use Philips 1361T ADC */
unsigned int invert_shared_spdif:1; /* analog/digital switch inverted */
const char *driver;
const char *name;
const char *id; /* for backward compatibility - can be NULL if not needed */
};
#define NUM_OUTPUT_DESTS 28
#define NUM_INPUT_DESTS 22
struct snd_emu1010 {
unsigned int output_source[64];
unsigned int input_source[64];
unsigned char output_source[NUM_OUTPUT_DESTS];
unsigned char input_source[NUM_INPUT_DESTS];
unsigned int adc_pads; /* bit mask */
unsigned int dac_pads; /* bit mask */
unsigned int internal_clock; /* 44100 or 48000 */
unsigned int wclock; /* Cached register value */
unsigned int word_clock; /* Cached effective value */
unsigned int clock_source;
unsigned int clock_fallback;
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
struct delayed_work firmware_work;
@ -1653,7 +1700,6 @@ struct snd_emu10k1 {
unsigned int address_mode; /* address mode */
unsigned long dma_mask; /* PCI DMA mask */
bool iommu_workaround; /* IOMMU workaround needed */
unsigned int delay_pcm_irq; /* in samples */
int max_cache_pages; /* max memory size / PAGE_SIZE */
struct snd_dma_buffer silent_page; /* silent page */
struct snd_dma_buffer ptb_pages; /* page table pages */
@ -1775,6 +1821,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu);
/* I/O functions */
unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, ...);
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
@ -1782,6 +1829,9 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value);
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src);
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst);
int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src);
void snd_emu1010_update_clock(struct snd_emu10k1 *emu);
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
@ -1791,13 +1841,17 @@ void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum);
void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum);
void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum);
void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum);
#if 0
void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum);
void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum);
#endif
void snd_emu10k1_voice_set_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices);
void snd_emu10k1_voice_clear_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices);
int snd_emu10k1_voice_clear_loop_stop_multiple_atomic(struct snd_emu10k1 *emu, u64 voices);
void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait);
static inline unsigned int snd_emu10k1_wc(struct snd_emu10k1 *emu) { return (inl(emu->port + WC) >> 6) & 0xfffff; }
unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
#ifdef CONFIG_PM_SLEEP
void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);
@ -1825,7 +1879,8 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me
int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk);
/* voice allocation */
int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int pair, struct snd_emu10k1_voice **rvoice);
int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels,
struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice);
int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice);
/* MIDI uart */

View File

@ -54,6 +54,7 @@ struct snd_emux_operators {
#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
int (*oss_ioctl)(struct snd_emux *emu, int cmd, int p1, int p2);
#endif
int (*get_pitch_shift)(struct snd_emux *emu);
};
@ -82,7 +83,6 @@ struct snd_emux {
int max_voices; /* Number of voices */
int mem_size; /* memory size (in byte) */
int num_ports; /* number of ports to be created */
int pitch_shift; /* pitch shift value (for Emu10k1) */
struct snd_emux_operators ops; /* operators */
void *hw; /* hardware */
unsigned long flags; /* other conditions */

View File

@ -347,6 +347,8 @@ struct hdac_bus {
bool corbrp_self_clear:1; /* CORBRP clears itself after reset */
bool polling_mode:1;
bool needs_damn_long_delay:1;
bool not_use_interrupts:1; /* prohibiting the RIRB IRQ */
bool access_sdnctl_in_dword:1; /* accessing the sdnctl register by dword */
int poll_count;

View File

@ -18,6 +18,7 @@
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
#include <sound/seq_device.h>
#endif
#include <sound/info.h>
/*
* Raw MIDI interface
@ -47,6 +48,10 @@ struct snd_rawmidi_global_ops {
int (*dev_unregister) (struct snd_rawmidi * rmidi);
void (*get_port_info)(struct snd_rawmidi *rmidi, int number,
struct snd_seq_port_info *info);
long (*ioctl)(struct snd_rawmidi *rmidi, unsigned int cmd,
void __user *argp);
void (*proc_read)(struct snd_info_entry *entry,
struct snd_info_buffer *buf);
};
struct snd_rawmidi_runtime {
@ -61,6 +66,7 @@ struct snd_rawmidi_runtime {
size_t avail_min; /* min avail for wakeup */
size_t avail; /* max used buffer for wakeup */
size_t xruns; /* over/underruns counter */
size_t align; /* alignment (0 = byte stream, 3 = UMP) */
int buffer_ref; /* buffer reference count */
/* misc */
wait_queue_head_t sleep;
@ -146,6 +152,13 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
const struct snd_rawmidi_ops *ops);
/* internal */
int snd_rawmidi_init(struct snd_rawmidi *rmidi,
struct snd_card *card, char *id, int device,
int output_count, int input_count,
unsigned int info_flags);
int snd_rawmidi_free(struct snd_rawmidi *rmidi);
/* callbacks */
int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
@ -161,7 +174,7 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
/* main midi functions */
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info);
int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile);
int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile);
int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,

View File

@ -78,5 +78,6 @@ void snd_seq_driver_unregister(struct snd_seq_driver *drv);
*/
#define SNDRV_SEQ_DEV_ID_MIDISYNTH "seq-midi"
#define SNDRV_SEQ_DEV_ID_OPL3 "opl3-synth"
#define SNDRV_SEQ_DEV_ID_UMP "seq-ump-client"
#endif /* __SOUND_SEQ_DEVICE_H */

View File

@ -70,9 +70,19 @@ int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void *arg);
typedef int (*snd_seq_dump_func_t)(void *ptr, void *buf, int count);
int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char *buf,
int in_kernel, int size_aligned);
int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count,
char *buf, int offset);
int snd_seq_dump_var_event(const struct snd_seq_event *event,
snd_seq_dump_func_t func, void *private_data);
/* size of the event packet; it can be greater than snd_seq_event size */
static inline size_t snd_seq_event_packet_size(struct snd_seq_event *ev)
{
if (snd_seq_ev_is_ump(ev))
return sizeof(struct snd_seq_ump_event);
return sizeof(struct snd_seq_event);
}
/* interface for OSS emulation */
int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo);

View File

@ -59,9 +59,6 @@ struct asoc_simple_priv {
struct simple_dai_props {
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platforms;
struct asoc_simple_data adata;
struct snd_soc_codec_conf *codec_conf;
struct prop_nums num;
@ -73,7 +70,6 @@ struct asoc_simple_priv {
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct snd_soc_dai_link_component *dlcs;
struct snd_soc_dai_link_component dummy;
struct snd_soc_codec_conf *codec_conf;
struct gpio_desc *pa_gpio;
const struct snd_soc_ops *ops;
@ -196,6 +192,9 @@ int asoc_simple_remove(struct platform_device *pdev);
int asoc_graph_card_probe(struct snd_soc_card *card);
int asoc_graph_is_ports0(struct device_node *port);
int asoc_graph_parse_dai(struct device_node *ep,
struct snd_soc_dai_link_component *dlc,
int *is_single_link);
#ifdef DEBUG
static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,

View File

@ -31,6 +31,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
@ -40,6 +41,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with

View File

@ -158,6 +158,15 @@ struct snd_soc_component_driver {
int probe_order;
int remove_order;
/*
* soc_pcm_trigger() start/stop sequence.
* see also
* snd_soc_dai_link
* soc_pcm_trigger()
*/
enum snd_soc_trigger_order trigger_start;
enum snd_soc_trigger_order trigger_stop;
/*
* signal if the module handling the component should not be removed
* if a pcm is open. Setting this would prevent the module
@ -190,8 +199,6 @@ struct snd_soc_component_driver {
bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */
int be_pcm_base; /* base device ID for all BE PCMs */
unsigned int start_dma_last;
#ifdef CONFIG_DEBUG_FS
const char *debugfs_prefix;
#endif
@ -454,6 +461,10 @@ int snd_soc_component_force_enable_pin_unlocked(
struct snd_soc_component *component,
const char *pin);
/* component controls */
int snd_soc_component_notify_control(struct snd_soc_component *component,
const char * const ctl);
/* component driver ops */
int snd_soc_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream);

View File

@ -607,6 +607,14 @@ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
enum snd_soc_trigger_order {
/* start stop */
SND_SOC_TRIGGER_ORDER_DEFAULT = 0, /* Link->Component->DAI DAI->Component->Link */
SND_SOC_TRIGGER_ORDER_LDC, /* Link->DAI->Component Component->DAI->Link */
SND_SOC_TRIGGER_ORDER_MAX,
};
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
const char *stream_name;
@ -633,7 +641,6 @@ struct snd_soc_compr_ops {
int (*startup)(struct snd_compr_stream *);
void (*shutdown)(struct snd_compr_stream *);
int (*set_params)(struct snd_compr_stream *);
int (*trigger)(struct snd_compr_stream *);
};
struct snd_soc_component*
@ -646,6 +653,11 @@ struct snd_soc_dai_link_component {
const char *dai_name;
};
struct snd_soc_dai_link_codec_ch_map {
unsigned int connected_cpu_id;
unsigned int ch_mask;
};
struct snd_soc_dai_link {
/* config - must be set by machine driver */
const char *name; /* Codec name */
@ -674,6 +686,7 @@ struct snd_soc_dai_link {
struct snd_soc_dai_link_component *codecs;
unsigned int num_codecs;
struct snd_soc_dai_link_codec_ch_map *codec_ch_maps;
/*
* You MAY specify the link's platform/PCM/DMA driver, either by
* device name, or by DT/OF node, but not both. Some forms of link
@ -708,6 +721,15 @@ struct snd_soc_dai_link {
const struct snd_soc_ops *ops;
const struct snd_soc_compr_ops *compr_ops;
/*
* soc_pcm_trigger() start/stop sequence.
* see also
* snd_soc_component_driver
* soc_pcm_trigger()
*/
enum snd_soc_trigger_order trigger_start;
enum snd_soc_trigger_order trigger_stop;
/* Mark this pcm with non atomic ops */
unsigned int nonatomic:1;
@ -746,12 +768,6 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1;
/* This flag will reorder stop sequence. By enabling this flag
* DMA controller stop sequence will be invoked first followed by
* CPU DAI driver stop sequence
*/
unsigned int stop_dma_first:1;
#ifdef CONFIG_SND_SOC_TOPOLOGY
struct snd_soc_dobj dobj; /* For topology */
#endif
@ -878,6 +894,7 @@ asoc_link_to_platform(struct snd_soc_dai_link *link, int n) {
#define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", }
extern struct snd_soc_dai_link_component null_dailink_component[0];
extern struct snd_soc_dai_link_component asoc_dummy_dlc;
struct snd_soc_codec_conf {
@ -1291,11 +1308,18 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
snd_soc_daifmt_clock_provider_from_bitmap( \
snd_soc_daifmt_parse_clock_provider_as_bitmap(np, prefix))
int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream);
int snd_soc_get_dlc(const struct of_phandle_args *args,
struct snd_soc_dai_link_component *dlc);
int snd_soc_of_get_dlc(struct device_node *of_node,
struct of_phandle_args *args,
struct snd_soc_dai_link_component *dlc,
int index);
int snd_soc_get_dai_id(struct device_node *ep);
int snd_soc_get_dai_name(const struct of_phandle_args *args,
const char **dai_name);
int snd_soc_of_get_dai_name(struct device_node *of_node,
const char **dai_name);
const char **dai_name, int index);
int snd_soc_of_get_dai_link_codecs(struct device *dev,
struct device_node *of_node,
struct snd_soc_dai_link *dai_link);

183
include/sound/tas2781-dsp.h Normal file
View File

@ -0,0 +1,183 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2781 driver implements a flexible and configurable
// algo coefficient setting for one, two, or even multiple
// TAS2781 chips.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
// Author: Kevin Lu <kevin-lu@ti.com>
//
#ifndef __TASDEVICE_DSP_H__
#define __TASDEVICE_DSP_H__
#define MAIN_ALL_DEVICES 0x0d
#define MAIN_DEVICE_A 0x01
#define MAIN_DEVICE_B 0x08
#define MAIN_DEVICE_C 0x10
#define MAIN_DEVICE_D 0x14
#define COEFF_DEVICE_A 0x03
#define COEFF_DEVICE_B 0x0a
#define COEFF_DEVICE_C 0x11
#define COEFF_DEVICE_D 0x15
#define PRE_DEVICE_A 0x04
#define PRE_DEVICE_B 0x0b
#define PRE_DEVICE_C 0x12
#define PRE_DEVICE_D 0x16
#define PPC3_VERSION 0x4100
#define PPC3_VERSION_TAS2781 0x14600
#define TASDEVICE_DEVICE_SUM 8
#define TASDEVICE_CONFIG_SUM 64
#define TASDEVICE_MAX_CHANNELS 8
enum tasdevice_dsp_dev_idx {
TASDEVICE_DSP_TAS_2555 = 0,
TASDEVICE_DSP_TAS_2555_STEREO,
TASDEVICE_DSP_TAS_2557_MONO,
TASDEVICE_DSP_TAS_2557_DUAL_MONO,
TASDEVICE_DSP_TAS_2559,
TASDEVICE_DSP_TAS_2563,
TASDEVICE_DSP_TAS_2563_DUAL_MONO = 7,
TASDEVICE_DSP_TAS_2563_QUAD,
TASDEVICE_DSP_TAS_2563_21,
TASDEVICE_DSP_TAS_2781,
TASDEVICE_DSP_TAS_2781_DUAL_MONO,
TASDEVICE_DSP_TAS_2781_21,
TASDEVICE_DSP_TAS_2781_QUAD,
TASDEVICE_DSP_TAS_MAX_DEVICE
};
struct tasdevice_fw_fixed_hdr {
unsigned int fwsize;
unsigned int ppcver;
unsigned int drv_ver;
};
struct tasdevice_dspfw_hdr {
struct tasdevice_fw_fixed_hdr fixed_hdr;
unsigned short device_family;
unsigned short device;
unsigned char ndev;
};
struct tasdev_blk {
int nr_retry;
unsigned int type;
unsigned char is_pchksum_present;
unsigned char pchksum;
unsigned char is_ychksum_present;
unsigned char ychksum;
unsigned int nr_cmds;
unsigned int blk_size;
unsigned int nr_subblocks;
unsigned char *data;
};
struct tasdevice_data {
char name[64];
unsigned int nr_blk;
struct tasdev_blk *dev_blks;
};
struct tasdevice_prog {
unsigned int prog_size;
struct tasdevice_data dev_data;
};
struct tasdevice_config {
unsigned int cfg_size;
char name[64];
struct tasdevice_data dev_data;
};
struct tasdevice_calibration {
struct tasdevice_data dev_data;
};
struct tasdevice_fw {
struct tasdevice_dspfw_hdr fw_hdr;
unsigned short nr_programs;
struct tasdevice_prog *programs;
unsigned short nr_configurations;
struct tasdevice_config *configs;
unsigned short nr_calibrations;
struct tasdevice_calibration *calibrations;
struct device *dev;
};
enum tasdevice_dsp_fw_state {
TASDEVICE_DSP_FW_NONE = 0,
TASDEVICE_DSP_FW_PENDING,
TASDEVICE_DSP_FW_FAIL,
TASDEVICE_DSP_FW_ALL_OK,
};
enum tasdevice_bin_blk_type {
TASDEVICE_BIN_BLK_COEFF = 1,
TASDEVICE_BIN_BLK_POST_POWER_UP,
TASDEVICE_BIN_BLK_PRE_SHUTDOWN,
TASDEVICE_BIN_BLK_PRE_POWER_UP,
TASDEVICE_BIN_BLK_POST_SHUTDOWN
};
struct tasdevice_rca_hdr {
unsigned int img_sz;
unsigned int checksum;
unsigned int binary_version_num;
unsigned int drv_fw_version;
unsigned char plat_type;
unsigned char dev_family;
unsigned char reserve;
unsigned char ndev;
unsigned char devs[TASDEVICE_DEVICE_SUM];
unsigned int nconfig;
unsigned int config_size[TASDEVICE_CONFIG_SUM];
};
struct tasdev_blk_data {
unsigned char dev_idx;
unsigned char block_type;
unsigned short yram_checksum;
unsigned int block_size;
unsigned int n_subblks;
unsigned char *regdata;
};
struct tasdevice_config_info {
unsigned int nblocks;
unsigned int real_nblocks;
unsigned char active_dev;
struct tasdev_blk_data **blk_data;
};
struct tasdevice_rca {
struct tasdevice_rca_hdr fw_hdr;
int ncfgs;
struct tasdevice_config_info **cfg_info;
int profile_cfg_id;
};
void tasdevice_select_cfg_blk(void *context, int conf_no,
unsigned char block_type);
void tasdevice_config_info_remove(void *context);
void tasdevice_dsp_remove(void *context);
int tasdevice_dsp_parser(void *context);
int tasdevice_rca_parser(void *context, const struct firmware *fmw);
void tasdevice_dsp_remove(void *context);
void tasdevice_calbin_remove(void *context);
int tasdevice_select_tuningprm_cfg(void *context, int prm,
int cfg_no, int rca_conf_no);
int tasdevice_prmg_load(void *context, int prm_no);
int tasdevice_prmg_calibdata_load(void *context, int prm_no);
void tasdevice_tuning_switch(void *context, int state);
int tas2781_load_calibration(void *context, char *file_name,
unsigned short i);
#endif

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2781 driver implements a flexible and configurable
// algo coefficient setting for one, two, or even multiple
// TAS2781 chips.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
//
#ifndef __TAS2781_TLV_H__
#define __TAS2781_TLV_H__
static const DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0);
static const DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0);
#endif

164
include/sound/tas2781.h Normal file
View File

@ -0,0 +1,164 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2022 - 2023 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2781 driver implements a flexible and configurable
// algo coefficient setting for one, two, or even multiple
// TAS2781 chips.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
// Author: Kevin Lu <kevin-lu@ti.com>
//
#ifndef __TAS2781_H__
#define __TAS2781_H__
#include "tas2781-dsp.h"
/* version number */
#define TAS2781_DRV_VER 1
#define SMARTAMP_MODULE_NAME "tas2781"
#define TAS2781_GLOBAL_ADDR 0x40
#define TASDEVICE_RATES (SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_88200)
#define TASDEVICE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
/*PAGE Control Register (available in page0 of each book) */
#define TASDEVICE_PAGE_SELECT 0x00
#define TASDEVICE_BOOKCTL_PAGE 0x00
#define TASDEVICE_BOOKCTL_REG 127
#define TASDEVICE_BOOK_ID(reg) (reg / (256 * 128))
#define TASDEVICE_PAGE_ID(reg) ((reg % (256 * 128)) / 128)
#define TASDEVICE_PAGE_REG(reg) ((reg % (256 * 128)) % 128)
#define TASDEVICE_PGRG(reg) (reg % (256 * 128))
#define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \
(page * 128)) + reg)
/*Software Reset */
#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0X0, 0x01)
#define TAS2781_REG_SWRESET_RESET BIT(0)
/*I2C Checksum */
#define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E)
/* Volume control */
#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A)
#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
#define TASDEVICE_CMD_SING_W 0x1
#define TASDEVICE_CMD_BURST 0x2
#define TASDEVICE_CMD_DELAY 0x3
#define TASDEVICE_CMD_FIELD_W 0x4
enum audio_device {
TAS2781 = 0,
};
enum device_catlog_id {
LENOVO = 0,
OTHERS
};
struct tasdevice {
struct tasdevice_fw *cali_data_fmw;
unsigned int dev_addr;
unsigned int err_code;
unsigned char cur_book;
short cur_prog;
short cur_conf;
bool is_loading;
bool is_loaderr;
};
struct tasdevice_irqinfo {
int irq_gpio;
int irq;
};
struct calidata {
unsigned char *data;
unsigned long total_sz;
};
struct tasdevice_priv {
struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS];
struct tasdevice_irqinfo irq_info;
struct tasdevice_rca rcabin;
struct calidata cali_data;
struct tasdevice_fw *fmw;
struct gpio_desc *reset;
struct mutex codec_lock;
struct regmap *regmap;
struct device *dev;
struct tm tm;
enum device_catlog_id catlog_id;
const char *acpi_subsystem_id;
unsigned char cal_binaryname[TASDEVICE_MAX_CHANNELS][64];
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
unsigned char coef_binaryname[64];
unsigned char rca_binaryname[64];
unsigned char dev_name[32];
unsigned char ndev;
unsigned int magic_num;
unsigned int chip_id;
unsigned int sysclk;
int cur_prog;
int cur_conf;
int fw_state;
int index;
void *client;
void *codec;
bool force_fwload_status;
bool playback_started;
bool isacpi;
int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
const struct firmware *fmw, int offset);
int (*fw_parse_program_data)(struct tasdevice_priv *tas_priv,
struct tasdevice_fw *tas_fmw,
const struct firmware *fmw, int offset);
int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv,
struct tasdevice_fw *tas_fmw,
const struct firmware *fmw, int offset);
int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
struct tasdev_blk *block);
};
void tas2781_reset(struct tasdevice_priv *tas_dev);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
void (*cont)(const struct firmware *fw, void *context));
struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c);
int tasdevice_init(struct tasdevice_priv *tas_priv);
void tasdevice_remove(struct tasdevice_priv *tas_priv);
int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *value);
int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int value);
int tasdevice_dev_bulk_write(
struct tasdevice_priv *tas_priv, unsigned short chn,
unsigned int reg, unsigned char *p_data, unsigned int n_length);
int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_dev_update_bits(
struct tasdevice_priv *tasdevice, unsigned short chn,
unsigned int reg, unsigned int mask, unsigned int value);
int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
#endif /* __TAS2781_H__ */

268
include/sound/ump.h Normal file
View File

@ -0,0 +1,268 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Universal MIDI Packet (UMP) Support
*/
#ifndef __SOUND_UMP_H
#define __SOUND_UMP_H
#include <sound/rawmidi.h>
struct snd_ump_endpoint;
struct snd_ump_block;
struct snd_ump_ops;
struct ump_cvt_to_ump;
struct snd_seq_ump_ops;
struct snd_ump_endpoint {
struct snd_rawmidi core; /* raw UMP access */
struct snd_ump_endpoint_info info;
const struct snd_ump_ops *ops; /* UMP ops set by the driver */
struct snd_rawmidi_substream *substreams[2]; /* opened substreams */
void *private_data;
void (*private_free)(struct snd_ump_endpoint *ump);
/* UMP Stream message processing */
u32 stream_wait_for; /* expected stream message status */
bool stream_finished; /* set when message has been processed */
bool parsed; /* UMP / FB parse finished? */
bool no_process_stream; /* suppress UMP stream messages handling */
wait_queue_head_t stream_wait;
struct snd_rawmidi_file stream_rfile;
struct list_head block_list; /* list of snd_ump_block objects */
/* intermediate buffer for UMP input */
u32 input_buf[4];
int input_buf_head;
int input_pending;
struct mutex open_mutex;
#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
spinlock_t legacy_locks[2];
struct snd_rawmidi *legacy_rmidi;
struct snd_rawmidi_substream *legacy_substreams[2][SNDRV_UMP_MAX_GROUPS];
/* for legacy output; need to open the actual substream unlike input */
int legacy_out_opens;
struct snd_rawmidi_file legacy_out_rfile;
struct ump_cvt_to_ump *out_cvts;
#endif
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
struct snd_seq_device *seq_dev;
const struct snd_seq_ump_ops *seq_ops;
void *seq_client;
#endif
};
/* ops filled by UMP drivers */
struct snd_ump_ops {
int (*open)(struct snd_ump_endpoint *ump, int dir);
void (*close)(struct snd_ump_endpoint *ump, int dir);
void (*trigger)(struct snd_ump_endpoint *ump, int dir, int up);
void (*drain)(struct snd_ump_endpoint *ump, int dir);
};
/* ops filled by sequencer binding */
struct snd_seq_ump_ops {
void (*input_receive)(struct snd_ump_endpoint *ump,
const u32 *data, int words);
int (*notify_fb_change)(struct snd_ump_endpoint *ump,
struct snd_ump_block *fb);
int (*switch_protocol)(struct snd_ump_endpoint *ump);
};
struct snd_ump_block {
struct snd_ump_block_info info;
struct snd_ump_endpoint *ump;
void *private_data;
void (*private_free)(struct snd_ump_block *blk);
struct list_head list;
};
#define rawmidi_to_ump(rmidi) container_of(rmidi, struct snd_ump_endpoint, core)
int snd_ump_endpoint_new(struct snd_card *card, char *id, int device,
int output, int input,
struct snd_ump_endpoint **ump_ret);
int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump);
int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk,
unsigned int direction, unsigned int first_group,
unsigned int num_groups, struct snd_ump_block **blk_ret);
int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count);
int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count);
#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
char *id, int device);
#else
static inline int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
char *id, int device)
{
return 0;
}
#endif
int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val);
int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol);
/*
* Some definitions for UMP
*/
/* MIDI 2.0 Message Type */
enum {
UMP_MSG_TYPE_UTILITY = 0x00,
UMP_MSG_TYPE_SYSTEM = 0x01,
UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE = 0x02,
UMP_MSG_TYPE_DATA = 0x03,
UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE = 0x04,
UMP_MSG_TYPE_EXTENDED_DATA = 0x05,
UMP_MSG_TYPE_FLEX_DATA = 0x0d,
UMP_MSG_TYPE_STREAM = 0x0f,
};
/* MIDI 2.0 SysEx / Data Status; same values for both 7-bit and 8-bit SysEx */
enum {
UMP_SYSEX_STATUS_SINGLE = 0,
UMP_SYSEX_STATUS_START = 1,
UMP_SYSEX_STATUS_CONTINUE = 2,
UMP_SYSEX_STATUS_END = 3,
};
/* UMP Utility Type Status (type 0x0) */
enum {
UMP_UTILITY_MSG_STATUS_NOOP = 0x00,
UMP_UTILITY_MSG_STATUS_JR_CLOCK = 0x01,
UMP_UTILITY_MSG_STATUS_JR_TSTAMP = 0x02,
UMP_UTILITY_MSG_STATUS_DCTPQ = 0x03,
UMP_UTILITY_MSG_STATUS_DC = 0x04,
};
/* UMP Stream Message Status (type 0xf) */
enum {
UMP_STREAM_MSG_STATUS_EP_DISCOVERY = 0x00,
UMP_STREAM_MSG_STATUS_EP_INFO = 0x01,
UMP_STREAM_MSG_STATUS_DEVICE_INFO = 0x02,
UMP_STREAM_MSG_STATUS_EP_NAME = 0x03,
UMP_STREAM_MSG_STATUS_PRODUCT_ID = 0x04,
UMP_STREAM_MSG_STATUS_STREAM_CFG_REQUEST = 0x05,
UMP_STREAM_MSG_STATUS_STREAM_CFG = 0x06,
UMP_STREAM_MSG_STATUS_FB_DISCOVERY = 0x10,
UMP_STREAM_MSG_STATUS_FB_INFO = 0x11,
UMP_STREAM_MSG_STATUS_FB_NAME = 0x12,
UMP_STREAM_MSG_STATUS_START_CLIP = 0x20,
UMP_STREAM_MSG_STATUS_END_CLIP = 0x21,
};
/* UMP Endpoint Discovery filter bitmap */
enum {
UMP_STREAM_MSG_REQUEST_EP_INFO = (1U << 0),
UMP_STREAM_MSG_REQUEST_DEVICE_INFO = (1U << 1),
UMP_STREAM_MSG_REQUEST_EP_NAME = (1U << 2),
UMP_STREAM_MSG_REQUEST_PRODUCT_ID = (1U << 3),
UMP_STREAM_MSG_REQUEST_STREAM_CFG = (1U << 4),
};
/* UMP Function Block Discovery filter bitmap */
enum {
UMP_STREAM_MSG_REQUEST_FB_INFO = (1U << 0),
UMP_STREAM_MSG_REQUEST_FB_NAME = (1U << 1),
};
/* UMP Endpoint Info capability bits (used for protocol request/notify, too) */
enum {
UMP_STREAM_MSG_EP_INFO_CAP_TXJR = (1U << 0), /* Sending JRTS */
UMP_STREAM_MSG_EP_INFO_CAP_RXJR = (1U << 1), /* Receiving JRTS */
UMP_STREAM_MSG_EP_INFO_CAP_MIDI1 = (1U << 8), /* MIDI 1.0 */
UMP_STREAM_MSG_EP_INFO_CAP_MIDI2 = (1U << 9), /* MIDI 2.0 */
};
/* UMP EP / FB name string format; same as SysEx string handling */
enum {
UMP_STREAM_MSG_FORMAT_SINGLE = 0,
UMP_STREAM_MSG_FORMAT_START = 1,
UMP_STREAM_MSG_FORMAT_CONTINUE = 2,
UMP_STREAM_MSG_FORMAT_END = 3,
};
/*
* Helpers for retrieving / filling bits from UMP
*/
/* get the message type (4bit) from a UMP packet (header) */
static inline unsigned char ump_message_type(u32 data)
{
return data >> 28;
}
/* get the group number (0-based, 4bit) from a UMP packet (header) */
static inline unsigned char ump_message_group(u32 data)
{
return (data >> 24) & 0x0f;
}
/* get the MIDI status code (4bit) from a UMP packet (header) */
static inline unsigned char ump_message_status_code(u32 data)
{
return (data >> 20) & 0x0f;
}
/* get the MIDI channel number (0-based, 4bit) from a UMP packet (header) */
static inline unsigned char ump_message_channel(u32 data)
{
return (data >> 16) & 0x0f;
}
/* get the MIDI status + channel combo byte (8bit) from a UMP packet (header) */
static inline unsigned char ump_message_status_channel(u32 data)
{
return (data >> 16) & 0xff;
}
/* compose a UMP packet (header) from type, group and status values */
static inline u32 ump_compose(unsigned char type, unsigned char group,
unsigned char status, unsigned char channel)
{
return ((u32)type << 28) | ((u32)group << 24) | ((u32)status << 20) |
((u32)channel << 16);
}
/* get SysEx message status (for both 7 and 8bits) from a UMP packet (header) */
static inline unsigned char ump_sysex_message_status(u32 data)
{
return (data >> 20) & 0xf;
}
/* get SysEx message length (for both 7 and 8bits) from a UMP packet (header) */
static inline unsigned char ump_sysex_message_length(u32 data)
{
return (data >> 16) & 0xf;
}
/* For Stream Messages */
static inline unsigned char ump_stream_message_format(u32 data)
{
return (data >> 26) & 0x03;
}
static inline unsigned int ump_stream_message_status(u32 data)
{
return (data >> 16) & 0x3ff;
}
static inline u32 ump_stream_compose(unsigned char status, unsigned short form)
{
return (UMP_MSG_TYPE_STREAM << 28) | ((u32)form << 26) |
((u32)status << 16);
}
#define ump_is_groupless_msg(type) \
((type) == UMP_MSG_TYPE_UTILITY || (type) == UMP_MSG_TYPE_STREAM)
#endif /* __SOUND_UMP_H */

View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef __SOUND_UMP_CONVERT_H
#define __SOUND_UMP_CONVERT_H
#include <sound/ump_msg.h>
/* context for converting from legacy control messages to UMP packet */
struct ump_cvt_to_ump_bank {
bool rpn_set;
bool nrpn_set;
bool bank_set;
unsigned char cc_rpn_msb, cc_rpn_lsb;
unsigned char cc_nrpn_msb, cc_nrpn_lsb;
unsigned char cc_data_msb, cc_data_lsb;
unsigned char cc_bank_msb, cc_bank_lsb;
};
/* context for converting from MIDI1 byte stream to UMP packet */
struct ump_cvt_to_ump {
/* MIDI1 intermediate buffer */
unsigned char buf[4];
int len;
int cmd_bytes;
/* UMP output packet */
u32 ump[4];
int ump_bytes;
/* various status */
unsigned int in_sysex;
struct ump_cvt_to_ump_bank bank[16]; /* per channel */
};
int snd_ump_convert_from_ump(const u32 *data, unsigned char *dst,
unsigned char *group_ret);
void snd_ump_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group,
unsigned int protocol, unsigned char c);
/* reset the converter context, called at each open to ump */
static inline void snd_ump_convert_reset(struct ump_cvt_to_ump *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
#endif /* __SOUND_UMP_CONVERT_H */

765
include/sound/ump_msg.h Normal file
View File

@ -0,0 +1,765 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Universal MIDI Packet (UMP): Message Definitions
*/
#ifndef __SOUND_UMP_MSG_H
#define __SOUND_UMP_MSG_H
/* MIDI 1.0 / 2.0 Status Code (4bit) */
enum {
UMP_MSG_STATUS_PER_NOTE_RCC = 0x0,
UMP_MSG_STATUS_PER_NOTE_ACC = 0x1,
UMP_MSG_STATUS_RPN = 0x2,
UMP_MSG_STATUS_NRPN = 0x3,
UMP_MSG_STATUS_RELATIVE_RPN = 0x4,
UMP_MSG_STATUS_RELATIVE_NRPN = 0x5,
UMP_MSG_STATUS_PER_NOTE_PITCH_BEND = 0x6,
UMP_MSG_STATUS_NOTE_OFF = 0x8,
UMP_MSG_STATUS_NOTE_ON = 0x9,
UMP_MSG_STATUS_POLY_PRESSURE = 0xa,
UMP_MSG_STATUS_CC = 0xb,
UMP_MSG_STATUS_PROGRAM = 0xc,
UMP_MSG_STATUS_CHANNEL_PRESSURE = 0xd,
UMP_MSG_STATUS_PITCH_BEND = 0xe,
UMP_MSG_STATUS_PER_NOTE_MGMT = 0xf,
};
/* MIDI 1.0 Channel Control (7bit) */
enum {
UMP_CC_BANK_SELECT = 0,
UMP_CC_MODULATION = 1,
UMP_CC_BREATH = 2,
UMP_CC_FOOT = 4,
UMP_CC_PORTAMENTO_TIME = 5,
UMP_CC_DATA = 6,
UMP_CC_VOLUME = 7,
UMP_CC_BALANCE = 8,
UMP_CC_PAN = 10,
UMP_CC_EXPRESSION = 11,
UMP_CC_EFFECT_CONTROL_1 = 12,
UMP_CC_EFFECT_CONTROL_2 = 13,
UMP_CC_GP_1 = 16,
UMP_CC_GP_2 = 17,
UMP_CC_GP_3 = 18,
UMP_CC_GP_4 = 19,
UMP_CC_BANK_SELECT_LSB = 32,
UMP_CC_MODULATION_LSB = 33,
UMP_CC_BREATH_LSB = 34,
UMP_CC_FOOT_LSB = 36,
UMP_CC_PORTAMENTO_TIME_LSB = 37,
UMP_CC_DATA_LSB = 38,
UMP_CC_VOLUME_LSB = 39,
UMP_CC_BALANCE_LSB = 40,
UMP_CC_PAN_LSB = 42,
UMP_CC_EXPRESSION_LSB = 43,
UMP_CC_EFFECT1_LSB = 44,
UMP_CC_EFFECT2_LSB = 45,
UMP_CC_GP_1_LSB = 48,
UMP_CC_GP_2_LSB = 49,
UMP_CC_GP_3_LSB = 50,
UMP_CC_GP_4_LSB = 51,
UMP_CC_SUSTAIN = 64,
UMP_CC_PORTAMENTO_SWITCH = 65,
UMP_CC_SOSTENUTO = 66,
UMP_CC_SOFT_PEDAL = 67,
UMP_CC_LEGATO = 68,
UMP_CC_HOLD_2 = 69,
UMP_CC_SOUND_CONTROLLER_1 = 70,
UMP_CC_SOUND_CONTROLLER_2 = 71,
UMP_CC_SOUND_CONTROLLER_3 = 72,
UMP_CC_SOUND_CONTROLLER_4 = 73,
UMP_CC_SOUND_CONTROLLER_5 = 74,
UMP_CC_SOUND_CONTROLLER_6 = 75,
UMP_CC_SOUND_CONTROLLER_7 = 76,
UMP_CC_SOUND_CONTROLLER_8 = 77,
UMP_CC_SOUND_CONTROLLER_9 = 78,
UMP_CC_SOUND_CONTROLLER_10 = 79,
UMP_CC_GP_5 = 80,
UMP_CC_GP_6 = 81,
UMP_CC_GP_7 = 82,
UMP_CC_GP_8 = 83,
UMP_CC_PORTAMENTO_CONTROL = 84,
UMP_CC_EFFECT_1 = 91,
UMP_CC_EFFECT_2 = 92,
UMP_CC_EFFECT_3 = 93,
UMP_CC_EFFECT_4 = 94,
UMP_CC_EFFECT_5 = 95,
UMP_CC_DATA_INC = 96,
UMP_CC_DATA_DEC = 97,
UMP_CC_NRPN_LSB = 98,
UMP_CC_NRPN_MSB = 99,
UMP_CC_RPN_LSB = 100,
UMP_CC_RPN_MSB = 101,
UMP_CC_ALL_SOUND_OFF = 120,
UMP_CC_RESET_ALL = 121,
UMP_CC_LOCAL_CONTROL = 122,
UMP_CC_ALL_NOTES_OFF = 123,
UMP_CC_OMNI_OFF = 124,
UMP_CC_OMNI_ON = 125,
UMP_CC_POLY_OFF = 126,
UMP_CC_POLY_ON = 127,
};
/* MIDI 1.0 / 2.0 System Messages (0xfx) */
enum {
UMP_SYSTEM_STATUS_MIDI_TIME_CODE = 0xf1,
UMP_SYSTEM_STATUS_SONG_POSITION = 0xf2,
UMP_SYSTEM_STATUS_SONG_SELECT = 0xf3,
UMP_SYSTEM_STATUS_TUNE_REQUEST = 0xf6,
UMP_SYSTEM_STATUS_TIMING_CLOCK = 0xf8,
UMP_SYSTEM_STATUS_START = 0xfa,
UMP_SYSTEM_STATUS_CONTINUE = 0xfb,
UMP_SYSTEM_STATUS_STOP = 0xfc,
UMP_SYSTEM_STATUS_ACTIVE_SENSING = 0xfe,
UMP_SYSTEM_STATUS_RESET = 0xff,
};
/* MIDI 1.0 Realtime and SysEx status messages (0xfx) */
enum {
UMP_MIDI1_MSG_REALTIME = 0xf0, /* mask */
UMP_MIDI1_MSG_SYSEX_START = 0xf0,
UMP_MIDI1_MSG_SYSEX_END = 0xf7,
};
/*
* UMP Message Definitions
*/
/* MIDI 1.0 Note Off / Note On (32bit) */
struct snd_ump_midi1_msg_note {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 velocity:8;
#else
u32 velocity:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* MIDI 1.0 Poly Pressure (32bit) */
struct snd_ump_midi1_msg_paf {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 data:8;
#else
u32 data:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* MIDI 1.0 Control Change (32bit) */
struct snd_ump_midi1_msg_cc {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 index:8;
u32 data:8;
#else
u32 data:8;
u32 index:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* MIDI 1.0 Program Change (32bit) */
struct snd_ump_midi1_msg_program {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 program:8;
u32 reserved:8;
#else
u32 reserved:8;
u32 program:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* MIDI 1.0 Channel Pressure (32bit) */
struct snd_ump_midi1_msg_caf {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 data:8;
u32 reserved:8;
#else
u32 reserved:8;
u32 data:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* MIDI 1.0 Pitch Bend (32bit) */
struct snd_ump_midi1_msg_pitchbend {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 data_lsb:8;
u32 data_msb:8;
#else
u32 data_msb:8;
u32 data_lsb:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* System Common and Real Time messages (32bit); no channel field */
struct snd_ump_system_msg {
#ifdef __BIG_ENDIAN_BITFIELD
u32 type:4;
u32 group:4;
u32 status:8;
u32 parm1:8;
u32 parm2:8;
#else
u32 parm2:8;
u32 parm1:8;
u32 status:8;
u32 group:4;
u32 type:4;
#endif
} __packed;
/* MIDI 1.0 UMP CVM (32bit) */
union snd_ump_midi1_msg {
struct snd_ump_midi1_msg_note note;
struct snd_ump_midi1_msg_paf paf;
struct snd_ump_midi1_msg_cc cc;
struct snd_ump_midi1_msg_program pg;
struct snd_ump_midi1_msg_caf caf;
struct snd_ump_midi1_msg_pitchbend pb;
struct snd_ump_system_msg system;
u32 raw;
};
/* MIDI 2.0 Note Off / Note On (64bit) */
struct snd_ump_midi2_msg_note {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 attribute_type:8;
/* 1 */
u32 velocity:16;
u32 attribute_data:16;
#else
/* 0 */
u32 attribute_type:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 attribute_data:16;
u32 velocity:16;
#endif
} __packed;
/* MIDI 2.0 Poly Pressure (64bit) */
struct snd_ump_midi2_msg_paf {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 reserved:8;
/* 1 */
u32 data;
#else
/* 0 */
u32 reserved:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 Per-Note Controller (64bit) */
struct snd_ump_midi2_msg_pernote_cc {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 index:8;
/* 1 */
u32 data;
#else
/* 0 */
u32 index:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 Per-Note Management (64bit) */
struct snd_ump_midi2_msg_pernote_mgmt {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 flags:8;
/* 1 */
u32 reserved;
#else
/* 0 */
u32 flags:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 reserved;
#endif
} __packed;
/* MIDI 2.0 Control Change (64bit) */
struct snd_ump_midi2_msg_cc {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 index:8;
u32 reserved:8;
/* 1 */
u32 data;
#else
/* 0 */
u32 reserved:8;
u32 index:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 Registered Controller (RPN) / Assignable Controller (NRPN) (64bit) */
struct snd_ump_midi2_msg_rpn {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 bank:8;
u32 index:8;
/* 1 */
u32 data;
#else
/* 0 */
u32 index:8;
u32 bank:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 Program Change (64bit) */
struct snd_ump_midi2_msg_program {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 reserved:15;
u32 bank_valid:1;
/* 1 */
u32 program:8;
u32 reserved2:8;
u32 bank_msb:8;
u32 bank_lsb:8;
#else
/* 0 */
u32 bank_valid:1;
u32 reserved:15;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 bank_lsb:8;
u32 bank_msb:8;
u32 reserved2:8;
u32 program:8;
#endif
} __packed;
/* MIDI 2.0 Channel Pressure (64bit) */
struct snd_ump_midi2_msg_caf {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 reserved:16;
/* 1 */
u32 data;
#else
/* 0 */
u32 reserved:16;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 Pitch Bend (64bit) */
struct snd_ump_midi2_msg_pitchbend {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 reserved:16;
/* 1 */
u32 data;
#else
/* 0 */
u32 reserved:16;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 Per-Note Pitch Bend (64bit) */
struct snd_ump_midi2_msg_pernote_pitchbend {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 group:4;
u32 status:4;
u32 channel:4;
u32 note:8;
u32 reserved:8;
/* 1 */
u32 data;
#else
/* 0 */
u32 reserved:8;
u32 note:8;
u32 channel:4;
u32 status:4;
u32 group:4;
u32 type:4;
/* 1 */
u32 data;
#endif
} __packed;
/* MIDI 2.0 UMP CVM (64bit) */
union snd_ump_midi2_msg {
struct snd_ump_midi2_msg_note note;
struct snd_ump_midi2_msg_paf paf;
struct snd_ump_midi2_msg_pernote_cc pernote_cc;
struct snd_ump_midi2_msg_pernote_mgmt pernote_mgmt;
struct snd_ump_midi2_msg_cc cc;
struct snd_ump_midi2_msg_rpn rpn;
struct snd_ump_midi2_msg_program pg;
struct snd_ump_midi2_msg_caf caf;
struct snd_ump_midi2_msg_pitchbend pb;
struct snd_ump_midi2_msg_pernote_pitchbend pernote_pb;
u32 raw[2];
};
/* UMP Stream Message: Endpoint Discovery (128bit) */
struct snd_ump_stream_msg_ep_discovery {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 format:2;
u32 status:10;
u32 ump_version_major:8;
u32 ump_version_minor:8;
/* 1 */
u32 reserved:24;
u32 filter_bitmap:8;
/* 2-3 */
u32 reserved2[2];
#else
/* 0 */
u32 ump_version_minor:8;
u32 ump_version_major:8;
u32 status:10;
u32 format:2;
u32 type:4;
/* 1 */
u32 filter_bitmap:8;
u32 reserved:24;
/* 2-3 */
u32 reserved2[2];
#endif
} __packed;
/* UMP Stream Message: Endpoint Info Notification (128bit) */
struct snd_ump_stream_msg_ep_info {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 format:2;
u32 status:10;
u32 ump_version_major:8;
u32 ump_version_minor:8;
/* 1 */
u32 static_function_block:1;
u32 num_function_blocks:7;
u32 reserved:8;
u32 protocol:8;
u32 reserved2:6;
u32 jrts:2;
/* 2-3 */
u32 reserved3[2];
#else
/* 0 */
u32 ump_version_minor:8;
u32 ump_version_major:8;
u32 status:10;
u32 format:2;
u32 type:4;
/* 1 */
u32 jrts:2;
u32 reserved2:6;
u32 protocol:8;
u32 reserved:8;
u32 num_function_blocks:7;
u32 static_function_block:1;
/* 2-3 */
u32 reserved3[2];
#endif
} __packed;
/* UMP Stream Message: Device Info Notification (128bit) */
struct snd_ump_stream_msg_devince_info {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 format:2;
u32 status:10;
u32 reserved:16;
/* 1 */
u32 manufacture_id;
/* 2 */
u8 family_lsb;
u8 family_msb;
u8 model_lsb;
u8 model_msb;
/* 3 */
u32 sw_revision;
#else
/* 0 */
u32 reserved:16;
u32 status:10;
u32 format:2;
u32 type:4;
/* 1 */
u32 manufacture_id;
/* 2 */
u8 model_msb;
u8 model_lsb;
u8 family_msb;
u8 family_lsb;
/* 3 */
u32 sw_revision;
#endif
} __packed;
/* UMP Stream Message: Stream Config Request / Notification (128bit) */
struct snd_ump_stream_msg_stream_cfg {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 format:2;
u32 status:10;
u32 protocol:8;
u32 reserved:6;
u32 jrts:2;
/* 1-3 */
u32 reserved2[3];
#else
/* 0 */
u32 jrts:2;
u32 reserved:6;
u32 protocol:8;
u32 status:10;
u32 format:2;
u32 type:4;
/* 1-3 */
u32 reserved2[3];
#endif
} __packed;
/* UMP Stream Message: Function Block Discovery (128bit) */
struct snd_ump_stream_msg_fb_discovery {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 format:2;
u32 status:10;
u32 function_block_id:8;
u32 filter:8;
/* 1-3 */
u32 reserved[3];
#else
/* 0 */
u32 filter:8;
u32 function_block_id:8;
u32 status:10;
u32 format:2;
u32 type:4;
/* 1-3 */
u32 reserved[3];
#endif
} __packed;
/* UMP Stream Message: Function Block Info Notification (128bit) */
struct snd_ump_stream_msg_fb_info {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u32 type:4;
u32 format:2;
u32 status:10;
u32 active:1;
u32 function_block_id:7;
u32 reserved:2;
u32 ui_hint:2;
u32 midi_10:2;
u32 direction:2;
/* 1 */
u32 first_group:8;
u32 num_groups:8;
u32 midi_ci_version:8;
u32 sysex8_streams:8;
/* 2-3 */
u32 reserved2[2];
#else
/* 0 */
u32 direction:2;
u32 midi_10:2;
u32 ui_hint:2;
u32 reserved:2;
u32 function_block_id:7;
u32 active:1;
u32 status:10;
u32 format:2;
u32 type:4;
/* 1 */
u32 sysex8_streams:8;
u32 midi_ci_version:8;
u32 num_groups:8;
u32 first_group:8;
/* 2-3 */
u32 reserved2[2];
#endif
} __packed;
/* UMP Stream Message: Function Block Name Notification (128bit) */
struct snd_ump_stream_msg_fb_name {
#ifdef __BIG_ENDIAN_BITFIELD
/* 0 */
u16 type:4;
u16 format:2;
u16 status:10;
u8 function_block_id;
u8 name0;
/* 1-3 */
u8 name[12];
#else
/* 0 */
u8 name0;
u8 function_block_id;
u16 status:10;
u16 format:2;
u16 type:4;
/* 1-3 */
u8 name[12]; // FIXME: byte order
#endif
} __packed;
/* MIDI 2.0 Stream Messages (128bit) */
union snd_ump_stream_msg {
struct snd_ump_stream_msg_ep_discovery ep_discovery;
struct snd_ump_stream_msg_ep_info ep_info;
struct snd_ump_stream_msg_devince_info device_info;
struct snd_ump_stream_msg_stream_cfg stream_cfg;
struct snd_ump_stream_msg_fb_discovery fb_discovery;
struct snd_ump_stream_msg_fb_info fb_info;
struct snd_ump_stream_msg_fb_name fb_name;
u32 raw[4];
};
#endif /* __SOUND_UMP_MSG_H */

View File

@ -10,7 +10,7 @@
#include <sound/asound.h>
/** version of the sequencer */
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 2)
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3)
/**
* definition of sequencer event types
@ -174,6 +174,7 @@ struct snd_seq_connect {
#define SNDRV_SEQ_PRIORITY_HIGH (1<<4) /* event should be processed before others */
#define SNDRV_SEQ_PRIORITY_MASK (1<<4)
#define SNDRV_SEQ_EVENT_UMP (1<<5) /* event holds a UMP packet */
/* note event */
struct snd_seq_ev_note {
@ -252,6 +253,19 @@ struct snd_seq_ev_quote {
struct snd_seq_event *event; /* quoted event */
} __attribute__((packed));
union snd_seq_event_data { /* event data... */
struct snd_seq_ev_note note;
struct snd_seq_ev_ctrl control;
struct snd_seq_ev_raw8 raw8;
struct snd_seq_ev_raw32 raw32;
struct snd_seq_ev_ext ext;
struct snd_seq_ev_queue_control queue;
union snd_seq_timestamp time;
struct snd_seq_addr addr;
struct snd_seq_connect connect;
struct snd_seq_result result;
struct snd_seq_ev_quote quote;
};
/* sequencer event */
struct snd_seq_event {
@ -262,25 +276,27 @@ struct snd_seq_event {
unsigned char queue; /* schedule queue */
union snd_seq_timestamp time; /* schedule time */
struct snd_seq_addr source; /* source address */
struct snd_seq_addr dest; /* destination address */
union { /* event data... */
struct snd_seq_ev_note note;
struct snd_seq_ev_ctrl control;
struct snd_seq_ev_raw8 raw8;
struct snd_seq_ev_raw32 raw32;
struct snd_seq_ev_ext ext;
struct snd_seq_ev_queue_control queue;
union snd_seq_timestamp time;
struct snd_seq_addr addr;
struct snd_seq_connect connect;
struct snd_seq_result result;
struct snd_seq_ev_quote quote;
} data;
union snd_seq_event_data data;
};
/* (compatible) event for UMP-capable clients */
struct snd_seq_ump_event {
snd_seq_event_type_t type; /* event type */
unsigned char flags; /* event flags */
char tag;
unsigned char queue; /* schedule queue */
union snd_seq_timestamp time; /* schedule time */
struct snd_seq_addr source; /* source address */
struct snd_seq_addr dest; /* destination address */
union {
union snd_seq_event_data data;
unsigned int ump[4];
};
};
/*
* bounce event - stored as variable size data
@ -331,6 +347,7 @@ typedef int __bitwise snd_seq_client_type_t;
#define SNDRV_SEQ_FILTER_BROADCAST (1U<<0) /* accept broadcast messages */
#define SNDRV_SEQ_FILTER_MULTICAST (1U<<1) /* accept multicast messages */
#define SNDRV_SEQ_FILTER_BOUNCE (1U<<2) /* accept bounce event in error */
#define SNDRV_SEQ_FILTER_NO_CONVERT (1U<<30) /* don't convert UMP events */
#define SNDRV_SEQ_FILTER_USE_EVENT (1U<<31) /* use event filter */
struct snd_seq_client_info {
@ -344,9 +361,18 @@ struct snd_seq_client_info {
int event_lost; /* number of lost events */
int card; /* RO: card number[kernel] */
int pid; /* RO: pid[user] */
char reserved[56]; /* for future use */
unsigned int midi_version; /* MIDI version */
unsigned int group_filter; /* UMP group filter bitmap
* (bit 0 = groupless messages,
* bit 1-16 = messages for groups 1-16)
*/
char reserved[48]; /* for future use */
};
/* MIDI version numbers in client info */
#define SNDRV_SEQ_CLIENT_LEGACY_MIDI 0 /* Legacy client */
#define SNDRV_SEQ_CLIENT_UMP_MIDI_1_0 1 /* UMP MIDI 1.0 */
#define SNDRV_SEQ_CLIENT_UMP_MIDI_2_0 2 /* UMP MIDI 2.0 */
/* client pool size */
struct snd_seq_client_pool {
@ -406,6 +432,8 @@ struct snd_seq_remove_events {
#define SNDRV_SEQ_PORT_CAP_SUBS_READ (1<<5) /* allow read subscription */
#define SNDRV_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /* allow write subscription */
#define SNDRV_SEQ_PORT_CAP_NO_EXPORT (1<<7) /* routing not allowed */
#define SNDRV_SEQ_PORT_CAP_INACTIVE (1<<8) /* inactive port */
#define SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT (1<<9) /* MIDI 2.0 UMP Endpoint port */
/* port type */
#define SNDRV_SEQ_PORT_TYPE_SPECIFIC (1<<0) /* hardware specific */
@ -415,6 +443,7 @@ struct snd_seq_remove_events {
#define SNDRV_SEQ_PORT_TYPE_MIDI_XG (1<<4) /* XG compatible device */
#define SNDRV_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) /* MT-32 compatible device */
#define SNDRV_SEQ_PORT_TYPE_MIDI_GM2 (1<<6) /* General MIDI 2 compatible device */
#define SNDRV_SEQ_PORT_TYPE_MIDI_UMP (1<<7) /* UMP */
/* other standards...*/
#define SNDRV_SEQ_PORT_TYPE_SYNTH (1<<10) /* Synth device (no MIDI compatible - direct wavetable) */
@ -432,6 +461,12 @@ struct snd_seq_remove_events {
#define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1)
#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2)
/* port direction */
#define SNDRV_SEQ_PORT_DIR_UNKNOWN 0
#define SNDRV_SEQ_PORT_DIR_INPUT 1
#define SNDRV_SEQ_PORT_DIR_OUTPUT 2
#define SNDRV_SEQ_PORT_DIR_BIDIRECTION 3
struct snd_seq_port_info {
struct snd_seq_addr addr; /* client/port numbers */
char name[64]; /* port name */
@ -448,7 +483,9 @@ struct snd_seq_port_info {
void *kernel; /* reserved for kernel use (must be NULL) */
unsigned int flags; /* misc. conditioning */
unsigned char time_queue; /* queue # for timestamping */
char reserved[59]; /* for future use */
unsigned char direction; /* port usage direction (r/w/bidir) */
unsigned char ump_group; /* 0 = UMP EP (no conversion), 1-16 = UMP group number */
char reserved[57]; /* for future use */
};
@ -552,6 +589,18 @@ struct snd_seq_query_subs {
char reserved[64]; /* for future use */
};
/*
* UMP-specific information
*/
/* type of UMP info query */
#define SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT 0
#define SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK 1
struct snd_seq_client_ump_info {
int client; /* client number to inquire/set */
int type; /* type to inquire/set */
unsigned char info[512]; /* info (either UMP ep or block info) */
} __packed;
/*
* IOCTL commands
@ -561,9 +610,12 @@ struct snd_seq_query_subs {
#define SNDRV_SEQ_IOCTL_CLIENT_ID _IOR ('S', 0x01, int)
#define SNDRV_SEQ_IOCTL_SYSTEM_INFO _IOWR('S', 0x02, struct snd_seq_system_info)
#define SNDRV_SEQ_IOCTL_RUNNING_MODE _IOWR('S', 0x03, struct snd_seq_running_info)
#define SNDRV_SEQ_IOCTL_USER_PVERSION _IOW('S', 0x04, int)
#define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct snd_seq_client_info)
#define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct snd_seq_client_info)
#define SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO _IOWR('S', 0x12, struct snd_seq_client_ump_info)
#define SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO _IOWR('S', 0x13, struct snd_seq_client_ump_info)
#define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct snd_seq_port_info)
#define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct snd_seq_port_info)

View File

@ -274,6 +274,7 @@ typedef int __bitwise snd_pcm_subformat_t;
#define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */
#define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */
#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */
#define SNDRV_PCM_INFO_PERFECT_DRAIN 0x00000040 /* silencing at the end of stream is not required */
#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */
#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */
#define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */
@ -383,6 +384,9 @@ typedef int snd_pcm_hw_param_t;
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */
#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */
#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress drain with the filling
* of the silence samples
*/
struct snd_interval {
unsigned int min, max;
@ -708,7 +712,7 @@ enum {
* Raw MIDI section - /dev/snd/midi??
*/
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2)
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
enum {
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
@ -719,6 +723,7 @@ enum {
#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001
#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
#define SNDRV_RAWMIDI_INFO_UMP 0x00000008
struct snd_rawmidi_info {
unsigned int device; /* RO/WR (control): device number */
@ -779,6 +784,72 @@ struct snd_rawmidi_status {
};
#endif
/* UMP EP info flags */
#define SNDRV_UMP_EP_INFO_STATIC_BLOCKS 0x01
/* UMP EP Protocol / JRTS capability bits */
#define SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK 0x0300
#define SNDRV_UMP_EP_INFO_PROTO_MIDI1 0x0100 /* MIDI 1.0 */
#define SNDRV_UMP_EP_INFO_PROTO_MIDI2 0x0200 /* MIDI 2.0 */
#define SNDRV_UMP_EP_INFO_PROTO_JRTS_MASK 0x0003
#define SNDRV_UMP_EP_INFO_PROTO_JRTS_TX 0x0001 /* JRTS Transmit */
#define SNDRV_UMP_EP_INFO_PROTO_JRTS_RX 0x0002 /* JRTS Receive */
/* UMP Endpoint information */
struct snd_ump_endpoint_info {
int card; /* card number */
int device; /* device number */
unsigned int flags; /* additional info */
unsigned int protocol_caps; /* protocol capabilities */
unsigned int protocol; /* current protocol */
unsigned int num_blocks; /* # of function blocks */
unsigned short version; /* UMP major/minor version */
unsigned short family_id; /* MIDI device family ID */
unsigned short model_id; /* MIDI family model ID */
unsigned int manufacturer_id; /* MIDI manufacturer ID */
unsigned char sw_revision[4]; /* software revision */
unsigned short padding;
unsigned char name[128]; /* endpoint name string */
unsigned char product_id[128]; /* unique product id string */
unsigned char reserved[32];
} __packed;
/* UMP direction */
#define SNDRV_UMP_DIR_INPUT 0x01
#define SNDRV_UMP_DIR_OUTPUT 0x02
#define SNDRV_UMP_DIR_BIDIRECTION 0x03
/* UMP block info flags */
#define SNDRV_UMP_BLOCK_IS_MIDI1 (1U << 0) /* MIDI 1.0 port w/o restrict */
#define SNDRV_UMP_BLOCK_IS_LOWSPEED (1U << 1) /* 31.25Kbps B/W MIDI1 port */
/* UMP block user-interface hint */
#define SNDRV_UMP_BLOCK_UI_HINT_UNKNOWN 0x00
#define SNDRV_UMP_BLOCK_UI_HINT_RECEIVER 0x01
#define SNDRV_UMP_BLOCK_UI_HINT_SENDER 0x02
#define SNDRV_UMP_BLOCK_UI_HINT_BOTH 0x03
/* UMP groups and blocks */
#define SNDRV_UMP_MAX_GROUPS 16
#define SNDRV_UMP_MAX_BLOCKS 32
/* UMP Block information */
struct snd_ump_block_info {
int card; /* card number */
int device; /* device number */
unsigned char block_id; /* block ID (R/W) */
unsigned char direction; /* UMP direction */
unsigned char active; /* Activeness */
unsigned char first_group; /* first group ID */
unsigned char num_groups; /* number of groups */
unsigned char midi_ci_version; /* MIDI-CI support version */
unsigned char sysex8_streams; /* max number of sysex8 streams */
unsigned char ui_hint; /* user interface hint */
unsigned int flags; /* various info flags */
unsigned char name[128]; /* block name string */
unsigned char reserved[32];
} __packed;
#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
#define SNDRV_RAWMIDI_IOCTL_USER_PVERSION _IOW('W', 0x02, int)
@ -786,6 +857,9 @@ struct snd_rawmidi_status {
#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
/* Additional ioctls for UMP rawmidi devices */
#define SNDRV_UMP_IOCTL_ENDPOINT_INFO _IOR('W', 0x40, struct snd_ump_endpoint_info)
#define SNDRV_UMP_IOCTL_BLOCK_INFO _IOR('W', 0x41, struct snd_ump_block_info)
/*
* Timer section - /dev/snd/timer
@ -961,7 +1035,7 @@ struct snd_timer_tread {
* *
****************************************************************************/
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8)
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9)
struct snd_ctl_card_info {
int card; /* card number */
@ -1122,6 +1196,9 @@ struct snd_ctl_tlv {
#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
#define SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE _IOWR('U', 0x43, int)
#define SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO _IOWR('U', 0x44, struct snd_ump_endpoint_info)
#define SNDRV_CTL_IOCTL_UMP_BLOCK_INFO _IOWR('U', 0x45, struct snd_ump_block_info)
#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)

View File

@ -308,6 +308,8 @@ struct snd_emu10k1_fx8010_info {
#define EMU10K1_GPR_TRANSLATION_BASS 2
#define EMU10K1_GPR_TRANSLATION_TREBLE 3
#define EMU10K1_GPR_TRANSLATION_ONOFF 4
#define EMU10K1_GPR_TRANSLATION_NEGATE 5
#define EMU10K1_GPR_TRANSLATION_NEG_TABLE100 6
enum emu10k1_ctl_elem_iface {
EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */
@ -328,9 +330,9 @@ struct snd_emu10k1_fx8010_control_gpr {
unsigned int vcount; /* visible count */
unsigned int count; /* count of GPR (1..16) */
unsigned short gpr[32]; /* GPR number(s) */
unsigned int value[32]; /* initial values */
unsigned int min; /* minimum range */
unsigned int max; /* maximum range */
int value[32]; /* initial values */
int min; /* minimum range */
int max; /* maximum range */
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
const unsigned int *tlv;
};

View File

@ -1048,7 +1048,7 @@ static struct i2c_driver onyx_driver = {
.driver = {
.name = "aoa_codec_onyx",
},
.probe_new = onyx_i2c_probe,
.probe = onyx_i2c_probe,
.remove = onyx_i2c_remove,
.id_table = onyx_i2c_id,
};

View File

@ -936,7 +936,7 @@ static struct i2c_driver tas_driver = {
.driver = {
.name = "aoa_codec_tas",
},
.probe_new = tas_i2c_probe,
.probe = tas_i2c_probe,
.remove = tas_i2c_remove,
.id_table = tas_i2c_id,
};

View File

@ -26,6 +26,19 @@ config SND_RAWMIDI
tristate
select SND_SEQ_DEVICE if SND_SEQUENCER != n
config SND_UMP
tristate
select SND_RAWMIDI
config SND_UMP_LEGACY_RAWMIDI
bool "Legacy raw MIDI support for UMP streams"
depends on SND_UMP
help
This option enables the legacy raw MIDI support for UMP streams.
When this option is set, an additional rawmidi device for the
legacy MIDI 1.0 byte streams is created for each UMP Endpoint.
The device contains 16 substreams corresponding to UMP groups.
config SND_COMPRESS_OFFLOAD
tristate

View File

@ -28,6 +28,8 @@ snd-pcm-dmaengine-objs := pcm_dmaengine.o
snd-ctl-led-objs := control_led.o
snd-rawmidi-objs := rawmidi.o
snd-ump-objs := ump.o
snd-ump-$(CONFIG_SND_UMP_LEGACY_RAWMIDI) += ump_convert.o
snd-timer-objs := timer.o
snd-hrtimer-objs := hrtimer.o
snd-rtctimer-objs := rtctimer.o
@ -45,6 +47,7 @@ obj-$(CONFIG_SND_PCM) += snd-pcm.o
obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o
obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
obj-$(CONFIG_SND_UMP) += snd-ump.o
obj-$(CONFIG_SND_OSSEMUL) += oss/
obj-$(CONFIG_SND_SEQUENCER) += seq/

View File

@ -589,7 +589,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
struct snd_compr_params *params;
int retval;
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
/*
* we should allow parameter change only when stream has been
* opened not in other cases
@ -612,6 +612,9 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
if (retval)
goto out;
if (stream->next_track)
goto out;
stream->metadata_set = false;
stream->next_track = false;

View File

@ -730,12 +730,20 @@ EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
* Finds the control with the old id from the card, and replaces the
* id with the new one.
*
* The function tries to keep the already assigned numid while replacing
* the rest.
*
* Note that this function should be used only in the card initialization
* phase. Calling after the card instantiation may cause issues with
* user-space expecting persistent numids.
*
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
struct snd_ctl_elem_id *dst_id)
{
struct snd_kcontrol *kctl;
int saved_numid;
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, src_id);
@ -743,10 +751,10 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
up_write(&card->controls_rwsem);
return -ENOENT;
}
saved_numid = kctl->id.numid;
remove_hash_entries(card, kctl);
kctl->id = *dst_id;
kctl->id.numid = card->last_numid + 1;
card->last_numid += kctl->count;
kctl->id.numid = saved_numid;
add_hash_entries(card, kctl);
up_write(&card->controls_rwsem);
return 0;

View File

@ -197,7 +197,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
return err;
}
static int get_elem_size(int type, int count)
static int get_elem_size(snd_ctl_elem_type_t type, int count)
{
switch (type) {
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
@ -234,8 +234,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
if (type < 0)
return type;
if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@ -244,7 +244,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
data->value.integer.value[i] = val;
}
} else {
size = get_elem_size(type, count);
size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
if (size < 0) {
dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
@ -267,8 +267,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
struct snd_ctl_elem_value32 __user *data32 = userdata;
int i, size;
if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@ -277,7 +277,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
return -EFAULT;
}
} else {
size = get_elem_size(type, count);
size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
if (copy_to_user(valuep, data->value.bytes.data, size))
return -EFAULT;
}

View File

@ -737,7 +737,7 @@ static int __init snd_ctl_led_init(void)
unsigned int group;
device_initialize(&snd_ctl_led_dev);
snd_ctl_led_dev.class = sound_class;
snd_ctl_led_dev.class = &sound_class;
snd_ctl_led_dev.release = snd_ctl_led_dev_release;
dev_set_name(&snd_ctl_led_dev, "ctl-led");
if (device_add(&snd_ctl_led_dev)) {

View File

@ -129,7 +129,7 @@ void snd_device_initialize(struct device *dev, struct snd_card *card)
device_initialize(dev);
if (card)
dev->parent = &card->card_dev;
dev->class = sound_class;
dev->class = &sound_class;
dev->release = default_release;
}
EXPORT_SYMBOL_GPL(snd_device_initialize);
@ -331,7 +331,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
card->card_dev.class = sound_class;
card->card_dev.class = &sound_class;
card->card_dev.release = release_card_device;
card->card_dev.groups = card->dev_groups;
card->dev_groups[0] = &card_dev_attr_group;

View File

@ -2,11 +2,25 @@
/*
* PCM DRM helpers
*/
#include <linux/bitfield.h>
#include <linux/export.h>
#include <linux/hdmi.h>
#include <drm/drm_edid.h>
#include <sound/pcm.h>
#include <sound/pcm_drm_eld.h>
#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */
#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */
#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */
#define SAD1_RATE_32000_MASK BIT(0)
#define SAD1_RATE_44100_MASK BIT(1)
#define SAD1_RATE_48000_MASK BIT(2)
#define SAD1_RATE_88200_MASK BIT(3)
#define SAD1_RATE_96000_MASK BIT(4)
#define SAD1_RATE_176400_MASK BIT(5)
#define SAD1_RATE_192000_MASK BIT(6)
static const unsigned int eld_rates[] = {
32000,
44100,
@ -17,9 +31,62 @@ static const unsigned int eld_rates[] = {
192000,
};
static unsigned int map_rate_families(const u8 *sad,
unsigned int mask_32000,
unsigned int mask_44100,
unsigned int mask_48000)
{
unsigned int rate_mask = 0;
if (sad[1] & SAD1_RATE_32000_MASK)
rate_mask |= mask_32000;
if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK))
rate_mask |= mask_44100;
if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK))
rate_mask |= mask_48000;
return rate_mask;
}
static unsigned int sad_rate_mask(const u8 *sad)
{
switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
case HDMI_AUDIO_CODING_TYPE_PCM:
return sad[1] & SAD1_RATE_MASK;
case HDMI_AUDIO_CODING_TYPE_AC3:
case HDMI_AUDIO_CODING_TYPE_DTS:
return map_rate_families(sad,
SAD1_RATE_32000_MASK,
SAD1_RATE_44100_MASK,
SAD1_RATE_48000_MASK);
case HDMI_AUDIO_CODING_TYPE_EAC3:
case HDMI_AUDIO_CODING_TYPE_DTS_HD:
case HDMI_AUDIO_CODING_TYPE_MLP:
return map_rate_families(sad,
0,
SAD1_RATE_176400_MASK,
SAD1_RATE_192000_MASK);
default:
/* TODO adjust for other compressed formats as well */
return sad[1] & SAD1_RATE_MASK;
}
}
static unsigned int sad_max_channels(const u8 *sad)
{
return 1 + (sad[0] & 7);
switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
case HDMI_AUDIO_CODING_TYPE_PCM:
return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
case HDMI_AUDIO_CODING_TYPE_AC3:
case HDMI_AUDIO_CODING_TYPE_DTS:
case HDMI_AUDIO_CODING_TYPE_EAC3:
return 2;
case HDMI_AUDIO_CODING_TYPE_DTS_HD:
case HDMI_AUDIO_CODING_TYPE_MLP:
return 8;
default:
/* TODO adjust for other compressed formats as well */
return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
}
}
static int eld_limit_rates(struct snd_pcm_hw_params *params,
@ -42,7 +109,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
* requested number of channels.
*/
if (c->min <= max_channels)
rate_mask |= sad[1];
rate_mask |= sad_rate_mask(sad);
}
}
@ -70,7 +137,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
rate_mask |= BIT(i);
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
if (rate_mask & sad[1])
if (rate_mask & sad_rate_mask(sad))
t.max = max(t.max, sad_max_channels(sad));
}

View File

@ -1605,10 +1605,6 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream,
{
if (substream->runtime->trigger_master != substream)
return 0;
/* some drivers might use hw_ptr to recover from the pause -
update the hw_ptr now */
if (pause_pushed(state))
snd_pcm_update_hw_ptr(substream);
/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
* a delta between the current jiffies, this gives a large enough
* delta, effectively to skip the check once.

View File

@ -21,6 +21,7 @@
#include <sound/control.h>
#include <sound/minors.h>
#include <sound/initval.h>
#include <sound/ump.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
@ -35,7 +36,6 @@ module_param_array(amidi_map, int, NULL, 0444);
MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
#endif /* CONFIG_SND_OSSEMUL */
static int snd_rawmidi_free(struct snd_rawmidi *rmidi);
static int snd_rawmidi_dev_free(struct snd_device *device);
static int snd_rawmidi_dev_register(struct snd_device *device);
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
@ -73,6 +73,9 @@ struct snd_rawmidi_status64 {
#define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64)
#define rawmidi_is_ump(rmidi) \
(IS_ENABLED(CONFIG_SND_UMP) && ((rmidi)->info_flags & SNDRV_RAWMIDI_INFO_UMP))
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
struct snd_rawmidi *rawmidi;
@ -181,9 +184,23 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
}
runtime->appl_ptr = runtime->hw_ptr = 0;
substream->runtime = runtime;
if (rawmidi_is_ump(substream->rmidi))
runtime->align = 3;
return 0;
}
/* get the current alignment (either 0 or 3) */
static inline int get_align(struct snd_rawmidi_runtime *runtime)
{
if (IS_ENABLED(CONFIG_SND_UMP))
return runtime->align;
else
return 0;
}
/* get the trimmed size with the current alignment */
#define get_aligned_size(runtime, size) ((size) & ~get_align(runtime))
static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
@ -406,24 +423,15 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
}
/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile)
{
struct snd_rawmidi *rmidi;
int err = 0;
int err;
if (snd_BUG_ON(!rfile))
return -EINVAL;
mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, device);
if (!rmidi)
err = -ENODEV;
else if (!try_module_get(rmidi->card->module))
err = -ENXIO;
mutex_unlock(&register_mutex);
if (err < 0)
return err;
if (!try_module_get(rmidi->card->module))
return -ENXIO;
mutex_lock(&rmidi->open_mutex);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
@ -730,6 +738,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
return -EINVAL;
if (params->avail_min < 1 || params->avail_min > params->buffer_size)
return -EINVAL;
if (params->buffer_size & get_align(runtime))
return -EINVAL;
if (params->buffer_size != runtime->buffer_size) {
newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
if (!newbuf)
@ -902,6 +912,7 @@ static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile,
static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct snd_rawmidi_file *rfile;
struct snd_rawmidi *rmidi;
void __user *argp = (void __user *)arg;
rfile = file->private_data;
@ -993,12 +1004,67 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
}
}
default:
rmidi_dbg(rfile->rmidi,
"rawmidi: unknown command = 0x%x\n", cmd);
rmidi = rfile->rmidi;
if (rmidi->ops && rmidi->ops->ioctl)
return rmidi->ops->ioctl(rmidi, cmd, argp);
rmidi_dbg(rmidi, "rawmidi: unknown command = 0x%x\n", cmd);
}
return -ENOTTY;
}
/* ioctl to find the next device; either legacy or UMP depending on @find_ump */
static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp,
bool find_ump)
{
struct snd_rawmidi *rmidi;
int device;
bool is_ump;
if (get_user(device, argp))
return -EFAULT;
if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
device = SNDRV_RAWMIDI_DEVICES - 1;
mutex_lock(&register_mutex);
device = device < 0 ? 0 : device + 1;
for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
rmidi = snd_rawmidi_search(card, device);
if (!rmidi)
continue;
is_ump = rawmidi_is_ump(rmidi);
if (find_ump == is_ump)
break;
}
if (device == SNDRV_RAWMIDI_DEVICES)
device = -1;
mutex_unlock(&register_mutex);
if (put_user(device, argp))
return -EFAULT;
return 0;
}
#if IS_ENABLED(CONFIG_SND_UMP)
/* inquiry of UMP endpoint and block info via control API */
static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd,
void __user *argp)
{
struct snd_ump_endpoint_info __user *info = argp;
struct snd_rawmidi *rmidi;
int device, ret;
if (get_user(device, &info->device))
return -EFAULT;
mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, device);
if (rmidi && rmidi->ops && rmidi->ops->ioctl)
ret = rmidi->ops->ioctl(rmidi, cmd, argp);
else
ret = -ENXIO;
mutex_unlock(&register_mutex);
return ret;
}
#endif
static int snd_rawmidi_control_ioctl(struct snd_card *card,
struct snd_ctl_file *control,
unsigned int cmd,
@ -1008,27 +1074,15 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
switch (cmd) {
case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
{
int device;
if (get_user(device, (int __user *)argp))
return -EFAULT;
if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
device = SNDRV_RAWMIDI_DEVICES - 1;
mutex_lock(&register_mutex);
device = device < 0 ? 0 : device + 1;
while (device < SNDRV_RAWMIDI_DEVICES) {
if (snd_rawmidi_search(card, device))
break;
device++;
}
if (device == SNDRV_RAWMIDI_DEVICES)
device = -1;
mutex_unlock(&register_mutex);
if (put_user(device, (int __user *)argp))
return -EFAULT;
return 0;
}
return snd_rawmidi_next_device(card, argp, false);
#if IS_ENABLED(CONFIG_SND_UMP)
case SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE:
return snd_rawmidi_next_device(card, argp, true);
case SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO:
return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_ENDPOINT_INFO, argp);
case SNDRV_CTL_IOCTL_UMP_BLOCK_INFO:
return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_BLOCK_INFO, argp);
#endif
case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
{
int val;
@ -1052,12 +1106,13 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec };
int orig_count = src_count;
int frame_size = sizeof(struct snd_rawmidi_framing_tstamp);
int align = get_align(runtime);
BUILD_BUG_ON(frame_size != 0x20);
if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0))
return -EINVAL;
while (src_count > 0) {
while (src_count > align) {
if ((int)(runtime->buffer_size - runtime->avail) < frame_size) {
runtime->xruns += src_count;
break;
@ -1065,7 +1120,9 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH)
frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH;
else {
frame.length = src_count;
frame.length = get_aligned_size(runtime, src_count);
if (!frame.length)
break;
memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH);
}
memcpy(frame.data, buffer, frame.length);
@ -1129,6 +1186,10 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
goto unlock;
}
count = get_aligned_size(runtime, count);
if (!count)
goto unlock;
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
} else if (count == 1) { /* special case, faster code */
@ -1148,6 +1209,9 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
count1 = count;
if (count1 > (int)(runtime->buffer_size - runtime->avail))
count1 = runtime->buffer_size - runtime->avail;
count1 = get_aligned_size(runtime, count1);
if (!count1)
goto unlock;
memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
runtime->hw_ptr += count1;
runtime->hw_ptr %= runtime->buffer_size;
@ -1348,12 +1412,18 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
count1 = count;
if (count1 > (int)(runtime->buffer_size - runtime->avail))
count1 = runtime->buffer_size - runtime->avail;
count1 = get_aligned_size(runtime, count1);
if (!count1)
goto __skip;
memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1);
count -= count1;
result += count1;
if (count > 0) {
if (count > (int)(runtime->buffer_size - runtime->avail - count1))
count = runtime->buffer_size - runtime->avail - count1;
count = get_aligned_size(runtime, count);
if (!count)
goto __skip;
memcpy(buffer + count1, runtime->buffer, count);
result += count;
}
@ -1410,6 +1480,7 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
return -EINVAL;
}
snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
count = get_aligned_size(runtime, count);
runtime->hw_ptr += count;
runtime->hw_ptr %= runtime->buffer_size;
runtime->avail += count;
@ -1696,6 +1767,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
if (IS_ENABLED(CONFIG_SND_UMP))
snd_iprintf(buffer, "Type: %s\n",
rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
if (rmidi->ops->proc_read)
rmidi->ops->proc_read(entry, buffer);
mutex_lock(&rmidi->open_mutex);
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
list_for_each_entry(substream,
@ -1806,6 +1882,56 @@ static void release_rawmidi_device(struct device *dev)
kfree(container_of(dev, struct snd_rawmidi, dev));
}
/* used for both rawmidi and ump */
int snd_rawmidi_init(struct snd_rawmidi *rmidi,
struct snd_card *card, char *id, int device,
int output_count, int input_count,
unsigned int info_flags)
{
int err;
static const struct snd_device_ops ops = {
.dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect,
};
rmidi->card = card;
rmidi->device = device;
mutex_init(&rmidi->open_mutex);
init_waitqueue_head(&rmidi->open_wait);
INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams);
INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);
rmidi->info_flags = info_flags;
if (id != NULL)
strscpy(rmidi->id, id, sizeof(rmidi->id));
snd_device_initialize(&rmidi->dev, card);
rmidi->dev.release = release_rawmidi_device;
if (rawmidi_is_ump(rmidi))
dev_set_name(&rmidi->dev, "umpC%iD%i", card->number, device);
else
dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
SNDRV_RAWMIDI_STREAM_INPUT,
input_count);
if (err < 0)
return err;
err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
SNDRV_RAWMIDI_STREAM_OUTPUT,
output_count);
if (err < 0)
return err;
err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops);
if (err < 0)
return err;
return 0;
}
EXPORT_SYMBOL_GPL(snd_rawmidi_init);
/**
* snd_rawmidi_new - create a rawmidi instance
* @card: the card instance
@ -1826,56 +1952,21 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
{
struct snd_rawmidi *rmidi;
int err;
static const struct snd_device_ops ops = {
.dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect,
};
if (snd_BUG_ON(!card))
return -ENXIO;
if (rrawmidi)
*rrawmidi = NULL;
rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
if (!rmidi)
return -ENOMEM;
rmidi->card = card;
rmidi->device = device;
mutex_init(&rmidi->open_mutex);
init_waitqueue_head(&rmidi->open_wait);
INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams);
INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);
if (id != NULL)
strscpy(rmidi->id, id, sizeof(rmidi->id));
snd_device_initialize(&rmidi->dev, card);
rmidi->dev.release = release_rawmidi_device;
dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
SNDRV_RAWMIDI_STREAM_INPUT,
input_count);
if (err < 0)
goto error;
err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
SNDRV_RAWMIDI_STREAM_OUTPUT,
output_count);
if (err < 0)
goto error;
err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops);
if (err < 0)
goto error;
err = snd_rawmidi_init(rmidi, card, id, device,
output_count, input_count, 0);
if (err < 0) {
snd_rawmidi_free(rmidi);
return err;
}
if (rrawmidi)
*rrawmidi = rmidi;
return 0;
error:
snd_rawmidi_free(rmidi);
return err;
}
EXPORT_SYMBOL(snd_rawmidi_new);
@ -1890,7 +1981,8 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
}
}
static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
/* called from ump.c, too */
int snd_rawmidi_free(struct snd_rawmidi *rmidi)
{
if (!rmidi)
return 0;
@ -1907,6 +1999,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
put_device(&rmidi->dev);
return 0;
}
EXPORT_SYMBOL_GPL(snd_rawmidi_free);
static int snd_rawmidi_dev_free(struct snd_device *device)
{
@ -1957,7 +2050,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
}
#ifdef CONFIG_SND_OSSEMUL
rmidi->ossreg = 0;
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
if (!rawmidi_is_ump(rmidi) &&
(int)rmidi->device == midi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
rmidi->card, 0, &snd_rawmidi_f_ops,
rmidi) < 0) {
@ -1971,7 +2065,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
#endif
}
}
if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
if (!rawmidi_is_ump(rmidi) &&
(int)rmidi->device == amidi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
rmidi->card, 1, &snd_rawmidi_f_ops,
rmidi) < 0) {
@ -1995,7 +2090,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
}
rmidi->proc_entry = entry;
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
/* no own registration mechanism? */
if (!rmidi->ops || !rmidi->ops->dev_register) {
if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
rmidi->seq_dev->private_data = rmidi;
rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free;

View File

@ -111,6 +111,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign
case SNDRV_RAWMIDI_IOCTL_INFO:
case SNDRV_RAWMIDI_IOCTL_DROP:
case SNDRV_RAWMIDI_IOCTL_DRAIN:
#if IS_ENABLED(CONFIG_SND_UMP)
case SNDRV_UMP_IOCTL_ENDPOINT_INFO:
case SNDRV_UMP_IOCTL_BLOCK_INFO:
#endif
return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_RAWMIDI_IOCTL_PARAMS32:
return snd_rawmidi_ioctl_params_compat(rfile, argp);

View File

@ -60,4 +60,18 @@ config SND_SEQ_MIDI_EMUL
config SND_SEQ_VIRMIDI
tristate
config SND_SEQ_UMP
bool "Support for UMP events"
default y if SND_SEQ_UMP_CLIENT
help
Say Y here to enable the support for handling UMP (Universal MIDI
Packet) events via ALSA sequencer infrastructure, which is an
essential feature for enabling MIDI 2.0 support.
It includes the automatic conversion of ALSA sequencer events
among legacy and UMP clients.
config SND_SEQ_UMP_CLIENT
tristate
def_tristate SND_UMP
endif # SND_SEQUENCER

View File

@ -8,17 +8,20 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
seq_fifo.o seq_prioq.o seq_timer.o \
seq_system.o seq_ports.o
snd-seq-$(CONFIG_SND_PROC_FS) += seq_info.o
snd-seq-$(CONFIG_SND_SEQ_UMP) += seq_ump_convert.o
snd-seq-midi-objs := seq_midi.o
snd-seq-midi-emul-objs := seq_midi_emul.o
snd-seq-midi-event-objs := seq_midi_event.o
snd-seq-dummy-objs := seq_dummy.o
snd-seq-virmidi-objs := seq_virmidi.o
snd-seq-ump-client-objs := seq_ump_client.o
obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o
obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/
obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o
obj-$(CONFIG_SND_SEQ_UMP_CLIENT) += snd-seq-ump-client.o
obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o
obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o
obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o

View File

@ -14,12 +14,14 @@
#include <linux/kmod.h>
#include <sound/seq_kernel.h>
#include <sound/ump.h>
#include "seq_clientmgr.h"
#include "seq_memory.h"
#include "seq_queue.h"
#include "seq_timer.h"
#include "seq_info.h"
#include "seq_system.h"
#include "seq_ump_convert.h"
#include <sound/seq_device.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
@ -70,6 +72,10 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
struct snd_seq_event *event,
int filter, int atomic, int hop);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
static void free_ump_info(struct snd_seq_client *client);
#endif
/*
*/
static inline unsigned short snd_seq_file_flags(struct file *file)
@ -239,6 +245,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
mutex_init(&client->ports_mutex);
INIT_LIST_HEAD(&client->ports_list_head);
mutex_init(&client->ioctl_mutex);
client->ump_endpoint_port = -1;
/* find free slot in the client table */
spin_lock_irq(&clients_lock);
@ -380,6 +387,9 @@ static int snd_seq_release(struct inode *inode, struct file *file)
seq_free_client(client);
if (client->data.user.fifo)
snd_seq_fifo_delete(&client->data.user.fifo);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
free_ump_info(client);
#endif
put_pid(client->data.user.owner);
kfree(client);
}
@ -387,6 +397,15 @@ static int snd_seq_release(struct inode *inode, struct file *file)
return 0;
}
static bool event_is_compatible(const struct snd_seq_client *client,
const struct snd_seq_event *ev)
{
if (snd_seq_ev_is_ump(ev) && !client->midi_version)
return false;
if (snd_seq_ev_is_ump(ev) && snd_seq_ev_is_variable(ev))
return false;
return true;
}
/* handle client read() */
/* possible error values:
@ -400,6 +419,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
{
struct snd_seq_client *client = file->private_data;
struct snd_seq_fifo *fifo;
size_t aligned_size;
int err;
long result = 0;
struct snd_seq_event_cell *cell;
@ -431,43 +451,54 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
err = 0;
snd_seq_fifo_lock(fifo);
if (IS_ENABLED(CONFIG_SND_SEQ_UMP) && client->midi_version > 0)
aligned_size = sizeof(struct snd_seq_ump_event);
else
aligned_size = sizeof(struct snd_seq_event);
/* while data available in queue */
while (count >= sizeof(struct snd_seq_event)) {
while (count >= aligned_size) {
int nonblock;
nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
err = snd_seq_fifo_cell_out(fifo, &cell, nonblock);
if (err < 0)
break;
if (!event_is_compatible(client, &cell->event)) {
snd_seq_cell_free(cell);
cell = NULL;
continue;
}
if (snd_seq_ev_is_variable(&cell->event)) {
struct snd_seq_event tmpev;
tmpev = cell->event;
struct snd_seq_ump_event tmpev;
memcpy(&tmpev, &cell->event, aligned_size);
tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
if (copy_to_user(buf, &tmpev, sizeof(struct snd_seq_event))) {
if (copy_to_user(buf, &tmpev, aligned_size)) {
err = -EFAULT;
break;
}
count -= sizeof(struct snd_seq_event);
buf += sizeof(struct snd_seq_event);
count -= aligned_size;
buf += aligned_size;
err = snd_seq_expand_var_event(&cell->event, count,
(char __force *)buf, 0,
sizeof(struct snd_seq_event));
aligned_size);
if (err < 0)
break;
result += err;
count -= err;
buf += err;
} else {
if (copy_to_user(buf, &cell->event, sizeof(struct snd_seq_event))) {
if (copy_to_user(buf, &cell->event, aligned_size)) {
err = -EFAULT;
break;
}
count -= sizeof(struct snd_seq_event);
buf += sizeof(struct snd_seq_event);
count -= aligned_size;
buf += aligned_size;
}
snd_seq_cell_free(cell);
cell = NULL; /* to be sure */
result += sizeof(struct snd_seq_event);
result += aligned_size;
}
if (err < 0) {
@ -590,6 +621,27 @@ static int update_timestamp_of_queue(struct snd_seq_event *event,
return 1;
}
/* deliver a single event; called from below and UMP converter */
int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
struct snd_seq_client_port *dest_port,
struct snd_seq_event *event,
int atomic, int hop)
{
switch (dest->type) {
case USER_CLIENT:
if (!dest->data.user.fifo)
return 0;
return snd_seq_fifo_event_in(dest->data.user.fifo, event);
case KERNEL_CLIENT:
if (!dest_port->event_input)
return 0;
return dest_port->event_input(event,
snd_seq_ev_is_direct(event),
dest_port->private_data,
atomic, hop);
}
return 0;
}
/*
* deliver an event to the specified destination.
@ -626,22 +678,22 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
update_timestamp_of_queue(event, dest_port->time_queue,
dest_port->time_real);
switch (dest->type) {
case USER_CLIENT:
if (dest->data.user.fifo)
result = snd_seq_fifo_event_in(dest->data.user.fifo, event);
break;
case KERNEL_CLIENT:
if (dest_port->event_input == NULL)
break;
result = dest_port->event_input(event, direct,
dest_port->private_data,
atomic, hop);
break;
default:
break;
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
if (snd_seq_ev_is_ump(event)) {
result = snd_seq_deliver_from_ump(client, dest, dest_port,
event, atomic, hop);
goto __skip;
} else if (snd_seq_client_is_ump(dest)) {
result = snd_seq_deliver_to_ump(client, dest, dest_port,
event, atomic, hop);
goto __skip;
}
}
#endif /* CONFIG_SND_SEQ_UMP */
result = __snd_seq_deliver_single_event(dest, dest_port, event,
atomic, hop);
__skip:
if (dest_port)
@ -659,21 +711,20 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
/*
* send the event to all subscribers:
*/
static int deliver_to_subscribers(struct snd_seq_client *client,
struct snd_seq_event *event,
int atomic, int hop)
static int __deliver_to_subscribers(struct snd_seq_client *client,
struct snd_seq_event *event,
struct snd_seq_client_port *src_port,
int atomic, int hop)
{
struct snd_seq_subscribers *subs;
int err, result = 0, num_ev = 0;
struct snd_seq_event event_saved;
struct snd_seq_client_port *src_port;
union __snd_seq_event event_saved;
size_t saved_size;
struct snd_seq_port_subs_info *grp;
src_port = snd_seq_port_use_ptr(client, event->source.port);
if (src_port == NULL)
return -EINVAL; /* invalid source port */
/* save original event record */
event_saved = *event;
saved_size = snd_seq_event_packet_size(event);
memcpy(&event_saved, event, saved_size);
grp = &src_port->c_src;
/* lock list */
@ -700,104 +751,41 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
}
num_ev++;
/* restore original event record */
*event = event_saved;
memcpy(event, &event_saved, saved_size);
}
if (atomic)
read_unlock(&grp->list_lock);
else
up_read(&grp->list_mutex);
*event = event_saved; /* restore */
memcpy(event, &event_saved, saved_size);
return (result < 0) ? result : num_ev;
}
static int deliver_to_subscribers(struct snd_seq_client *client,
struct snd_seq_event *event,
int atomic, int hop)
{
struct snd_seq_client_port *src_port;
int ret = 0, ret2;
src_port = snd_seq_port_use_ptr(client, event->source.port);
if (src_port) {
ret = __deliver_to_subscribers(client, event, src_port, atomic, hop);
snd_seq_port_unlock(src_port);
}
if (client->ump_endpoint_port < 0 ||
event->source.port == client->ump_endpoint_port)
return ret;
src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port);
if (!src_port)
return ret;
ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop);
snd_seq_port_unlock(src_port);
return (result < 0) ? result : num_ev;
return ret2 < 0 ? ret2 : ret;
}
#ifdef SUPPORT_BROADCAST
/*
* broadcast to all ports:
*/
static int port_broadcast_event(struct snd_seq_client *client,
struct snd_seq_event *event,
int atomic, int hop)
{
int num_ev = 0, err, result = 0;
struct snd_seq_client *dest_client;
struct snd_seq_client_port *port;
dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
if (dest_client == NULL)
return 0; /* no matching destination */
read_lock(&dest_client->ports_lock);
list_for_each_entry(port, &dest_client->ports_list_head, list) {
event->dest.port = port->addr.port;
/* pass NULL as source client to avoid error bounce */
err = snd_seq_deliver_single_event(NULL, event,
SNDRV_SEQ_FILTER_BROADCAST,
atomic, hop);
if (err < 0) {
/* save first error that occurs and continue */
if (!result)
result = err;
continue;
}
num_ev++;
}
read_unlock(&dest_client->ports_lock);
snd_seq_client_unlock(dest_client);
event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
return (result < 0) ? result : num_ev;
}
/*
* send the event to all clients:
* if destination port is also ADDRESS_BROADCAST, deliver to all ports.
*/
static int broadcast_event(struct snd_seq_client *client,
struct snd_seq_event *event, int atomic, int hop)
{
int err, result = 0, num_ev = 0;
int dest;
struct snd_seq_addr addr;
addr = event->dest; /* save */
for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) {
/* don't send to itself */
if (dest == client->number)
continue;
event->dest.client = dest;
event->dest.port = addr.port;
if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST)
err = port_broadcast_event(client, event, atomic, hop);
else
/* pass NULL as source client to avoid error bounce */
err = snd_seq_deliver_single_event(NULL, event,
SNDRV_SEQ_FILTER_BROADCAST,
atomic, hop);
if (err < 0) {
/* save first error that occurs and continue */
if (!result)
result = err;
continue;
}
num_ev += err;
}
event->dest = addr; /* restore */
return (result < 0) ? result : num_ev;
}
/* multicast - not supported yet */
static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event,
int atomic, int hop)
{
pr_debug("ALSA: seq: multicast not supported yet.\n");
return 0; /* ignored */
}
#endif /* SUPPORT_BROADCAST */
/* deliver an event to the destination port(s).
* if the event is to subscribers or broadcast, the event is dispatched
* to multiple targets.
@ -826,15 +814,6 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS ||
event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)
result = deliver_to_subscribers(client, event, atomic, hop);
#ifdef SUPPORT_BROADCAST
else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST ||
event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST)
result = broadcast_event(client, event, atomic, hop);
else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS)
result = multicast_event(client, event, atomic, hop);
else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST)
result = port_broadcast_event(client, event, atomic, hop);
#endif
else
result = snd_seq_deliver_single_event(client, event, 0, atomic, hop);
@ -865,7 +844,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
return -EINVAL;
}
if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) {
if (!snd_seq_ev_is_ump(&cell->event) &&
cell->event.type == SNDRV_SEQ_EVENT_NOTE) {
/* NOTE event:
* the event cell is re-used as a NOTE-OFF event and
* enqueued again.
@ -889,7 +869,7 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
/* add the duration time */
switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) {
case SNDRV_SEQ_TIME_STAMP_TICK:
ev->time.tick += ev->data.note.duration;
cell->event.time.tick += ev->data.note.duration;
break;
case SNDRV_SEQ_TIME_STAMP_REAL:
/* unit for duration is ms */
@ -936,14 +916,7 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
event->queue = SNDRV_SEQ_QUEUE_DIRECT;
} else
#ifdef SUPPORT_BROADCAST
if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) {
event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST;
event->queue = SNDRV_SEQ_QUEUE_DIRECT;
}
#endif
if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
} else if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
/* check presence of source port */
struct snd_seq_client_port *src_port = snd_seq_port_use_ptr(client, event->source.port);
if (src_port == NULL)
@ -953,7 +926,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
/* direct event processing without enqueued */
if (snd_seq_ev_is_direct(event)) {
if (event->type == SNDRV_SEQ_EVENT_NOTE)
if (!snd_seq_ev_is_ump(event) &&
event->type == SNDRV_SEQ_EVENT_NOTE)
return -EINVAL; /* this event must be enqueued! */
return snd_seq_deliver_event(client, event, atomic, hop);
}
@ -1023,7 +997,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
struct snd_seq_client *client = file->private_data;
int written = 0, len;
int err, handled;
struct snd_seq_event event;
union __snd_seq_event __event;
struct snd_seq_event *ev = &__event.legacy;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
return -ENXIO;
@ -1049,49 +1024,66 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
err = -EINVAL;
while (count >= sizeof(struct snd_seq_event)) {
/* Read in the event header from the user */
len = sizeof(event);
if (copy_from_user(&event, buf, len)) {
len = sizeof(struct snd_seq_event);
if (copy_from_user(ev, buf, len)) {
err = -EFAULT;
break;
}
event.source.client = client->number; /* fill in client number */
/* read in the rest bytes for UMP events */
if (snd_seq_ev_is_ump(ev)) {
if (count < sizeof(struct snd_seq_ump_event))
break;
if (copy_from_user((char *)ev + len, buf + len,
sizeof(struct snd_seq_ump_event) - len)) {
err = -EFAULT;
break;
}
len = sizeof(struct snd_seq_ump_event);
}
ev->source.client = client->number; /* fill in client number */
/* Check for extension data length */
if (check_event_type_and_length(&event)) {
if (check_event_type_and_length(ev)) {
err = -EINVAL;
break;
}
if (!event_is_compatible(client, ev)) {
err = -EINVAL;
break;
}
/* check for special events */
if (event.type == SNDRV_SEQ_EVENT_NONE)
goto __skip_event;
else if (snd_seq_ev_is_reserved(&event)) {
err = -EINVAL;
break;
if (!snd_seq_ev_is_ump(ev)) {
if (ev->type == SNDRV_SEQ_EVENT_NONE)
goto __skip_event;
else if (snd_seq_ev_is_reserved(ev)) {
err = -EINVAL;
break;
}
}
if (snd_seq_ev_is_variable(&event)) {
int extlen = event.data.ext.len & ~SNDRV_SEQ_EXT_MASK;
if (snd_seq_ev_is_variable(ev)) {
int extlen = ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
if ((size_t)(extlen + len) > count) {
/* back out, will get an error this time or next */
err = -EINVAL;
break;
}
/* set user space pointer */
event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
event.data.ext.ptr = (char __force *)buf
+ sizeof(struct snd_seq_event);
ev->data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
ev->data.ext.ptr = (char __force *)buf + len;
len += extlen; /* increment data length */
} else {
#ifdef CONFIG_COMPAT
if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]);
event.data.ext.ptr = ptr;
}
if (client->convert32 && snd_seq_ev_is_varusr(ev))
ev->data.ext.ptr =
(void __force *)compat_ptr(ev->data.raw32.d[1]);
#endif
}
/* ok, enqueue it */
err = snd_seq_client_enqueue_event(client, &event, file,
err = snd_seq_client_enqueue_event(client, ev, file,
!(file->f_flags & O_NONBLOCK),
0, 0, &client->ioctl_mutex);
if (err < 0)
@ -1159,6 +1151,12 @@ static int snd_seq_ioctl_pversion(struct snd_seq_client *client, void *arg)
return 0;
}
static int snd_seq_ioctl_user_pversion(struct snd_seq_client *client, void *arg)
{
client->user_pversion = *(unsigned int *)arg;
return 0;
}
static int snd_seq_ioctl_client_id(struct snd_seq_client *client, void *arg)
{
int *client_id = arg;
@ -1231,6 +1229,7 @@ static void get_client_info(struct snd_seq_client *cptr,
info->filter = cptr->filter;
info->event_lost = cptr->event_lost;
memcpy(info->event_filter, cptr->event_filter, 32);
info->group_filter = cptr->group_filter;
info->num_ports = cptr->num_ports;
if (cptr->type == USER_CLIENT)
@ -1243,6 +1242,7 @@ static void get_client_info(struct snd_seq_client *cptr,
else
info->card = -1;
info->midi_version = cptr->midi_version;
memset(info->reserved, 0, sizeof(info->reserved));
}
@ -1277,14 +1277,21 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
if (client->type != client_info->type)
return -EINVAL;
/* check validity of midi_version field */
if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3) &&
client_info->midi_version > SNDRV_SEQ_CLIENT_UMP_MIDI_2_0)
return -EINVAL;
/* fill the info fields */
if (client_info->name[0])
strscpy(client->name, client_info->name, sizeof(client->name));
client->filter = client_info->filter;
client->event_lost = client_info->event_lost;
if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3))
client->midi_version = client_info->midi_version;
memcpy(client->event_filter, client_info->event_filter, 32);
client->group_filter = client_info->group_filter;
return 0;
}
@ -1297,22 +1304,27 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
struct snd_seq_port_info *info = arg;
struct snd_seq_client_port *port;
struct snd_seq_port_callback *callback;
int port_idx;
int port_idx, err;
/* it is not allowed to create the port for an another client */
if (info->addr.client != client->number)
return -EPERM;
port = snd_seq_create_port(client, (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info->addr.port : -1);
if (port == NULL)
return -ENOMEM;
if (client->type == USER_CLIENT && info->kernel) {
port_idx = port->addr.port;
snd_seq_port_unlock(port);
snd_seq_delete_port(client, port_idx);
if (client->type == USER_CLIENT && info->kernel)
return -EINVAL;
}
if ((info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT) &&
client->ump_endpoint_port >= 0)
return -EBUSY;
if (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT)
port_idx = info->addr.port;
else
port_idx = -1;
if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN)
return -EINVAL;
err = snd_seq_create_port(client, port_idx, &port);
if (err < 0)
return err;
if (client->type == KERNEL_CLIENT) {
callback = info->kernel;
if (callback) {
@ -1331,6 +1343,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
info->addr = port->addr;
snd_seq_set_port_info(port, info);
if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT)
client->ump_endpoint_port = port->addr.port;
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
snd_seq_port_unlock(port);
@ -1350,8 +1364,11 @@ static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg)
return -EPERM;
err = snd_seq_delete_port(client, info->addr.port);
if (err >= 0)
if (err >= 0) {
if (client->ump_endpoint_port == info->addr.port)
client->ump_endpoint_port = -1;
snd_seq_system_client_ev_port_exit(client->number, info->addr.port);
}
return err;
}
@ -2079,6 +2096,135 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
return 0;
}
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
#define NUM_UMP_INFOS (SNDRV_UMP_MAX_BLOCKS + 1)
static void free_ump_info(struct snd_seq_client *client)
{
int i;
if (!client->ump_info)
return;
for (i = 0; i < NUM_UMP_INFOS; i++)
kfree(client->ump_info[i]);
kfree(client->ump_info);
client->ump_info = NULL;
}
static void terminate_ump_info_strings(void *p, int type)
{
if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) {
struct snd_ump_endpoint_info *ep = p;
ep->name[sizeof(ep->name) - 1] = 0;
} else {
struct snd_ump_block_info *bp = p;
bp->name[sizeof(bp->name) - 1] = 0;
}
}
#ifdef CONFIG_SND_PROC_FS
static void dump_ump_info(struct snd_info_buffer *buffer,
struct snd_seq_client *client)
{
struct snd_ump_endpoint_info *ep;
struct snd_ump_block_info *bp;
int i;
if (!client->ump_info)
return;
ep = client->ump_info[SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT];
if (ep && *ep->name)
snd_iprintf(buffer, " UMP Endpoint: \"%s\"\n", ep->name);
for (i = 0; i < SNDRV_UMP_MAX_BLOCKS; i++) {
bp = client->ump_info[i + 1];
if (bp && *bp->name) {
snd_iprintf(buffer, " UMP Block %d: \"%s\" [%s]\n",
i, bp->name,
bp->active ? "Active" : "Inactive");
snd_iprintf(buffer, " Groups: %d-%d\n",
bp->first_group + 1,
bp->first_group + bp->num_groups);
}
}
}
#endif
/* UMP-specific ioctls -- called directly without data copy */
static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
unsigned int cmd,
unsigned long arg)
{
struct snd_seq_client_ump_info __user *argp =
(struct snd_seq_client_ump_info __user *)arg;
struct snd_seq_client *cptr;
int client, type, err = 0;
size_t size;
void *p;
if (get_user(client, &argp->client) || get_user(type, &argp->type))
return -EFAULT;
if (cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO &&
caller->number != client)
return -EPERM;
if (type < 0 || type >= NUM_UMP_INFOS)
return -EINVAL;
if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
size = sizeof(struct snd_ump_endpoint_info);
else
size = sizeof(struct snd_ump_block_info);
cptr = snd_seq_client_use_ptr(client);
if (!cptr)
return -ENOENT;
mutex_lock(&cptr->ioctl_mutex);
if (!cptr->midi_version) {
err = -EBADFD;
goto error;
}
if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) {
if (!cptr->ump_info)
p = NULL;
else
p = cptr->ump_info[type];
if (!p) {
err = -ENODEV;
goto error;
}
if (copy_to_user(argp->info, p, size)) {
err = -EFAULT;
goto error;
}
} else {
if (cptr->type != USER_CLIENT) {
err = -EBADFD;
goto error;
}
if (!cptr->ump_info) {
cptr->ump_info = kcalloc(NUM_UMP_INFOS,
sizeof(void *), GFP_KERNEL);
if (!cptr->ump_info) {
err = -ENOMEM;
goto error;
}
}
p = memdup_user(argp->info, size);
if (IS_ERR(p)) {
err = PTR_ERR(p);
goto error;
}
kfree(cptr->ump_info[type]);
terminate_ump_info_strings(p, type);
cptr->ump_info[type] = p;
}
error:
mutex_unlock(&cptr->ioctl_mutex);
snd_seq_client_unlock(cptr);
return err;
}
#endif
/* -------------------------------------------------------- */
static const struct ioctl_handler {
@ -2086,6 +2232,7 @@ static const struct ioctl_handler {
int (*func)(struct snd_seq_client *client, void *arg);
} ioctl_handlers[] = {
{ SNDRV_SEQ_IOCTL_PVERSION, snd_seq_ioctl_pversion },
{ SNDRV_SEQ_IOCTL_USER_PVERSION, snd_seq_ioctl_user_pversion },
{ SNDRV_SEQ_IOCTL_CLIENT_ID, snd_seq_ioctl_client_id },
{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
@ -2148,6 +2295,15 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd,
if (snd_BUG_ON(!client))
return -ENXIO;
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
/* exception - handling large data */
switch (cmd) {
case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO:
case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO:
return snd_seq_ioctl_client_ump_info(client, cmd, arg);
}
#endif
for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
if (handler->cmd == cmd)
break;
@ -2226,6 +2382,7 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
client->accept_input = 1;
client->accept_output = 1;
client->data.kernel.card = card;
client->user_pversion = SNDRV_SEQ_VERSION;
va_start(args, name_fmt);
vsnprintf(client->name, sizeof(client->name), name_fmt, args);
@ -2274,10 +2431,12 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
if (snd_BUG_ON(!ev))
return -EINVAL;
if (ev->type == SNDRV_SEQ_EVENT_NONE)
return 0; /* ignore this */
if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
return -EINVAL; /* quoted events can't be enqueued */
if (!snd_seq_ev_is_ump(ev)) {
if (ev->type == SNDRV_SEQ_EVENT_NONE)
return 0; /* ignore this */
if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
return -EINVAL; /* quoted events can't be enqueued */
}
/* fill in client number */
ev->source.client = client;
@ -2390,6 +2549,21 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
}
EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
/* get a sequencer client object; for internal use from a kernel client */
struct snd_seq_client *snd_seq_kernel_client_get(int id)
{
return snd_seq_client_use_ptr(id);
}
EXPORT_SYMBOL_GPL(snd_seq_kernel_client_get);
/* put a sequencer client object; for internal use from a kernel client */
void snd_seq_kernel_client_put(struct snd_seq_client *cptr)
{
if (cptr)
snd_seq_client_unlock(cptr);
}
EXPORT_SYMBOL_GPL(snd_seq_kernel_client_put);
/*---------------------------------------------------------------------------*/
#ifdef CONFIG_SND_PROC_FS
@ -2435,6 +2609,17 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')
static const char *port_direction_name(unsigned char dir)
{
static const char *names[4] = {
"-", "In", "Out", "In/Out"
};
if (dir > SNDRV_SEQ_PORT_DIR_BIDIRECTION)
return "Invalid";
return names[dir];
}
static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
struct snd_seq_client *client)
{
@ -2442,18 +2627,34 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
mutex_lock(&client->ports_mutex);
list_for_each_entry(p, &client->ports_list_head, list) {
snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE)
continue;
snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c) [%s]\n",
p->addr.port, p->name,
FLAG_PERM_RD(p->capability),
FLAG_PERM_WR(p->capability),
FLAG_PERM_EX(p->capability),
FLAG_PERM_DUPLEX(p->capability));
FLAG_PERM_DUPLEX(p->capability),
port_direction_name(p->direction));
snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: ");
snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: ");
}
mutex_unlock(&client->ports_mutex);
}
static const char *midi_version_string(unsigned int version)
{
switch (version) {
case SNDRV_SEQ_CLIENT_LEGACY_MIDI:
return "Legacy";
case SNDRV_SEQ_CLIENT_UMP_MIDI_1_0:
return "UMP MIDI1";
case SNDRV_SEQ_CLIENT_UMP_MIDI_2_0:
return "UMP MIDI2";
default:
return "Unknown";
}
}
/* exported to seq_info.c */
void snd_seq_info_clients_read(struct snd_info_entry *entry,
@ -2478,9 +2679,13 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
continue;
}
snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n",
snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n",
c, client->name,
client->type == USER_CLIENT ? "User" : "Kernel");
client->type == USER_CLIENT ? "User" : "Kernel",
midi_version_string(client->midi_version));
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
dump_ump_info(buffer, client);
#endif
snd_seq_info_dump_ports(buffer, client);
if (snd_seq_write_pool_allocated(client)) {
snd_iprintf(buffer, " Output pool :\n");

View File

@ -12,7 +12,6 @@
#include "seq_ports.h"
#include "seq_lock.h"
/* client manager */
struct snd_seq_user_client {
@ -35,10 +34,13 @@ struct snd_seq_client {
snd_seq_client_type_t type;
unsigned int accept_input: 1,
accept_output: 1;
unsigned int midi_version;
unsigned int user_pversion;
char name[64]; /* client name */
int number; /* client number */
unsigned int filter; /* filter flags */
DECLARE_BITMAP(event_filter, 256);
unsigned short group_filter;
snd_use_lock_t use_lock;
int event_lost;
/* ports */
@ -48,6 +50,7 @@ struct snd_seq_client {
struct mutex ports_mutex;
struct mutex ioctl_mutex;
int convert32; /* convert 32->64bit */
int ump_endpoint_port;
/* output pool */
struct snd_seq_pool *pool; /* memory pool for this client */
@ -56,6 +59,9 @@ struct snd_seq_client {
struct snd_seq_user_client user;
struct snd_seq_kernel_client kernel;
} data;
/* for UMP */
void **ump_info;
};
/* usage statistics */
@ -82,10 +88,29 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
int snd_seq_client_notify_subscription(int client, int port,
struct snd_seq_port_subscribe *info, int evtype);
int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
struct snd_seq_client_port *dest_port,
struct snd_seq_event *event,
int atomic, int hop);
/* only for OSS sequencer */
bool snd_seq_client_ioctl_lock(int clientid);
void snd_seq_client_ioctl_unlock(int clientid);
extern int seq_client_load[15];
/* for internal use between kernel sequencer clients */
struct snd_seq_client *snd_seq_kernel_client_get(int client);
void snd_seq_kernel_client_put(struct snd_seq_client *cptr);
static inline bool snd_seq_client_is_ump(struct snd_seq_client *c)
{
return c->midi_version != SNDRV_SEQ_CLIENT_LEGACY_MIDI;
}
static inline bool snd_seq_client_is_midi2(struct snd_seq_client *c)
{
return c->midi_version == SNDRV_SEQ_CLIENT_UMP_MIDI_2_0;
}
#endif

View File

@ -81,10 +81,13 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
switch (cmd) {
case SNDRV_SEQ_IOCTL_PVERSION:
case SNDRV_SEQ_IOCTL_USER_PVERSION:
case SNDRV_SEQ_IOCTL_CLIENT_ID:
case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO:
case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO:
case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_CREATE_QUEUE:

View File

@ -127,6 +127,7 @@ create_port(int idx, int type)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
if (duplex)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
pinfo.direction = SNDRV_SEQ_PORT_DIR_BIDIRECTION;
pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
| SNDRV_SEQ_PORT_TYPE_SOFTWARE
| SNDRV_SEQ_PORT_TYPE_PORT;
@ -151,6 +152,7 @@ static int __init
register_client(void)
{
struct snd_seq_dummy_port *rec1, *rec2;
struct snd_seq_client *client;
int i;
if (ports < 1) {
@ -164,6 +166,13 @@ register_client(void)
if (my_client < 0)
return my_client;
/* don't convert events but just pass-through */
client = snd_seq_kernel_client_get(my_client);
if (!client)
return -EINVAL;
client->filter = SNDRV_SEQ_FILTER_NO_CONVERT;
snd_seq_kernel_client_put(client);
/* create ports */
for (i = 0; i < ports; i++) {
rec1 = create_port(i, 0);

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