return ret;
}
+static int q6usb_get_pcm_id_from_widget(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *dai;
+
+ for_each_card_rtds(w->dapm->card, rtd) {
+ dai = snd_soc_rtd_to_cpu(rtd, 0);
+ /*
+ * Only look for playback widget. RTD number carries the assigned
+ * PCM index.
+ */
+ if (dai->stream[0].widget == w)
+ return rtd->id;
+ }
+
+ return -1;
+}
+
+static int q6usb_usb_mixer_enabled(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+
+ /* Checks to ensure USB path is enabled/connected */
+ snd_soc_dapm_widget_for_each_sink_path(w, p)
+ if (!strcmp(p->sink->name, "USB Mixer") && p->connect)
+ return 1;
+
+ return 0;
+}
+
+static int q6usb_get_pcm_id(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_path *p;
+ int pidx;
+
+ /*
+ * Traverse widgets to find corresponding FE widget. The DAI links are
+ * built like the following:
+ * MultiMedia* <-> MM_DL* <-> USB Mixer*
+ */
+ for_each_card_widgets(component->card, w) {
+ if (!strncmp(w->name, "MultiMedia", 10)) {
+ /*
+ * Look up all paths associated with the FE widget to see if
+ * the USB BE is enabled. The sink widget is responsible to
+ * link with the USB mixers.
+ */
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (q6usb_usb_mixer_enabled(p->sink)) {
+ pidx = q6usb_get_pcm_id_from_widget(w);
+ return pidx;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int q6usb_update_offload_route(struct snd_soc_component *component, int card,
+ int pcm, int direction, enum snd_soc_usb_kctl path,
+ long *route)
+{
+ struct q6usb_port_data *data = dev_get_drvdata(component->dev);
+ struct snd_soc_usb_device *sdev;
+ int ret = 0;
+ int idx = -1;
+
+ mutex_lock(&data->mutex);
+
+ if (list_empty(&data->devices) ||
+ direction == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ sdev = list_last_entry(&data->devices, struct snd_soc_usb_device, list);
+
+ /*
+ * Will always look for last PCM device discovered/probed as the
+ * active offload index.
+ */
+ if (card == sdev->card_idx &&
+ pcm == sdev->ppcm_idx[sdev->num_playback - 1]) {
+ idx = path == SND_SOC_USB_KCTL_CARD_ROUTE ?
+ component->card->snd_card->number :
+ q6usb_get_pcm_id(component);
+ }
+
+out:
+ route[0] = idx;
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
static int q6usb_alsa_connection_cb(struct snd_soc_usb *usb,
struct snd_soc_usb_device *sdev, bool connected)
{
return -ENOMEM;
usb->connection_status_cb = q6usb_alsa_connection_cb;
+ usb->update_offload_route_info = q6usb_update_offload_route;
snd_soc_usb_add_port(usb);
data->usb = usb;