| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/usb.h>
- #include <sound/core.h>
- #include <sound/control.h>
- #include <sound/soc-usb.h>
- #include "../usbaudio.h"
- #include "../card.h"
- #include "../helper.h"
- #include "../mixer.h"
- #include "mixer_usb_offload.h"
- #define PCM_IDX(n) ((n) & 0xffff)
- #define CARD_IDX(n) ((n) >> 16)
- static int
- snd_usb_offload_card_route_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct device *sysdev = snd_kcontrol_chip(kcontrol);
- int ret;
- ret = snd_soc_usb_update_offload_route(sysdev,
- CARD_IDX(kcontrol->private_value),
- PCM_IDX(kcontrol->private_value),
- SNDRV_PCM_STREAM_PLAYBACK,
- SND_SOC_USB_KCTL_CARD_ROUTE,
- ucontrol->value.integer.value);
- if (ret < 0) {
- ucontrol->value.integer.value[0] = -1;
- ucontrol->value.integer.value[1] = -1;
- }
- return 0;
- }
- static int snd_usb_offload_card_route_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = -1;
- uinfo->value.integer.max = SNDRV_CARDS;
- return 0;
- }
- static struct snd_kcontrol_new snd_usb_offload_mapped_card_ctl = {
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .access = SNDRV_CTL_ELEM_ACCESS_READ,
- .info = snd_usb_offload_card_route_info,
- .get = snd_usb_offload_card_route_get,
- };
- static int
- snd_usb_offload_pcm_route_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct device *sysdev = snd_kcontrol_chip(kcontrol);
- int ret;
- ret = snd_soc_usb_update_offload_route(sysdev,
- CARD_IDX(kcontrol->private_value),
- PCM_IDX(kcontrol->private_value),
- SNDRV_PCM_STREAM_PLAYBACK,
- SND_SOC_USB_KCTL_PCM_ROUTE,
- ucontrol->value.integer.value);
- if (ret < 0) {
- ucontrol->value.integer.value[0] = -1;
- ucontrol->value.integer.value[1] = -1;
- }
- return 0;
- }
- static int snd_usb_offload_pcm_route_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = -1;
- /* Arbitrary max value, as there is no 'limit' on number of PCM devices */
- uinfo->value.integer.max = 0xff;
- return 0;
- }
- static struct snd_kcontrol_new snd_usb_offload_mapped_pcm_ctl = {
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .access = SNDRV_CTL_ELEM_ACCESS_READ,
- .info = snd_usb_offload_pcm_route_info,
- .get = snd_usb_offload_pcm_route_get,
- };
- /**
- * snd_usb_offload_create_ctl() - Add USB offload bounded mixer
- * @chip: USB SND chip device
- * @bedev: Reference to USB backend DAI device
- *
- * Creates a sound control for a USB audio device, so that applications can
- * query for if there is an available USB audio offload path, and which
- * card is managing it.
- */
- int snd_usb_offload_create_ctl(struct snd_usb_audio *chip, struct device *bedev)
- {
- struct snd_kcontrol_new *chip_kctl;
- struct snd_usb_substream *subs;
- struct snd_usb_stream *as;
- char ctl_name[48];
- int ret;
- list_for_each_entry(as, &chip->pcm_list, list) {
- subs = &as->substream[SNDRV_PCM_STREAM_PLAYBACK];
- if (!subs->ep_num || as->pcm_index > 0xff)
- continue;
- chip_kctl = &snd_usb_offload_mapped_card_ctl;
- chip_kctl->count = 1;
- /*
- * Store the associated USB SND card number and PCM index for
- * the kctl.
- */
- chip_kctl->private_value = as->pcm_index |
- chip->card->number << 16;
- sprintf(ctl_name, "USB Offload Playback Card Route PCM#%d",
- as->pcm_index);
- chip_kctl->name = ctl_name;
- ret = snd_ctl_add(chip->card, snd_ctl_new1(chip_kctl, bedev));
- if (ret < 0)
- break;
- chip_kctl = &snd_usb_offload_mapped_pcm_ctl;
- chip_kctl->count = 1;
- /*
- * Store the associated USB SND card number and PCM index for
- * the kctl.
- */
- chip_kctl->private_value = as->pcm_index |
- chip->card->number << 16;
- sprintf(ctl_name, "USB Offload Playback PCM Route PCM#%d",
- as->pcm_index);
- chip_kctl->name = ctl_name;
- ret = snd_ctl_add(chip->card, snd_ctl_new1(chip_kctl, bedev));
- if (ret < 0)
- break;
- }
- return ret;
- }
|