diff options
author | Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com> | 2021-04-15 20:21:22 +0300 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2021-04-30 16:58:41 +0000 |
commit | 191ce24bf7878fff02ecad9d949dd2e42f5dfc0b (patch) | |
tree | 03b72572d142c66a479ea83e22a3d437984ca976 /meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch | |
parent | 80b175fa5dc5afbb62883e1d6152b55c0a786c2d (diff) |
virtio: Backport virtio sound driver.
Added patch series is the latest implementation [1] of virtio sound
device [2] driver. It was accepted [3] by sound maintainer for the next
kernel version.
virtio-snd.cfg snippet has been generated using menuconfig/diffconfig
tasks by selecting SND_VIRTIO, other configs have been selected
automatically.
[1]: https://lore.kernel.org/alsa-devel/20210302164709.3142702-1-anton.yakovlev@opensynergy.com/
[2]: https://github.com/oasis-tcs/virtio-spec/blob/master/virtio-sound.tex
[3]: https://lore.kernel.org/alsa-devel/s5hsg575q5z.wl-tiwai@suse.de/
Bug-AGL: SPEC-3894
Change-Id: Ide484b4a70e5d2aef0726f701f87d783e128c4d3
Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
Reviewed-on: https://gerrit.automotivelinux.org/gerrit/c/AGL/meta-agl/+/26291
Tested-by: Jenkins Job builder account
ci-image-build: Jenkins Job builder account
ci-image-boot-test: Jenkins Job builder account
Reviewed-by: Jan-Simon Moeller <jsmoeller@linuxfoundation.org>
Diffstat (limited to 'meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch')
-rw-r--r-- | meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch new file mode 100644 index 000000000..d27ddb435 --- /dev/null +++ b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch @@ -0,0 +1,335 @@ +From 861932797d59b807b4fcc8a2e12dafbddd5ca4d9 Mon Sep 17 00:00:00 2001 +From: Anton Yakovlev <anton.yakovlev@opensynergy.com> +Date: Tue, 2 Mar 2021 17:47:08 +0100 +Subject: [PATCH] ALSA: virtio: introduce PCM channel map support + +Enumerate all available PCM channel maps and create ALSA controls. + +Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com> +Link: https://lore.kernel.org/r/20210302164709.3142702-9-anton.yakovlev@opensynergy.com +Signed-off-by: Takashi Iwai <tiwai@suse.de> +Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com> +--- + sound/virtio/Makefile | 1 + + sound/virtio/virtio_card.c | 10 ++ + sound/virtio/virtio_card.h | 8 ++ + sound/virtio/virtio_chmap.c | 219 ++++++++++++++++++++++++++++++++++++ + sound/virtio/virtio_pcm.h | 4 + + 5 files changed, 242 insertions(+) + create mode 100644 sound/virtio/virtio_chmap.c + +diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile +index 09f485291285..2742bddb8874 100644 +--- a/sound/virtio/Makefile ++++ b/sound/virtio/Makefile +@@ -4,6 +4,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o + + virtio_snd-objs := \ + virtio_card.o \ ++ virtio_chmap.o \ + virtio_ctl_msg.o \ + virtio_jack.o \ + virtio_pcm.o \ +diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c +index 89bd66c1256e..1c03fcc41c3b 100644 +--- a/sound/virtio/virtio_card.c ++++ b/sound/virtio/virtio_card.c +@@ -231,6 +231,10 @@ static int virtsnd_build_devs(struct virtio_snd *snd) + if (rc) + return rc; + ++ rc = virtsnd_chmap_parse_cfg(snd); ++ if (rc) ++ return rc; ++ + if (snd->njacks) { + rc = virtsnd_jack_build_devs(snd); + if (rc) +@@ -243,6 +247,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd) + return rc; + } + ++ if (snd->nchmaps) { ++ rc = virtsnd_chmap_build_devs(snd); ++ if (rc) ++ return rc; ++ } ++ + return snd_card_register(snd->card); + } + +diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h +index f154313c79fd..86ef3941895e 100644 +--- a/sound/virtio/virtio_card.h ++++ b/sound/virtio/virtio_card.h +@@ -43,6 +43,8 @@ struct virtio_snd_queue { + * @njacks: Number of jacks. + * @substreams: VirtIO PCM substreams. + * @nsubstreams: Number of PCM substreams. ++ * @chmaps: VirtIO channel maps. ++ * @nchmaps: Number of channel maps. + */ + struct virtio_snd { + struct virtio_device *vdev; +@@ -55,6 +57,8 @@ struct virtio_snd { + u32 njacks; + struct virtio_pcm_substream *substreams; + u32 nsubstreams; ++ struct virtio_snd_chmap_info *chmaps; ++ u32 nchmaps; + }; + + /* Message completion timeout in milliseconds (module parameter). */ +@@ -100,4 +104,8 @@ int virtsnd_jack_build_devs(struct virtio_snd *snd); + void virtsnd_jack_event(struct virtio_snd *snd, + struct virtio_snd_event *event); + ++int virtsnd_chmap_parse_cfg(struct virtio_snd *snd); ++ ++int virtsnd_chmap_build_devs(struct virtio_snd *snd); ++ + #endif /* VIRTIO_SND_CARD_H */ +diff --git a/sound/virtio/virtio_chmap.c b/sound/virtio/virtio_chmap.c +new file mode 100644 +index 000000000000..5bc924933a59 +--- /dev/null ++++ b/sound/virtio/virtio_chmap.c +@@ -0,0 +1,219 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * virtio-snd: Virtio sound device ++ * Copyright (C) 2021 OpenSynergy GmbH ++ */ ++#include <linux/virtio_config.h> ++ ++#include "virtio_card.h" ++ ++/* VirtIO->ALSA channel position map */ ++static const u8 g_v2a_position_map[] = { ++ [VIRTIO_SND_CHMAP_NONE] = SNDRV_CHMAP_UNKNOWN, ++ [VIRTIO_SND_CHMAP_NA] = SNDRV_CHMAP_NA, ++ [VIRTIO_SND_CHMAP_MONO] = SNDRV_CHMAP_MONO, ++ [VIRTIO_SND_CHMAP_FL] = SNDRV_CHMAP_FL, ++ [VIRTIO_SND_CHMAP_FR] = SNDRV_CHMAP_FR, ++ [VIRTIO_SND_CHMAP_RL] = SNDRV_CHMAP_RL, ++ [VIRTIO_SND_CHMAP_RR] = SNDRV_CHMAP_RR, ++ [VIRTIO_SND_CHMAP_FC] = SNDRV_CHMAP_FC, ++ [VIRTIO_SND_CHMAP_LFE] = SNDRV_CHMAP_LFE, ++ [VIRTIO_SND_CHMAP_SL] = SNDRV_CHMAP_SL, ++ [VIRTIO_SND_CHMAP_SR] = SNDRV_CHMAP_SR, ++ [VIRTIO_SND_CHMAP_RC] = SNDRV_CHMAP_RC, ++ [VIRTIO_SND_CHMAP_FLC] = SNDRV_CHMAP_FLC, ++ [VIRTIO_SND_CHMAP_FRC] = SNDRV_CHMAP_FRC, ++ [VIRTIO_SND_CHMAP_RLC] = SNDRV_CHMAP_RLC, ++ [VIRTIO_SND_CHMAP_RRC] = SNDRV_CHMAP_RRC, ++ [VIRTIO_SND_CHMAP_FLW] = SNDRV_CHMAP_FLW, ++ [VIRTIO_SND_CHMAP_FRW] = SNDRV_CHMAP_FRW, ++ [VIRTIO_SND_CHMAP_FLH] = SNDRV_CHMAP_FLH, ++ [VIRTIO_SND_CHMAP_FCH] = SNDRV_CHMAP_FCH, ++ [VIRTIO_SND_CHMAP_FRH] = SNDRV_CHMAP_FRH, ++ [VIRTIO_SND_CHMAP_TC] = SNDRV_CHMAP_TC, ++ [VIRTIO_SND_CHMAP_TFL] = SNDRV_CHMAP_TFL, ++ [VIRTIO_SND_CHMAP_TFR] = SNDRV_CHMAP_TFR, ++ [VIRTIO_SND_CHMAP_TFC] = SNDRV_CHMAP_TFC, ++ [VIRTIO_SND_CHMAP_TRL] = SNDRV_CHMAP_TRL, ++ [VIRTIO_SND_CHMAP_TRR] = SNDRV_CHMAP_TRR, ++ [VIRTIO_SND_CHMAP_TRC] = SNDRV_CHMAP_TRC, ++ [VIRTIO_SND_CHMAP_TFLC] = SNDRV_CHMAP_TFLC, ++ [VIRTIO_SND_CHMAP_TFRC] = SNDRV_CHMAP_TFRC, ++ [VIRTIO_SND_CHMAP_TSL] = SNDRV_CHMAP_TSL, ++ [VIRTIO_SND_CHMAP_TSR] = SNDRV_CHMAP_TSR, ++ [VIRTIO_SND_CHMAP_LLFE] = SNDRV_CHMAP_LLFE, ++ [VIRTIO_SND_CHMAP_RLFE] = SNDRV_CHMAP_RLFE, ++ [VIRTIO_SND_CHMAP_BC] = SNDRV_CHMAP_BC, ++ [VIRTIO_SND_CHMAP_BLC] = SNDRV_CHMAP_BLC, ++ [VIRTIO_SND_CHMAP_BRC] = SNDRV_CHMAP_BRC ++}; ++ ++/** ++ * virtsnd_chmap_parse_cfg() - Parse the channel map configuration. ++ * @snd: VirtIO sound device. ++ * ++ * This function is called during initial device initialization. ++ * ++ * Context: Any context that permits to sleep. ++ * Return: 0 on success, -errno on failure. ++ */ ++int virtsnd_chmap_parse_cfg(struct virtio_snd *snd) ++{ ++ struct virtio_device *vdev = snd->vdev; ++ u32 i; ++ int rc; ++ ++ virtio_cread_le(vdev, struct virtio_snd_config, chmaps, &snd->nchmaps); ++ if (!snd->nchmaps) ++ return 0; ++ ++ snd->chmaps = devm_kcalloc(&vdev->dev, snd->nchmaps, ++ sizeof(*snd->chmaps), GFP_KERNEL); ++ if (!snd->chmaps) ++ return -ENOMEM; ++ ++ rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CHMAP_INFO, 0, ++ snd->nchmaps, sizeof(*snd->chmaps), ++ snd->chmaps); ++ if (rc) ++ return rc; ++ ++ /* Count the number of channel maps per each PCM device/stream. */ ++ for (i = 0; i < snd->nchmaps; ++i) { ++ struct virtio_snd_chmap_info *info = &snd->chmaps[i]; ++ u32 nid = le32_to_cpu(info->hdr.hda_fn_nid); ++ struct virtio_pcm *vpcm; ++ struct virtio_pcm_stream *vs; ++ ++ vpcm = virtsnd_pcm_find_or_create(snd, nid); ++ if (IS_ERR(vpcm)) ++ return PTR_ERR(vpcm); ++ ++ switch (info->direction) { ++ case VIRTIO_SND_D_OUTPUT: ++ vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; ++ break; ++ case VIRTIO_SND_D_INPUT: ++ vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE]; ++ break; ++ default: ++ dev_err(&vdev->dev, ++ "chmap #%u: unknown direction (%u)\n", i, ++ info->direction); ++ return -EINVAL; ++ } ++ ++ vs->nchmaps++; ++ } ++ ++ return 0; ++} ++ ++/** ++ * virtsnd_chmap_add_ctls() - Create an ALSA control for channel maps. ++ * @pcm: ALSA PCM device. ++ * @direction: PCM stream direction (SNDRV_PCM_STREAM_XXX). ++ * @vs: VirtIO PCM stream. ++ * ++ * Context: Any context. ++ * Return: 0 on success, -errno on failure. ++ */ ++static int virtsnd_chmap_add_ctls(struct snd_pcm *pcm, int direction, ++ struct virtio_pcm_stream *vs) ++{ ++ u32 i; ++ int max_channels = 0; ++ ++ for (i = 0; i < vs->nchmaps; i++) ++ if (max_channels < vs->chmaps[i].channels) ++ max_channels = vs->chmaps[i].channels; ++ ++ return snd_pcm_add_chmap_ctls(pcm, direction, vs->chmaps, max_channels, ++ 0, NULL); ++} ++ ++/** ++ * virtsnd_chmap_build_devs() - Build ALSA controls for channel maps. ++ * @snd: VirtIO sound device. ++ * ++ * Context: Any context. ++ * Return: 0 on success, -errno on failure. ++ */ ++int virtsnd_chmap_build_devs(struct virtio_snd *snd) ++{ ++ struct virtio_device *vdev = snd->vdev; ++ struct virtio_pcm *vpcm; ++ struct virtio_pcm_stream *vs; ++ u32 i; ++ int rc; ++ ++ /* Allocate channel map elements per each PCM device/stream. */ ++ list_for_each_entry(vpcm, &snd->pcm_list, list) { ++ for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { ++ vs = &vpcm->streams[i]; ++ ++ if (!vs->nchmaps) ++ continue; ++ ++ vs->chmaps = devm_kcalloc(&vdev->dev, vs->nchmaps + 1, ++ sizeof(*vs->chmaps), ++ GFP_KERNEL); ++ if (!vs->chmaps) ++ return -ENOMEM; ++ ++ vs->nchmaps = 0; ++ } ++ } ++ ++ /* Initialize channel maps per each PCM device/stream. */ ++ for (i = 0; i < snd->nchmaps; ++i) { ++ struct virtio_snd_chmap_info *info = &snd->chmaps[i]; ++ unsigned int channels = info->channels; ++ unsigned int ch; ++ struct snd_pcm_chmap_elem *chmap; ++ ++ vpcm = virtsnd_pcm_find(snd, le32_to_cpu(info->hdr.hda_fn_nid)); ++ if (IS_ERR(vpcm)) ++ return PTR_ERR(vpcm); ++ ++ if (info->direction == VIRTIO_SND_D_OUTPUT) ++ vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; ++ else ++ vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE]; ++ ++ chmap = &vs->chmaps[vs->nchmaps++]; ++ ++ if (channels > ARRAY_SIZE(chmap->map)) ++ channels = ARRAY_SIZE(chmap->map); ++ ++ chmap->channels = channels; ++ ++ for (ch = 0; ch < channels; ++ch) { ++ u8 position = info->positions[ch]; ++ ++ if (position >= ARRAY_SIZE(g_v2a_position_map)) ++ return -EINVAL; ++ ++ chmap->map[ch] = g_v2a_position_map[position]; ++ } ++ } ++ ++ /* Create an ALSA control per each PCM device/stream. */ ++ list_for_each_entry(vpcm, &snd->pcm_list, list) { ++ if (!vpcm->pcm) ++ continue; ++ ++ for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { ++ vs = &vpcm->streams[i]; ++ ++ if (!vs->nchmaps) ++ continue; ++ ++ rc = virtsnd_chmap_add_ctls(vpcm->pcm, i, vs); ++ if (rc) ++ return rc; ++ } ++ } ++ ++ return 0; ++} +diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h +index efd0228746cf..1353fdc9bd69 100644 +--- a/sound/virtio/virtio_pcm.h ++++ b/sound/virtio/virtio_pcm.h +@@ -63,10 +63,14 @@ struct virtio_pcm_substream { + * struct virtio_pcm_stream - VirtIO PCM stream. + * @substreams: VirtIO substreams belonging to the stream. + * @nsubstreams: Number of substreams. ++ * @chmaps: Kernel channel maps belonging to the stream. ++ * @nchmaps: Number of channel maps. + */ + struct virtio_pcm_stream { + struct virtio_pcm_substream **substreams; + u32 nsubstreams; ++ struct snd_pcm_chmap_elem *chmaps; ++ u32 nchmaps; + }; + + /** |