sound fixes for 4.5-rc7

It's our tradition to get a high volume of fixes late at rc7: this
 time, X32 ABI breakage was found and this resulted in a high number
 LOCs.  The necessary changes to ALSA core codes were fairly
 straightforward, and more importantly, they are specific to X32, thus
 should be safe to apply.
 
 Other than that, rather a collection of small fixes:
 - Removal of the code that blocks too long at closing the OSS
   sequencer client (which was spotted by syzkaller, unsurprisingly)
 - Fixes races at HD-audio HDMI i915 audio binding
 - a few HDSP/HDPM zero-division fixes
 - Quirks for HD-audio and USB-audio as usual
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJW2yCGAAoJEGwxgFQ9KSmkijgQAJddLx3JVpuFS1xh1AxdnoY4
 DV/3nSHOWJ1e6MfBlkp8+V14AcuA/AG+iRUONkA6il2dGKW5oArpCwXoV14P3eK+
 hrMM1UtSikyiPdnzm2lKZVI2D/aZcrIgsUsBtX+tMunzaO8DhvPwblyL8bMbdbf9
 tflrZ0FfiDrt45tjCklUFEzdzqI3qmIg4vl/GMM7og5MnHnM/WaOaamq7Fi6CGar
 LujpGIQ2Loz82t7kbjAn3pOVY5IrHSihvYYNUQ4gke1rkZqY3e13CcZ8Z6y/aYkf
 yaaIgFbdklTpydukEAUaT0EQ2KSMrzAFwejrw3ywOtSivv/bi+sHb/tNFRgLNay9
 BR7Nz+Aw/8oQsnbkUI/FMmfdGNqldfzJ2ukyReFV5+k4E4hZtLsvUh/iPb9VaJ4p
 xD4Oiqi9cAYcL8MxgbwntlgHPraKovdGXlIdnmv0Jkl4/FOlVLJ3wWpSqYnWlhOo
 DqtrjahJTWGT0Gy7Mwg59hy+2CqDJ6YCa3iPwBTsOebIVOE6ZRxP1H3sQS8Phxjr
 uW9pRdcx+Y5tPbhOoJqqkAmL4cpkRrfQMfXqGGf+sKL24Yz/fevDl1F/qvcViyc1
 VWy/H4sTLSLoX4zfDd4fvg+2iCNGNVhou5Ixld9SLcZwFg2PF2a06RBH44WdV/Gq
 CwMyGnvN6omx0CUcnl05
 =6vCP
 -----END PGP SIGNATURE-----

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

Pull sound fixes from Takashi Iwai:
 "It's our tradition to get a high volume of fixes late at rc7: this
  time, X32 ABI breakage was found and this resulted in a high number
  LOCs.  The necessary changes to ALSA core codes were fairly
  straightforward, and more importantly, they are specific to X32, thus
  should be safe to apply.

  Other than that, rather a collection of small fixes:
   - Removal of the code that blocks too long at closing the OSS
     sequencer client (which was spotted by syzkaller, unsurprisingly)
   - Fixes races at HD-audio HDMI i915 audio binding
   - a few HDSP/HDPM zero-division fixes
   - Quirks for HD-audio and USB-audio as usual"

* tag 'sound-4.5-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda - hdmi defer to register acomp eld notifier
  ALSA: hda - hdmi add wmb barrier for audio component
  ALSA: hda - Fix mic issues on Acer Aspire E1-472
  ALSA: seq: oss: Don't drain at closing a client
  ALSA: usb-audio: Add a quirk for Plantronics DA45
  ALSA: hdsp: Fix wrong boolean ctl value accesses
  ALSA: hdspm: Fix zero-division
  ALSA: hdspm: Fix wrong boolean ctl value accesses
  ALSA: timer: Fix ioctls for X32 ABI
  ALSA: timer: Fix broken compat timer user status ioctl
  ALSA: rawmidi: Fix ioctls X32 ABI
  ALSA: rawmidi: Use comapt_put_timespec()
  ALSA: pcm: Fix ioctls for X32 ABI
  ALSA: ctl: Fix ioctls for X32 ABI
This commit is contained in:
Linus Torvalds 2016-03-05 12:35:48 -08:00
commit 67944024c1
12 changed files with 348 additions and 53 deletions

View file

@ -170,6 +170,19 @@ struct snd_ctl_elem_value32 {
unsigned char reserved[128]; unsigned char reserved[128];
}; };
#ifdef CONFIG_X86_X32
/* x32 has a different alignment for 64bit values from ia32 */
struct snd_ctl_elem_value_x32 {
struct snd_ctl_elem_id id;
unsigned int indirect; /* bit-field causes misalignment */
union {
s32 integer[128];
unsigned char data[512];
s64 integer64[64];
} value;
unsigned char reserved[128];
};
#endif /* CONFIG_X86_X32 */
/* get the value type and count of the control */ /* get the value type and count of the control */
static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
@ -219,9 +232,11 @@ static int get_elem_size(int type, int count)
static int copy_ctl_value_from_user(struct snd_card *card, static int copy_ctl_value_from_user(struct snd_card *card,
struct snd_ctl_elem_value *data, struct snd_ctl_elem_value *data,
struct snd_ctl_elem_value32 __user *data32, void __user *userdata,
void __user *valuep,
int *typep, int *countp) int *typep, int *countp)
{ {
struct snd_ctl_elem_value32 __user *data32 = userdata;
int i, type, size; int i, type, size;
int uninitialized_var(count); int uninitialized_var(count);
unsigned int indirect; unsigned int indirect;
@ -239,8 +254,9 @@ static int copy_ctl_value_from_user(struct snd_card *card,
if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
type == SNDRV_CTL_ELEM_TYPE_INTEGER) { type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val; int val;
if (get_user(val, &data32->value.integer[i])) if (get_user(val, &intp[i]))
return -EFAULT; return -EFAULT;
data->value.integer.value[i] = val; data->value.integer.value[i] = val;
} }
@ -250,8 +266,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL; return -EINVAL;
} }
if (copy_from_user(data->value.bytes.data, if (copy_from_user(data->value.bytes.data, valuep, size))
data32->value.data, size))
return -EFAULT; return -EFAULT;
} }
@ -261,7 +276,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
} }
/* restore the value to 32bit */ /* restore the value to 32bit */
static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, static int copy_ctl_value_to_user(void __user *userdata,
void __user *valuep,
struct snd_ctl_elem_value *data, struct snd_ctl_elem_value *data,
int type, int count) int type, int count)
{ {
@ -270,22 +286,22 @@ static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32,
if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
type == SNDRV_CTL_ELEM_TYPE_INTEGER) { type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val; int val;
val = data->value.integer.value[i]; val = data->value.integer.value[i];
if (put_user(val, &data32->value.integer[i])) if (put_user(val, &intp[i]))
return -EFAULT; return -EFAULT;
} }
} else { } else {
size = get_elem_size(type, count); size = get_elem_size(type, count);
if (copy_to_user(data32->value.data, if (copy_to_user(valuep, data->value.bytes.data, size))
data->value.bytes.data, size))
return -EFAULT; return -EFAULT;
} }
return 0; return 0;
} }
static int snd_ctl_elem_read_user_compat(struct snd_card *card, static int ctl_elem_read_user(struct snd_card *card,
struct snd_ctl_elem_value32 __user *data32) void __user *userdata, void __user *valuep)
{ {
struct snd_ctl_elem_value *data; struct snd_ctl_elem_value *data;
int err, type, count; int err, type, count;
@ -294,7 +310,9 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card,
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) err = copy_ctl_value_from_user(card, data, userdata, valuep,
&type, &count);
if (err < 0)
goto error; goto error;
snd_power_lock(card); snd_power_lock(card);
@ -303,14 +321,15 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card,
err = snd_ctl_elem_read(card, data); err = snd_ctl_elem_read(card, data);
snd_power_unlock(card); snd_power_unlock(card);
if (err >= 0) if (err >= 0)
err = copy_ctl_value_to_user(data32, data, type, count); err = copy_ctl_value_to_user(userdata, valuep, data,
type, count);
error: error:
kfree(data); kfree(data);
return err; return err;
} }
static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, static int ctl_elem_write_user(struct snd_ctl_file *file,
struct snd_ctl_elem_value32 __user *data32) void __user *userdata, void __user *valuep)
{ {
struct snd_ctl_elem_value *data; struct snd_ctl_elem_value *data;
struct snd_card *card = file->card; struct snd_card *card = file->card;
@ -320,7 +339,9 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) err = copy_ctl_value_from_user(card, data, userdata, valuep,
&type, &count);
if (err < 0)
goto error; goto error;
snd_power_lock(card); snd_power_lock(card);
@ -329,12 +350,39 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
err = snd_ctl_elem_write(card, file, data); err = snd_ctl_elem_write(card, file, data);
snd_power_unlock(card); snd_power_unlock(card);
if (err >= 0) if (err >= 0)
err = copy_ctl_value_to_user(data32, data, type, count); err = copy_ctl_value_to_user(userdata, valuep, data,
type, count);
error: error:
kfree(data); kfree(data);
return err; return err;
} }
static int snd_ctl_elem_read_user_compat(struct snd_card *card,
struct snd_ctl_elem_value32 __user *data32)
{
return ctl_elem_read_user(card, data32, &data32->value);
}
static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
struct snd_ctl_elem_value32 __user *data32)
{
return ctl_elem_write_user(file, data32, &data32->value);
}
#ifdef CONFIG_X86_X32
static int snd_ctl_elem_read_user_x32(struct snd_card *card,
struct snd_ctl_elem_value_x32 __user *data32)
{
return ctl_elem_read_user(card, data32, &data32->value);
}
static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file,
struct snd_ctl_elem_value_x32 __user *data32)
{
return ctl_elem_write_user(file, data32, &data32->value);
}
#endif /* CONFIG_X86_X32 */
/* add or replace a user control */ /* add or replace a user control */
static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
struct snd_ctl_elem_info32 __user *data32, struct snd_ctl_elem_info32 __user *data32,
@ -393,6 +441,10 @@ enum {
SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32),
SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32),
SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32),
#ifdef CONFIG_X86_X32
SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32),
SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32),
#endif /* CONFIG_X86_X32 */
}; };
static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@ -431,6 +483,12 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
return snd_ctl_elem_add_compat(ctl, argp, 0); return snd_ctl_elem_add_compat(ctl, argp, 0);
case SNDRV_CTL_IOCTL_ELEM_REPLACE32: case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
return snd_ctl_elem_add_compat(ctl, argp, 1); return snd_ctl_elem_add_compat(ctl, argp, 1);
#ifdef CONFIG_X86_X32
case SNDRV_CTL_IOCTL_ELEM_READ_X32:
return snd_ctl_elem_read_user_x32(ctl->card, argp);
case SNDRV_CTL_IOCTL_ELEM_WRITE_X32:
return snd_ctl_elem_write_user_x32(ctl, argp);
#endif /* CONFIG_X86_X32 */
} }
down_read(&snd_ioctl_rwsem); down_read(&snd_ioctl_rwsem);

View file

@ -183,6 +183,14 @@ static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream
return err; return err;
} }
#ifdef CONFIG_X86_X32
/* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */
static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info __user *src);
#define snd_pcm_ioctl_channel_info_x32(s, p) \
snd_pcm_channel_info_user(s, p)
#endif /* CONFIG_X86_X32 */
struct snd_pcm_status32 { struct snd_pcm_status32 {
s32 state; s32 state;
struct compat_timespec trigger_tstamp; struct compat_timespec trigger_tstamp;
@ -243,6 +251,71 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
return err; return err;
} }
#ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_pcm_status_x32 {
s32 state;
u32 rsvd; /* alignment */
struct timespec trigger_tstamp;
struct timespec tstamp;
u32 appl_ptr;
u32 hw_ptr;
s32 delay;
u32 avail;
u32 avail_max;
u32 overrange;
s32 suspended_state;
u32 audio_tstamp_data;
struct timespec audio_tstamp;
struct timespec driver_tstamp;
u32 audio_tstamp_accuracy;
unsigned char reserved[52-2*sizeof(struct timespec)];
} __packed;
#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
struct snd_pcm_status_x32 __user *src,
bool ext)
{
struct snd_pcm_status status;
int err;
memset(&status, 0, sizeof(status));
/*
* with extension, parameters are read/write,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
if (ext && get_user(status.audio_tstamp_data,
(u32 __user *)(&src->audio_tstamp_data)))
return -EFAULT;
err = snd_pcm_status(substream, &status);
if (err < 0)
return err;
if (clear_user(src, sizeof(*src)))
return -EFAULT;
if (put_user(status.state, &src->state) ||
put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
put_timespec(&status.tstamp, &src->tstamp) ||
put_user(status.appl_ptr, &src->appl_ptr) ||
put_user(status.hw_ptr, &src->hw_ptr) ||
put_user(status.delay, &src->delay) ||
put_user(status.avail, &src->avail) ||
put_user(status.avail_max, &src->avail_max) ||
put_user(status.overrange, &src->overrange) ||
put_user(status.suspended_state, &src->suspended_state) ||
put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
return -EFAULT;
return err;
}
#endif /* CONFIG_X86_X32 */
/* both for HW_PARAMS and HW_REFINE */ /* both for HW_PARAMS and HW_REFINE */
static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
int refine, int refine,
@ -469,6 +542,93 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
return 0; return 0;
} }
#ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_pcm_mmap_status_x32 {
s32 state;
s32 pad1;
u32 hw_ptr;
u32 pad2; /* alignment */
struct timespec tstamp;
s32 suspended_state;
struct timespec audio_tstamp;
} __packed;
struct snd_pcm_mmap_control_x32 {
u32 appl_ptr;
u32 avail_min;
};
struct snd_pcm_sync_ptr_x32 {
u32 flags;
u32 rsvd; /* alignment */
union {
struct snd_pcm_mmap_status_x32 status;
unsigned char reserved[64];
} s;
union {
struct snd_pcm_mmap_control_x32 control;
unsigned char reserved[64];
} c;
} __packed;
static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr_x32 __user *src)
{
struct snd_pcm_runtime *runtime = substream->runtime;
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
u32 sflags;
struct snd_pcm_mmap_control scontrol;
struct snd_pcm_mmap_status sstatus;
snd_pcm_uframes_t boundary;
int err;
if (snd_BUG_ON(!runtime))
return -EINVAL;
if (get_user(sflags, &src->flags) ||
get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
get_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
if (err < 0)
return err;
}
status = runtime->status;
control = runtime->control;
boundary = recalculate_boundary(runtime);
if (!boundary)
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) ||
put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
put_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
return 0;
}
#endif /* CONFIG_X86_X32 */
/* /*
*/ */
@ -487,7 +647,12 @@ enum {
SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32), SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32), SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32), SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
#ifdef CONFIG_X86_X32
SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32),
SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32),
SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
#endif /* CONFIG_X86_X32 */
}; };
static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@ -559,6 +724,16 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
return snd_pcm_ioctl_rewind_compat(substream, argp); return snd_pcm_ioctl_rewind_compat(substream, argp);
case SNDRV_PCM_IOCTL_FORWARD32: case SNDRV_PCM_IOCTL_FORWARD32:
return snd_pcm_ioctl_forward_compat(substream, argp); return snd_pcm_ioctl_forward_compat(substream, argp);
#ifdef CONFIG_X86_X32
case SNDRV_PCM_IOCTL_STATUS_X32:
return snd_pcm_status_user_x32(substream, argp, false);
case SNDRV_PCM_IOCTL_STATUS_EXT_X32:
return snd_pcm_status_user_x32(substream, argp, true);
case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
return snd_pcm_ioctl_channel_info_x32(substream, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;

View file

@ -85,8 +85,7 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
if (err < 0) if (err < 0)
return err; return err;
if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) || if (compat_put_timespec(&status.tstamp, &src->tstamp) ||
put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
put_user(status.avail, &src->avail) || put_user(status.avail, &src->avail) ||
put_user(status.xruns, &src->xruns)) put_user(status.xruns, &src->xruns))
return -EFAULT; return -EFAULT;
@ -94,9 +93,58 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
return 0; return 0;
} }
#ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_rawmidi_status_x32 {
s32 stream;
u32 rsvd; /* alignment */
struct timespec tstamp;
u32 avail;
u32 xruns;
unsigned char reserved[16];
} __attribute__((packed));
#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status_x32 __user *src)
{
int err;
struct snd_rawmidi_status status;
if (rfile->output == NULL)
return -EINVAL;
if (get_user(status.stream, &src->stream))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (put_timespec(&status.tstamp, &src->tstamp) ||
put_user(status.avail, &src->avail) ||
put_user(status.xruns, &src->xruns))
return -EFAULT;
return 0;
}
#endif /* CONFIG_X86_X32 */
enum { enum {
SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
#ifdef CONFIG_X86_X32
SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32),
#endif /* CONFIG_X86_X32 */
}; };
static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@ -115,6 +163,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign
return snd_rawmidi_ioctl_params_compat(rfile, argp); return snd_rawmidi_ioctl_params_compat(rfile, argp);
case SNDRV_RAWMIDI_IOCTL_STATUS32: case SNDRV_RAWMIDI_IOCTL_STATUS32:
return snd_rawmidi_ioctl_status_compat(rfile, argp); return snd_rawmidi_ioctl_status_compat(rfile, argp);
#ifdef CONFIG_X86_X32
case SNDRV_RAWMIDI_IOCTL_STATUS_X32:
return snd_rawmidi_ioctl_status_x32(rfile, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }

View file

@ -149,8 +149,6 @@ odev_release(struct inode *inode, struct file *file)
if ((dp = file->private_data) == NULL) if ((dp = file->private_data) == NULL)
return 0; return 0;
snd_seq_oss_drain_write(dp);
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
snd_seq_oss_release(dp); snd_seq_oss_release(dp);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);

View file

@ -127,7 +127,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co
unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait); unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait);
void snd_seq_oss_reset(struct seq_oss_devinfo *dp); void snd_seq_oss_reset(struct seq_oss_devinfo *dp);
void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp);
/* */ /* */
void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time);

View file

@ -435,22 +435,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp)
} }
/*
* Wait until the queue is empty (if we don't have nonblock)
*/
void
snd_seq_oss_drain_write(struct seq_oss_devinfo *dp)
{
if (! dp->timer->running)
return;
if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
dp->writeq) {
while (snd_seq_oss_writeq_sync(dp->writeq))
;
}
}
/* /*
* reset sequencer devices * reset sequencer devices
*/ */

View file

@ -70,13 +70,14 @@ static int snd_timer_user_status_compat(struct file *file,
struct snd_timer_status32 __user *_status) struct snd_timer_status32 __user *_status)
{ {
struct snd_timer_user *tu; struct snd_timer_user *tu;
struct snd_timer_status status; struct snd_timer_status32 status;
tu = file->private_data; tu = file->private_data;
if (snd_BUG_ON(!tu->timeri)) if (snd_BUG_ON(!tu->timeri))
return -ENXIO; return -ENXIO;
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp; status.tstamp.tv_sec = tu->tstamp.tv_sec;
status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
status.resolution = snd_timer_resolution(tu->timeri); status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost; status.lost = tu->timeri->lost;
status.overrun = tu->overrun; status.overrun = tu->overrun;
@ -88,12 +89,21 @@ static int snd_timer_user_status_compat(struct file *file,
return 0; return 0;
} }
#ifdef CONFIG_X86_X32
/* X32 ABI has the same struct as x86-64 */
#define snd_timer_user_status_x32(file, s) \
snd_timer_user_status(file, s)
#endif /* CONFIG_X86_X32 */
/* /*
*/ */
enum { enum {
SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
#ifdef CONFIG_X86_X32
SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status),
#endif /* CONFIG_X86_X32 */
}; };
static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@ -122,6 +132,10 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
return snd_timer_user_info_compat(file, argp); return snd_timer_user_info_compat(file, argp);
case SNDRV_TIMER_IOCTL_STATUS32: case SNDRV_TIMER_IOCTL_STATUS32:
return snd_timer_user_status_compat(file, argp); return snd_timer_user_status_compat(file, argp);
#ifdef CONFIG_X86_X32
case SNDRV_TIMER_IOCTL_STATUS_X32:
return snd_timer_user_status_x32(file, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }

View file

@ -2477,13 +2477,6 @@ static int patch_generic_hdmi(struct hda_codec *codec)
is_broxton(codec)) is_broxton(codec))
codec->core.link_power_control = 1; codec->core.link_power_control = 1;
if (codec_has_acomp(codec)) {
codec->depop_delay = 0;
spec->i915_audio_ops.audio_ptr = codec;
spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
}
if (hdmi_parse_codec(codec) < 0) { if (hdmi_parse_codec(codec) < 0) {
if (spec->i915_bound) if (spec->i915_bound)
snd_hdac_i915_exit(&codec->bus->core); snd_hdac_i915_exit(&codec->bus->core);
@ -2505,6 +2498,18 @@ static int patch_generic_hdmi(struct hda_codec *codec)
init_channel_allocations(); init_channel_allocations();
if (codec_has_acomp(codec)) {
codec->depop_delay = 0;
spec->i915_audio_ops.audio_ptr = codec;
/* intel_audio_codec_enable() or intel_audio_codec_disable()
* will call pin_eld_notify with using audio_ptr pointer
* We need make sure audio_ptr is really setup
*/
wmb();
spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
}
return 0; return 0;
} }

View file

@ -5412,6 +5412,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),

View file

@ -2879,7 +2879,7 @@ static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
{ {
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp); ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp);
return 0; return 0;
} }
@ -2891,7 +2891,7 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
if (!snd_hdsp_use_is_exclusive(hdsp)) if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY; return -EBUSY;
val = ucontrol->value.enumerated.item[0]; val = ucontrol->value.integer.value[0];
spin_lock_irq(&hdsp->lock); spin_lock_irq(&hdsp->lock);
if (val != hdsp_dds_offset(hdsp)) if (val != hdsp_dds_offset(hdsp))
change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0; change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;

View file

@ -1601,6 +1601,9 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
{ {
u64 n; u64 n;
if (snd_BUG_ON(rate <= 0))
return;
if (rate >= 112000) if (rate >= 112000)
rate /= 4; rate /= 4;
else if (rate >= 56000) else if (rate >= 56000)
@ -2215,6 +2218,8 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
} else { } else {
/* slave mode, return external sample rate */ /* slave mode, return external sample rate */
rate = hdspm_external_sample_rate(hdspm); rate = hdspm_external_sample_rate(hdspm);
if (!rate)
rate = hdspm->system_sample_rate;
} }
} }
@ -2260,8 +2265,11 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol,
ucontrol) ucontrol)
{ {
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
int rate = ucontrol->value.integer.value[0];
hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); if (rate < 27000 || rate > 207000)
return -EINVAL;
hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]);
return 0; return 0;
} }
@ -4449,7 +4457,7 @@ static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol,
{ {
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hdspm->tco->term; ucontrol->value.integer.value[0] = hdspm->tco->term;
return 0; return 0;
} }
@ -4460,8 +4468,8 @@ static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol,
{ {
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) { if (hdspm->tco->term != ucontrol->value.integer.value[0]) {
hdspm->tco->term = ucontrol->value.enumerated.item[0]; hdspm->tco->term = ucontrol->value.integer.value[0];
hdspm_tco_write(hdspm); hdspm_tco_write(hdspm);

View file

@ -1124,6 +1124,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */
case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */
case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */