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

Commit 90e4b68f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "sound: usb: Find alt setting using format and service interval" into msm-4.14

parents 442a734c a1f9bad3
Loading
Loading
Loading
Loading
+68 −2
Original line number Original line Diff line number Diff line
@@ -150,6 +150,69 @@ static struct audioformat *find_format(struct snd_usb_substream *subs)
	return found;
	return found;
}
}


/*
 * find a matching audio format as well as non-zero service interval
 */
static struct audioformat *find_format_and_si(struct snd_usb_substream *subs,
	unsigned int datainterval)
{
	unsigned int i;
	struct audioformat *fp;
	struct audioformat *found = NULL;
	int cur_attr = 0, attr;

	list_for_each_entry(fp, &subs->fmt_list, list) {
		if (datainterval != fp->datainterval)
			continue;
		if (!(fp->formats & pcm_format_to_bits(subs->pcm_format)))
			continue;
		if (fp->channels != subs->channels)
			continue;
		if (subs->cur_rate < fp->rate_min ||
		    subs->cur_rate > fp->rate_max)
			continue;
		if (!(fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
			for (i = 0; i < fp->nr_rates; i++)
				if (fp->rate_table[i] == subs->cur_rate)
					break;
			if (i >= fp->nr_rates)
				continue;
		}
		attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE;
		if (!found) {
			found = fp;
			cur_attr = attr;
			continue;
		}
		/* avoid async out and adaptive in if the other method
		 * supports the same format.
		 * this is a workaround for the case like
		 * M-audio audiophile USB.
		 */
		if (attr != cur_attr) {
			if ((attr == USB_ENDPOINT_SYNC_ASYNC &&
			     subs->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
			    (attr == USB_ENDPOINT_SYNC_ADAPTIVE &&
			     subs->direction == SNDRV_PCM_STREAM_CAPTURE))
				continue;
			if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC &&
			     subs->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
			    (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE &&
			     subs->direction == SNDRV_PCM_STREAM_CAPTURE)) {
				found = fp;
				cur_attr = attr;
				continue;
			}
		}
		/* find the format with the largest max. packet size */
		if (fp->maxpacksize > found->maxpacksize) {
			found = fp;
			cur_attr = attr;
		}
	}
	return found;
}

static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
			 struct usb_host_interface *alts,
			 struct usb_host_interface *alts,
			 struct audioformat *fmt)
			 struct audioformat *fmt)
@@ -574,7 +637,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
}
}


int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
	bool enable)
	int datainterval, bool enable)
{
{
	struct audioformat *fmt;
	struct audioformat *fmt;
	struct usb_host_interface *alts;
	struct usb_host_interface *alts;
@@ -594,6 +657,9 @@ int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
	}
	}


	snd_usb_autoresume(subs->stream->chip);
	snd_usb_autoresume(subs->stream->chip);
	if (datainterval != -EINVAL)
		fmt = find_format_and_si(subs, datainterval);
	else
		fmt = find_format(subs);
		fmt = find_format(subs);
	if (!fmt) {
	if (!fmt) {
		dev_err(&subs->dev->dev,
		dev_err(&subs->dev->dev,
+1 −1
Original line number Original line Diff line number Diff line
@@ -11,6 +11,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
		       struct usb_host_interface *alts,
		       struct usb_host_interface *alts,
		       struct audioformat *fmt);
		       struct audioformat *fmt);
int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
int snd_usb_enable_audio_stream(struct snd_usb_substream *subs,
	bool enable);
	int datainterval, bool enable);


#endif /* __USBAUDIO_PCM_H */
#endif /* __USBAUDIO_PCM_H */
+47 −3
Original line number Original line Diff line number Diff line
@@ -35,6 +35,10 @@
#include "pcm.h"
#include "pcm.h"
#include "usb_audio_qmi_v01.h"
#include "usb_audio_qmi_v01.h"


#define BUS_INTERVAL_FULL_SPEED 1000 /* in us */
#define BUS_INTERVAL_HIGHSPEED_AND_ABOVE 125 /* in us */
#define MAX_BINTERVAL_ISOC_EP 16

#define SND_PCM_CARD_NUM_MASK 0xffff0000
#define SND_PCM_CARD_NUM_MASK 0xffff0000
#define SND_PCM_DEV_NUM_MASK 0xff00
#define SND_PCM_DEV_NUM_MASK 0xff00
#define SND_PCM_STREAM_DIRECTION 0xff
#define SND_PCM_STREAM_DIRECTION 0xff
@@ -948,6 +952,32 @@ static int info_idx_from_ifnum(int card_num, int intf_num, bool enable)
	return -EINVAL;
	return -EINVAL;
}
}


static int get_data_interval_from_si(struct snd_usb_substream *subs,
	u32 service_interval)
{
	unsigned int bus_intval, bus_intval_mult, binterval;

	if (subs->dev->speed >= USB_SPEED_HIGH)
		bus_intval = BUS_INTERVAL_HIGHSPEED_AND_ABOVE;
	else
		bus_intval = BUS_INTERVAL_FULL_SPEED;

	if (service_interval % bus_intval)
		return -EINVAL;

	bus_intval_mult = service_interval / bus_intval;
	binterval = ffs(bus_intval_mult);
	if (!binterval || binterval > MAX_BINTERVAL_ISOC_EP)
		return -EINVAL;

	/* check if another bit is set then bail out */
	bus_intval_mult = bus_intval_mult >> binterval;
	if (bus_intval_mult)
		return -EINVAL;

	return (binterval - 1);
}

static void handle_uaudio_stream_req(struct qmi_handle *handle,
static void handle_uaudio_stream_req(struct qmi_handle *handle,
			struct sockaddr_qrtr *sq,
			struct sockaddr_qrtr *sq,
			struct qmi_txn *txn,
			struct qmi_txn *txn,
@@ -961,7 +991,7 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
	struct intf_info *info;
	struct intf_info *info;
	int pcm_format;
	int pcm_format;
	u8 pcm_card_num, pcm_dev_num, direction;
	u8 pcm_card_num, pcm_dev_num, direction;
	int info_idx = -EINVAL, ret = 0;
	int info_idx = -EINVAL, datainterval = -EINVAL, ret = 0;


	req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)decoded_msg;
	req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)decoded_msg;


@@ -1028,9 +1058,23 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
	subs->pcm_format = pcm_format;
	subs->pcm_format = pcm_format;
	subs->channels = req_msg->number_of_ch;
	subs->channels = req_msg->number_of_ch;
	subs->cur_rate = req_msg->bit_rate;
	subs->cur_rate = req_msg->bit_rate;
	if (req_msg->service_interval_valid) {
		ret = get_data_interval_from_si(subs,
						req_msg->service_interval);
		if (ret == -EINVAL) {
			pr_err("%s: invalid service interval %u\n", __func__,
					req_msg->service_interval);
			mutex_unlock(&chip->dev_lock);
			goto response;
		}

		datainterval = ret;
		pr_debug("%s: data interval %u\n", __func__, ret);
	}

	uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf;
	uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf;


	ret = snd_usb_enable_audio_stream(subs, req_msg->enable);
	ret = snd_usb_enable_audio_stream(subs, datainterval, req_msg->enable);


	if (!ret && req_msg->enable)
	if (!ret && req_msg->enable)
		ret = prepare_qmi_response(subs, req_msg, &resp, info_idx);
		ret = prepare_qmi_response(subs, req_msg, &resp, info_idx);
@@ -1097,7 +1141,7 @@ static void uaudio_qmi_disconnect_work(struct work_struct *w)
					info->direction);
					info->direction);
				continue;
				continue;
			}
			}
			snd_usb_enable_audio_stream(subs, 0);
			snd_usb_enable_audio_stream(subs, -EINVAL, 0);
		}
		}
		atomic_set(&uadev[idx].in_use, 0);
		atomic_set(&uadev[idx].in_use, 0);
		mutex_lock(&chip->dev_lock);
		mutex_lock(&chip->dev_lock);
+18 −0
Original line number Original line Diff line number Diff line
@@ -367,6 +367,24 @@ struct qmi_elem_info qmi_uaudio_stream_req_msg_v01_ei[] = {
		.offset         = offsetof(struct qmi_uaudio_stream_req_msg_v01,
		.offset         = offsetof(struct qmi_uaudio_stream_req_msg_v01,
					   xfer_buff_size),
					   xfer_buff_size),
	},
	},
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(uint8_t),
		.is_array       = NO_ARRAY,
		.tlv_type       = 0x14,
		.offset         = offsetof(struct qmi_uaudio_stream_req_msg_v01,
					   service_interval_valid),
	},
	{
		.data_type      = QMI_UNSIGNED_4_BYTE,
		.elem_len       = 1,
		.elem_size      = sizeof(uint32_t),
		.is_array       = NO_ARRAY,
		.tlv_type       = 0x14,
		.offset         = offsetof(struct qmi_uaudio_stream_req_msg_v01,
					   service_interval),
	},
	{
	{
		.data_type      = QMI_EOTI,
		.data_type      = QMI_EOTI,
		.is_array       = NO_ARRAY,
		.is_array       = NO_ARRAY,
+3 −1
Original line number Original line Diff line number Diff line
@@ -99,8 +99,10 @@ struct qmi_uaudio_stream_req_msg_v01 {
	uint32_t bit_rate;
	uint32_t bit_rate;
	uint8_t xfer_buff_size_valid;
	uint8_t xfer_buff_size_valid;
	uint32_t xfer_buff_size;
	uint32_t xfer_buff_size;
	uint8_t service_interval_valid;
	uint32_t service_interval;
};
};
#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 39
#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 46
extern struct qmi_elem_info qmi_uaudio_stream_req_msg_v01_ei[];
extern struct qmi_elem_info qmi_uaudio_stream_req_msg_v01_ei[];


struct qmi_uaudio_stream_resp_msg_v01 {
struct qmi_uaudio_stream_resp_msg_v01 {