Alsa-devel
Threads by month
- ----- 2024 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
February 2016
- 131 participants
- 298 discussions
[alsa-devel] [PATCH] ASoC: dapm: Don't prefix autodisable widgets twice
by Lars-Peter Clausen 04 Feb '16
by Lars-Peter Clausen 04 Feb '16
04 Feb '16
When a DAPM context has a prefix the autodisable widgets get prefixed
twice, once for the control and once for the widget. To avoid this use
the un-prefixed control name to construct the autodisable widget name.
This change is purely cosmetic.
Signed-off-by: Lars-Peter Clausen <lars(a)metafoo.de>
---
sound/soc/soc-dapm.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5a2812f..0d37079 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -310,7 +310,7 @@ struct dapm_kcontrol_data {
};
static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
- struct snd_kcontrol *kcontrol)
+ struct snd_kcontrol *kcontrol, const char *ctrl_name)
{
struct dapm_kcontrol_data *data;
struct soc_mixer_control *mc;
@@ -333,7 +333,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
if (mc->autodisable) {
struct snd_soc_dapm_widget template;
- name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+ name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
"Autodisable");
if (!name) {
ret = -ENOMEM;
@@ -371,7 +371,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
if (e->autodisable) {
struct snd_soc_dapm_widget template;
- name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+ name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
"Autodisable");
if (!name) {
ret = -ENOMEM;
@@ -871,7 +871,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
kcontrol->private_free = dapm_kcontrol_free;
- ret = dapm_kcontrol_data_alloc(w, kcontrol);
+ ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
if (ret) {
snd_ctl_free_one(kcontrol);
goto exit_free;
--
2.1.4
2
1
[alsa-devel] [PATCH] ASoC: fsl-asoc-card: Don't add DAPM routes for ASRC if it doesn't exist
by Nicolin Chen 04 Feb '16
by Nicolin Chen 04 Feb '16
04 Feb '16
From: Nicolin Chen <nicolinc(a)nvidia.com>
There are a pair of warnings when ASRC is absent in the DTB:
fsl-asoc-card sound: ASoC: no source widget found for ASRC-Playback
fsl-asoc-card sound: ASoC: Failed to add route ASRC-Playback -> direct -> CPU-Playback
fsl-asoc-card sound: ASoC: no sink widget found for ASRC-Capture
fsl-asoc-card sound: ASoC: Failed to add route CPU-Capture -> direct -> ASRC-Capture
This is because the driver is still trying to add DAPM routes for ASRC
even if it doesn't exist on that platform.
The warnings are harmless but it might be annoying. So this patch drops
the DAPM routes of ASRC when it's absent in the DAI link.
Signed-off-by: Nicolin Chen <nicolinc(a)nvidia.com>
---
sound/soc/fsl/fsl-asoc-card.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 562b3bd..3d40797 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -99,19 +99,26 @@ struct fsl_asoc_card_priv {
/**
* This dapm route map exsits for DPCM link only.
* The other routes shall go through Device Tree.
+ *
+ * Note: keep all ASRC routes in the second half
+ * to drop them easily for non-ASRC cases.
*/
static const struct snd_soc_dapm_route audio_map[] = {
- {"CPU-Playback", NULL, "ASRC-Playback"},
+ /* 1st half -- Normal DAPM routes */
{"Playback", NULL, "CPU-Playback"},
- {"ASRC-Capture", NULL, "CPU-Capture"},
{"CPU-Capture", NULL, "Capture"},
+ /* 2nd half -- ASRC DAPM routes */
+ {"CPU-Playback", NULL, "ASRC-Playback"},
+ {"ASRC-Capture", NULL, "CPU-Capture"},
};
static const struct snd_soc_dapm_route audio_map_ac97[] = {
- {"AC97 Playback", NULL, "ASRC-Playback"},
+ /* 1st half -- Normal DAPM routes */
{"Playback", NULL, "AC97 Playback"},
- {"ASRC-Capture", NULL, "AC97 Capture"},
{"AC97 Capture", NULL, "Capture"},
+ /* 2nd half -- ASRC DAPM routes */
+ {"AC97 Playback", NULL, "ASRC-Playback"},
+ {"ASRC-Capture", NULL, "AC97 Capture"},
};
/* Add all possible widgets into here without being redundant */
@@ -593,6 +600,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
+ /* Drop the second half of DAPM routes -- ASRC */
+ if (!asrc_pdev)
+ priv->card.num_dapm_routes /= 2;
+
memcpy(priv->dai_link, fsl_asoc_card_dai,
sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
--
1.9.1
2
1
[alsa-devel] [PATCH] ASoC: cs42xx8: fix the noise in the right dac channel when playback mono wav with record in background
by Zidan Wang 04 Feb '16
by Zidan Wang 04 Feb '16
04 Feb '16
When playback mono wav with record in background, there will be some
nosie in the right dac channel. It seems that the ADC data has been
routed to the dac channel.
The cs42888 have 8 dac channels, it's appropriate to mute the unused
dac channels, and the noise will disappear.
Steps to reproduce this issue:
arecord -D hw:0,0 -f S16_LE -r 48000 -c 1 a.wav &
aplay -Dhw:0,0 audio48k16M.wav
Signed-off-by: Zidan Wang <zidan.wang(a)freescale.com>
---
sound/soc/codecs/cs42xx8.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index d562e1b..1179101 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -44,6 +44,7 @@ struct cs42xx8_priv {
bool slave_mode;
unsigned long sysclk;
+ u32 tx_channels;
};
/* -127.5dB to 0dB with step of 0.5dB */
@@ -257,6 +258,9 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
u32 ratio = cs42xx8->sysclk / params_rate(params);
u32 i, fm, val, mask;
+ if (tx)
+ cs42xx8->tx_channels = params_channels(params);
+
for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
if (cs42xx8_ratios[i].ratio == ratio)
break;
@@ -283,9 +287,11 @@ static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+ u8 dac_unmute = cs42xx8->tx_channels ?
+ ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
- regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
- CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
+ regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
+ mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
return 0;
}
--
1.9.1
2
1
Hello Linux firmware maintainers,
Please PULL to receive the updated version of Skylake audio firmware.
This PULL request has two patches, first one creates a sym link for binary
name which helps us to keep different versions of firmware in git
Second one updates to latest FW v869
The following changes since commit 52442afee9907bc32a058f22bb3295d040677c26:
brcm: add firmware for bcm4366 device (2016-01-25 15:15:34 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/firmware.git skl
for you to fetch changes up to f7996657e8f25386541593242cb8e906d9808ec7:
linux-firmware: intel: Update Skylake audio firmware (2016-02-04 10:36:52 +0530)
----------------------------------------------------------------
Vinod Koul (2):
linux-firmware: intel: add symbolic link and file versions
linux-firmware: intel: Update Skylake audio firmware
WHENCE | 4 ++--
intel/dsp_fw_release.bin | Bin 233472 -> 23 bytes
intel/dsp_fw_release_v827.bin | Bin 0 -> 233472 bytes
intel/dsp_fw_release_v869.bin | Bin 0 -> 233472 bytes
4 files changed, 2 insertions(+), 2 deletions(-)
mode change 100644 => 120000 intel/dsp_fw_release.bin
create mode 100644 intel/dsp_fw_release_v827.bin
create mode 100644 intel/dsp_fw_release_v869.bin
Thanks
--
~Vinod
1
0
[alsa-devel] [PATCH 00/31] Sharing media resources across ALSA and au0828 drivers
by Shuah Khan 03 Feb '16
by Shuah Khan 03 Feb '16
03 Feb '16
This patch series updates ALSA driver, and au0828 core
driver to use Managed Media controller API and Media
Controller API to share tuner.
Media Controller Next Generation API has been enhanced
to add two new interfaces to register and unregister
entity_notify hooks to allow drivers to take appropriate
actions when as new entities get added to the shared media
device.
Mauro and Takashi: I am hoping you can both coordinate
and decide on ALSA patches once the reviews are done
and the patches look good.
Design Highlights:
1. ALSA to check for resources and hold in snd_usb_hw_params(),
and release from snd_usb_hw_free(). This change fixed the
lockdep warnings seen when resources were held in
TRIGGER_START and released from TRIGGER_STOP which could
run in IRQ context. I acknowledge Clemens Ladisch for
suggesting the correct places to hold/free resources to
avoid IRQ path complications.
2. The Bridge driver (au0828) owns and drives the graph creation
as well as enabling and disabling tuner. It also keeps state
information to avoid graph walks in enable_source and
disable_source handler. I acknowledge Hans Verkuil for his
suggestions and ideas for this change.
Tested exclusion between digital, analog, and audio to ensure
when tuner has an active link to DVB FE, analog, and audio will
detect and honor the tuner busy conditions and vice versa.
Please find the graphs generated using mc_nextgen_test tool at
various points during testing at:
https://drive.google.com/folderview?id=0B0NIL0BQg-AlRndaaXViSXdPeTA&usp=sha…
This patch series is a rebase and update to the latest Media
Controller Next Gen API of the Media Controller Next Generation
API port.
Rebase highlights:
1. Changes to videobuf2 framework required additional
v4l2 helper function to enable the tuner from
vb2_core_streamon(). Patch 9 has this work.
2. Media device initialization and registration steps
are now split in the latest Media Controller Next Gen
API. This required changes to au0828 and ALSA to coordinate
initialization and registration of the Managed Media Device
they share. Patch 19 shows au0828 changes. ALSA changes
for this are folded into the main ALSA patch 26.
3. Media device unregistration does more cleanup now. As a
result, au0828 and ALSA need to coordinate so media device
is done only once. These changes are in patches: 29, 30,
and 31.
4. In addition, media device resources cleanup gets done
before snd_card_disconnect(). This work is in patch 30.
Media Controller Next Generation API port from Media Controller API:
The patch series below was a port of the Patch v3 - Media Controller API
to Next Gen API and Mixer patch update to address comments and bug fixes:
https://www.mail-archive.com/linux-media@vger.kernel.org/msg93086.html
https://www.mail-archive.com/linux-media@vger.kernel.org/msg93417.html
Patch v3 - Media Controller API:
https://www.mail-archive.com/linux-media@vger.kernel.org/msg92572.html
Mauro Carvalho Chehab (1):
uapi/media.h: Declare interface types for ALSA
Shuah Khan (30):
media: Add ALSA Media Controller function entities
media: Media Controller register/unregister entity_notify API
media: Media Controller enable/disable source handler API
media: Media Controller fix to not let stream_count go negative
media: Media Controller export non locking __media_entity_setup_link()
media: Media Controller non-locking
__media_entity_pipeline_start/stop()
media: v4l-core add v4l_enable/disable_media_tuner() helper functions
media: v4l2-core add v4l_vb2q_enable_media_tuner() helper
media: Move au8522_media_pads enum to au8522.h from au8522_priv.h
media: au8522 change to create MC pad for ALSA Audio Out
media: au0828 Use au8522_media_pads enum for pad defines
media: au0828 fix au0828_create_media_graph() entity checks
media: Change v4l-core to check for tuner availability
media: dvb-frontend invoke enable/disable_source handlers
media: au0828 video remove au0828_enable_analog_tuner()
media: au0828 video change to use v4l_enable_media_tuner()
media: au0828 change to use Managed Media Controller API
media: au0828 handle media_init and media_register window
media: au0828 change to register/unregister entity_notify hook
media: au0828 create tuner to decoder link in deactivated state
media: dvb-core create tuner to demod pad link in disabled state
media: au0828 implement enable_source and disable_source handlers
media: au0828 fix null pointer reference in
au0828_create_media_graph()
media: au0828 fix to not call media_device_unregister_entity_notify()
sound/usb: Update ALSA driver to use Managed Media Controller API
sound/usb: Create media mixer function and control interface entities
media: au0828 create link between ALSA Mixer and decoder
media: track media device unregister in progress
sound/usb: Check media device unregister progress state
media: au0828 change to check media device unregister progress state
drivers/media/dvb-core/dvb_frontend.c | 139 ++---------
drivers/media/dvb-core/dvb_frontend.h | 3 +
drivers/media/dvb-core/dvbdev.c | 3 +-
drivers/media/dvb-frontends/au8522.h | 8 +
drivers/media/dvb-frontends/au8522_decoder.c | 1 +
drivers/media/dvb-frontends/au8522_priv.h | 8 -
drivers/media/media-device.c | 66 ++++-
drivers/media/media-entity.c | 65 +++--
drivers/media/usb/au0828/au0828-core.c | 355 ++++++++++++++++++++++-----
drivers/media/usb/au0828/au0828-video.c | 75 +-----
drivers/media/usb/au0828/au0828.h | 9 +
drivers/media/v4l2-core/v4l2-dev.c | 48 ++++
drivers/media/v4l2-core/v4l2-fh.c | 1 +
drivers/media/v4l2-core/v4l2-ioctl.c | 29 +++
drivers/media/v4l2-core/videobuf2-core.c | 4 +
include/media/media-device.h | 61 +++++
include/media/media-entity.h | 12 +
include/media/v4l2-dev.h | 5 +
include/uapi/linux/media.h | 17 +-
sound/usb/Makefile | 15 +-
sound/usb/card.c | 16 ++
sound/usb/card.h | 1 +
sound/usb/media.c | 325 ++++++++++++++++++++++++
sound/usb/media.h | 75 ++++++
sound/usb/mixer.h | 1 +
sound/usb/pcm.c | 26 +-
sound/usb/quirks-table.h | 1 +
sound/usb/quirks.c | 9 +-
sound/usb/stream.c | 1 +
sound/usb/usbaudio.h | 2 +
30 files changed, 1111 insertions(+), 270 deletions(-)
create mode 100644 sound/usb/media.c
create mode 100644 sound/usb/media.h
--
2.5.0
5
78
Hi,
I'm tinkering on the wintron 7.0 together with Tobias Mädel and have
tested your patch with your UCM config on Linux 4.5.0-rc2. It looks like
we are getting somewhere. The soundcard is now being recognized by ALSA.
But there are still some errors in that seem to be related to the audio
driver.
As soon as I try to output any sound I get an error:
[ 88.906739] intel_sst_acpi 80860F28:00: fw download failed -16
[ 88.909262] intel_sst_acpi 80860F28:00: FW download fail -16
[ 88.948434] Audio Port: ASoC: no backend DAIs enabled for Audio Port
Does anybody have an idea why the sound chip is not responding and the
fw download timeouts?
I've uploaded dmesg, lsmod and tree /proc/asound output here:
https://github.com/TobleMiner/wintron7.0/tree/master/logs/4.5.0-rc2-ARCH-ts…
Regards,
Tobias Mädel and Tobias Schramm
2
1
This is the initial codec driver for rt5514. The codec includes a low power
DSP for voice wake up. The register address is incremental by 4 in the DSP
memory map. In order to recover the codec settings in the codec mode and
manipulate the DSP mode for voice wake up, we use the multi-level register
map. One is for ALSA API in codec mode that can be recovered by cache
before recording. Another is for DSP related settings that can be accessed
with 32bit address of the DSP in the application of voice wake up.
Signed-off-by: Oder Chiou <oder_chiou(a)realtek.com>
---
Documentation/devicetree/bindings/sound/rt5514.txt | 25 +
sound/soc/codecs/Kconfig | 6 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/rt5514.c | 982 +++++++++++++++++++++
sound/soc/codecs/rt5514.h | 252 ++++++
5 files changed, 1267 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/rt5514.txt
create mode 100644 sound/soc/codecs/rt5514.c
create mode 100644 sound/soc/codecs/rt5514.h
diff --git a/Documentation/devicetree/bindings/sound/rt5514.txt b/Documentation/devicetree/bindings/sound/rt5514.txt
new file mode 100644
index 0000000..e24436f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5514.txt
@@ -0,0 +1,25 @@
+RT5514 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5514".
+
+- reg : The I2C address of the device.
+
+Pins on the device (for linking into audio routes) for RT5514:
+
+ * DMIC1L
+ * DMIC1R
+ * DMIC2L
+ * DMIC2R
+ * AMICL
+ * AMICR
+
+Example:
+
+codec: rt5514@57 {
+ compatible = "realtek,rt5514";
+ reg = <0x57>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 50693c8..dabd479 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -95,6 +95,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
+ select SND_SOC_RT5514 if I2C
select SND_SOC_RT5616 if I2C
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
@@ -565,6 +566,7 @@ config SND_SOC_PCM512x_SPI
config SND_SOC_RL6231
tristate
+ default y if SND_SOC_RT5514=y
default y if SND_SOC_RT5616=y
default y if SND_SOC_RT5640=y
default y if SND_SOC_RT5645=y
@@ -572,6 +574,7 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5659=y
default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y
+ default m if SND_SOC_RT5514=m
default m if SND_SOC_RT5616=m
default m if SND_SOC_RT5640=m
default m if SND_SOC_RT5645=m
@@ -595,6 +598,9 @@ config SND_SOC_RT298
tristate
depends on I2C
+config SND_SOC_RT5514
+ tristate
+
config SND_SOC_RT5616
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d44f7d3..79f95dd 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -92,6 +92,7 @@ snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
+snd-soc-rt5514-objs := rt5514.o
snd-soc-rt5616-objs := rt5616.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
@@ -296,6 +297,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
+obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o
obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
new file mode 100644
index 0000000..879bf60
--- /dev/null
+++ b/sound/soc/codecs/rt5514.c
@@ -0,0 +1,982 @@
+/*
+ * rt5514.c -- RT5514 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou(a)realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5514.h"
+
+static const struct reg_sequence rt5514_i2c_patch[] = {
+ {0x1800101c, 0x00000000},
+ {0x18001100, 0x0000031f},
+ {0x18001104, 0x00000007},
+ {0x18001108, 0x00000000},
+ {0x1800110c, 0x00000000},
+ {0x18001110, 0x00000000},
+ {0x18001114, 0x00000001},
+ {0x18001118, 0x00000000},
+ {0x18002f08, 0x00000006},
+ {0x18002f00, 0x00055149},
+ {0x18002f00, 0x0005514b},
+ {0x18002f00, 0x00055149},
+ {0xfafafafa, 0x00000001},
+ {0x18002f10, 0x00000001},
+ {0x18002f10, 0x00000000},
+ {0x18002f10, 0x00000001},
+ {0xfafafafa, 0x00000001},
+ {0x18002000, 0x000010ec},
+ {0xfafafafa, 0x00000000},
+};
+
+static const struct reg_sequence rt5514_patch[] = {
+ {RT5514_DIG_IO_CTRL, 0x00000040},
+ {RT5514_CLK_CTRL1, 0x38020041},
+ {RT5514_SRC_CTRL, 0x44000eee},
+ {RT5514_ANA_CTRL_LDO10, 0x00028604},
+ {RT5514_ANA_CTRL_ADCFED, 0x00000800},
+};
+
+static const struct reg_default rt5514_reg[] = {
+ {RT5514_RESET, 0x00000000},
+ {RT5514_PWR_ANA1, 0x00808880},
+ {RT5514_PWR_ANA2, 0x00220000},
+ {RT5514_I2S_CTRL1, 0x00000330},
+ {RT5514_I2S_CTRL2, 0x20000000},
+ {RT5514_VAD_CTRL6, 0xc00007d2},
+ {RT5514_EXT_VAD_CTRL, 0x80000080},
+ {RT5514_DIG_IO_CTRL, 0x00000040},
+ {RT5514_PAD_CTRL1, 0x00804000},
+ {RT5514_DMIC_DATA_CTRL, 0x00000005},
+ {RT5514_DIG_SOURCE_CTRL, 0x00000002},
+ {RT5514_SRC_CTRL, 0x44000eee},
+ {RT5514_DOWNFILTER2_CTRL1, 0x0000882f},
+ {RT5514_PLL_SOURCE_CTRL, 0x00000004},
+ {RT5514_CLK_CTRL1, 0x38020041},
+ {RT5514_CLK_CTRL2, 0x00000000},
+ {RT5514_PLL3_CALIB_CTRL1, 0x00400200},
+ {RT5514_PLL3_CALIB_CTRL5, 0x40220012},
+ {RT5514_DELAY_BUF_CTRL1, 0x7fff006a},
+ {RT5514_DELAY_BUF_CTRL3, 0x00000000},
+ {RT5514_DOWNFILTER0_CTRL1, 0x00020c2f},
+ {RT5514_DOWNFILTER0_CTRL2, 0x00020c2f},
+ {RT5514_DOWNFILTER0_CTRL3, 0x00000362},
+ {RT5514_DOWNFILTER1_CTRL1, 0x00020c2f},
+ {RT5514_DOWNFILTER1_CTRL2, 0x00020c2f},
+ {RT5514_DOWNFILTER1_CTRL3, 0x00000362},
+ {RT5514_ANA_CTRL_LDO10, 0x00028604},
+ {RT5514_ANA_CTRL_LDO18_16, 0x02000345},
+ {RT5514_ANA_CTRL_ADC12, 0x0000a2a8},
+ {RT5514_ANA_CTRL_ADC21, 0x00001180},
+ {RT5514_ANA_CTRL_ADC22, 0x0000aaa8},
+ {RT5514_ANA_CTRL_ADC23, 0x00151427},
+ {RT5514_ANA_CTRL_MICBST, 0x00002000},
+ {RT5514_ANA_CTRL_ADCFED, 0x00000800},
+ {RT5514_ANA_CTRL_INBUF, 0x00000143},
+ {RT5514_ANA_CTRL_VREF, 0x00008d50},
+ {RT5514_ANA_CTRL_PLL3, 0x0000000e},
+ {RT5514_ANA_CTRL_PLL1_1, 0x00000000},
+ {RT5514_ANA_CTRL_PLL1_2, 0x00030220},
+ {RT5514_DMIC_LP_CTRL, 0x00000000},
+ {RT5514_MISC_CTRL_DSP, 0x00000000},
+ {RT5514_DSP_CTRL1, 0x00055149},
+ {RT5514_DSP_CTRL3, 0x00000006},
+ {RT5514_DSP_CTRL4, 0x00000001},
+ {RT5514_VENDOR_ID1, 0x00000001},
+ {RT5514_VENDOR_ID2, 0x10ec5514},
+};
+
+static bool rt5514_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5514_VENDOR_ID1:
+ case RT5514_VENDOR_ID2:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt5514_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5514_RESET:
+ case RT5514_PWR_ANA1:
+ case RT5514_PWR_ANA2:
+ case RT5514_I2S_CTRL1:
+ case RT5514_I2S_CTRL2:
+ case RT5514_VAD_CTRL6:
+ case RT5514_EXT_VAD_CTRL:
+ case RT5514_DIG_IO_CTRL:
+ case RT5514_PAD_CTRL1:
+ case RT5514_DMIC_DATA_CTRL:
+ case RT5514_DIG_SOURCE_CTRL:
+ case RT5514_SRC_CTRL:
+ case RT5514_DOWNFILTER2_CTRL1:
+ case RT5514_PLL_SOURCE_CTRL:
+ case RT5514_CLK_CTRL1:
+ case RT5514_CLK_CTRL2:
+ case RT5514_PLL3_CALIB_CTRL1:
+ case RT5514_PLL3_CALIB_CTRL5:
+ case RT5514_DELAY_BUF_CTRL1:
+ case RT5514_DELAY_BUF_CTRL3:
+ case RT5514_DOWNFILTER0_CTRL1:
+ case RT5514_DOWNFILTER0_CTRL2:
+ case RT5514_DOWNFILTER0_CTRL3:
+ case RT5514_DOWNFILTER1_CTRL1:
+ case RT5514_DOWNFILTER1_CTRL2:
+ case RT5514_DOWNFILTER1_CTRL3:
+ case RT5514_ANA_CTRL_LDO10:
+ case RT5514_ANA_CTRL_LDO18_16:
+ case RT5514_ANA_CTRL_ADC12:
+ case RT5514_ANA_CTRL_ADC21:
+ case RT5514_ANA_CTRL_ADC22:
+ case RT5514_ANA_CTRL_ADC23:
+ case RT5514_ANA_CTRL_MICBST:
+ case RT5514_ANA_CTRL_ADCFED:
+ case RT5514_ANA_CTRL_INBUF:
+ case RT5514_ANA_CTRL_VREF:
+ case RT5514_ANA_CTRL_PLL3:
+ case RT5514_ANA_CTRL_PLL1_1:
+ case RT5514_ANA_CTRL_PLL1_2:
+ case RT5514_DMIC_LP_CTRL:
+ case RT5514_MISC_CTRL_DSP:
+ case RT5514_DSP_CTRL1:
+ case RT5514_DSP_CTRL3:
+ case RT5514_DSP_CTRL4:
+ case RT5514_VENDOR_ID1:
+ case RT5514_VENDOR_ID2:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt5514_i2c_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case RT5514_DSP_MAPPING | RT5514_RESET:
+ case RT5514_DSP_MAPPING | RT5514_PWR_ANA1:
+ case RT5514_DSP_MAPPING | RT5514_PWR_ANA2:
+ case RT5514_DSP_MAPPING | RT5514_I2S_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_I2S_CTRL2:
+ case RT5514_DSP_MAPPING | RT5514_VAD_CTRL6:
+ case RT5514_DSP_MAPPING | RT5514_EXT_VAD_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_DIG_IO_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_PAD_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_DMIC_DATA_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_DIG_SOURCE_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_SRC_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER2_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_PLL_SOURCE_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_CLK_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_CLK_CTRL2:
+ case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL5:
+ case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL3:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL2:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL3:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL2:
+ case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL3:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_LDO10:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_LDO18_16:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC12:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC21:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC22:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC23:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_MICBST:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADCFED:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_INBUF:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_VREF:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL3:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL1_1:
+ case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL1_2:
+ case RT5514_DSP_MAPPING | RT5514_DMIC_LP_CTRL:
+ case RT5514_DSP_MAPPING | RT5514_MISC_CTRL_DSP:
+ case RT5514_DSP_MAPPING | RT5514_DSP_CTRL1:
+ case RT5514_DSP_MAPPING | RT5514_DSP_CTRL3:
+ case RT5514_DSP_MAPPING | RT5514_DSP_CTRL4:
+ case RT5514_DSP_MAPPING | RT5514_VENDOR_ID1:
+ case RT5514_DSP_MAPPING | RT5514_VENDOR_ID2:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* {-3, 0, +3, +4.5, +7.5, +9.5, +12, +14, +17} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+ 0, 2, TLV_DB_SCALE_ITEM(-300, 300, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
+ 4, 4, TLV_DB_SCALE_ITEM(750, 0, 0),
+ 5, 5, TLV_DB_SCALE_ITEM(950, 0, 0),
+ 6, 6, TLV_DB_SCALE_ITEM(1200, 0, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(1400, 0, 0),
+ 8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+
+static const struct snd_kcontrol_new rt5514_snd_controls[] = {
+ SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST,
+ RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv),
+ SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1,
+ RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
+ adc_vol_tlv),
+ SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1,
+ RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
+ adc_vol_tlv),
+};
+
+/* ADC Mixer*/
+static const struct snd_kcontrol_new rt5514_sto1_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER0_CTRL1,
+ RT5514_AD_DMIC_MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER0_CTRL1,
+ RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5514_sto1_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER0_CTRL2,
+ RT5514_AD_DMIC_MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER0_CTRL2,
+ RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5514_sto2_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER1_CTRL1,
+ RT5514_AD_DMIC_MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER1_CTRL1,
+ RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5514_sto2_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER1_CTRL2,
+ RT5514_AD_DMIC_MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER1_CTRL2,
+ RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+/* DMIC Source */
+static const char * const rt5514_dmic_src[] = {
+ "DMIC1", "DMIC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5514_stereo1_dmic_enum, RT5514_DIG_SOURCE_CTRL,
+ RT5514_AD0_DMIC_INPUT_SEL_SFT, rt5514_dmic_src);
+
+static const struct snd_kcontrol_new rt5514_sto1_dmic_mux =
+ SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5514_stereo1_dmic_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5514_stereo2_dmic_enum, RT5514_DIG_SOURCE_CTRL,
+ RT5514_AD1_DMIC_INPUT_SEL_SFT, rt5514_dmic_src);
+
+static const struct snd_kcontrol_new rt5514_sto2_dmic_mux =
+ SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5514_stereo2_dmic_enum);
+
+/**
+ * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic.
+ *
+ * @rate: base clock rate.
+ *
+ * Choose divider parameter that gives the highest possible DMIC frequency in
+ * 1MHz - 3MHz range.
+ */
+static int rt5514_calc_dmic_clk(struct snd_soc_codec *codec, int rate)
+{
+ int div[] = {2, 3, 4, 8, 12, 16, 24, 32};
+ int i;
+
+ if (rate < 1000000 * div[0]) {
+ pr_warn("Base clock rate %d is too low\n", rate);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(div); i++) {
+ /* find divider that gives DMIC frequency below 3.072MHz */
+ if (3072000 * div[i] >= rate)
+ return i;
+ }
+
+ dev_warn(codec->dev, "Base clock rate %d is too high\n", rate);
+ return -EINVAL;
+}
+
+static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ int idx;
+
+ idx = rt5514_calc_dmic_clk(codec, rt5514->sysclk);
+ if (idx < 0)
+ dev_err(codec->dev, "Failed to set DMIC clock\n");
+ else
+ regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1,
+ RT5514_CLK_DMIC_OUT_SEL_MASK,
+ idx << RT5514_CLK_DMIC_OUT_SEL_SFT);
+
+ return idx;
+}
+
+static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+
+ if (rt5514->sysclk_src == RT5514_SCLK_S_PLL1)
+ return 1;
+ else
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("DMIC1L"),
+ SND_SOC_DAPM_INPUT("DMIC1R"),
+ SND_SOC_DAPM_INPUT("DMIC2L"),
+ SND_SOC_DAPM_INPUT("DMIC2R"),
+
+ SND_SOC_DAPM_INPUT("AMICL"),
+ SND_SOC_DAPM_INPUT("AMICR"),
+
+ SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+ rt5514_set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_SUPPLY("ADC CLK", RT5514_CLK_CTRL1,
+ RT5514_CLK_AD_ANA1_EN_BIT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("LDO18 IN", RT5514_PWR_ANA1,
+ RT5514_POW_LDO18_IN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("LDO18 ADC", RT5514_PWR_ANA1,
+ RT5514_POW_LDO18_ADC_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("LDO21", RT5514_PWR_ANA1, RT5514_POW_LDO21_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BG LDO18 IN", RT5514_PWR_ANA1,
+ RT5514_POW_BG_LDO18_IN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BG LDO21", RT5514_PWR_ANA1,
+ RT5514_POW_BG_LDO21_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BG MBIAS", RT5514_PWR_ANA2,
+ RT5514_POW_BG_MBIAS_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MBIAS", RT5514_PWR_ANA2, RT5514_POW_MBIAS_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VREF2", RT5514_PWR_ANA2, RT5514_POW_VREF2_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VREF1", RT5514_PWR_ANA2, RT5514_POW_VREF1_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Power", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+
+ SND_SOC_DAPM_SUPPLY("LDO16L", RT5514_PWR_ANA2, RT5514_POWL_LDO16_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC1L", RT5514_PWR_ANA2, RT5514_POW_ADC1_L_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BSTL2", RT5514_PWR_ANA2, RT5514_POW2_BSTL_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BSTL", RT5514_PWR_ANA2, RT5514_POW_BSTL_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADCFEDL", RT5514_PWR_ANA2, RT5514_POW_ADCFEDL_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADCL Power", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("LDO16R", RT5514_PWR_ANA2, RT5514_POWR_LDO16_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC1R", RT5514_PWR_ANA2, RT5514_POW_ADC1_R_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BSTR2", RT5514_PWR_ANA2, RT5514_POW2_BSTR_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BSTR", RT5514_PWR_ANA2, RT5514_POW_BSTR_BIT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADCFEDR", RT5514_PWR_ANA2, RT5514_POW_ADCFEDR_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADCR Power", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PLL1 LDO ENABLE", RT5514_ANA_CTRL_PLL1_2,
+ RT5514_EN_LDO_PLL1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL1 LDO", RT5514_PWR_ANA2,
+ RT5514_POW_PLL1_LDO_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL1", RT5514_PWR_ANA2, RT5514_POW_PLL1_BIT, 0,
+ NULL, 0),
+
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
+ &rt5514_sto1_dmic_mux),
+ SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0,
+ &rt5514_sto2_dmic_mux),
+
+ /* ADC Mixer */
+ SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5514_CLK_CTRL1,
+ RT5514_CLK_AD0_EN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("adc stereo2 filter", RT5514_CLK_CTRL1,
+ RT5514_CLK_AD1_EN_BIT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5514_sto1_adc_l_mix, ARRAY_SIZE(rt5514_sto1_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5514_sto1_adc_r_mix, ARRAY_SIZE(rt5514_sto1_adc_r_mix)),
+ SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5514_sto2_adc_l_mix, ARRAY_SIZE(rt5514_sto2_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5514_sto2_adc_r_mix, ARRAY_SIZE(rt5514_sto2_adc_r_mix)),
+
+ SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5514_DOWNFILTER0_CTRL1,
+ RT5514_AD_AD_MUTE_BIT, 1),
+ SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5514_DOWNFILTER0_CTRL2,
+ RT5514_AD_AD_MUTE_BIT, 1),
+ SND_SOC_DAPM_ADC("Stereo2 ADC MIXL", NULL, RT5514_DOWNFILTER1_CTRL1,
+ RT5514_AD_AD_MUTE_BIT, 1),
+ SND_SOC_DAPM_ADC("Stereo2 ADC MIXR", NULL, RT5514_DOWNFILTER1_CTRL2,
+ RT5514_AD_AD_MUTE_BIT, 1),
+
+ /* ADC PGA */
+ SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
+ { "DMIC1", NULL, "DMIC1L" },
+ { "DMIC1", NULL, "DMIC1R" },
+ { "DMIC2", NULL, "DMIC2L" },
+ { "DMIC2", NULL, "DMIC2R" },
+
+ { "DMIC1L", NULL, "DMIC CLK" },
+ { "DMIC1R", NULL, "DMIC CLK" },
+ { "DMIC2L", NULL, "DMIC CLK" },
+ { "DMIC2R", NULL, "DMIC CLK" },
+
+ { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
+ { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+
+ { "Sto1 ADC MIXL", "DMIC Switch", "Stereo1 DMIC Mux" },
+ { "Sto1 ADC MIXL", "ADC Switch", "AMICL" },
+ { "Sto1 ADC MIXR", "DMIC Switch", "Stereo1 DMIC Mux" },
+ { "Sto1 ADC MIXR", "ADC Switch", "AMICR" },
+
+ { "ADC Power", NULL, "LDO18 IN" },
+ { "ADC Power", NULL, "LDO18 ADC" },
+ { "ADC Power", NULL, "LDO21" },
+ { "ADC Power", NULL, "BG LDO18 IN" },
+ { "ADC Power", NULL, "BG LDO21" },
+ { "ADC Power", NULL, "BG MBIAS" },
+ { "ADC Power", NULL, "MBIAS" },
+ { "ADC Power", NULL, "VREF2" },
+ { "ADC Power", NULL, "VREF1" },
+
+ { "ADCL Power", NULL, "LDO16L" },
+ { "ADCL Power", NULL, "ADC1L" },
+ { "ADCL Power", NULL, "BSTL2" },
+ { "ADCL Power", NULL, "BSTL" },
+ { "ADCL Power", NULL, "ADCFEDL" },
+
+ { "ADCR Power", NULL, "LDO16R" },
+ { "ADCR Power", NULL, "ADC1R" },
+ { "ADCR Power", NULL, "BSTR2" },
+ { "ADCR Power", NULL, "BSTR" },
+ { "ADCR Power", NULL, "ADCFEDR" },
+
+ { "AMICL", NULL, "ADC CLK" },
+ { "AMICL", NULL, "ADC Power" },
+ { "AMICL", NULL, "ADCL Power" },
+ { "AMICR", NULL, "ADC CLK" },
+ { "AMICR", NULL, "ADC Power" },
+ { "AMICR", NULL, "ADCR Power" },
+
+ { "PLL1 LDO", NULL, "PLL1 LDO ENABLE" },
+ { "PLL1", NULL, "PLL1 LDO" },
+
+ { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+ { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+
+ { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" },
+ { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" },
+ { "Stereo1 ADC MIX", NULL, "adc stereo1 filter" },
+ { "adc stereo1 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+
+ { "Stereo2 DMIC Mux", "DMIC1", "DMIC1" },
+ { "Stereo2 DMIC Mux", "DMIC2", "DMIC2" },
+
+ { "Sto2 ADC MIXL", "DMIC Switch", "Stereo2 DMIC Mux" },
+ { "Sto2 ADC MIXL", "ADC Switch", "AMICL" },
+ { "Sto2 ADC MIXR", "DMIC Switch", "Stereo2 DMIC Mux" },
+ { "Sto2 ADC MIXR", "ADC Switch", "AMICR" },
+
+ { "Stereo2 ADC MIXL", NULL, "Sto2 ADC MIXL" },
+ { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
+
+ { "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL" },
+ { "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" },
+ { "Stereo2 ADC MIX", NULL, "adc stereo2 filter" },
+ { "adc stereo2 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+
+ { "AIF1TX", NULL, "Stereo1 ADC MIX"},
+ { "AIF1TX", NULL, "Stereo2 ADC MIX"},
+};
+
+static int rt5514_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ int pre_div, bclk_ms, frame_size;
+ unsigned int val_len = 0;
+
+ rt5514->lrck = params_rate(params);
+ pre_div = rl6231_get_clk_info(rt5514->sysclk, rt5514->lrck);
+ if (pre_div < 0) {
+ dev_err(codec->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+ return -EINVAL;
+ }
+
+ bclk_ms = frame_size > 32;
+ rt5514->bclk = rt5514->lrck * (32 << bclk_ms);
+
+ dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+ rt5514->bclk, rt5514->lrck);
+ dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+ bclk_ms, pre_div, dai->id);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ val_len = RT5514_I2S_DL_20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val_len = RT5514_I2S_DL_24;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ val_len = RT5514_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_I2S_DL_MASK,
+ val_len);
+ regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
+ RT5514_CLK_SYS_DIV_OUT_MASK | RT5514_SEL_ADC_OSR_MASK,
+ pre_div << RT5514_CLK_SYS_DIV_OUT_SFT |
+ pre_div << RT5514_SEL_ADC_OSR_SFT);
+
+ return 0;
+}
+
+static int rt5514_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+
+ case SND_SOC_DAIFMT_NB_IF:
+ reg_val |= RT5514_I2S_LR_INV;
+ break;
+
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT5514_I2S_BP_INV;
+ break;
+
+ case SND_SOC_DAIFMT_IB_IF:
+ reg_val |= RT5514_I2S_BP_INV | RT5514_I2S_LR_INV;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT5514_I2S_DF_LEFT;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT5514_I2S_DF_PCM_A;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT5514_I2S_DF_PCM_B;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1,
+ RT5514_I2S_DF_MASK | RT5514_I2S_BP_MASK | RT5514_I2S_LR_MASK,
+ reg_val);
+
+ return 0;
+}
+
+static int rt5514_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ if (freq == rt5514->sysclk && clk_id == rt5514->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT5514_SCLK_S_MCLK:
+ reg_val |= RT5514_CLK_SYS_PRE_SEL_MCLK;
+ break;
+
+ case RT5514_SCLK_S_PLL1:
+ reg_val |= RT5514_CLK_SYS_PRE_SEL_PLL;
+ break;
+
+ default:
+ dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
+ RT5514_CLK_SYS_PRE_SEL_MASK, reg_val);
+
+ rt5514->sysclk = freq;
+ rt5514->sysclk_src = clk_id;
+
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+ return 0;
+}
+
+static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(codec->dev, "PLL disabled\n");
+
+ rt5514->pll_in = 0;
+ rt5514->pll_out = 0;
+ regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
+ RT5514_CLK_SYS_PRE_SEL_MASK,
+ RT5514_CLK_SYS_PRE_SEL_MCLK);
+
+ return 0;
+ }
+
+ if (source == rt5514->pll_src && freq_in == rt5514->pll_in &&
+ freq_out == rt5514->pll_out)
+ return 0;
+
+ switch (source) {
+ case RT5514_PLL1_S_MCLK:
+ regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL,
+ RT5514_PLL_1_SEL_MASK, RT5514_PLL_1_SEL_MCLK);
+ break;
+
+ case RT5514_PLL1_S_BCLK:
+ regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL,
+ RT5514_PLL_1_SEL_MASK, RT5514_PLL_1_SEL_SCLK);
+ break;
+
+ default:
+ dev_err(codec->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ regmap_write(rt5514->regmap, RT5514_ANA_CTRL_PLL1_1,
+ pll_code.k_code << RT5514_PLL_K_SFT |
+ pll_code.n_code << RT5514_PLL_N_SFT |
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT5514_PLL_M_SFT);
+ regmap_update_bits(rt5514->regmap, RT5514_ANA_CTRL_PLL1_2,
+ RT5514_PLL_M_BP, pll_code.m_bp << RT5514_PLL_M_BP_SFT);
+
+ rt5514->pll_in = freq_in;
+ rt5514->pll_out = freq_out;
+ rt5514->pll_src = source;
+
+ return 0;
+}
+
+static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = 0;
+
+ if (rx_mask || tx_mask)
+ val |= RT5514_TDM_MODE;
+
+ if (slots == 4)
+ val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH;
+
+
+ switch (slot_width) {
+ case 20:
+ val |= RT5514_CH_LEN_RX_20 | RT5514_CH_LEN_TX_20;
+ break;
+
+ case 24:
+ val |= RT5514_CH_LEN_RX_24 | RT5514_CH_LEN_TX_24;
+ break;
+
+ case 32:
+ val |= RT5514_CH_LEN_RX_32 | RT5514_CH_LEN_TX_32;
+ break;
+
+ case 16:
+ default:
+ break;
+ }
+
+ regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_TDM_MODE |
+ RT5514_TDMSLOT_SEL_RX_MASK | RT5514_TDMSLOT_SEL_TX_MASK |
+ RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK, val);
+
+ return 0;
+}
+
+static int rt5514_probe(struct snd_soc_codec *codec)
+{
+ struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+
+ rt5514->codec = codec;
+
+ return 0;
+}
+
+static int rt5514_i2c_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct i2c_client *client = context;
+ struct rt5514_priv *rt5514 = i2c_get_clientdata(client);
+
+ regmap_read(rt5514->i2c_regmap, reg | RT5514_DSP_MAPPING, val);
+
+ return 0;
+}
+
+static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i2c_client *client = context;
+ struct rt5514_priv *rt5514 = i2c_get_clientdata(client);
+
+ regmap_write(rt5514->i2c_regmap, reg | RT5514_DSP_MAPPING, val);
+
+ return 0;
+}
+
+#define RT5514_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+struct snd_soc_dai_ops rt5514_aif_dai_ops = {
+ .hw_params = rt5514_hw_params,
+ .set_fmt = rt5514_set_dai_fmt,
+ .set_sysclk = rt5514_set_dai_sysclk,
+ .set_pll = rt5514_set_dai_pll,
+ .set_tdm_slot = rt5514_set_tdm_slot,
+};
+
+struct snd_soc_dai_driver rt5514_dai[] = {
+ {
+ .name = "rt5514-aif1",
+ .id = 0,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT5514_STEREO_RATES,
+ .formats = RT5514_FORMATS,
+ },
+ .ops = &rt5514_aif_dai_ops,
+ }
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
+ .probe = rt5514_probe,
+ .idle_bias_off = true,
+ .controls = rt5514_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5514_snd_controls),
+ .dapm_widgets = rt5514_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5514_dapm_widgets),
+ .dapm_routes = rt5514_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes),
+};
+
+static const struct regmap_config rt5514_i2c_regmap = {
+ .name = "i2c",
+ .reg_bits = 32,
+ .val_bits = 32,
+
+ .max_register = RT5514_DSP_MAPPING | RT5514_VENDOR_ID2,
+ .readable_reg = rt5514_i2c_readable_register,
+
+ .cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_config rt5514_regmap = {
+ .reg_bits = 16,
+ .val_bits = 32,
+
+ .max_register = RT5514_VENDOR_ID2,
+ .volatile_reg = rt5514_volatile_register,
+ .readable_reg = rt5514_readable_register,
+ .reg_read = rt5514_i2c_read,
+ .reg_write = rt5514_i2c_write,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5514_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5514_reg),
+ .use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5514_i2c_id[] = {
+ { "rt5514", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5514_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5514_of_match[] = {
+ { .compatible = "realtek,rt5514", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt5514_of_match);
+#endif
+
+static int rt5514_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5514_priv *rt5514;
+ int ret;
+ unsigned int val;
+
+ rt5514 = devm_kzalloc(&i2c->dev, sizeof(struct rt5514_priv),
+ GFP_KERNEL);
+ if (rt5514 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5514);
+
+ rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap);
+ if (IS_ERR(rt5514->i2c_regmap)) {
+ ret = PTR_ERR(rt5514->i2c_regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ rt5514->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5514_regmap);
+ if (IS_ERR(rt5514->regmap)) {
+ ret = PTR_ERR(rt5514->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+ if (val != RT5514_DEVICE_ID) {
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt5514\n", val);
+ return -ENODEV;
+ }
+
+ ret = regmap_register_patch(rt5514->i2c_regmap, rt5514_i2c_patch,
+ ARRAY_SIZE(rt5514_i2c_patch));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n",
+ ret);
+
+ ret = regmap_register_patch(rt5514->regmap, rt5514_patch,
+ ARRAY_SIZE(rt5514_patch));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5514,
+ rt5514_dai, ARRAY_SIZE(rt5514_dai));
+}
+
+static int rt5514_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+struct i2c_driver rt5514_i2c_driver = {
+ .driver = {
+ .name = "rt5514",
+ .of_match_table = of_match_ptr(rt5514_of_match),
+ },
+ .probe = rt5514_i2c_probe,
+ .remove = rt5514_i2c_remove,
+ .id_table = rt5514_i2c_id,
+};
+module_i2c_driver(rt5514_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5514 driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou(a)realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
new file mode 100644
index 0000000..6ad8a61
--- /dev/null
+++ b/sound/soc/codecs/rt5514.h
@@ -0,0 +1,252 @@
+/*
+ * rt5514.h -- RT5514 ALSA SoC audio driver
+ *
+ * Copyright 2015 Realtek Microelectronics
+ * Author: Oder Chiou <oder_chiou(a)realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5514_H__
+#define __RT5514_H__
+
+#define RT5514_DEVICE_ID 0x10ec5514
+
+#define RT5514_RESET 0x2000
+#define RT5514_PWR_ANA1 0x2004
+#define RT5514_PWR_ANA2 0x2008
+#define RT5514_I2S_CTRL1 0x2010
+#define RT5514_I2S_CTRL2 0x2014
+#define RT5514_VAD_CTRL6 0x2030
+#define RT5514_EXT_VAD_CTRL 0x206c
+#define RT5514_DIG_IO_CTRL 0x2070
+#define RT5514_PAD_CTRL1 0x2080
+#define RT5514_DMIC_DATA_CTRL 0x20a0
+#define RT5514_DIG_SOURCE_CTRL 0x20a4
+#define RT5514_SRC_CTRL 0x20ac
+#define RT5514_DOWNFILTER2_CTRL1 0x20d0
+#define RT5514_PLL_SOURCE_CTRL 0x2100
+#define RT5514_CLK_CTRL1 0x2104
+#define RT5514_CLK_CTRL2 0x2108
+#define RT5514_PLL3_CALIB_CTRL1 0x2110
+#define RT5514_PLL3_CALIB_CTRL5 0x2124
+#define RT5514_DELAY_BUF_CTRL1 0x2140
+#define RT5514_DELAY_BUF_CTRL3 0x2148
+#define RT5514_DOWNFILTER0_CTRL1 0x2190
+#define RT5514_DOWNFILTER0_CTRL2 0x2194
+#define RT5514_DOWNFILTER0_CTRL3 0x2198
+#define RT5514_DOWNFILTER1_CTRL1 0x21a0
+#define RT5514_DOWNFILTER1_CTRL2 0x21a4
+#define RT5514_DOWNFILTER1_CTRL3 0x21a8
+#define RT5514_ANA_CTRL_LDO10 0x2200
+#define RT5514_ANA_CTRL_LDO18_16 0x2204
+#define RT5514_ANA_CTRL_ADC12 0x2210
+#define RT5514_ANA_CTRL_ADC21 0x2214
+#define RT5514_ANA_CTRL_ADC22 0x2218
+#define RT5514_ANA_CTRL_ADC23 0x221c
+#define RT5514_ANA_CTRL_MICBST 0x2220
+#define RT5514_ANA_CTRL_ADCFED 0x2224
+#define RT5514_ANA_CTRL_INBUF 0x2228
+#define RT5514_ANA_CTRL_VREF 0x222c
+#define RT5514_ANA_CTRL_PLL3 0x2240
+#define RT5514_ANA_CTRL_PLL1_1 0x2260
+#define RT5514_ANA_CTRL_PLL1_2 0x2264
+#define RT5514_DMIC_LP_CTRL 0x2e00
+#define RT5514_MISC_CTRL_DSP 0x2e04
+#define RT5514_DSP_CTRL1 0x2f00
+#define RT5514_DSP_CTRL3 0x2f08
+#define RT5514_DSP_CTRL4 0x2f10
+#define RT5514_VENDOR_ID1 0x2ff0
+#define RT5514_VENDOR_ID2 0x2ff4
+
+#define RT5514_DSP_MAPPING 0x18000000
+
+/* RT5514_PWR_ANA1 (0x2004) */
+#define RT5514_POW_LDO18_IN (0x1 << 5)
+#define RT5514_POW_LDO18_IN_BIT 5
+#define RT5514_POW_LDO18_ADC (0x1 << 4)
+#define RT5514_POW_LDO18_ADC_BIT 4
+#define RT5514_POW_LDO21 (0x1 << 3)
+#define RT5514_POW_LDO21_BIT 3
+#define RT5514_POW_BG_LDO18_IN (0x1 << 2)
+#define RT5514_POW_BG_LDO18_IN_BIT 2
+#define RT5514_POW_BG_LDO21 (0x1 << 1)
+#define RT5514_POW_BG_LDO21_BIT 1
+
+/* RT5514_PWR_ANA2 (0x2008) */
+#define RT5514_POW_PLL1 (0x1 << 18)
+#define RT5514_POW_PLL1_BIT 18
+#define RT5514_POW_PLL1_LDO (0x1 << 16)
+#define RT5514_POW_PLL1_LDO_BIT 16
+#define RT5514_POW_BG_MBIAS (0x1 << 15)
+#define RT5514_POW_BG_MBIAS_BIT 15
+#define RT5514_POW_MBIAS (0x1 << 14)
+#define RT5514_POW_MBIAS_BIT 14
+#define RT5514_POW_VREF2 (0x1 << 13)
+#define RT5514_POW_VREF2_BIT 13
+#define RT5514_POW_VREF1 (0x1 << 12)
+#define RT5514_POW_VREF1_BIT 12
+#define RT5514_POWR_LDO16 (0x1 << 11)
+#define RT5514_POWR_LDO16_BIT 11
+#define RT5514_POWL_LDO16 (0x1 << 10)
+#define RT5514_POWL_LDO16_BIT 10
+#define RT5514_POW_ADC2 (0x1 << 9)
+#define RT5514_POW_ADC2_BIT 9
+#define RT5514_POW_INPUT_BUF (0x1 << 8)
+#define RT5514_POW_INPUT_BUF_BIT 8
+#define RT5514_POW_ADC1_R (0x1 << 7)
+#define RT5514_POW_ADC1_R_BIT 7
+#define RT5514_POW_ADC1_L (0x1 << 6)
+#define RT5514_POW_ADC1_L_BIT 6
+#define RT5514_POW2_BSTR (0x1 << 5)
+#define RT5514_POW2_BSTR_BIT 5
+#define RT5514_POW2_BSTL (0x1 << 4)
+#define RT5514_POW2_BSTL_BIT 4
+#define RT5514_POW_BSTR (0x1 << 3)
+#define RT5514_POW_BSTR_BIT 3
+#define RT5514_POW_BSTL (0x1 << 2)
+#define RT5514_POW_BSTL_BIT 2
+#define RT5514_POW_ADCFEDR (0x1 << 1)
+#define RT5514_POW_ADCFEDR_BIT 1
+#define RT5514_POW_ADCFEDL (0x1 << 0)
+#define RT5514_POW_ADCFEDL_BIT 0
+
+/* RT5514_I2S_CTRL1 (0x2010) */
+#define RT5514_TDM_MODE (0x1 << 28)
+#define RT5514_TDM_MODE_SFT 28
+#define RT5514_I2S_LR_MASK (0x1 << 26)
+#define RT5514_I2S_LR_SFT 26
+#define RT5514_I2S_LR_NOR (0x0 << 26)
+#define RT5514_I2S_LR_INV (0x1 << 26)
+#define RT5514_I2S_BP_MASK (0x1 << 25)
+#define RT5514_I2S_BP_SFT 25
+#define RT5514_I2S_BP_NOR (0x0 << 25)
+#define RT5514_I2S_BP_INV (0x1 << 25)
+#define RT5514_I2S_DF_MASK (0x7 << 16)
+#define RT5514_I2S_DF_SFT 16
+#define RT5514_I2S_DF_I2S (0x0 << 16)
+#define RT5514_I2S_DF_LEFT (0x1 << 16)
+#define RT5514_I2S_DF_PCM_A (0x2 << 16)
+#define RT5514_I2S_DF_PCM_B (0x3 << 16)
+#define RT5514_TDMSLOT_SEL_RX_MASK (0x3 << 10)
+#define RT5514_TDMSLOT_SEL_RX_SFT 10
+#define RT5514_TDMSLOT_SEL_RX_4CH (0x1 << 10)
+#define RT5514_CH_LEN_RX_MASK (0x3 << 8)
+#define RT5514_CH_LEN_RX_SFT 8
+#define RT5514_CH_LEN_RX_16 (0x0 << 8)
+#define RT5514_CH_LEN_RX_20 (0x1 << 8)
+#define RT5514_CH_LEN_RX_24 (0x2 << 8)
+#define RT5514_CH_LEN_RX_32 (0x3 << 8)
+#define RT5514_TDMSLOT_SEL_TX_MASK (0x3 << 6)
+#define RT5514_TDMSLOT_SEL_TX_SFT 6
+#define RT5514_TDMSLOT_SEL_TX_4CH (0x1 << 6)
+#define RT5514_CH_LEN_TX_MASK (0x3 << 4)
+#define RT5514_CH_LEN_TX_SFT 4
+#define RT5514_CH_LEN_TX_16 (0x0 << 4)
+#define RT5514_CH_LEN_TX_20 (0x1 << 4)
+#define RT5514_CH_LEN_TX_24 (0x2 << 4)
+#define RT5514_CH_LEN_TX_32 (0x3 << 4)
+#define RT5514_I2S_DL_MASK (0x3 << 0)
+#define RT5514_I2S_DL_SFT 0
+#define RT5514_I2S_DL_16 (0x0 << 0)
+#define RT5514_I2S_DL_20 (0x1 << 0)
+#define RT5514_I2S_DL_24 (0x2 << 0)
+#define RT5514_I2S_DL_8 (0x3 << 0)
+
+/* RT5514_DIG_SOURCE_CTRL (0x20a4) */
+#define RT5514_AD1_DMIC_INPUT_SEL (0x1 << 1)
+#define RT5514_AD1_DMIC_INPUT_SEL_SFT 1
+#define RT5514_AD0_DMIC_INPUT_SEL (0x1 << 0)
+#define RT5514_AD0_DMIC_INPUT_SEL_SFT 0
+
+/* RT5514_PLL_SOURCE_CTRL (0x2100) */
+#define RT5514_PLL_1_SEL_MASK (0x7 << 12)
+#define RT5514_PLL_1_SEL_SFT 12
+#define RT5514_PLL_1_SEL_SCLK (0x3 << 12)
+#define RT5514_PLL_1_SEL_MCLK (0x4 << 12)
+
+/* RT5514_CLK_CTRL1 (0x2104) */
+#define RT5514_CLK_AD_ANA1_EN (0x1 << 31)
+#define RT5514_CLK_AD_ANA1_EN_BIT 31
+#define RT5514_CLK_AD1_EN (0x1 << 24)
+#define RT5514_CLK_AD1_EN_BIT 24
+#define RT5514_CLK_AD0_EN (0x1 << 23)
+#define RT5514_CLK_AD0_EN_BIT 23
+#define RT5514_CLK_DMIC_OUT_SEL_MASK (0x7 << 8)
+#define RT5514_CLK_DMIC_OUT_SEL_SFT 8
+
+/* RT5514_CLK_CTRL2 (0x2108) */
+#define RT5514_CLK_SYS_DIV_OUT_MASK (0x7 << 8)
+#define RT5514_CLK_SYS_DIV_OUT_SFT 8
+#define RT5514_SEL_ADC_OSR_MASK (0x7 << 4)
+#define RT5514_SEL_ADC_OSR_SFT 4
+#define RT5514_CLK_SYS_PRE_SEL_MASK (0x3 << 0)
+#define RT5514_CLK_SYS_PRE_SEL_SFT 0
+#define RT5514_CLK_SYS_PRE_SEL_MCLK (0x2 << 0)
+#define RT5514_CLK_SYS_PRE_SEL_PLL (0x3 << 0)
+
+/* RT5514_DOWNFILTER_CTRL (0x2190 0x2194 0x21a0 0x21a4) */
+#define RT5514_AD_DMIC_MIX (0x1 << 11)
+#define RT5514_AD_DMIC_MIX_BIT 11
+#define RT5514_AD_AD_MIX (0x1 << 10)
+#define RT5514_AD_AD_MIX_BIT 10
+#define RT5514_AD_AD_MUTE (0x1 << 7)
+#define RT5514_AD_AD_MUTE_BIT 7
+#define RT5514_AD_GAIN_MASK (0x7f << 0)
+#define RT5514_AD_GAIN_SFT 0
+
+/* RT5514_ANA_CTRL_MICBST (0x2220) */
+#define RT5514_SEL_BSTL_MASK (0xf << 4)
+#define RT5514_SEL_BSTL_SFT 4
+#define RT5514_SEL_BSTR_MASK (0xf << 0)
+#define RT5514_SEL_BSTR_SFT 0
+
+/* RT5514_ANA_CTRL_PLL1_1 (0x2260) */
+#define RT5514_PLL_K_MAX 0x1f
+#define RT5514_PLL_K_MASK (RT5514_PLL_K_MAX << 16)
+#define RT5514_PLL_K_SFT 16
+#define RT5514_PLL_N_MAX 0x1ff
+#define RT5514_PLL_N_MASK (RT5514_PLL_N_MAX << 7)
+#define RT5514_PLL_N_SFT 4
+#define RT5514_PLL_M_MAX 0xf
+#define RT5514_PLL_M_MASK (RT5514_PLL_M_MAX << 0)
+#define RT5514_PLL_M_SFT 0
+
+/* RT5514_ANA_CTRL_PLL1_2 (0x2264) */
+#define RT5514_PLL_M_BP (0x1 << 2)
+#define RT5514_PLL_M_BP_SFT 2
+#define RT5514_PLL_K_BP (0x1 << 1)
+#define RT5514_PLL_K_BP_SFT 1
+#define RT5514_EN_LDO_PLL1 (0x1 << 0)
+#define RT5514_EN_LDO_PLL1_BIT 0
+
+#define RT5514_PLL_INP_MAX 40000000
+#define RT5514_PLL_INP_MIN 256000
+
+/* System Clock Source */
+enum {
+ RT5514_SCLK_S_MCLK,
+ RT5514_SCLK_S_PLL1,
+};
+
+/* PLL1 Source */
+enum {
+ RT5514_PLL1_S_MCLK,
+ RT5514_PLL1_S_BCLK,
+};
+
+struct rt5514_priv {
+ struct snd_soc_codec *codec;
+ struct regmap *i2c_regmap, *regmap;
+ int sysclk;
+ int sysclk_src;
+ int lrck;
+ int bclk;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+};
+
+#endif /* __RT5514_H__ */
--
1.8.1.1.439.g50a6b54
2
1
[alsa-devel] Can't use adau1361 as i2s master due to bad write ordering
by Andreas Irestål 03 Feb '16
by Andreas Irestål 03 Feb '16
03 Feb '16
I've run into problems using the adau1361 codec (adau1761) as i2s master.
I'm using i2c to set up the codec, and according to the datasheet there
is an enable bit, which must be set in order to be able to access any
other register than the first two registers.
This enable bit is set when the codec enters bias level standby,
however, before entering this bias level, some other registers are
written which will have no effect due to the inner workings of this
codec. Oddly enough, it does ack all writes when measuring the i2c bus.
One of these registers is the serial port 0 register, which
configures the i2s bus. This results in the situation that the CODEC dai
thinks it is running as i2s slave and the CPU dai thinks too as well,
and the bus is dead. Since the other register fields does not change
with our dai configuration, the register never gets physically updated
by an i2c write.
If I reset/reboot the system, which in our case does not power cycle the
codec, the i2s bus is correctly set up and everything works as one would
expect.
So, either the driver behaves incorrectly relying on bias level being
set before any other registers are written, or the underlying subsystem
are behaving incorrectly. We're using the simple-card board driver as it
is sufficient for our needs.
/Andreas
2
1
Hello,
The following program triggers a splash of WARNINGs in rawmidi_transmit_ack.
Takashi, I am on commit 36f90b0a2ddd60823fe193a85e60ff1906c2a9b3 + a
bunch of your recent fixes:
https://gist.githubusercontent.com/dvyukov/40640128a433ad16a56a/raw/ab3a086…
------------[ cut here ]------------
WARNING: CPU: 2 PID: 6954 at sound/core/rawmidi.c:1133
rawmidi_transmit_ack+0x24a/0x3b0()
Modules linked in:
CPU: 2 PID: 6954 Comm: syz-executor Not tainted 4.5.0-rc2+ #306
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
00000000ffffffff ffff8800309d78b8 ffffffff82be2c0d 0000000000000000
ffff880031238000 ffffffff8719a820 ffff8800309d78f8 ffffffff81355139
ffffffff8527e69a ffffffff8719a820 000000000000046d 0000000000000005
Call Trace:
[< inline >] __dump_stack lib/dump_stack.c:15
[<ffffffff82be2c0d>] dump_stack+0x6f/0xa2 lib/dump_stack.c:50
[<ffffffff81355139>] warn_slowpath_common+0xd9/0x140 kernel/panic.c:482
[<ffffffff81355369>] warn_slowpath_null+0x29/0x30 kernel/panic.c:515
[<ffffffff8527e69a>] rawmidi_transmit_ack+0x24a/0x3b0 sound/core/rawmidi.c:1133
[<ffffffff8527e851>] snd_rawmidi_transmit_ack+0x51/0x80
sound/core/rawmidi.c:1163
[<ffffffff852d9046>] snd_virmidi_output_trigger+0x2b6/0x570
sound/core/seq/seq_virmidi.c:185
[< inline >] snd_rawmidi_output_trigger sound/core/rawmidi.c:150
[<ffffffff85285a0b>] snd_rawmidi_kernel_write1+0x4bb/0x760
sound/core/rawmidi.c:1252
[<ffffffff85287b73>] snd_rawmidi_write+0x543/0xb30 sound/core/rawmidi.c:1302
[<ffffffff817ba5f3>] __vfs_write+0x113/0x480 fs/read_write.c:528
[<ffffffff817bc087>] vfs_write+0x167/0x4a0 fs/read_write.c:577
[< inline >] SYSC_write fs/read_write.c:624
[<ffffffff817bf371>] SyS_write+0x111/0x220 fs/read_write.c:616
[<ffffffff86660276>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
---[ end trace 6f686d9dad133d99 ]---
// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <pthread.h>
#include <stdint.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
long r[28];
void* thr(void* arg)
{
switch ((long)arg) {
case 0:
r[0] = syscall(SYS_mmap, 0x20000000ul, 0xd90000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 1:
memcpy(
(void*)0x20d8f000,
"\x2f\x64\x65\x76\x2f\x73\x65\x71\x75\x65\x6e\x63\x65\x72\x32",
15);
r[2] = syscall(SYS_open, "/dev/sequencer2", 0x181800ul, 0,
0, 0);
break;
case 2:
memcpy((void*)0x20d8df5b, "\x2f\x64\x65\x76\x2f\x73\x6e\x64\x2f\x6d"
"\x69\x64\x69\x43\x23\x44\x23",
17);
r[4] = syscall(SYS_open, "/dev/snd/midiC2D0", 0x802ul, 0, 0,
0);
break;
case 3:
r[5] = syscall(SYS_mmap, 0x20d90000ul, 0x1000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 4:
r[6] = syscall(SYS_mmap, 0x20d90000ul, 0x1000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 5:
r[7] = syscall(SYS_mmap, 0x20000000ul, 0x0ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 6:
r[8] = syscall(SYS_mmap, 0x20d91000ul, 0x1000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 7:
*(uint32_t*)0x20d91000 = (uint32_t)0xf834;
r[10] =
syscall(SYS_ioctl, r[2], 0x40045201ul, 0x20d91000ul, 0, 0, 0);
break;
case 8:
r[11] = syscall(SYS_mmap, 0x20d91000ul, 0x1000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 9:
r[12] =
syscall(SYS_ioctl, r[2], 0x80404509ul, 0x20d91000ul, 0, 0, 0);
break;
case 10:
r[13] = syscall(SYS_mmap, 0x20d90000ul, 0x1000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
break;
case 11:
*(uint64_t*)0x20d90ffd = (uint64_t)0x20a962b0;
*(uint64_t*)0x20d91005 = (uint64_t)0xd3;
*(uint64_t*)0x20d9100d = (uint64_t)0x20d902e4;
*(uint64_t*)0x20d91015 = (uint64_t)0xf6;
*(uint64_t*)0x20d9101d = (uint64_t)0x20d907cd;
*(uint64_t*)0x20d91025 = (uint64_t)0x67;
*(uint64_t*)0x20d9102d = (uint64_t)0x20000000;
*(uint64_t*)0x20d91035 = (uint64_t)0x0;
memcpy((void*)0x20a962b0,
"\xea\x7e\xf1\x21\xe0\xc7\xaa\xa3\x6d\x6c\xb3\x94\x27\x70"
"\xed\x74\xab\xee\x27\x7c\x1b\x9e\x66\x76\x79\xa6\x4f\x69"
"\xf6\x63\x0a\x5c\x31\xe3\xef\x43\x43\x93\x6a\x40\x53\x03"
"\x0d\x61\xd9\xb5\xac\xc0\xe9\x10\x1c\x5d\x50\x6e\x7f\xe1"
"\x0a\x65\x7e\x09\xa5\x57\x89\x33\x52\x49\x01\xaf\x5f\xdd"
"\x55\xb2\x59\xca\xf6\x0d\x39\x26\xa6\xad\x9f\x93\x7e\xda"
"\x06\x6f\xae\x4e\xce\x3d\xd9\xbd\x4f\x6a\xec\x7b\xb7\xc8"
"\xe0\xd8\x25\x85\xca\xda\x7f\x04\x7a\x0e\x23\x66\x63\xc0"
"\xfb\x9a\xe7\x87\xb2\x85\x83\x6e\x07\xd5\x8c\x8e\xb1\x8a"
"\x9a\x43\xb8\x5c\x2d\xe4\xe9\x9b\x8d\xfb\x23\x52\xfd\xf9"
"\x7e\xa4\xc1\x8b\x90\xf9\x14\x98\xba\x75\xa5\xf2\x88\xbf"
"\x8f\x28\x8f\xee\xf3\xc7\x20\xfc\xa3\x53\xd2\x1c\x1b\x02"
"\xc5\x2b\x1b\x9a\x17\xb6\xef\xd5\x6b\x46\x4c\x66\x75\x45"
"\xcc\xb4\x1d\x41\x13\xb1\x1f\xc7\x76\x7f\x28\x8b\x3d\x85"
"\x16\x38\x2f\x27\xdb\x17\x71\x05\xd6\x0e\x5e\x53\x3b\x19"
"\xbb",
211);
memcpy((void*)0x20d902e4,
"\xe8\x61\x5b\xd6\x03\xc7\x69\x3a\xa4\x17\x85\xce\xf4\x49"
"\x07\x42\xee\x24\x4a\x9e\xe5\xff\x3e\xa1\xbc\x97\xc7\x66"
"\x01\x9f\x34\x57\x1b\xf6\x99\x2b\xd0\x45\xa0\xc9\x2b\x2d"
"\x45\x45\x7a\xb0\xf9\x9d\xc8\x3b\x53\x78\x3a\x93\x42\xcc"
"\x88\xa9\xf4\x79\xab\x1c\xfe\x48\x8d\x61\x6a\x84\x26\x2d"
"\x74\xb6\x2d\xa7\xbb\x8c\x33\x6e\xca\x38\x57\xf8\x39\x91"
"\xc7\x57\x6f\x28\xbc\x2e\x9e\xca\xc8\xcb\x08\x0c\x1e\xe6"
"\x49\x5d\x32\xe6\x33\xd0\x92\x20\xb5\x7f\x96\x2a\x47\x3f"
"\xa5\x9d\x9b\xeb\x67\xd9\x36\x48\xeb\x0d\x16\xd4\xc9\x48"
"\x7d\xa4\xfd\x42\xde\x2d\xf6\xae\x48\xe6\x50\x1c\x24\x86"
"\xe5\x0d\x23\x04\xa6\xcc\xfb\x98\xbe\x61\xb2\xed\x59\x28"
"\x82\xd1\x80\x06\xf1\x90\xae\xd4\x99\x28\x92\x92\x30\xdc"
"\x12\x29\x5e\x47\x69\x74\x7b\x1b\x82\x14\xce\xaa\x35\x06"
"\xa3\x24\x00\x34\xf8\xeb\x3f\x24\xf7\xdf\x30\x59\xb5\x54"
"\x1a\x60\xfa\x23\x1b\x67\xf8\x3c\x59\x56\x0b\xef\xaf\x09"
"\x7d\xaa\xe5\x4b\xce\x0b\x6a\x3b\xde\x94\xa1\x80\x37\xae"
"\x5c\x8c\xac\x0f\x1a\xfd\x36\x9a\xa8\x8a\xd2\x2d\xe5\xf1"
"\xb2\x8e\x29\x30\xe1\x39\x72\xef",
246);
memcpy((void*)0x20d907cd,
"\x3e\x14\x32\x60\x81\x87\xfb\x49\xb5\x66\xa3\x99\xe5\x9b"
"\xfd\xae\xec\xa8\x66\x6b\x6b\x52\xa4\x13\xbd\x8a\x2a\xe7"
"\x26\x6a\x48\x8d\x09\x1f\x6e\x60\x25\x75\xd0\x62\xfa\x32"
"\xc0\x40\x16\x21\xc0\x41\xa9\xd3\x30\x77\x64\x5d\xf4\x50"
"\xfd\x63\x06\xbf\xc2\xad\xfa\xf6\xa5\x2a\x51\x60\x5b\x47"
"\x60\x4d\xbe\x25\x16\x2e\xd7\xdc\x43\xe3\xc9\x57\x4a\x00"
"\x9f\x4f\x23\x40\xb0\x9b\xc7\x25\x5f\xef\xb1\x97\x9e\xb3"
"\x09\xc8\x99\x34\xf2",
103);
r[25] = syscall(SYS_writev, r[4], 0x20d90ffdul, 0x4ul, 0, 0, 0);
break;
case 12:
memcpy(
(void*)0x20d8a029,
"\x41\x30\x85\x16\x79\x50\x97\xdd\x70\xc7\x66\xcd\x0b\xa5\x9e"
"\x92\xe8\xba\x6c\x3f\x30\x00\x24\x10\x48\xa9\x47\xe4\x96\x91"
"\x7d\x4b\x68\x92\xe9\x81\x54\xd5\xe8\x72\xdf\x42\x12\xa3\xfd"
"\xe7\x30\xa0\xd7\x9f\xd0\x88\xeb\x6b\x42\x43\x78\x80\xfb\x51"
"\x39\xcd\xab\x77\x9a\xb4\x9a\x79\xa4\x0b\xa0\x3a\x9e\x09\x0d"
"\x1d\xda\x32\x68\x64\xf9\x03\x3f\xed\x07\xd2\xd3\xea\x82\xb8"
"\x8e\x47\xf9\x7a\x78\x73\x6f\x46\x9a\x6e\xb3\xa8\xb7\x9f\xac"
"\x1c\x47\x66\x0a\x67\x59\xb4\x6b\x52\xab\x3b\xe6\x6d\x74\xe2"
"\xf0\x84\xfe\x1b\x3a\xe8\x82\x2b\x2a\xad\x3e\x61\x69\xdb\xe0"
"\xff\x65\xa9\xab\xf9\xa1\x69\x30\xcd\xc2\xbb\x2e\xac\x11\xf6"
"\x3c\x31\x25\x2e\x77\x12\x86\xdf\x24\x37\xf8\xdc\x9a\xc3\x11"
"\xd4\x25\xce\x12\xbe\x2f\xb0\x4a\x50\x64\x8a\xf1\xb3\xf0\x75"
"\xae\x5a\x0b\x5d\xf3\x8d\xe8\x75\x07\xaa\x0a\x93\x6c\x85\x2c"
"\x48\x3e\xae\xbc\xe1\x49\xab\xa9\x7b\xe3\x57\x7e\xa8\x90\x1a"
"\x04\x5f\x10\x9a\x96\x5b\xf4\xd0\xa1\xec\xed\x0f\xd8\x0a\x40"
"\xd8\x75\x05\x0d\x14\xc6\x28\xbb\x7a\xc5\x42\x69\xb0\xea\x26"
"\x0d\x2f\xb6\xba\xcc\x23\x28\x28\x61\x6b\x55\xf8\x10\xb8\xb8"
"\x2d\xba\x9f\xfd\x2e\x1d\xa7\xf1\x3f\x8e\x54\x64\xf5\x6f\xfe"
"\x33\x93\x1d\xcb\x82\x60\x8f\x90\x85\xf7\x58\xc2\x3b\x9d\x9a"
"\x7f\xe0\x55\x2e\xa2\x1a\xd5\x39\xe6\xfd\xcf\x2c\x2c\x5b\x7e"
"\xfb\xfd\x81\x17\x92\x95\x97\x40\x74\x9d\xfb\x81\xc2\x02\x85"
"\x0c\x55\xed\xbf\x1f\xce\xad\x58\x88\xd2\x10\xf0\x4e\x18\x28"
"\x86\xe0\x1c\xa7\xce\x7c\xdb\xdd\x15\x3c\xd2\xd8\x1d\x9e\x43"
"\x18\x0e\x1d\xc2\xb8\x8e\xf0\x0f\xd6\x6b\x89\x40\x00\x28\x1d"
"\x5a\xa2\x5a\xeb\x2f\x60\x7b\x02\xc9\x86\x88\xfb\x94\x89\x81"
"\xec\x4c\x9f\xe8\xaf\xcb\x7b\x68\x21\xe1\xa3\x60\x32\x7d\x23"
"\xcf\x71\x20\x22\x1b\x8e\xec\x51\x17\x05\x70\x2c\x92\x70\x59"
"\x35\x6a\x25\x71\x39\x2c\x66\x42\x3f\x46\x78\x88\x7f\xdb\x71"
"\xb8\xd6\x7c\xce\x8b\x4a\xb1\x8d\xa2\xc5\xb9\xac\xe7\x89\x4b"
"\x7a\x6c\x91\x11\x6d\xe9\x2b\x27\x80\x49\x32\x66\x16\xed\xf1"
"\x74\x51\xcd\x44\x4a\x94\x5c\xfc\xe5\x11\x54\xf5\x61\xbe\xed"
"\xbc\x00\xbd\xde\x02\xd4\x40\xa5\x13\x4f\x48\x6e\x43\x1a\xc2"
"\x56\xe8\x95\x16\xcc\x5f\x4d\xf8\x80\x40\x2c\x59\x07\x32\x49"
"\x84\xff\x31\x53\xd9\x26\x08\xc1\x06\xf2\x69\x4b\x35\xa4\x41"
"\xe5\x00\xdd\x64\x23\x1a\xb7\x29\xde\xef\x90\x03\xe3\xe1\x7d"
"\x61\x74\xfd\xe5\xd1\xa6\xa8\x9b\xc5\x07\x90\xfb\x75\x5e\x64"
"\xa3\x22\xcc\xd2\xc9\x29\xdb\x71\x84\x5c\x67\x51\x75\xc6\xdc"
"\x22\x78\xb8\x6d\x2e\x8f\xf5\x51\x87\x53\xd5\xc5\x10\x53\xc3"
"\x0c\x96\xf0\x6c\xca\x61\x37\xfc\x63\xff\xe0\xd4\x77\x3d\xea"
"\x64\xe0\x43\xfb\xca\xf6\xd0\x2d\xd2\xc4\x67\x35\x58\x70\xa5"
"\x6f\x0c\x19\x93\x45\xdd\xf4\x0f\xad\x60\xf4\x8e\x8d\x6a\xb6"
"\x8d\x66\xaa\xe6\x19\xc3\x60\x4a\x77\xaa\x7b\x15\x9b\x89\x65"
"\x11\x70\xc6\xa1\x86\xf1\x7c\xac\xac\xe4\x94\xb3\x08\xdd\xd0"
"\x7c\xfb\x60\x2f\x5f\x42\xe6\x97\xfc\x1c\x40\xc1\xb1\x2c\x4b"
"\x9d\xc0\x66\x48\xf1\x1b\x74\x54\x5b\x97\xc8\xb1\xba\x0b\xa5"
"\x36\x7b\xf9\x70\x09\x2e\x7e\x57\x07\x98\xaa\xa4\x40\x7b\xc7"
"\x6c\xe3\x43\x8b\xc0\xff\x87\x1a\x91\xaa\x07\x1a\x39\x29\xf2"
"\x81\xf8\xfe\x22\x77\x31\xbe\x89\x30\x91\x31\xe8\xa2\xe6\xd1"
"\x68\x99\x2d\x5a\xbf\x42\x26\x3b\x19\x5a\x18\x20\xf9\xd6\x21"
"\x8b\x6c\x2b\x1d\x6a\x99\xbe\x02\x39\xe9\x50\x0c\xf1\xb2\x9f"
"\x10\xdd\x7d\x85\x95\xa7\x0d\x08\x90\x73\x26\xf8\x52\xb3\x39"
"\x2c\x6a\x42\x60\x99\xf5\x65\xae\x4b\xd6\xd3\xc5\x21\x19\x96"
"\x85\x08\xcb\xd6\xb3\xce\xda\xd1\x75\xc3\x86\xd2\x7c\x79\x78"
"\xea\x8b\x88\xf4\xe1\x82\x12\x1a\xe4\x57\x57\xa6\x51\x3c\xa4"
"\xf0\x42\xbb\x21\xca\x5d\xec\xcd\x89\xec\x0c\x1b\xb8\x5b\x21"
"\x17\xb3\xca\x32\x50\xc3\xad\x06\x05\xfa\x5e\x9c\x19\xfe\x81"
"\x8a\x18\x06\x76\x46\xda\x93\xd7\x90\xee\xb7\x30\x23\x09\xfd"
"\xd9\xa8\x40\x5c\xf0\xfc\xb3\xf7\xb1\x6f\x2b\x01\xe1\x0f\x27"
"\x98\xff\xf9\xd4\x01\x89\x91\x79\x71\x11\xdb\x30\xc0\x83\x1e"
"\x12\x62\x0e\x50\xa1\x47\x80\x99\xa4\xb6\x78\x19\xc5\x50\x4f"
"\x82\x87\x35\x3e\x9c\x22\x20\x81\xef\xfe\xc3\x3e\x79\x2c\xf4"
"\x7c\x7a\xcc\xfd\xbd\x63\xb4\x6b\x98\xd3\x56\x1c\xeb\xed\x1a"
"\x3a\xff\x5c\x8e\x0e\x7e\x70\x78\xfc\x91\xfc\x29\x14\xa3\x8e"
"\xcf\x47\x78\x0f\x98\x97\xb4\x21\x3d\x9c\x19\xbf\x27\x9b\xb4"
"\x16\xe6\x50\xad\xe4\x6b\xa9\x1b\xa1\xe2\x05\xc1\x0a\x83\x1d"
"\x03\xaf\x7b\x7d\x8c\x88\xa3\x11\x7e\x5d\x72\xe0\x5d\xad\x50"
"\xc4\xc8\x75\xc8\xcc\xaa\x7d\x8f\xb4\x47\x5e\x34\xe8\x04\x71"
"\x10\xdb\x92\xb7\xfe\x9b\x77\x9f\x04\xe3\x74\x72\x16\xb7\x4e"
"\x31\xf8\x00\x98\x5c\x59\xf7\x4d\x7d\x89\xd7\x1c\xbd\xd7\x85"
"\xf5\x79\xf3\xd8\x51\xcb\xab\x14\x61\xf6\xc0\xb9\xc0\xff\xec"
"\xa2\x62\xc9\xec\x1e\xb9\xc8\x28\x20\xa8\x15\xc0\x57\xe2\xce"
"\x62\x8a\xcc\xe0\xec\x47\xe2\x9e\x82\xcf\xf8\xe7\x2b\x98\x4c"
"\x64\x8c\xec\x5e\x85\xd5\xe3\x21\x46\x82\xe4\x56\x4b\x59\x13"
"\x39\x9c\x4e\x70\xbb\xfc\x7b\xd4\xc2\xdf\x5a\xde\x21\x67\x5d"
"\x1f\xf0\xea\xd6\x4d\xaa\xb7\x2c\xdb\x70\x3c\xb4\x08\x6e\x59"
"\x02\xf8\x8d\xdc\xac\x21\xda\x51\x70\xb1\xdd\x83\x16\xd3\x9c"
"\xa6\x17\xb8\x93\x74\x57\x38\xa4\xab\x5e\x4b\x3a\x3b\xb6\xa1"
"\x45\xe0\x86\x63\xd7\xd4\x2d\xc3\xc0\x39\x06\xd2\x45\x6d\x6a"
"\x4d\xa4\x24\x48\x97\x88\x02\xa9\xb8\x10\xee\xb9\x60\xfb\x3b"
"\xdd\x2b\xd5\x51\xf2\x09\xe8\x22\x43\xf8\x67\x62\xca\x27\x49"
"\xbe\xb2\x82\x70\x57\xcd\x33\x7e\x8b\x8a\x0b\x42\x6f\xf1\x39"
"\xc1\x04\x83\x5e\xd4\xe2\xc5\x26\xfe\x5e\x07\x57\x60\x7a\x09"
"\x9e\x46\x2f\x2c\x82\xd9\x13\xf5\xdc\x70\xbd\x28\xd3\x82\x6d"
"\xb7\x68\xb2\xb7\xb7\x58\x4d\x08\x83\x04\x40\xdd\xa0\x58\x77"
"\x5a\xca\x90\x86\x7a\xa2\x14\x6a\x6a\xe3\xd7\xa6\x63\xd2\x89"
"\x44\x9c\x3a\xc1\x96\x9d\x5c\x35\x16\x70\x10\x0d\x12\xf2\xc9"
"\x1d\x50\xf9\xd6\x38\x93\x60\xc9\x3c\x3a\xd9\x3e\x89\x5e\x36"
"\x4f\x82\x8d\x0f\xb2\x1c\xcb\xd3\xc3\xaa\x37\x86\x27\x7e\x43"
"\xf1\x90\x1d\x8a\x05\xaf\xbe\x87\x52\xf5\x82\xe0\xea\x3c\xfc"
"\x71\x3d\xe6\x82\x83\xa3\x01\x77\xb4\x0d\xbc\xed\x69\xb7\xea"
"\x64\x81\x9d\x71\x7e\x9e\xfe\x96\xb3\x61\xa7\xdb\x29\xf1\x5f"
"\xdc\xcc\x39\x31\xee\x01\xaa\xe7\x66\xbd\x35\x5c\xd4\xbf\x8d"
"\x6c\x3e\x30\xe5\x12\x03\x6c\xd3\xb2\x82\x02\x8e\x3e\x17\x85"
"\x7e\x31\xe0\xd4\x74\x07\x55\x77\xac\x63\x46\x51\x33\xf0\x9d"
"\xfa\x2b\xf3\x4d\x68\xf5\x37\x64\x99\xf4\xc6\x76\xbc\x37\x07"
"\xc5\xa3\xad\x61\x98\xe2\x85\xef\x87\xf7\xf5\x11\xfc\xb4\xd9"
"\x4b\x68\xc9\xe9\xbd\x22\xc9\x22\xa1\x08\x1f\xfe\xeb\x81\x91"
"\xf0\xea\xf2\x0e\x4f\xde\x4e\xcb\xb2\x28\x7f\x34\xf4\x1a\x5a"
"\x7c\x97\x75\xbf\x94\x91\x97\xef\xcc\x2c\x52\x8d\x14\x9d\xbb"
"\xe0\x03\x15\xf2\xc5\x06\x7d\xe7\x45\xd4\x77\x9f\xa6\x88\xf0"
"\x04\x31\x81\xb8\x0b\x80\x7b\x05\x61\x48\x34\x78\x92\xdd\xa9"
"\xc3\x81\x31\xf5\xe1\xde\xac\x34\xd2\x1a\x06\x41\x67\xf4\x49"
"\x38\x2c\xce\x76\xb5\x7e\xa0\xb4\xa1\x71\xf8\x79\x62\x48\x1e"
"\x5f\x63\x85\x6e\xb0\xdd\x50\x66\xe4\xd5\x45\xaf\x08\xc4\x2f"
"\x4f\x8f\xe3\xdd\x78\x95\x8a\x4f\x79\xb0\x76\x20\xa6\x83\x59"
"\x2a\x40\x3c\x10\x8d\x10\x2d\xb6\xcb\x46\x50\x4f\x33\xdb\x97"
"\xa5\xdc\xb5\xd2\xee\xcb\xdb\xc9\x78\x33\x50\x1f\x9f\x00\x6f"
"\x9e\x83\x5a\xa6\x26\xeb\xf4\x94\x7f\x93\x2f\xb2\xa8\x33\x8d"
"\x6d\x9b\x5e\xd7\x98\x54\xc0\xaf\x96\x15\x2f\x0f\xba\x9e\x29"
"\xa7\x7b\x36\xf8\x8a\x11\xb7\xe3\x7a\x9d\xc0\xb8\x89\xe1\x70"
"\x36\xb5\x4d\x25\xff\x2f\xd1\xb4\x66\x35\xbf\xd1\x3c\xca\xb7"
"\x5e\xbf\x9b\x3e\x89\xc3\xa2\xd7\x91\x22\x57\x99\xaa\x28\xf0"
"\xb6\xc0\x96\xe2\x56\x8b\x99\xcd\x81\x23\xc3\x1e\xca\xaa\x97"
"\x02\xba\xec\x1b\xee\x07\x74\xd1\x7e\xd3\x5f\x42\xf3\x71\xe6"
"\xbf\x93\x33\x29\x89\x30\x46\xdd\x13\xb3\xf8\xee\xb2\xd7\x2a"
"\xc6\xf1\xce\xa4\xf3\x61\x67\x51\xd6\xdc\xa8\x3f\x49\x59\x85"
"\x64\xcc\x38\xff\xad\x49\x5b\x3b\xa8\x50\x82\x41\x84\x8b\x31"
"\xbf\xfc\x06\x1a\x3f\xcc\x93\x0b\xe7\x04\x4b\x1d\xa9\xa4\x63"
"\x67\xc2\xf6\xd7\x77\xef\x22\x58\x24\xa0\x4d\xf8\xd1\x36\x22"
"\x4a\xee\x97\x7d\xe1\x2d\x31\xbf\x0a\x81\x85\xc4\x23\xee\x63"
"\xab\xed\xb0\x9b\xf6\xf5\xc0\x73\x31\x22\x24\xf9\x3e\x2b\xf8"
"\xed\xd2\x2a\xa1\xd2\x77\xa8\x72\xe2\xd3\xc5\xb9\xb8\x0b\xd6"
"\x06\x22\x37\xa6\xef\x5e\xe6\x17\xdb\xb9\x7b\xfc\x8a\x89\x16"
"\x82\xf3\x16\x52\x14\xbe\x7e\x44\x78\xdf\x6d\x83\x9e\x9e\x58"
"\xb6\xdf\xd7\x83\x7d\x0e\x4a\x48\x95\x6b\x4f\xf2\xd6\x64\x89"
"\x0a\xe4\x46\x44\xe7\x2c\x2f\x6a\x87\x2e\x56\x15\x31\x8c\xe8"
"\xbf\xa4\x9d\x7a\xae\x51\xa1\xb6\xa5\xb9\x85\xcf\xa8\x8f\xd8"
"\xf7\xd9\x03\xe6\x04\x95\x2f\xd9\x93\x44\xf3\x2c\xb9\x8b\x8c"
"\x4c\x8c\xa8\xbc\xdc\xcc\x69\xf0\xc0\xef\x3f\x6b\xe5\x7d\x58"
"\x8e\xc0\x39\x3e\xaa\xd7\x3a\xfb\x00\x89\x5a\x15\xc5\x59\x11"
"\x5e\x35\xac\xa3\x29\x4e\xcc\xbb\x0d\x37\x3e\xff\xc2\xc1\xb5"
"\x7d\x0c\x3f\xde\xe3\xdd\x7a\xca\xd3\xae\x03\x6d\xd5\x0a\x2a"
"\x5a\x2f\x1b\x1b\x68\xf2\xb7\xf6\x6f\x77\xc2\x26\xb7\x64\xc2"
"\x65\x5a\x2d\x6b\x30\xe5\x2a\x71\x93\x48\x25\x4b\xe3\xfe\xb6"
"\xf6\xbc\xcc\xb6\xff\x28\x9d\xa8\x74\x24\x88\x11\x45\xba\xa5"
"\x1d\x80\xf8\x35\xb8\x3e\x22\x04\x6f\x41\x6c\x80\xe6\xd0\x0c"
"\x31\x9b\x59\x78\xbf\xaa\xb1\xc2\x57\xec\x42\xe2\xc3\x17\x1b"
"\x72\x3e\x42\x49\xda\x19\x0e\xd1\x17\x23\xcd\x59\x5f\xd3\x90"
"\xd6\x16\xe2\xdf\xe1\xcb\xf6\x72\x8d\x35\x33\xc5\xb4\xbc\xe9"
"\x0b\x58\x4b\x7a\xe6\xc7\x5c\xb3\x7a\xbd\x64\xa7\xda\x42\xa1"
"\xfd\xdf\x4d\xa6\xc9\xbf\x96\xf4\x8f\x68\xcf\xe7\x3a\xf7\x01"
"\xeb\xd2\x4a\xfb\x86\xf3\xfc\xd7\x3f\xaf\x39\x5a\xbe\x19\xb7"
"\x71\xb8\x5e\xf8\x47\xcc\xcc\xb6\x3a\x18\xbf\x4b\xea\xf0\xa6"
"\x78\xd5\x81\x84\x46\x8e\x63\x46\x90\xb5\xd9\x38\x0c\xa6\x7b"
"\x15\x61\x2d\x6f\xac\x61\xa9\xfd\xe0\x85\x94\x1d\x4e\x0f\x1e"
"\x22\x3f\x4f\x17\x80\x86\x3f\x2f\xd5\x6b\xea\x20\x54\x21\xe3"
"\x85\xd2\xdc\x9b\xbf\x83\x54\x82\xa8\x1e\xc3\xaf\xba\x1a\x35"
"\x5d\xb1\xa8\xae\x5f\x3a\xae\x48\x5b\x95\xa1\x27\x74\x4e\xa9"
"\x44\xed\x40\x11\xde\xdf\x30\x96\xea\x2a\x93\xa6\x8b\xfe\xaf"
"\x59\xd7\xe4\x8d\xc6\xde\x07\x8b\x58\xb1\xc3\x5e\xbf\xba\x51"
"\x4f\xa7\xea\x12\xb8\xfd\x8c\x9f\xa8\x04\x1c\x6e\xa7\x94\xdb"
"\x1d\x9a\x82\x36\x96\xf8\x0c\x8e\xa4\xc6\xb0\x1d\x0b\xc8\x22"
"\x74\x21\x0e\x8f\x67\xf5\xa6\xb6\xe9\x34\x8a\xca\xda\x22\xde"
"\xc7\xde\x69\x3c\x4a\xa3\xcd\xba\xf8\x0e\x1f\x5e\x48\xe0\x52"
"\x65\xa4\x6b\x74\x8e\xca\x5e\x7e\x3e\xe5\xec\xe1\x1d\x88\xc0"
"\xd6\xcb\x13\x61\xf0\x19\x74\xa1\x0a\xdc\x76\x0a\x85\x35\xaa"
"\x36\xaf\x39\x15\x60\x3c\x65\x45\x97\x2f\x72\x3a\x7e\x8e\x00"
"\x5d\x0c\x6c\x4c\xdc\xd7\xac\xa6\xc3\x63\xcd\xb9\x8a\xf8\xb2"
"\xc1\x46\xec\x1a\x88\xf1\x09\x30\x82\x8d\xcb\x07\x58\xf2\x40"
"\x5f\x97\x4f\xe4\xa3\x80\x1e\xd0\xe1\x94\x55\x20\xdd\x6b\x19"
"\xc8\x9b\x3c\x36\xdc\x4d\x5c\xf3\xba\x7c\x51\x31\x0e\x7f\xbf"
"\x1b\x13\xcb\x72\x14\xad\x7c\x34\x61\x8d\xe8\x63\x2c\x81\xab"
"\xee\x7a\x40\xcf\x19\x38\x45\xb3\x84\xe0\xa4\xcf\xe4\x7a\x34"
"\x2a\xc9\x9a\x1e\xca\xd8\x2e\x03\x79\x56\x82\xea\x2a\x68\x64"
"\xcd\x01\x51\x09\x71\x7a\xf4\x75\x63\x2c\x05\x26\x2d\x0d\xf7"
"\x50\x86\x85\x4f\x88\x0d\x37\x6a\x1e\xf4\x8d\x42\xc1\xd1\x91"
"\xfb\x7d\xff\x5a\x1e\xcc\xfa\x9e\x83\xcd\x10\x98\x7b\x35\x5c"
"\x31\xb8\x35\x28\x7f\x73\x66\xbd\xb8\x0a\x72\x5c\x46\xf2\x38"
"\x53\xfe\x45\x7c\x61\x76\x9e\x04\x89\x34\x5c\x85\xd0\x85\x5f"
"\x68\x83\x1a\x89\x7f\x00\x8f\x25\xb8\x46\xcd\x4e\x9e\xea\x18"
"\x0c\x52\x7c\x8a\xe6\x67\xa1\xc5\x2a\x53\x59\x12\x83\x56\x86"
"\xe8\x59\x1d\xc6\xa0\x2a\xf1\xc8\xaf\x0d\x98\xdc\xec\x9a\x29"
"\x1c\x8e\x55\xd3\x79\x76\x9e\xe9\xfa\x7a\x9a\xa7\xd7\xa3\xd7"
"\x8c\x00\x83\xfd\x82\x78\x23\x55\x73\xa1\xf6\x3a\xc1\xa1\x7b"
"\x18\x7d\xd0\x81\x93\x38\xcc\x57\xf8\x31\xfc\x96\x57\x0f\xe2"
"\xf2\xdd\x89\x6e\x52\x26\xf2\xfa\x57\xa5\xdc\x7b\xa2\xef\xbd"
"\x5b\x39\x1f\x42\x2d\xbd\x26\xb9\x8d\x62\xa8\x41\x37\x7d\xc9"
"\xb0\xde\x82\x42\x5a\x66\xff\x15\xbe\x60\x1a\xbc\xad\x63\xf2"
"\xf4\x8e\xe7\x22\xfb\x10\xc7\xb2\x64\x3e\xd2\x9b\x47\x48\xa3"
"\x9b\xb5\xf2\xe0\xc7\x87\x5b\x1f\x06\xc8\xaf\x47\x54\x45\x16"
"\xa7\x3f\x10\x96\x55\x83\x70\x17\x18\x93\x59\x4d\xa0\x3a\xc4"
"\x74\xe3\x04\x11\x04\x91\x20\xb5\xab\x79\xff\x00\x4a\x7e\xc1"
"\x6a\x18\x9e\x28\xbf\x6b\xc1\xe3\x32\x53\x6e\xab\xf9\xd1\xdc"
"\x68\x25\xb6\x9b\x70\x75\xf6\x00\xe3\xb8\xee\x65\x82\xf0\x89"
"\x52\x86\x6b\x33\x89\xa6\xd5\x34\x2e\x28\x0d\x30\x2f\xba\x96"
"\x5b\xba\xf1\x4e\x07\x45\x47\xa2\xb3\xb5\xd5\x38\x91\xb1\x8b"
"\x1c\x5e\x22\x73\x53\x66\x5f\xe6\x49\x7b\xa0\x48\xb7\xb0\x07"
"\x79\xa4\x22\x17\x3e\x35\xbe\xdc\xb1\x38\xd3\x17\x81\x7c\x97"
"\xfa\x7f\xb9\x33\xc6\xcb\x33\x2b\x54\xe1\xd7\x09\x32\x8a\xa8"
"\x6e\x80\x19\x8e\xe5\x1c\x76\xf9\x02\xd5\x55\x75\xeb\xa0\x68"
"\x44\x4c\xec\x7a\x4e\x0f\x25\xc8\x1d\x89\xfc\xb2\x77\x26\x46"
"\x80\xa7\xf3\xfa\xa7\x18\xd8\xa0\x13\xa6\x8c\x09\x9a\x03\xc9"
"\x66\x67\x2c\x35\x88\x98\xa3\x08\x59\xda\xe6\x60\x26\xa3\x4c"
"\x41\x44\x6c\xbd\xb8\xab\x4d\x19\x04\x5b\x36\xa1\x48\xa9\x36"
"\x9a\xfe\xdd\x58\x81\xff\x94\x93\x62\x92\x2d\x1c\x2d\x07\xc0"
"\x76\x62\xb5\x91\xfc\x0b\x03\x31\x31\x12\x76\xaf\x79\x8e\x5d"
"\xb8\x40\x69\xff\x14\x1c\xcc\x31\xc0\x01\xc8\xc5\x7a\x38\xe1"
"\xdf\x77\x15\xd5\x33\x80\xe1\x24\x94\xc7\x6c\xe2\x9f\x5c\xee"
"\x18\xa8\xe4\x60\xca\x08\x49\x17\xca\x5d\x32\xa0\x85\x63\x7d"
"\x23\xc7\x90\x7b\x3c\xf6\x51\x63\x29\x70\x99\x4e\xf9\x1d\xd0"
"\x2c\x13\x16\x8a\xf6\x09\x42\x88\x06\xfd\x19\x0e\xa0\xca\x9e"
"\xb3\x4e\x2e\x99\x34\x36\x5a\x8c\x88\xc1\x72\xf7\x66\x6b\x99"
"\xe3\x7e\x71\xb5\xb3\xed\xde\x78\x21\x16\x03\x48\x61\x52\xe4"
"\xb3\x9b\x3a\x2b\x9f\x6b\x83\x31\x0e\xe2\xc1\x7d\x8e\x03\x3c"
"\x0b\x08\x0d\x06\x88\x8b\xd8\x21\x67\xb0\xf0\xbb\xf6\x94\xbe"
"\x1a\xdc\x0c\x9f\xd1\x2f\x0e\x8e\xbb\x44\x2c\x39\x45\x0a\x82"
"\x9f\x70\x24\x3c\x41\x8a\xc5\xc2\x48\x33\x85\x72\xae\xd1\xa7"
"\xb6\x58\xb9\x06\xfc\x4e\xeb\x16\xd5\xab\x22\x82\x49\xbc\x33"
"\xa4\xab\xda\xa1\x92\xdf\xb2\xa1\x0e\x6a\x45\x7e\x00\x9b\xb7"
"\x01\x5a\xa2\x05\x77\x78\x5a\x0f\x9b\xf3\x29\x92\xa6\x1b\x2e"
"\x52\x4a\x97\xb4\x06\x16\x4e\x94\xeb\x20\x92\x40\x41\x88\x25"
"\x51\xf6\xa6\x53\xc7\xc3\x43\xa0\x05\x6a\xe0\xa5\x86\x28\x69"
"\xf7\xb7\xce\x77\xea\x78\x81\x9d\x8e\xea\x66\xdb\x08\xcc\x05"
"\x27\x82\x5a\x1d\x3a\x58\x68\x88\x0b\x86\x2e\xb4\x8b\x9a\x05"
"\xed\x30\x53\xf2\x01\x0a\x7b\x2d\x99\x9d\xb3\x53\x39\x95\x1c"
"\x73\x69\xdd\x76\xcf\x25\xb8\x26\x5e\x6a\x93\xe7\xee\x5e\xdd"
"\xf6\x01\xca\x93\x4b\xd4\x1e\xc4\x41\x68\x59\xf7\x1b\x59\x5a"
"\x12\xc6\x26\x64\xff\x0d\x44\xec\xd5\xd3\xa5\x83\xd7\x98\x63"
"\xb8\x7d\xeb\xe8\xc0\x7a\x7d\xea\x98\x29\xaa\x02\x0e\xe1\xc1"
"\x05\x09\x70\x4e\x96\x76\x3c\xcf\xfb\x4d\x6d\x50\x48\xce\x17"
"\x6c\x33\x49\x2b\xd3\xb6\xcc\x5a\x2d\xee\x0e\x76\x99\x74\x60"
"\x79\xe6\x3d\x01\x3b\x75\xf0\x13\x4f\x87\x43\x13\x74\xe2\x33"
"\x39\x7c\x3b\x0b\x52\x8c\xc7\xf2\xa4\x77\x49\x27\x1b\xb1\x9e"
"\x28\xe7\x2c\xc5\xd5\xde\x7b\x39\x55\xc5\x2a\x2c\xb9\x22\x3a"
"\x29\xc3\x71\x05\xf3\x15\xc6\x94\x11\x30\xf6\xd1\xda\x5b\xa6"
"\xdd\xf9\xb5\xe7\x87\x74\x9d\x58\x09\xdc\x65\xdc\xf0\x6a\x24"
"\xfd\x72\x09\xdd\x3c\x8c\x2d\xae\x3e\xd5\x15\x62\xd1\xa4\x65"
"\x49\x16\x57\x49\x12\x52\x0c\xf1\x1c\x7c\x26\xda\x28\xe8\x6f"
"\x57\x53\x02\x6a\xcb\x13\x4b\x00\x96\x07\xc8\xb1\xeb\xc6\x6b"
"\x96\x69\xfd\x5b\x29\x31\xfc\x35\x44\x5d\x2f\xeb\x87\x56\x9f"
"\x88\xfe\xbf\x6d\xa2\x6e\xdf\x2f\xc4\x6e\x17\xdc\xfa\x8b\xa4"
"\x26\x55\x01\xda\xfa\x81\x64\xba\x00\x5c\x83\xb2\x9e\x07\x54"
"\x9e\x40\x91\xf6\xcb\x57\xbc\x68\x72\xa7\x63\x22\x36\x57\x5b"
"\x93\x6f\x03\xd3\x90\x81\xc3\x10\x69\x25\xe4\x17\x16\xe1\x00"
"\xf3\xba\x14\x98\x4a\x73\xc9\xe6\xd2\xfc\x1c\xc3\x68\xee\x8b"
"\x7d\xec\x88\x2e\xf3\x2e\x25\x75\x6f\xf9\x7d\xd1\xde\xa8\xb4"
"\x09\xab\xda\x68\xf7\x7a\x45\x79\xba\xe7\xe9\xad\x45\x77\x33"
"\xcf\xe2\x8a\xca\x83\xa8\x2f\x75\xee\x52\xa5\x1f\xce\x4e\x75"
"\xdd\x96\x84\x4f\xd2\xa5\x19\xeb\x5f\xb0\xbb\xf7\xf7\x57\x8d"
"\x63\xd2\x92\x1a\x6b\xa1\x7f\x5e\x3d\x80\x8f\x8b\x7d\x94\x76"
"\x9d\x52\xcd\x87\x76\x58\xdc\x7e\x9f\xde\x7d\x9a\x80\x8b\xaf"
"\x22\xaf\xb8\x37\x88\xf7\x63\x88\x2c\xaa\xd2\x8a\xfc\x85\xb8"
"\x42\xe3\xad\x20\x29\xdc\x9f\xd6\x93\x38\x4a\xc4\x1d\xd5\x49"
"\xfb\x71\xaa\x25\x5a\x07\xcb\x3b\x0f\xd8\x84\xa9\x48\xe8\x0e"
"\xff\x4d\xe5\x7b\x00\x0d\x19\x47\x94\x3b\xb4\xc6\x60\xed\x83"
"\x38\x55\x56\x04\x0c\xec\x08\x2d\x2f\x19\x90\xee\xac\x35\x68"
"\xe3\x2c\x9b\x91\x99\x0c\xec\x6b\x83\x70\x3d\xd8\x92\x8d\x74"
"\x34\xfa\xf1\x09\x18\xce\x03\xe0\x89\xb6\x3c\x41\xac\x1a\x02"
"\x5c\x02\xc1\x0a\x48\x7b\xa1\x47\x19\xba\xd1\x57\x4d\xca\x7e"
"\x08\xf6\xea\xa5\x55\x9d\x91\xfb\xdb\x06\xc0\x77\xd4\xdd\xc2"
"\x3a\xfa\x7e\x31\xe7\xac\x25\x1d\xa2\x53\x1c\x79\xbe\xb1\xb7"
"\x21\x77\xee\xd3\xb1\x8b\xf9\xe2\x78\x69\x63\x31\xe9\x28\xb8"
"\x1c\x4b\xe1\x98\x41\x3c\x02\x42\x2a\x98\x5d\xbd\x75\x9d\x61"
"\xf6\xd8\xf2\x59\xf4\x54\x34\x1b\xb0\x80\x93\xa9\x52\xe6\x59"
"\xe9\x2f\xe3\xbd\x37\x75\x6d\xe4\xab\x99\x6b\xbc\xf1\x64\xda"
"\xdf\x14\xe7\x22\x1c\x20\xe7\xf7\x12\x0d\xeb\xbd\x77\x5e\x46"
"\x2c\xb9\x08\xc4\x84\xe2\x2c\xc9\xa7\xe4\x7f\xab\x84\xd9\xbb"
"\x39\xbf\xe7\x5b\xed\xeb\x75\x7d\x67\xa5\xc3\x3d\x8d\xd3\x77"
"\x52\x68\x1c\x20\x29\x66\xeb\x2f\xd5\xc7\x66\x60\x59\xfb\x85"
"\x19\xb5\x5a\x24\xbd\x99\xf9\x8e\x00\xd4\xd7\xc2\x21\x0f\x59"
"\xe8\xd2\x26\x92\x2c\x7b\x38\x95\x10\xe8\x02\x66\xee\x16\x1f"
"\x4a\xc4\x58\x72\x0b\x1f\x86\xd4\xee\x09\x3c\x4b\x4e\x74\xbc"
"\x97\x6f\x52\x12\xc1\xc7\xae\x3a\x8a\x54\x52\xe6\xc7\x7c\xb9"
"\x05\x65\xcc\x5f\x71\x07\xa3\x35\xd4\x35\xf2\x05\xf8\x0c\x27"
"\x02\xfb\x93\x10\xe6\xbe\xcc\xc2\xcf\x5d\x71\x77\x86\x03\x6c"
"\xa3\xbd\x6a\x06\xd4\x4c\xb0\xf5\xc8\xb8\xc7\x11\x2a\xda\x99"
"\xb6\xf7\x68\x39\xf3\x2c\x2f\x45\xed\xaa\x24\x56\x46\xfe\x05"
"\x8b\x9f\x93\x6a\xc7\x8e\x0b\x9f\xb3\xe9\x45\xee\x59\xcd\x69"
"\xf1\x5a\xe9\x14\x22\x66\xa0\x3f\x00\x27\x87\x6d\x67\x68\x79"
"\x54\xb8\x7f\xd2\x63\xb4\x3f\x48\xf5\xf6\x3e\xa1\x9b\x60\x66"
"\x2d\x85\xe7\x08\xd3\x37\x37\xca\x3b\xc1\xb0\xcd\x07\x3d\xec"
"\x39\x0b\x79\xd3\xd2\x7d\xfe\x1b\xaa\x35\xf6\xab\x01\xf7\x64"
"\x52\x42\xdd\x9c\xce\xea\x12\xd5\xb6\xfe\xda\x76\xf0\x28\x24"
"\x64\x61\xb2\x8b\x52",
4100);
r[27] = syscall(SYS_write, r[4], 0x20d8a029ul, 0x1004ul, 0, 0, 0);
break;
}
return 0;
}
int main()
{
long i;
pthread_t th[13];
memset(r, -1, sizeof(r));
for (i = 0; i < 13; i++) {
pthread_create(&th[i], 0, thr, (void*)i);
usleep(10000);
}
for (i = 0; i < 13; i++) {
pthread_create(&th[i], 0, thr, (void*)i);
if (i % 2 == 0)
usleep(10000);
}
usleep(100000);
return 0;
}
2
5
[alsa-devel] sound: deadlock between snd_rawmidi_kernel_open/snd_seq_port_connect
by Dmitry Vyukov 03 Feb '16
by Dmitry Vyukov 03 Feb '16
03 Feb '16
Hello,
While running syzkaller fuzzer I've got the following lockdep report:
======================================================
[ INFO: possible circular locking dependency detected ]
4.4.0+ #276 Not tainted
-------------------------------------------------------
syz-executor/21025 is trying to acquire lock:
(register_mutex#5){+.+.+.}, at: [<ffffffff84f889cb>]
snd_rawmidi_kernel_open+0x4b/0x260 sound/core/rawmidi.c:341
but task is already holding lock:
(&grp->list_mutex/1){+.+...}, at: [<ffffffff84fc4afa>]
snd_seq_port_connect+0x1ba/0x840 sound/core/seq/seq_ports.c:506
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (&grp->list_mutex/1){+.+...}:
[<ffffffff8145ad8c>] lock_acquire+0x1dc/0x430
kernel/locking/lockdep.c:3585
[<ffffffff8144851a>] down_write_nested+0x4a/0xa0
kernel/locking/rwsem.c:149
[<ffffffff84fc4afa>] snd_seq_port_connect+0x1ba/0x840
sound/core/seq/seq_ports.c:506
[<ffffffff84fb6f54>] snd_seq_ioctl_subscribe_port+0x1c4/0x290
sound/core/seq/seq_clientmgr.c:1464
[<ffffffff84fb126d>] snd_seq_do_ioctl+0x19d/0x1c0
sound/core/seq/seq_clientmgr.c:2209
[<ffffffff84fb2c2b>] snd_seq_kernel_client_ctl+0xdb/0x170
sound/core/seq/seq_clientmgr.c:2423
[<ffffffff88413c20>] snd_seq_oss_create_client+0x253/0x2d5
sound/core/seq/oss/seq_oss_init.c:119
[<ffffffff8841393e>] alsa_seq_oss_init+0x1af/0x23e
sound/core/seq/oss/seq_oss.c:89
[<ffffffff81002259>] do_one_initcall+0x159/0x380 init/main.c:794
[< inline >] do_initcall_level init/main.c:859
[< inline >] do_initcalls init/main.c:867
[< inline >] do_basic_setup init/main.c:885
[<ffffffff88315c1a>] kernel_init_freeable+0x474/0x52d init/main.c:1010
[<ffffffff86312683>] kernel_init+0x13/0x150 init/main.c:936
[<ffffffff86336fef>] ret_from_fork+0x3f/0x70
arch/x86/entry/entry_64.S:468
-> #1 (&grp->list_mutex){++++.+}:
[<ffffffff8145ad8c>] lock_acquire+0x1dc/0x430
kernel/locking/lockdep.c:3585
[<ffffffff863323a7>] down_read+0x47/0x60 kernel/locking/rwsem.c:22
[< inline >] deliver_to_subscribers
sound/core/seq/seq_clientmgr.c:679
[<ffffffff84fb5509>] snd_seq_deliver_event+0x5a9/0x800
sound/core/seq/seq_clientmgr.c:817
[<ffffffff84fb6466>] snd_seq_kernel_client_dispatch+0x126/0x170
sound/core/seq/seq_clientmgr.c:2401
[<ffffffff84fc1e62>] snd_seq_system_broadcast+0xb2/0xf0
sound/core/seq/seq_system.c:101
[<ffffffff84fb248e>] snd_seq_create_kernel_client+0x21e/0x300
sound/core/seq/seq_clientmgr.c:2280
[< inline >] snd_virmidi_dev_attach_seq
sound/core/seq/seq_virmidi.c:372
[<ffffffff84fdc55f>] snd_virmidi_dev_register+0x29f/0x750
sound/core/seq/seq_virmidi.c:439
[<ffffffff84f824ec>] snd_rawmidi_dev_register+0x30c/0xd40
sound/core/rawmidi.c:1589
[<ffffffff84f33583>] __snd_device_register.part.0+0x63/0xc0
sound/core/device.c:164
[< inline >] __snd_device_register sound/core/device.c:162
[<ffffffff84f341ed>] snd_device_register_all+0xad/0x110
sound/core/device.c:212
[<ffffffff84f277cf>] snd_card_register+0xef/0x6a0 sound/core/init.c:749
[<ffffffff84fefc0f>] snd_virmidi_probe+0x3ef/0x590
sound/drivers/virmidi.c:123
[<ffffffff832feb6c>] platform_drv_probe+0x8c/0x160
drivers/base/platform.c:562
[< inline >] really_probe drivers/base/dd.c:377
[<ffffffff832f862e>] driver_probe_device+0x37e/0xc90
drivers/base/dd.c:499
[<ffffffff832f926e>] __device_attach_driver+0x19e/0x250
drivers/base/dd.c:584
[<ffffffff832f23df>] bus_for_each_drv+0x13f/0x1d0 drivers/base/bus.c:464
[<ffffffff832f809f>] __device_attach+0x1ef/0x2e0 drivers/base/dd.c:641
[<ffffffff832f93ba>] device_initial_probe+0x1a/0x20 drivers/base/dd.c:688
[<ffffffff832f5939>] bus_probe_device+0x1e9/0x290 drivers/base/bus.c:558
[<ffffffff832ef11b>] device_add+0x84b/0x1490 drivers/base/core.c:1120
[<ffffffff832fe2c9>] platform_device_add+0x389/0x790
drivers/base/platform.c:403
[<ffffffff832fff26>] platform_device_register_full+0x396/0x4c0
drivers/base/platform.c:535
[< inline >] platform_device_register_resndata
include/linux/platform_device.h:111
[< inline >] platform_device_register_simple
include/linux/platform_device.h:140
[<ffffffff884146d1>] alsa_card_virmidi_init+0x104/0x1da
sound/drivers/virmidi.c:172
[<ffffffff81002259>] do_one_initcall+0x159/0x380 init/main.c:794
[< inline >] do_initcall_level init/main.c:859
[< inline >] do_initcalls init/main.c:867
[< inline >] do_basic_setup init/main.c:885
[<ffffffff88315c1a>] kernel_init_freeable+0x474/0x52d init/main.c:1010
[<ffffffff86312683>] kernel_init+0x13/0x150 init/main.c:936
[<ffffffff86336fef>] ret_from_fork+0x3f/0x70
arch/x86/entry/entry_64.S:468
-> #0 (register_mutex#5){+.+.+.}:
[< inline >] check_prev_add kernel/locking/lockdep.c:1853
[< inline >] check_prevs_add kernel/locking/lockdep.c:1958
[< inline >] validate_chain kernel/locking/lockdep.c:2144
[<ffffffff8145742b>] __lock_acquire+0x31eb/0x4700
kernel/locking/lockdep.c:3206
[<ffffffff8145ad8c>] lock_acquire+0x1dc/0x430
kernel/locking/lockdep.c:3585
[< inline >] __mutex_lock_common kernel/locking/mutex.c:518
[<ffffffff8632cf61>] mutex_lock_nested+0xb1/0xa50
kernel/locking/mutex.c:618
[<ffffffff84f889cb>] snd_rawmidi_kernel_open+0x4b/0x260
sound/core/rawmidi.c:341
[<ffffffff84fdda77>] midisynth_subscribe+0xf7/0x340
sound/core/seq/seq_midi.c:188
[<ffffffff84fc2a4e>] subscribe_port.isra.2+0x14e/0x2b0
sound/core/seq/seq_ports.c:426
[<ffffffff84fc4dd0>] snd_seq_port_connect+0x490/0x840
sound/core/seq/seq_ports.c:527
[<ffffffff84fb6f54>] snd_seq_ioctl_subscribe_port+0x1c4/0x290
sound/core/seq/seq_clientmgr.c:1464
[<ffffffff84fb126d>] snd_seq_do_ioctl+0x19d/0x1c0
sound/core/seq/seq_clientmgr.c:2209
[<ffffffff84fb2c2b>] snd_seq_kernel_client_ctl+0xdb/0x170
sound/core/seq/seq_clientmgr.c:2423
[<ffffffff84fd69e4>] snd_seq_oss_midi_open+0x3b4/0x610
sound/core/seq/oss/seq_oss_midi.c:375
[<ffffffff84fd6ccb>] snd_seq_oss_midi_open_all+0x8b/0xd0
sound/core/seq/oss/seq_oss_midi.c:306
[<ffffffff84fca1d5>] snd_seq_oss_open+0x5c5/0x8d0
sound/core/seq/oss/seq_oss_init.c:276
[<ffffffff84fc903a>] odev_open+0x6a/0x90 sound/core/seq/oss/seq_oss.c:138
[<ffffffff84f2279f>] soundcore_open+0x30f/0x640 sound/sound_core.c:639
[<ffffffff817be1fa>] chrdev_open+0x22a/0x4c0 fs/char_dev.c:388
[<ffffffff817a9c02>] do_dentry_open+0x6a2/0xcb0 fs/open.c:736
[<ffffffff817ad2db>] vfs_open+0x17b/0x1f0 fs/open.c:853
[< inline >] do_last fs/namei.c:3254
[<ffffffff817e00d9>] path_openat+0xde9/0x5e30 fs/namei.c:3386
[<ffffffff817e895e>] do_filp_open+0x18e/0x250 fs/namei.c:3421
[<ffffffff817ada5c>] do_sys_open+0x1fc/0x420 fs/open.c:1022
[< inline >] SYSC_open fs/open.c:1040
[<ffffffff817adcad>] SyS_open+0x2d/0x40 fs/open.c:1035
[<ffffffff86336c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
other info that might help us debug this:
Chain exists of:
register_mutex#5 --> &grp->list_mutex --> &grp->list_mutex/1
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&grp->list_mutex/1);
lock(&grp->list_mutex);
lock(&grp->list_mutex/1);
lock(register_mutex#5);
*** DEADLOCK ***
3 locks held by syz-executor/21025:
#0: (register_mutex#4){+.+.+.}, at: [<ffffffff84fc902f>]
odev_open+0x5f/0x90 sound/core/seq/oss/seq_oss.c:137
#1: (&grp->list_mutex){++++.+}, at: [<ffffffff84fc4ae2>]
snd_seq_port_connect+0x1a2/0x840 sound/core/seq/seq_ports.c:505
#2: (&grp->list_mutex/1){+.+...}, at: [<ffffffff84fc4afa>]
snd_seq_port_connect+0x1ba/0x840 sound/core/seq/seq_ports.c:506
stack backtrace:
CPU: 2 PID: 21025 Comm: syz-executor Not tainted 4.4.0+ #276
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
00000000ffffffff ffff88006d0af0c0 ffffffff82999e2d ffffffff88fa1eb0
ffffffff88fa2f90 ffffffff88fa2060 ffff88006d0af110 ffffffff81450658
ffff880065c8df00 ffff880065c8e79a 0000000000000000 ffff880065c8e778
Call Trace:
[< inline >] __dump_stack lib/dump_stack.c:15
[<ffffffff82999e2d>] dump_stack+0x6f/0xa2 lib/dump_stack.c:50
[<ffffffff81450658>] print_circular_bug+0x288/0x340
kernel/locking/lockdep.c:1226
[< inline >] check_prev_add kernel/locking/lockdep.c:1853
[< inline >] check_prevs_add kernel/locking/lockdep.c:1958
[< inline >] validate_chain kernel/locking/lockdep.c:2144
[<ffffffff8145742b>] __lock_acquire+0x31eb/0x4700 kernel/locking/lockdep.c:3206
[<ffffffff8145ad8c>] lock_acquire+0x1dc/0x430 kernel/locking/lockdep.c:3585
[< inline >] __mutex_lock_common kernel/locking/mutex.c:518
[<ffffffff8632cf61>] mutex_lock_nested+0xb1/0xa50 kernel/locking/mutex.c:618
[<ffffffff84f889cb>] snd_rawmidi_kernel_open+0x4b/0x260
sound/core/rawmidi.c:341
[<ffffffff84fdda77>] midisynth_subscribe+0xf7/0x340
sound/core/seq/seq_midi.c:188
[<ffffffff84fc2a4e>] subscribe_port.isra.2+0x14e/0x2b0
sound/core/seq/seq_ports.c:426
[<ffffffff84fc4dd0>] snd_seq_port_connect+0x490/0x840
sound/core/seq/seq_ports.c:527
[<ffffffff84fb6f54>] snd_seq_ioctl_subscribe_port+0x1c4/0x290
sound/core/seq/seq_clientmgr.c:1464
[<ffffffff84fb126d>] snd_seq_do_ioctl+0x19d/0x1c0
sound/core/seq/seq_clientmgr.c:2209
[<ffffffff84fb2c2b>] snd_seq_kernel_client_ctl+0xdb/0x170
sound/core/seq/seq_clientmgr.c:2423
[<ffffffff84fd69e4>] snd_seq_oss_midi_open+0x3b4/0x610
sound/core/seq/oss/seq_oss_midi.c:375
[<ffffffff84fd6ccb>] snd_seq_oss_midi_open_all+0x8b/0xd0
sound/core/seq/oss/seq_oss_midi.c:306
[<ffffffff84fca1d5>] snd_seq_oss_open+0x5c5/0x8d0
sound/core/seq/oss/seq_oss_init.c:276
[<ffffffff84fc903a>] odev_open+0x6a/0x90 sound/core/seq/oss/seq_oss.c:138
[<ffffffff84f2279f>] soundcore_open+0x30f/0x640 sound/sound_core.c:639
[<ffffffff817be1fa>] chrdev_open+0x22a/0x4c0 fs/char_dev.c:388
[<ffffffff817a9c02>] do_dentry_open+0x6a2/0xcb0 fs/open.c:736
[<ffffffff817ad2db>] vfs_open+0x17b/0x1f0 fs/open.c:853
[< inline >] do_last fs/namei.c:3254
[<ffffffff817e00d9>] path_openat+0xde9/0x5e30 fs/namei.c:3386
[<ffffffff817e895e>] do_filp_open+0x18e/0x250 fs/namei.c:3421
[<ffffffff817ada5c>] do_sys_open+0x1fc/0x420 fs/open.c:1022
[< inline >] SYSC_open fs/open.c:1040
[<ffffffff817adcad>] SyS_open+0x2d/0x40 fs/open.c:1035
[<ffffffff86336c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
On commit 30f05309bde49295e02e45c7e615f73aa4e0ccc2.
2
5