sound fixes for 4.14

The amount of the changes isn't as quite small as wished, nevertheless
 they are straight fixes that deserve merging to 4.14 final.
 
 Most of fixes are about ALSA core bugs spotted by fuzzer: a follow-up
 fix for the previous nested rwsem patch, a fix to avoid the resource
 hogs due to too many concurrent ALSA timer invocations, and a fix for
 a crash with SYSEX MIDI transfer over OSS sequencer emulation that is
 used by none but fuzzer.
 
 The rest are usual HD-audio and USB-audio device-specific quirks,
 which are safe to apply.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEECxfAB4MH3rD5mfB6bDGAVD0pKaQFAloEM2wOHHRpd2FpQHN1
 c2UuZGUACgkQbDGAVD0pKaTBhA//RLxylDxyZ/OPOpvCIcF9pPhZdt5Ep16h5bFd
 fr/AmipflVkba6K7auT5JpcwBC+w+24VN2G8huUTZ+HAH1lVVqiSs+XZYw2sHlOi
 uL/DZ0pEVN8412UH/7Iu4vYeiz/XRzd1YtGQkFI4KKrwm10Vz2sR6JHgvLh30/Zz
 pyZrMSsu29yrT1R4l0zI5abEBs23n7vYpi9vsKInP44UkGZwi5iKPH0ThTrCJ92A
 uKOAhIJkGZk0q9GCWnVhe/NWF6t0YK7c4FWqTgXOmIdDpGfylwdjdAsFAFG/cs4x
 n4pZiwO3seFH+6fr4fc0esNqN/adj+15YEyzUmt12ctLKLEELFhJowT9Grnz1Zoq
 jswfkXMJIWdqHQ3YBxlhs4Q8ZM7fDXf/gYqsOIRolxy6dtrJ1SLVjJkhtYWx/T+V
 P++ftn9CQneji1/wqAqUw4HVyc+36rLYK60GKDVtrTCigyilCrq84Yj8W0qAqKJD
 /CK77d1NKdVZ4do+GpzXjwpwNs6LzjSjqkNH2hdDG4gBNoILxxo9GNYSnjOiLxm4
 UCFA6SkD4vlq70VT3vn9YleFq2FzNADQ8jVgliyL1+4mF5baPXKHAdtGJA/HI7Nz
 23wf/1zIoOXd+GymaI20ke2EaVvTVVLDyvQSwFVspmSfu6MA0faGy8AUFJWCR8Nh
 heXgbu0=
 =Q2mh
 -----END PGP SIGNATURE-----

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

Pull sound fixes from Takashi Iwai:
 "The amount of the changes isn't as quite small as wished, nevertheless
  they are straight fixes that deserve merging to 4.14 final.

  Most of fixes are about ALSA core bugs spotted by fuzzer: a follow-up
  fix for the previous nested rwsem patch, a fix to avoid the resource
  hogs due to too many concurrent ALSA timer invocations, and a fix for
  a crash with SYSEX MIDI transfer over OSS sequencer emulation that is
  used by none but fuzzer.

  The rest are usual HD-audio and USB-audio device-specific quirks,
  which are safe to apply"

* tag 'sound-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda - fix headset mic problem for Dell machines with alc274
  ALSA: seq: Fix OSS sysex delivery in OSS emulation
  ALSA: seq: Avoid invalid lockdep class warning
  ALSA: timer: Limit max instances per timer
  ALSA: usb-audio: support new Amanero Combo384 firmware version
This commit is contained in:
Linus Torvalds 2017-11-09 09:58:11 -08:00
commit d93d4ce103
9 changed files with 97 additions and 17 deletions

View File

@ -49,7 +49,8 @@ typedef union snd_seq_timestamp snd_seq_timestamp_t;
#define SNDRV_SEQ_DEFAULT_CLIENT_EVENTS 200 #define SNDRV_SEQ_DEFAULT_CLIENT_EVENTS 200
/* max delivery path length */ /* max delivery path length */
#define SNDRV_SEQ_MAX_HOPS 10 /* NOTE: this shouldn't be greater than MAX_LOCKDEP_SUBCLASSES */
#define SNDRV_SEQ_MAX_HOPS 8
/* max size of event size */ /* max size of event size */
#define SNDRV_SEQ_MAX_EVENT_LEN 0x3fffffff #define SNDRV_SEQ_MAX_EVENT_LEN 0x3fffffff

View File

@ -90,6 +90,8 @@ struct snd_timer {
struct list_head ack_list_head; struct list_head ack_list_head;
struct list_head sack_list_head; /* slow ack list head */ struct list_head sack_list_head; /* slow ack list head */
struct tasklet_struct task_queue; struct tasklet_struct task_queue;
int max_instances; /* upper limit of timer instances */
int num_instances; /* current number of timer instances */
}; };
struct snd_timer_instance { struct snd_timer_instance {

View File

@ -159,6 +159,7 @@ static int __init snd_hrtimer_init(void)
timer->hw = hrtimer_hw; timer->hw = hrtimer_hw;
timer->hw.resolution = resolution; timer->hw.resolution = resolution;
timer->hw.ticks = NANO_SEC / resolution; timer->hw.ticks = NANO_SEC / resolution;
timer->max_instances = 100; /* lower the limit */
err = snd_timer_global_register(timer); err = snd_timer_global_register(timer);
if (err < 0) { if (err < 0) {

View File

@ -612,9 +612,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
if (!dp->timer->running) if (!dp->timer->running)
len = snd_seq_oss_timer_start(dp->timer); len = snd_seq_oss_timer_start(dp->timer);
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE) snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
ev->data.ext.ptr, ev->data.ext.len);
} else { } else {
len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev); len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
if (len > 0) if (len > 0)

View File

@ -117,6 +117,35 @@ snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, in
return 0; return 0;
} }
/*
* put MIDI sysex bytes; the event buffer may be chained, thus it has
* to be expanded via snd_seq_dump_var_event().
*/
struct readq_sysex_ctx {
struct seq_oss_readq *readq;
int dev;
};
static int readq_dump_sysex(void *ptr, void *buf, int count)
{
struct readq_sysex_ctx *ctx = ptr;
return snd_seq_oss_readq_puts(ctx->readq, ctx->dev, buf, count);
}
int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
struct snd_seq_event *ev)
{
struct readq_sysex_ctx ctx = {
.readq = q,
.dev = dev
};
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
return 0;
return snd_seq_dump_var_event(ev, readq_dump_sysex, &ctx);
}
/* /*
* copy an event to input queue: * copy an event to input queue:
* return zero if enqueued * return zero if enqueued

View File

@ -44,6 +44,8 @@ void snd_seq_oss_readq_delete(struct seq_oss_readq *q);
void snd_seq_oss_readq_clear(struct seq_oss_readq *readq); void snd_seq_oss_readq_clear(struct seq_oss_readq *readq);
unsigned int snd_seq_oss_readq_poll(struct seq_oss_readq *readq, struct file *file, poll_table *wait); unsigned int snd_seq_oss_readq_poll(struct seq_oss_readq *readq, struct file *file, poll_table *wait);
int snd_seq_oss_readq_puts(struct seq_oss_readq *readq, int dev, unsigned char *data, int len); int snd_seq_oss_readq_puts(struct seq_oss_readq *readq, int dev, unsigned char *data, int len);
int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
struct snd_seq_event *ev);
int snd_seq_oss_readq_put_event(struct seq_oss_readq *readq, union evrec *ev); int snd_seq_oss_readq_put_event(struct seq_oss_readq *readq, union evrec *ev);
int snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *readq, unsigned long curt, int seq_mode); int snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *readq, unsigned long curt, int seq_mode);
int snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec); int snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec);

View File

@ -180,7 +180,7 @@ static void snd_timer_request(struct snd_timer_id *tid)
* *
* call this with register_mutex down. * call this with register_mutex down.
*/ */
static void snd_timer_check_slave(struct snd_timer_instance *slave) static int snd_timer_check_slave(struct snd_timer_instance *slave)
{ {
struct snd_timer *timer; struct snd_timer *timer;
struct snd_timer_instance *master; struct snd_timer_instance *master;
@ -190,16 +190,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
list_for_each_entry(master, &timer->open_list_head, open_list) { list_for_each_entry(master, &timer->open_list_head, open_list) {
if (slave->slave_class == master->slave_class && if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) { slave->slave_id == master->slave_id) {
if (master->timer->num_instances >=
master->timer->max_instances)
return -EBUSY;
list_move_tail(&slave->open_list, list_move_tail(&slave->open_list,
&master->slave_list_head); &master->slave_list_head);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock); spin_lock_irq(&slave_active_lock);
slave->master = master; slave->master = master;
slave->timer = master->timer; slave->timer = master->timer;
spin_unlock_irq(&slave_active_lock); spin_unlock_irq(&slave_active_lock);
return; return 0;
} }
} }
} }
return 0;
} }
/* /*
@ -208,7 +213,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
* *
* call this with register_mutex down. * call this with register_mutex down.
*/ */
static void snd_timer_check_master(struct snd_timer_instance *master) static int snd_timer_check_master(struct snd_timer_instance *master)
{ {
struct snd_timer_instance *slave, *tmp; struct snd_timer_instance *slave, *tmp;
@ -216,7 +221,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
if (slave->slave_class == master->slave_class && if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) { slave->slave_id == master->slave_id) {
if (master->timer->num_instances >=
master->timer->max_instances)
return -EBUSY;
list_move_tail(&slave->open_list, &master->slave_list_head); list_move_tail(&slave->open_list, &master->slave_list_head);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock); spin_lock_irq(&slave_active_lock);
spin_lock(&master->timer->lock); spin_lock(&master->timer->lock);
slave->master = master; slave->master = master;
@ -228,8 +237,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
spin_unlock_irq(&slave_active_lock); spin_unlock_irq(&slave_active_lock);
} }
} }
return 0;
} }
static int snd_timer_close_locked(struct snd_timer_instance *timeri);
/* /*
* open a timer instance * open a timer instance
* when opening a master, the slave id must be here given. * when opening a master, the slave id must be here given.
@ -240,6 +252,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
{ {
struct snd_timer *timer; struct snd_timer *timer;
struct snd_timer_instance *timeri = NULL; struct snd_timer_instance *timeri = NULL;
int err;
if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
/* open a slave instance */ /* open a slave instance */
@ -259,10 +272,14 @@ int snd_timer_open(struct snd_timer_instance **ti,
timeri->slave_id = tid->device; timeri->slave_id = tid->device;
timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
list_add_tail(&timeri->open_list, &snd_timer_slave_list); list_add_tail(&timeri->open_list, &snd_timer_slave_list);
snd_timer_check_slave(timeri); err = snd_timer_check_slave(timeri);
if (err < 0) {
snd_timer_close_locked(timeri);
timeri = NULL;
}
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
*ti = timeri; *ti = timeri;
return 0; return err;
} }
/* open a master instance */ /* open a master instance */
@ -288,6 +305,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
return -EBUSY; return -EBUSY;
} }
} }
if (timer->num_instances >= timer->max_instances) {
mutex_unlock(&register_mutex);
return -EBUSY;
}
timeri = snd_timer_instance_new(owner, timer); timeri = snd_timer_instance_new(owner, timer);
if (!timeri) { if (!timeri) {
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
@ -314,25 +335,27 @@ int snd_timer_open(struct snd_timer_instance **ti,
} }
list_add_tail(&timeri->open_list, &timer->open_list_head); list_add_tail(&timeri->open_list, &timer->open_list_head);
snd_timer_check_master(timeri); timer->num_instances++;
err = snd_timer_check_master(timeri);
if (err < 0) {
snd_timer_close_locked(timeri);
timeri = NULL;
}
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
*ti = timeri; *ti = timeri;
return 0; return err;
} }
EXPORT_SYMBOL(snd_timer_open); EXPORT_SYMBOL(snd_timer_open);
/* /*
* close a timer instance * close a timer instance
* call this with register_mutex down.
*/ */
int snd_timer_close(struct snd_timer_instance *timeri) static int snd_timer_close_locked(struct snd_timer_instance *timeri)
{ {
struct snd_timer *timer = NULL; struct snd_timer *timer = NULL;
struct snd_timer_instance *slave, *tmp; struct snd_timer_instance *slave, *tmp;
if (snd_BUG_ON(!timeri))
return -ENXIO;
mutex_lock(&register_mutex);
list_del(&timeri->open_list); list_del(&timeri->open_list);
/* force to stop the timer */ /* force to stop the timer */
@ -340,6 +363,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
timer = timeri->timer; timer = timeri->timer;
if (timer) { if (timer) {
timer->num_instances--;
/* wait, until the active callback is finished */ /* wait, until the active callback is finished */
spin_lock_irq(&timer->lock); spin_lock_irq(&timer->lock);
while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@ -355,6 +379,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) { open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list); list_move_tail(&slave->open_list, &snd_timer_slave_list);
timer->num_instances--;
slave->master = NULL; slave->master = NULL;
slave->timer = NULL; slave->timer = NULL;
list_del_init(&slave->ack_list); list_del_init(&slave->ack_list);
@ -382,9 +407,24 @@ int snd_timer_close(struct snd_timer_instance *timeri)
module_put(timer->module); module_put(timer->module);
} }
mutex_unlock(&register_mutex);
return 0; return 0;
} }
/*
* close a timer instance
*/
int snd_timer_close(struct snd_timer_instance *timeri)
{
int err;
if (snd_BUG_ON(!timeri))
return -ENXIO;
mutex_lock(&register_mutex);
err = snd_timer_close_locked(timeri);
mutex_unlock(&register_mutex);
return err;
}
EXPORT_SYMBOL(snd_timer_close); EXPORT_SYMBOL(snd_timer_close);
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
@ -856,6 +896,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
spin_lock_init(&timer->lock); spin_lock_init(&timer->lock);
tasklet_init(&timer->task_queue, snd_timer_tasklet, tasklet_init(&timer->task_queue, snd_timer_tasklet,
(unsigned long)timer); (unsigned long)timer);
timer->max_instances = 1000; /* default limit per timer */
if (card != NULL) { if (card != NULL) {
timer->module = card->module; timer->module = card->module;
err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);

View File

@ -6544,6 +6544,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x14, 0x90170110}, {0x14, 0x90170110},
{0x1b, 0x90a70130}, {0x1b, 0x90a70130},
{0x21, 0x03211020}), {0x21, 0x03211020}),
SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0xb7a60130},
{0x13, 0xb8a61140},
{0x16, 0x90170110},
{0x21, 0x04211020}),
SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
{0x12, 0x90a60130}, {0x12, 0x90a60130},
{0x14, 0x90170110}, {0x14, 0x90170110},

View File

@ -1375,6 +1375,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
case 0x199: case 0x199:
return SNDRV_PCM_FMTBIT_DSD_U32_LE; return SNDRV_PCM_FMTBIT_DSD_U32_LE;
case 0x19b: case 0x19b:
case 0x203:
return SNDRV_PCM_FMTBIT_DSD_U32_BE; return SNDRV_PCM_FMTBIT_DSD_U32_BE;
default: default:
break; break;