Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d5c6ac6 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "sound: usb: Add helper APIs to enable audio stream" into msm-4.9

parents f7332276 9d9dac16
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -113,6 +113,71 @@ static DEFINE_MUTEX(register_mutex);
static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
static struct usb_driver usb_audio_driver;

struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num,
	unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio
	**uchip, void (*disconnect_cb)(struct snd_usb_audio *chip))
{
	int idx;
	struct snd_usb_stream *as;
	struct snd_usb_substream *subs = NULL;
	struct snd_usb_audio *chip = NULL;

	mutex_lock(&register_mutex);
	/*
	 * legacy audio snd card number assignment is dynamic. Hence
	 * search using chip->card->number
	 */
	for (idx = 0; idx < SNDRV_CARDS; idx++) {
		if (!usb_chip[idx])
			continue;
		if (usb_chip[idx]->card->number == card_num) {
			chip = usb_chip[idx];
			break;
		}
	}

	if (!chip || atomic_read(&chip->shutdown)) {
		pr_debug("%s: instance of usb crad # %d does not exist\n",
			__func__, card_num);
		goto err;
	}

	if (pcm_idx >= chip->pcm_devs) {
		pr_err("%s: invalid pcm dev number %u > %d\n", __func__,
			pcm_idx, chip->pcm_devs);
		goto err;
	}

	if (direction > SNDRV_PCM_STREAM_CAPTURE) {
		pr_err("%s: invalid direction %u\n", __func__, direction);
		goto err;
	}

	list_for_each_entry(as, &chip->pcm_list, list) {
		if (as->pcm_index == pcm_idx) {
			subs = &as->substream[direction];
			if (subs->interface < 0 && !subs->data_endpoint &&
				!subs->sync_endpoint) {
				pr_debug("%s: stream disconnected, bail out\n",
					__func__);
				subs = NULL;
				goto err;
			}
			goto done;
		}
	}

done:
	chip->card_num = card_num;
	chip->disconnect_cb = disconnect_cb;
err:
	*uchip = chip;
	if (!subs)
		pr_debug("%s: substream instance not found\n", __func__);
	mutex_unlock(&register_mutex);
	return subs;
}

/*
 * disconnect streams
 * called from usb_audio_disconnect()
@@ -693,6 +758,8 @@ static void usb_audio_disconnect(struct usb_interface *intf)
	if (chip->num_interfaces <= 0) {
		usb_chip[chip->index] = NULL;
		mutex_unlock(&register_mutex);
		if (chip->disconnect_cb)
			chip->disconnect_cb(chip);
		snd_card_free_when_closed(card);
	} else {
		mutex_unlock(&register_mutex);
+4 −0
Original line number Diff line number Diff line
@@ -167,4 +167,8 @@ struct snd_usb_stream {
	struct list_head list;
};

struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num,
	unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio
	**uchip, void (*disconnect_cb)(struct snd_usb_audio *chip));

#endif /* __USBAUDIO_CARD_H */
+64 −0
Original line number Diff line number Diff line
@@ -554,6 +554,70 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
	return 0;
}

int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
	bool enable)
{
	struct audioformat *fmt;
	struct usb_host_interface *alts;
	struct usb_interface *iface;
	int ret;

	if (!enable) {
		if (subs->interface >= 0) {
			usb_set_interface(subs->dev, subs->interface, 0);
			subs->altset_idx = 0;
			subs->interface = -1;
			subs->cur_audiofmt = NULL;
		}

		snd_usb_autosuspend(subs->stream->chip);
		return 0;
	}

	snd_usb_autoresume(subs->stream->chip);
	fmt = find_format(subs);
	if (!fmt) {
		dev_dbg(&subs->dev->dev,
		"cannot set format: format = %#x, rate = %d, channels = %d\n",
			   subs->pcm_format, subs->cur_rate, subs->channels);
		return -EINVAL;
	}

	subs->altset_idx = 0;
	subs->interface = -1;
	if (atomic_read(&subs->stream->chip->shutdown)) {
		ret = -ENODEV;
	} else {
		ret = set_format(subs, fmt);
		if (ret < 0)
			return ret;

		iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
		if (!iface) {
			dev_err(&subs->dev->dev, "Could not get iface %d\n",
				subs->cur_audiofmt->iface);
			return -ENODEV;
		}

		alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
		ret = snd_usb_init_sample_rate(subs->stream->chip,
					       subs->cur_audiofmt->iface,
					       alts,
					       subs->cur_audiofmt,
					       subs->cur_rate);
		if (ret < 0) {
			dev_err(&subs->dev->dev, "failed to set rate %d\n",
				subs->cur_rate);
			return ret;
		}
	}

	subs->interface = fmt->iface;
	subs->altset_idx = fmt->altset_idx;

	return 0;
}

/*
 * Return the score of matching two audioformats.
 * Veto the audioformat if:
+2 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
		       struct usb_host_interface *alts,
		       struct audioformat *fmt);

int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
	bool enable);

#endif /* __USBAUDIO_PCM_H */
+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ struct snd_usb_audio {
	bool autoclock;			/* from the 'autoclock' module param */

	struct usb_host_interface *ctrl_intf;	/* the audio control interface */
	int card_num;	/* cache pcm card number to use upon disconnect */
	void (*disconnect_cb)(struct snd_usb_audio *chip);
};

#define usb_audio_err(chip, fmt, args...) \