mixer_usb_offload.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/usb.h>
  6. #include <sound/core.h>
  7. #include <sound/control.h>
  8. #include <sound/soc-usb.h>
  9. #include "../usbaudio.h"
  10. #include "../card.h"
  11. #include "../helper.h"
  12. #include "../mixer.h"
  13. #include "mixer_usb_offload.h"
  14. #define PCM_IDX(n) ((n) & 0xffff)
  15. #define CARD_IDX(n) ((n) >> 16)
  16. static int
  17. snd_usb_offload_card_route_get(struct snd_kcontrol *kcontrol,
  18. struct snd_ctl_elem_value *ucontrol)
  19. {
  20. struct device *sysdev = snd_kcontrol_chip(kcontrol);
  21. int ret;
  22. ret = snd_soc_usb_update_offload_route(sysdev,
  23. CARD_IDX(kcontrol->private_value),
  24. PCM_IDX(kcontrol->private_value),
  25. SNDRV_PCM_STREAM_PLAYBACK,
  26. SND_SOC_USB_KCTL_CARD_ROUTE,
  27. ucontrol->value.integer.value);
  28. if (ret < 0) {
  29. ucontrol->value.integer.value[0] = -1;
  30. ucontrol->value.integer.value[1] = -1;
  31. }
  32. return 0;
  33. }
  34. static int snd_usb_offload_card_route_info(struct snd_kcontrol *kcontrol,
  35. struct snd_ctl_elem_info *uinfo)
  36. {
  37. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  38. uinfo->count = 1;
  39. uinfo->value.integer.min = -1;
  40. uinfo->value.integer.max = SNDRV_CARDS;
  41. return 0;
  42. }
  43. static struct snd_kcontrol_new snd_usb_offload_mapped_card_ctl = {
  44. .iface = SNDRV_CTL_ELEM_IFACE_CARD,
  45. .access = SNDRV_CTL_ELEM_ACCESS_READ,
  46. .info = snd_usb_offload_card_route_info,
  47. .get = snd_usb_offload_card_route_get,
  48. };
  49. static int
  50. snd_usb_offload_pcm_route_get(struct snd_kcontrol *kcontrol,
  51. struct snd_ctl_elem_value *ucontrol)
  52. {
  53. struct device *sysdev = snd_kcontrol_chip(kcontrol);
  54. int ret;
  55. ret = snd_soc_usb_update_offload_route(sysdev,
  56. CARD_IDX(kcontrol->private_value),
  57. PCM_IDX(kcontrol->private_value),
  58. SNDRV_PCM_STREAM_PLAYBACK,
  59. SND_SOC_USB_KCTL_PCM_ROUTE,
  60. ucontrol->value.integer.value);
  61. if (ret < 0) {
  62. ucontrol->value.integer.value[0] = -1;
  63. ucontrol->value.integer.value[1] = -1;
  64. }
  65. return 0;
  66. }
  67. static int snd_usb_offload_pcm_route_info(struct snd_kcontrol *kcontrol,
  68. struct snd_ctl_elem_info *uinfo)
  69. {
  70. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  71. uinfo->count = 1;
  72. uinfo->value.integer.min = -1;
  73. /* Arbitrary max value, as there is no 'limit' on number of PCM devices */
  74. uinfo->value.integer.max = 0xff;
  75. return 0;
  76. }
  77. static struct snd_kcontrol_new snd_usb_offload_mapped_pcm_ctl = {
  78. .iface = SNDRV_CTL_ELEM_IFACE_CARD,
  79. .access = SNDRV_CTL_ELEM_ACCESS_READ,
  80. .info = snd_usb_offload_pcm_route_info,
  81. .get = snd_usb_offload_pcm_route_get,
  82. };
  83. /**
  84. * snd_usb_offload_create_ctl() - Add USB offload bounded mixer
  85. * @chip: USB SND chip device
  86. * @bedev: Reference to USB backend DAI device
  87. *
  88. * Creates a sound control for a USB audio device, so that applications can
  89. * query for if there is an available USB audio offload path, and which
  90. * card is managing it.
  91. */
  92. int snd_usb_offload_create_ctl(struct snd_usb_audio *chip, struct device *bedev)
  93. {
  94. struct snd_kcontrol_new *chip_kctl;
  95. struct snd_usb_substream *subs;
  96. struct snd_usb_stream *as;
  97. char ctl_name[48];
  98. int ret;
  99. list_for_each_entry(as, &chip->pcm_list, list) {
  100. subs = &as->substream[SNDRV_PCM_STREAM_PLAYBACK];
  101. if (!subs->ep_num || as->pcm_index > 0xff)
  102. continue;
  103. chip_kctl = &snd_usb_offload_mapped_card_ctl;
  104. chip_kctl->count = 1;
  105. /*
  106. * Store the associated USB SND card number and PCM index for
  107. * the kctl.
  108. */
  109. chip_kctl->private_value = as->pcm_index |
  110. chip->card->number << 16;
  111. sprintf(ctl_name, "USB Offload Playback Card Route PCM#%d",
  112. as->pcm_index);
  113. chip_kctl->name = ctl_name;
  114. ret = snd_ctl_add(chip->card, snd_ctl_new1(chip_kctl, bedev));
  115. if (ret < 0)
  116. break;
  117. chip_kctl = &snd_usb_offload_mapped_pcm_ctl;
  118. chip_kctl->count = 1;
  119. /*
  120. * Store the associated USB SND card number and PCM index for
  121. * the kctl.
  122. */
  123. chip_kctl->private_value = as->pcm_index |
  124. chip->card->number << 16;
  125. sprintf(ctl_name, "USB Offload Playback PCM Route PCM#%d",
  126. as->pcm_index);
  127. chip_kctl->name = ctl_name;
  128. ret = snd_ctl_add(chip->card, snd_ctl_new1(chip_kctl, bedev));
  129. if (ret < 0)
  130. break;
  131. }
  132. return ret;
  133. }