Commit 0004654f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-5.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "A collection of small fixes as usual:

   - More coverage of USB-audio descriptor sanity checks

   - A fix for mute LED regression on Conexant HD-audio codecs

   - A few device-specific fixes and quirks for USB-audio and HD-audio

   - A fix for (die-hard remaining) possible race in sequencer core

   - FireWire oxfw regression fix that was introduced in 5.3-rc1"

* tag 'sound-5.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: oxfw: fix to handle correct stream for PCM playback
  ALSA: seq: Fix potential concurrent access to the deleted pool
  ALSA: usb-audio: Check mixer unit bitmap yet more strictly
  ALSA: line6: Fix memory leak at line6_init_pcm() error path
  ALSA: usb-audio: Fix invalid NULL check in snd_emuusb_set_samplerate()
  ALSA: hda/ca0132 - Add new SBZ quirk
  ALSA: usb-audio: Add implicit fb quirk for Behringer UFX1604
  ALSA: hda - Fixes inverted Conexant GPIO mic mute led
parents 452a0444 2fd23293
...@@ -1835,8 +1835,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client, ...@@ -1835,8 +1835,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
if (cptr->type == USER_CLIENT) { if (cptr->type == USER_CLIENT) {
info->input_pool = cptr->data.user.fifo_pool_size; info->input_pool = cptr->data.user.fifo_pool_size;
info->input_free = info->input_pool; info->input_free = info->input_pool;
if (cptr->data.user.fifo) info->input_free = snd_seq_fifo_unused_cells(cptr->data.user.fifo);
info->input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool);
} else { } else {
info->input_pool = 0; info->input_pool = 0;
info->input_free = 0; info->input_free = 0;
......
...@@ -263,3 +263,20 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) ...@@ -263,3 +263,20 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
return 0; return 0;
} }
/* get the number of unused cells safely */
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
{
unsigned long flags;
int cells;
if (!f)
return 0;
snd_use_lock_use(&f->use_lock);
spin_lock_irqsave(&f->lock, flags);
cells = snd_seq_unused_cells(f->pool);
spin_unlock_irqrestore(&f->lock, flags);
snd_use_lock_free(&f->use_lock);
return cells;
}
...@@ -53,5 +53,7 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file, poll_table ...@@ -53,5 +53,7 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file, poll_table
/* resize pool in fifo */ /* resize pool in fifo */
int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize); int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize);
/* get the number of unused cells safely */
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f);
#endif #endif
...@@ -248,7 +248,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, ...@@ -248,7 +248,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
unsigned int channels = params_channels(hw_params); unsigned int channels = params_channels(hw_params);
mutex_lock(&oxfw->mutex); mutex_lock(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream,
rate, channels); rate, channels);
if (err >= 0) if (err >= 0)
++oxfw->substreams_count; ++oxfw->substreams_count;
......
...@@ -1175,6 +1175,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = { ...@@ -1175,6 +1175,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE), SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE),
SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ), SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ),
SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ), SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ),
SND_PCI_QUIRK(0x1102, 0x0027, "Sound Blaster Z", QUIRK_SBZ),
SND_PCI_QUIRK(0x1102, 0x0033, "Sound Blaster ZxR", QUIRK_SBZ), SND_PCI_QUIRK(0x1102, 0x0033, "Sound Blaster ZxR", QUIRK_SBZ),
SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI), SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI), SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
......
...@@ -611,18 +611,20 @@ static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec, ...@@ -611,18 +611,20 @@ static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
/* update LED status via GPIO */ /* update LED status via GPIO */
static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask, static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
bool enabled) bool led_on)
{ {
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
unsigned int oldval = spec->gpio_led; unsigned int oldval = spec->gpio_led;
if (spec->mute_led_polarity) if (spec->mute_led_polarity)
enabled = !enabled; led_on = !led_on;
if (enabled) if (led_on)
spec->gpio_led &= ~mask;
else
spec->gpio_led |= mask; spec->gpio_led |= mask;
else
spec->gpio_led &= ~mask;
codec_dbg(codec, "mask:%d enabled:%d gpio_led:%d\n",
mask, led_on, spec->gpio_led);
if (spec->gpio_led != oldval) if (spec->gpio_led != oldval)
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led); spec->gpio_led);
...@@ -633,8 +635,8 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled) ...@@ -633,8 +635,8 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
{ {
struct hda_codec *codec = private_data; struct hda_codec *codec = private_data;
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
/* muted -> LED on */
cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled); cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, !enabled);
} }
/* turn on/off mic-mute LED via GPIO per capture hook */ /* turn on/off mic-mute LED via GPIO per capture hook */
...@@ -656,7 +658,6 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec, ...@@ -656,7 +658,6 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 }, { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
{} {}
}; };
codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led);
if (action == HDA_FIXUP_ACT_PRE_PROBE) { if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook; spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
......
...@@ -550,6 +550,15 @@ int line6_init_pcm(struct usb_line6 *line6, ...@@ -550,6 +550,15 @@ int line6_init_pcm(struct usb_line6 *line6,
line6pcm->volume_monitor = 255; line6pcm->volume_monitor = 255;
line6pcm->line6 = line6; line6pcm->line6 = line6;
spin_lock_init(&line6pcm->out.lock);
spin_lock_init(&line6pcm->in.lock);
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
line6->line6pcm = line6pcm;
pcm->private_data = line6pcm;
pcm->private_free = line6_cleanup_pcm;
line6pcm->max_packet_size_in = line6pcm->max_packet_size_in =
usb_maxpacket(line6->usbdev, usb_maxpacket(line6->usbdev,
usb_rcvisocpipe(line6->usbdev, ep_read), 0); usb_rcvisocpipe(line6->usbdev, ep_read), 0);
...@@ -562,15 +571,6 @@ int line6_init_pcm(struct usb_line6 *line6, ...@@ -562,15 +571,6 @@ int line6_init_pcm(struct usb_line6 *line6,
return -EINVAL; return -EINVAL;
} }
spin_lock_init(&line6pcm->out.lock);
spin_lock_init(&line6pcm->in.lock);
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
line6->line6pcm = line6pcm;
pcm->private_data = line6pcm;
pcm->private_free = line6_cleanup_pcm;
err = line6_create_audio_out_urbs(line6pcm); err = line6_create_audio_out_urbs(line6pcm);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -739,7 +739,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state, ...@@ -739,7 +739,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
struct uac_mixer_unit_descriptor *desc) struct uac_mixer_unit_descriptor *desc)
{ {
int mu_channels; int mu_channels;
void *c;
if (desc->bLength < sizeof(*desc)) if (desc->bLength < sizeof(*desc))
return -EINVAL; return -EINVAL;
...@@ -762,13 +761,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state, ...@@ -762,13 +761,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
break; break;
} }
if (!mu_channels)
return 0;
c = uac_mixer_unit_bmControls(desc, state->mixer->protocol);
if (c - (void *)desc + (mu_channels - 1) / 8 >= desc->bLength)
return 0; /* no bmControls -> skip */
return mu_channels; return mu_channels;
} }
...@@ -2009,6 +2001,31 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, ...@@ -2009,6 +2001,31 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
* Mixer Unit * Mixer Unit
*/ */
/* check whether the given in/out overflows bmMixerControls matrix */
static bool mixer_bitmap_overflow(struct uac_mixer_unit_descriptor *desc,
int protocol, int num_ins, int num_outs)
{
u8 *hdr = (u8 *)desc;
u8 *c = uac_mixer_unit_bmControls(desc, protocol);
size_t rest; /* remaining bytes after bmMixerControls */
switch (protocol) {
case UAC_VERSION_1:
default:
rest = 1; /* iMixer */
break;
case UAC_VERSION_2:
rest = 2; /* bmControls + iMixer */
break;
case UAC_VERSION_3:
rest = 6; /* bmControls + wMixerDescrStr */
break;
}
/* overflow? */
return c + (num_ins * num_outs + 7) / 8 + rest > hdr + hdr[0];
}
/* /*
* build a mixer unit control * build a mixer unit control
* *
...@@ -2137,6 +2154,9 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, ...@@ -2137,6 +2154,9 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
if (err < 0) if (err < 0)
return err; return err;
num_ins += iterm.channels; num_ins += iterm.channels;
if (mixer_bitmap_overflow(desc, state->mixer->protocol,
num_ins, num_outs))
break;
for (; ich < num_ins; ich++) { for (; ich < num_ins; ich++) {
int och, ich_has_controls = 0; int och, ich_has_controls = 0;
......
...@@ -1155,17 +1155,17 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, ...@@ -1155,17 +1155,17 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
{ {
struct usb_mixer_interface *mixer; struct usb_mixer_interface *mixer;
struct usb_mixer_elem_info *cval; struct usb_mixer_elem_info *cval;
int unitid = 12; /* SamleRate ExtensionUnit ID */ int unitid = 12; /* SampleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) { list_for_each_entry(mixer, &chip->mixer_list, list) {
cval = mixer_elem_list_to_info(mixer->id_elems[unitid]); if (mixer->id_elems[unitid]) {
if (cval) { cval = mixer_elem_list_to_info(mixer->id_elems[unitid]);
snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
cval->control << 8, cval->control << 8,
samplerate_id); samplerate_id);
snd_usb_mixer_notify_id(mixer, unitid); snd_usb_mixer_notify_id(mixer, unitid);
break;
} }
break;
} }
} }
......
...@@ -339,6 +339,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, ...@@ -339,6 +339,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
ep = 0x81; ep = 0x81;
ifnum = 2; ifnum = 2;
goto add_sync_ep_from_ifnum; goto add_sync_ep_from_ifnum;
case USB_ID(0x1397, 0x0001): /* Behringer UFX1604 */
case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */ case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */
ep = 0x81; ep = 0x81;
ifnum = 1; ifnum = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment