Merge branch 'for-linus' into for-next
Back-merge 5.7-rc devel branch for further changes. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Tento commit je obsažen v:
@@ -277,6 +277,52 @@ static bool s1810c_valid_sample_rate(struct audioformat *fp,
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Many Focusrite devices supports a limited set of sampling rates per
|
||||
* altsetting. Maximum rate is exposed in the last 4 bytes of Format Type
|
||||
* descriptor which has a non-standard bLength = 10.
|
||||
*/
|
||||
static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp,
|
||||
unsigned int rate)
|
||||
{
|
||||
struct usb_interface *iface;
|
||||
struct usb_host_interface *alts;
|
||||
unsigned char *fmt;
|
||||
unsigned int max_rate;
|
||||
|
||||
iface = usb_ifnum_to_if(chip->dev, fp->iface);
|
||||
if (!iface)
|
||||
return true;
|
||||
|
||||
alts = &iface->altsetting[fp->altset_idx];
|
||||
fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen,
|
||||
NULL, UAC_FORMAT_TYPE);
|
||||
if (!fmt)
|
||||
return true;
|
||||
|
||||
if (fmt[0] == 10) { /* bLength */
|
||||
max_rate = combine_quad(&fmt[6]);
|
||||
|
||||
/* Validate max rate */
|
||||
if (max_rate != 48000 &&
|
||||
max_rate != 96000 &&
|
||||
max_rate != 192000 &&
|
||||
max_rate != 384000) {
|
||||
|
||||
usb_audio_info(chip,
|
||||
"%u:%d : unexpected max rate: %u\n",
|
||||
fp->iface, fp->altsetting, max_rate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return rate <= max_rate;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to walk the array of sample rate triplets reported by
|
||||
* the device. The problem is that we need to parse whole array first to
|
||||
@@ -319,6 +365,11 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
|
||||
!s1810c_valid_sample_rate(fp, rate))
|
||||
goto skip_rate;
|
||||
|
||||
/* Filter out invalid rates on Focusrite devices */
|
||||
if (USB_ID_VENDOR(chip->usb_id) == 0x1235 &&
|
||||
!focusrite_valid_sample_rate(chip, fp, rate))
|
||||
goto skip_rate;
|
||||
|
||||
if (fp->rate_table)
|
||||
fp->rate_table[nr_rates] = rate;
|
||||
if (!fp->rate_min || rate < fp->rate_min)
|
||||
|
@@ -1776,8 +1776,10 @@ static void build_connector_control(struct usb_mixer_interface *mixer,
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
struct usb_mixer_elem_info *cval;
|
||||
const struct usbmix_name_map *map;
|
||||
|
||||
if (check_ignored_ctl(find_map(imap, term->id, 0)))
|
||||
map = find_map(imap, term->id, 0);
|
||||
if (check_ignored_ctl(map))
|
||||
return;
|
||||
|
||||
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
|
||||
@@ -1809,8 +1811,12 @@ static void build_connector_control(struct usb_mixer_interface *mixer,
|
||||
usb_mixer_elem_info_free(cval);
|
||||
return;
|
||||
}
|
||||
get_connector_control_name(mixer, term, is_input, kctl->id.name,
|
||||
sizeof(kctl->id.name));
|
||||
|
||||
if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)))
|
||||
strlcat(kctl->id.name, " Jack", sizeof(kctl->id.name));
|
||||
else
|
||||
get_connector_control_name(mixer, term, is_input, kctl->id.name,
|
||||
sizeof(kctl->id.name));
|
||||
kctl->private_free = snd_usb_mixer_elem_free;
|
||||
snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
}
|
||||
@@ -3111,6 +3117,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
|
||||
if (map->id == state.chip->usb_id) {
|
||||
state.map = map->map;
|
||||
state.selector_map = map->selector_map;
|
||||
mixer->connector_map = map->connector_map;
|
||||
mixer->ignore_ctl_error |= map->ignore_ctl_error;
|
||||
break;
|
||||
}
|
||||
@@ -3192,10 +3199,32 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delegate_notify(struct usb_mixer_interface *mixer, int unitid,
|
||||
u8 *control, u8 *channel)
|
||||
{
|
||||
const struct usbmix_connector_map *map = mixer->connector_map;
|
||||
|
||||
if (!map)
|
||||
return unitid;
|
||||
|
||||
for (; map->id; map++) {
|
||||
if (map->id == unitid) {
|
||||
if (control && map->control)
|
||||
*control = map->control;
|
||||
if (channel && map->channel)
|
||||
*channel = map->channel;
|
||||
return map->delegated_id;
|
||||
}
|
||||
}
|
||||
return unitid;
|
||||
}
|
||||
|
||||
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
|
||||
{
|
||||
struct usb_mixer_elem_list *list;
|
||||
|
||||
unitid = delegate_notify(mixer, unitid, NULL, NULL);
|
||||
|
||||
for_each_mixer_elem(list, mixer, unitid) {
|
||||
struct usb_mixer_elem_info *info =
|
||||
mixer_elem_list_to_info(list);
|
||||
@@ -3265,6 +3294,8 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
|
||||
return;
|
||||
}
|
||||
|
||||
unitid = delegate_notify(mixer, unitid, &control, &channel);
|
||||
|
||||
for_each_mixer_elem(list, mixer, unitid)
|
||||
count++;
|
||||
|
||||
|
@@ -6,6 +6,13 @@
|
||||
|
||||
struct media_mixer_ctl;
|
||||
|
||||
struct usbmix_connector_map {
|
||||
u8 id;
|
||||
u8 delegated_id;
|
||||
u8 control;
|
||||
u8 channel;
|
||||
};
|
||||
|
||||
struct usb_mixer_interface {
|
||||
struct snd_usb_audio *chip;
|
||||
struct usb_host_interface *hostif;
|
||||
@@ -18,6 +25,9 @@ struct usb_mixer_interface {
|
||||
/* the usb audio specification version this interface complies to */
|
||||
int protocol;
|
||||
|
||||
/* optional connector delegation map */
|
||||
const struct usbmix_connector_map *connector_map;
|
||||
|
||||
/* Sound Blaster remote control stuff */
|
||||
const struct rc_config *rc_cfg;
|
||||
u32 rc_code;
|
||||
|
@@ -27,6 +27,7 @@ struct usbmix_ctl_map {
|
||||
u32 id;
|
||||
const struct usbmix_name_map *map;
|
||||
const struct usbmix_selector_map *selector_map;
|
||||
const struct usbmix_connector_map *connector_map;
|
||||
int ignore_ctl_error;
|
||||
};
|
||||
|
||||
@@ -369,6 +370,33 @@ static const struct usbmix_name_map asus_rog_map[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
/* TRX40 mobos with Realtek ALC1220-VB */
|
||||
static const struct usbmix_name_map trx40_mobo_map[] = {
|
||||
{ 18, NULL }, /* OT, IEC958 - broken response, disabled */
|
||||
{ 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */
|
||||
{ 16, "Speaker" }, /* OT */
|
||||
{ 22, "Speaker Playback" }, /* FU */
|
||||
{ 7, "Line" }, /* IT */
|
||||
{ 19, "Line Capture" }, /* FU */
|
||||
{ 17, "Front Headphone" }, /* OT */
|
||||
{ 23, "Front Headphone Playback" }, /* FU */
|
||||
{ 8, "Mic" }, /* IT */
|
||||
{ 20, "Mic Capture" }, /* FU */
|
||||
{ 9, "Front Mic" }, /* IT */
|
||||
{ 21, "Front Mic Capture" }, /* FU */
|
||||
{ 24, "IEC958 Playback" }, /* FU */
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct usbmix_connector_map trx40_mobo_connector_map[] = {
|
||||
{ 10, 16 }, /* (Back) Speaker */
|
||||
{ 11, 17 }, /* Front Headphone */
|
||||
{ 13, 7 }, /* Line */
|
||||
{ 14, 8 }, /* Mic */
|
||||
{ 15, 9 }, /* Front Mic */
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Control map entries
|
||||
*/
|
||||
@@ -500,7 +528,8 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
},
|
||||
{ /* Gigabyte TRX40 Aorus Pro WiFi */
|
||||
.id = USB_ID(0x0414, 0xa002),
|
||||
.map = asus_rog_map,
|
||||
.map = trx40_mobo_map,
|
||||
.connector_map = trx40_mobo_connector_map,
|
||||
},
|
||||
{ /* ASUS ROG Zenith II */
|
||||
.id = USB_ID(0x0b05, 0x1916),
|
||||
@@ -512,11 +541,13 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
},
|
||||
{ /* MSI TRX40 Creator */
|
||||
.id = USB_ID(0x0db0, 0x0d64),
|
||||
.map = asus_rog_map,
|
||||
.map = trx40_mobo_map,
|
||||
.connector_map = trx40_mobo_connector_map,
|
||||
},
|
||||
{ /* MSI TRX40 */
|
||||
.id = USB_ID(0x0db0, 0x543d),
|
||||
.map = asus_rog_map,
|
||||
.map = trx40_mobo_map,
|
||||
.connector_map = trx40_mobo_connector_map,
|
||||
},
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
@@ -1509,11 +1509,15 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
|
||||
|
||||
/* use known values for that card: interface#1 altsetting#1 */
|
||||
iface = usb_ifnum_to_if(chip->dev, 1);
|
||||
if (!iface || iface->num_altsetting < 2)
|
||||
return -EINVAL;
|
||||
if (!iface || iface->num_altsetting < 2) {
|
||||
err = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
alts = &iface->altsetting[1];
|
||||
if (get_iface_desc(alts)->bNumEndpoints < 1)
|
||||
return -EINVAL;
|
||||
if (get_iface_desc(alts)->bNumEndpoints < 1) {
|
||||
err = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
ep = get_endpoint(alts, 0)->bEndpointAddress;
|
||||
|
||||
err = snd_usb_ctl_msg(chip->dev,
|
||||
|
@@ -2756,90 +2756,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.type = QUIRK_MIDI_NOVATION
|
||||
}
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Focusrite Scarlett Solo 2nd generation
|
||||
* Reports that playback should use Synch: Synchronous
|
||||
* while still providing a feedback endpoint. Synchronous causes
|
||||
* snapping on some sample rates.
|
||||
* Force it to use Synch: Asynchronous.
|
||||
*/
|
||||
USB_DEVICE(0x1235, 0x8205),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 2,
|
||||
.iface = 1,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = 0,
|
||||
.endpoint = 0x01,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC,
|
||||
.protocol = UAC_VERSION_2,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 192000,
|
||||
.nr_rates = 6,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000, 88200,
|
||||
96000, 176400, 192000
|
||||
},
|
||||
.clock = 41
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 2,
|
||||
.iface = 2,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = 0,
|
||||
.endpoint = 0x82,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC |
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
.protocol = UAC_VERSION_2,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 192000,
|
||||
.nr_rates = 6,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000, 88200,
|
||||
96000, 176400, 192000
|
||||
},
|
||||
.clock = 41
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Access Music devices */
|
||||
{
|
||||
@@ -3635,4 +3551,18 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
}
|
||||
},
|
||||
|
||||
#define ALC1220_VB_DESKTOP(vend, prod) { \
|
||||
USB_DEVICE(vend, prod), \
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
|
||||
.vendor_name = "Realtek", \
|
||||
.product_name = "ALC1220-VB-DT", \
|
||||
.profile_name = "Realtek-ALC1220-VB-Desktop", \
|
||||
.ifnum = QUIRK_NO_INTERFACE \
|
||||
} \
|
||||
}
|
||||
ALC1220_VB_DESKTOP(0x0414, 0xa002), /* Gigabyte TRX40 Aorus Pro WiFi */
|
||||
ALC1220_VB_DESKTOP(0x0db0, 0x0d64), /* MSI TRX40 Creator */
|
||||
ALC1220_VB_DESKTOP(0x0db0, 0x543d), /* MSI TRX40 */
|
||||
#undef ALC1220_VB_DESKTOP
|
||||
|
||||
#undef USB_DEVICE_VENDOR_SPEC
|
||||
|
@@ -1806,6 +1806,20 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
|
||||
*/
|
||||
fp->attributes &= ~UAC_EP_CS_ATTR_FILL_MAX;
|
||||
break;
|
||||
case USB_ID(0x1235, 0x8200): /* Focusrite Scarlett 2i4 2nd gen */
|
||||
case USB_ID(0x1235, 0x8202): /* Focusrite Scarlett 2i2 2nd gen */
|
||||
case USB_ID(0x1235, 0x8205): /* Focusrite Scarlett Solo 2nd gen */
|
||||
/*
|
||||
* Reports that playback should use Synch: Synchronous
|
||||
* while still providing a feedback endpoint.
|
||||
* Synchronous causes snapping on some sample rates.
|
||||
* Force it to use Synch: Asynchronous.
|
||||
*/
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
|
||||
fp->ep_attr |= USB_ENDPOINT_SYNC_ASYNC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -681,6 +681,8 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
|
||||
us->submitted = 2*NOOF_SETRATE_URBS;
|
||||
for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
|
||||
struct urb *urb = us->urb[i];
|
||||
if (!urb)
|
||||
continue;
|
||||
if (urb->status) {
|
||||
if (!err)
|
||||
err = -ENODEV;
|
||||
|
Odkázat v novém úkolu
Zablokovat Uživatele