Skip to content

Commit

Permalink
Merge tag 'sound-4.14' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/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
  • Loading branch information
torvalds committed Nov 9, 2017
2 parents d1041cd + 75ee94b commit d93d4ce
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 17 deletions.
3 changes: 2 additions & 1 deletion include/sound/seq_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ typedef union snd_seq_timestamp snd_seq_timestamp_t;
#define SNDRV_SEQ_DEFAULT_CLIENT_EVENTS 200

/* 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 */
#define SNDRV_SEQ_MAX_EVENT_LEN 0x3fffffff
Expand Down
2 changes: 2 additions & 0 deletions include/sound/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ struct snd_timer {
struct list_head ack_list_head;
struct list_head sack_list_head; /* slow ack list head */
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 {
Expand Down
1 change: 1 addition & 0 deletions sound/core/hrtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ static int __init snd_hrtimer_init(void)
timer->hw = hrtimer_hw;
timer->hw.resolution = resolution;
timer->hw.ticks = NANO_SEC / resolution;
timer->max_instances = 100; /* lower the limit */

err = snd_timer_global_register(timer);
if (err < 0) {
Expand Down
4 changes: 1 addition & 3 deletions sound/core/seq/oss/seq_oss_midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
if (!dp->timer->running)
len = snd_seq_oss_timer_start(dp->timer);
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
ev->data.ext.ptr, ev->data.ext.len);
snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
} else {
len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
if (len > 0)
Expand Down
29 changes: 29 additions & 0 deletions sound/core/seq/oss/seq_oss_readq.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,35 @@ snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, in
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:
* return zero if enqueued
Expand Down
2 changes: 2 additions & 0 deletions sound/core/seq/oss/seq_oss_readq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
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_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_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);
Expand Down
67 changes: 54 additions & 13 deletions sound/core/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ static void snd_timer_request(struct snd_timer_id *tid)
*
* 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_instance *master;
Expand All @@ -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) {
if (slave->slave_class == master->slave_class &&
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);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
spin_unlock_irq(&slave_active_lock);
return;
return 0;
}
}
}
return 0;
}

/*
Expand All @@ -208,15 +213,19 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
*
* 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;

/* check all pending slaves */
list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
if (slave->slave_class == master->slave_class &&
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);
master->timer->num_instances++;
spin_lock_irq(&slave_active_lock);
spin_lock(&master->timer->lock);
slave->master = master;
Expand All @@ -228,8 +237,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
spin_unlock_irq(&slave_active_lock);
}
}
return 0;
}

static int snd_timer_close_locked(struct snd_timer_instance *timeri);

/*
* open a timer instance
* when opening a master, the slave id must be here given.
Expand All @@ -240,6 +252,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
{
struct snd_timer *timer;
struct snd_timer_instance *timeri = NULL;
int err;

if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
/* open a slave instance */
Expand All @@ -259,10 +272,14 @@ int snd_timer_open(struct snd_timer_instance **ti,
timeri->slave_id = tid->device;
timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
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);
*ti = timeri;
return 0;
return err;
}

/* open a master instance */
Expand All @@ -288,6 +305,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
return -EBUSY;
}
}
if (timer->num_instances >= timer->max_instances) {
mutex_unlock(&register_mutex);
return -EBUSY;
}
timeri = snd_timer_instance_new(owner, timer);
if (!timeri) {
mutex_unlock(&register_mutex);
Expand All @@ -314,32 +335,35 @@ int snd_timer_open(struct snd_timer_instance **ti,
}

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);
*ti = timeri;
return 0;
return err;
}
EXPORT_SYMBOL(snd_timer_open);

/*
* 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_instance *slave, *tmp;

if (snd_BUG_ON(!timeri))
return -ENXIO;

mutex_lock(&register_mutex);
list_del(&timeri->open_list);

/* force to stop the timer */
snd_timer_stop(timeri);

timer = timeri->timer;
if (timer) {
timer->num_instances--;
/* wait, until the active callback is finished */
spin_lock_irq(&timer->lock);
while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
Expand All @@ -355,6 +379,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list);
timer->num_instances--;
slave->master = NULL;
slave->timer = NULL;
list_del_init(&slave->ack_list);
Expand Down Expand Up @@ -382,9 +407,24 @@ int snd_timer_close(struct snd_timer_instance *timeri)
module_put(timer->module);
}

mutex_unlock(&register_mutex);
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);

unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
Expand Down Expand Up @@ -856,6 +896,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
spin_lock_init(&timer->lock);
tasklet_init(&timer->task_queue, snd_timer_tasklet,
(unsigned long)timer);
timer->max_instances = 1000; /* default limit per timer */
if (card != NULL) {
timer->module = card->module;
err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
Expand Down
5 changes: 5 additions & 0 deletions sound/pci/hda/patch_realtek.c
Original file line number Diff line number Diff line change
Expand Up @@ -6544,6 +6544,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x14, 0x90170110},
{0x1b, 0x90a70130},
{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,
{0x12, 0x90a60130},
{0x14, 0x90170110},
Expand Down
1 change: 1 addition & 0 deletions sound/usb/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
case 0x199:
return SNDRV_PCM_FMTBIT_DSD_U32_LE;
case 0x19b:
case 0x203:
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
default:
break;
Expand Down

0 comments on commit d93d4ce

Please sign in to comment.