[PATCH Fix for Kingston HyperX Amp (0951:16d8) 0/2 (Try #2)]
From: Chris Wulff crwulff@gmail.com
This patch set is modified to use an inline function for the mixer control interface lookup. The attempt at preventing modifications to a PCM that has previously been registered has been changed to defer registration instead, and has been split into a separate patch. This approach now works with pulseaudio.
From: Chris Wulff crwulff@gmail.com
Use the USB interface of the mixer that the control was created on instead of the default control interface.
This fixes the Kingston HyperX AMP (0951:16d8) which has controls on two interfaces.
Signed-off-by: Chris Wulff crwulff@gmail.com
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 81b2db0edd5f..93d7f4601751 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -292,6 +292,11 @@ static int uac2_ctl_value_size(int val_type) * retrieve a mixer value */
+static inline int mixer_ctrl_intf(struct usb_mixer_interface *mixer) +{ + return get_iface_desc(mixer->hostif)->bInterfaceNumber; +} + static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) { @@ -306,7 +311,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, return -EIO;
while (timeout-- > 0) { - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, val_len); @@ -354,7 +359,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, if (ret) goto error;
- idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, size); @@ -479,7 +484,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, return -EIO;
while (timeout-- > 0) { - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, @@ -1203,7 +1208,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { usb_audio_err(cval->head.mixer->chip, "%d:%d: cannot get min/max values for control %d (id %d)\n", - cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip), + cval->head.id, mixer_ctrl_intf(cval->head.mixer), cval->control, cval->head.id); return -EINVAL; } @@ -1422,7 +1427,7 @@ static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, if (ret) goto error;
- idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); if (cval->head.mixer->protocol == UAC_VERSION_2) { struct uac2_connectors_ctl_blk uac2_conn;
@@ -3203,7 +3208,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, list_for_each_entry(mixer, &chip->mixer_list, list) { snd_iprintf(buffer, "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n", - chip->usb_id, snd_usb_ctrl_intf(chip), + chip->usb_id, mixer_ctrl_intf(mixer), mixer->ignore_ctl_error); snd_iprintf(buffer, "Card: %s\n", chip->card->longname); for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
From: Chris Wulff crwulff@gmail.com
Create a quirk that allows special processing and/or skipping the call to snd_card_register.
For HyperX AMP, which uses two interfaces, but only has a capture stream in the second, this allows the capture stream to merge with the first PCM.
Signed-off-by: Chris Wulff crwulff@gmail.com
diff --git a/sound/usb/card.c b/sound/usb/card.c index 827fb0bc8b56..16bbe2a50fb7 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -662,10 +662,14 @@ static int usb_audio_probe(struct usb_interface *intf, goto __error; }
- /* we are allowed to call snd_card_register() many times */ - err = snd_card_register(chip->card); - if (err < 0) - goto __error; + /* we are allowed to call snd_card_register() many times, but first + * check to see if a device needs to skip it or do anything special + */ + if (snd_usb_registration_quirk(chip, ifnum) == 0) { + err = snd_card_register(chip->card); + if (err < 0) + goto __error; + }
if (quirk && quirk->shares_media_device) { /* don't want to fail when snd_media_device_create() fails */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 7f558f4b4520..c73da0721e30 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1756,3 +1756,17 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, break; } } + +int snd_usb_registration_quirk(struct snd_usb_audio *chip, + int iface) +{ + switch (chip->usb_id) { + case USB_ID(0x0951, 0x16d8): /* Kingston HyperX AMP */ + /* Register only when we reach interface 2 so that streams can + * merge correctly into PCMs from interface 0 + */ + return (iface != 2); + } + /* Register as normal */ + return 0; +} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index df0355843a4c..3afc01eabc7e 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -51,4 +51,7 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, struct audioformat *fp, int stream);
+int snd_usb_registration_quirk(struct snd_usb_audio *chip, + int iface); + #endif /* __USBAUDIO_QUIRKS_H */
On Sat, 14 Mar 2020 17:54:47 +0100, crwulff@gmail.com wrote:
From: Chris Wulff crwulff@gmail.com
This patch set is modified to use an inline function for the mixer control interface lookup. The attempt at preventing modifications to a PCM that has previously been registered has been changed to defer registration instead, and has been split into a separate patch. This approach now works with pulseaudio.
Thanks, it looks better now. I applied both patches with a slight modification of subject lines.
Takashi
participants (2)
-
crwulff@gmail.com
-
Takashi Iwai