summaryrefslogtreecommitdiff
path: root/sound/usb
diff options
context:
space:
mode:
authorHemant Kumar <hemantk@codeaurora.org>2016-12-14 13:19:40 -0800
committerHemant Kumar <hemantk@codeaurora.org>2016-12-15 14:25:28 -0800
commitba3a6e254d432a06fb093862dcd8b5c21846b413 (patch)
tree25bc48a7228429a8d2695f9dc9aec4052d477302 /sound/usb
parenta80e267a8c0d61790c3d1d5f7181ebd1be39c438 (diff)
sound: usb: Handle audio control interface descriptor properly
usb audio qmi driver is incorrectly passing non-zero alternate interface related class specific buffer to parse the UAC header. This is causing driver to respond with incorrect bcdADC value. Fix this issue by reading the cached audio control interface context which is saved upon driver probe for the first audio interface. Also differentiate UAC version of header when type casting the UAC header descriptor. Change-Id: Ice62887451e91901cb16a6356b64f554b95eacc4 Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/usb_audio_qmi_svc.c38
1 files changed, 26 insertions, 12 deletions
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index 8ce87195548e..2cdf4901b8c7 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
#include <linux/uaccess.h>
#include <sound/pcm.h>
#include <sound/core.h>
@@ -76,6 +77,8 @@ struct intf_info {
struct uaudio_dev {
struct usb_device *udev;
+ /* audio control interface */
+ struct usb_host_interface *ctrl_intf;
unsigned int card_num;
atomic_t in_use;
struct kref kref;
@@ -400,8 +403,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
struct uac_format_type_i_discrete_descriptor *fmt_v1;
struct uac_format_type_i_ext_descriptor *fmt_v2;
struct uac1_as_header_descriptor *as;
- struct uac1_ac_header_descriptor *ac;
int protocol;
+ void *hdr_ptr;
u8 *xfer_buf;
u32 len, mult, remainder;
unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0,
@@ -436,6 +439,19 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
goto err;
}
+ if (!uadev[card_num].ctrl_intf) {
+ pr_err("%s: audio ctrl intf info not cached\n", __func__);
+ goto err;
+ }
+
+ hdr_ptr = snd_usb_find_csint_desc(uadev[card_num].ctrl_intf->extra,
+ uadev[card_num].ctrl_intf->extralen,
+ NULL, UAC_HEADER);
+ if (!hdr_ptr) {
+ pr_err("%s: no UAC_HEADER desc\n", __func__);
+ goto err;
+ }
+
if (protocol == UAC_VERSION_1) {
as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
UAC_AS_GENERAL);
@@ -449,26 +465,23 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
fmt_v1 = (struct uac_format_type_i_discrete_descriptor *)fmt;
resp->usb_audio_subslot_size = fmt_v1->bSubframeSize;
resp->usb_audio_subslot_size_valid = 1;
+
+ resp->usb_audio_spec_revision =
+ ((struct uac1_ac_header_descriptor *)hdr_ptr)->bcdADC;
+ resp->usb_audio_spec_revision_valid = 1;
} else if (protocol == UAC_VERSION_2) {
fmt_v2 = (struct uac_format_type_i_ext_descriptor *)fmt;
resp->usb_audio_subslot_size = fmt_v2->bSubslotSize;
resp->usb_audio_subslot_size_valid = 1;
+
+ resp->usb_audio_spec_revision =
+ ((struct uac2_ac_header_descriptor *)hdr_ptr)->bcdADC;
+ resp->usb_audio_spec_revision_valid = 1;
} else {
pr_err("%s: unknown protocol version %x\n", __func__, protocol);
goto err;
}
- ac = snd_usb_find_csint_desc(alts->extra,
- alts->extralen,
- NULL, UAC_HEADER);
- if (!ac) {
- pr_err("%s: %u:%d : no UAC_HEADER desc\n", __func__,
- subs->interface, subs->altset_idx);
- goto err;
- }
- resp->usb_audio_spec_revision = ac->bcdADC;
- resp->usb_audio_spec_revision_valid = 1;
-
resp->slot_id = subs->dev->slot_id;
resp->slot_id_valid = 1;
@@ -919,6 +932,7 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
subs->pcm_format = pcm_format;
subs->channels = req_msg->number_of_ch;
subs->cur_rate = req_msg->bit_rate;
+ uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf;
ret = snd_usb_enable_audio_stream(subs, req_msg->enable);