Merge branch 'for-next' into for-linus
This commit is contained in:
commit
4dda3a1914
|
@ -117,6 +117,10 @@ struct drm_audio_component {
|
|||
* @audio_ops: Ops implemented by hda driver, called by DRM driver
|
||||
*/
|
||||
const struct drm_audio_component_audio_ops *audio_ops;
|
||||
/**
|
||||
* @master_bind_complete: completion held during component master binding
|
||||
*/
|
||||
struct completion master_bind_complete;
|
||||
};
|
||||
|
||||
#endif /* _DRM_AUDIO_COMPONENT_H_ */
|
||||
|
|
|
@ -23,11 +23,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
|
|||
#define MASK_OFS(i) ((i) >> 5)
|
||||
#define MASK_BIT(i) (1U << ((i) & 31))
|
||||
|
||||
static inline size_t snd_mask_sizeof(void)
|
||||
{
|
||||
return sizeof(struct snd_mask);
|
||||
}
|
||||
|
||||
static inline void snd_mask_none(struct snd_mask *mask)
|
||||
{
|
||||
memset(mask, 0, sizeof(*mask));
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
#define SNDRV_TIMER_HW_STOP 0x00000002 /* call stop before start */
|
||||
#define SNDRV_TIMER_HW_SLAVE 0x00000004 /* only slave timer (variable resolution) */
|
||||
#define SNDRV_TIMER_HW_FIRST 0x00000008 /* first tick can be incomplete */
|
||||
#define SNDRV_TIMER_HW_TASKLET 0x00000010 /* timer is called from tasklet */
|
||||
#define SNDRV_TIMER_HW_WORK 0x00000010 /* timer is called from work */
|
||||
|
||||
#define SNDRV_TIMER_IFLG_SLAVE 0x00000001
|
||||
#define SNDRV_TIMER_IFLG_RUNNING 0x00000002
|
||||
#define SNDRV_TIMER_IFLG_START 0x00000004
|
||||
#define SNDRV_TIMER_IFLG_AUTO 0x00000008 /* auto restart */
|
||||
#define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use tasklet) */
|
||||
#define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use work) */
|
||||
#define SNDRV_TIMER_IFLG_CALLBACK 0x00000020 /* timer callback is active */
|
||||
#define SNDRV_TIMER_IFLG_EXCLUSIVE 0x00000040 /* exclusive owner - no more instances */
|
||||
#define SNDRV_TIMER_IFLG_EARLY_EVENT 0x00000080 /* write early event to the poll queue */
|
||||
|
@ -74,7 +74,7 @@ struct snd_timer {
|
|||
struct list_head active_list_head;
|
||||
struct list_head ack_list_head;
|
||||
struct list_head sack_list_head; /* slow ack list head */
|
||||
struct tasklet_struct task_queue;
|
||||
struct work_struct task_work;
|
||||
int max_instances; /* upper limit of timer instances */
|
||||
int num_instances; /* current number of timer instances */
|
||||
};
|
||||
|
@ -96,7 +96,7 @@ struct snd_timer_instance {
|
|||
unsigned long ticks; /* auto-load ticks when expired */
|
||||
unsigned long cticks; /* current ticks */
|
||||
unsigned long pticks; /* accumulated ticks for callback */
|
||||
unsigned long resolution; /* current resolution for tasklet */
|
||||
unsigned long resolution; /* current resolution for work */
|
||||
unsigned long lost; /* lost ticks */
|
||||
int slave_class;
|
||||
unsigned int slave_id;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
|
||||
*/
|
||||
|
||||
unsigned int snd_ac97_bus_scan_one(struct ac97_controller *ac97,
|
||||
unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,
|
||||
unsigned int codec_num);
|
||||
|
||||
static inline bool ac97_ids_match(unsigned int id1, unsigned int id2,
|
||||
|
|
|
@ -254,12 +254,11 @@ static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
|
|||
struct pcm_info *pi)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct completion done;
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
long timeout;
|
||||
|
||||
spin_lock_irqsave(&i2sdev->low_lock, flags);
|
||||
if (pi->dbdma_ring.stopping) {
|
||||
init_completion(&done);
|
||||
pi->stop_completion = &done;
|
||||
spin_unlock_irqrestore(&i2sdev->low_lock, flags);
|
||||
timeout = wait_for_completion_timeout(&done, HZ);
|
||||
|
|
|
@ -475,12 +475,12 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
|
|||
struct snd_pcm_runtime *runtime;
|
||||
int offset, next_period, block_size;
|
||||
dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
|
||||
casr & AC97C_CSR_OVRUN ? " OVRUN" : "",
|
||||
casr & AC97C_CSR_RXRDY ? " RXRDY" : "",
|
||||
casr & AC97C_CSR_UNRUN ? " UNRUN" : "",
|
||||
casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
|
||||
casr & AC97C_CSR_TXRDY ? " TXRDY" : "",
|
||||
!casr ? " NONE" : "");
|
||||
(casr & AC97C_CSR_OVRUN) ? " OVRUN" : "",
|
||||
(casr & AC97C_CSR_RXRDY) ? " RXRDY" : "",
|
||||
(casr & AC97C_CSR_UNRUN) ? " UNRUN" : "",
|
||||
(casr & AC97C_CSR_TXEMPTY) ? " TXEMPTY" : "",
|
||||
(casr & AC97C_CSR_TXRDY) ? " TXRDY" : "",
|
||||
!casr ? " NONE" : "");
|
||||
if ((casr & camr) & AC97C_CSR_ENDTX) {
|
||||
runtime = chip->playback_substream->runtime;
|
||||
block_size = frames_to_bytes(runtime, runtime->period_size);
|
||||
|
@ -521,11 +521,11 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
|
|||
|
||||
if (sr & AC97C_SR_COEVT) {
|
||||
dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
|
||||
cosr & AC97C_CSR_OVRUN ? " OVRUN" : "",
|
||||
cosr & AC97C_CSR_RXRDY ? " RXRDY" : "",
|
||||
cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
|
||||
cosr & AC97C_CSR_TXRDY ? " TXRDY" : "",
|
||||
!cosr ? " NONE" : "");
|
||||
(cosr & AC97C_CSR_OVRUN) ? " OVRUN" : "",
|
||||
(cosr & AC97C_CSR_RXRDY) ? " RXRDY" : "",
|
||||
(cosr & AC97C_CSR_TXEMPTY) ? " TXEMPTY" : "",
|
||||
(cosr & AC97C_CSR_TXRDY) ? " TXRDY" : "",
|
||||
!cosr ? " NONE" : "");
|
||||
retval = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -513,10 +513,11 @@ EXPORT_SYMBOL(snd_compr_malloc_pages);
|
|||
|
||||
int snd_compr_free_pages(struct snd_compr_stream *stream)
|
||||
{
|
||||
struct snd_compr_runtime *runtime = stream->runtime;
|
||||
struct snd_compr_runtime *runtime;
|
||||
|
||||
if (snd_BUG_ON(!(stream) || !(stream)->runtime))
|
||||
return -EINVAL;
|
||||
runtime = stream->runtime;
|
||||
if (runtime->dma_area == NULL)
|
||||
return 0;
|
||||
if (runtime->dma_buffer_p != &stream->dma_buffer) {
|
||||
|
@ -1031,7 +1032,7 @@ static const struct file_operations snd_compr_file_ops = {
|
|||
|
||||
static int snd_compress_dev_register(struct snd_device *device)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int ret;
|
||||
struct snd_compr *compr;
|
||||
|
||||
if (snd_BUG_ON(!device || !device->device_data))
|
||||
|
|
|
@ -150,14 +150,14 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
|
|||
return;
|
||||
if (card->shutdown)
|
||||
return;
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
read_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||||
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
|
||||
card->mixer_oss_change_count++;
|
||||
#endif
|
||||
list_for_each_entry(ctl, &card->ctl_files, list) {
|
||||
if (!ctl->subscribed)
|
||||
continue;
|
||||
spin_lock_irqsave(&ctl->read_lock, flags);
|
||||
spin_lock(&ctl->read_lock);
|
||||
list_for_each_entry(ev, &ctl->events, list) {
|
||||
if (ev->id.numid == id->numid) {
|
||||
ev->mask |= mask;
|
||||
|
@ -174,10 +174,10 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
|
|||
}
|
||||
_found:
|
||||
wake_up(&ctl->change_sleep);
|
||||
spin_unlock_irqrestore(&ctl->read_lock, flags);
|
||||
spin_unlock(&ctl->read_lock);
|
||||
kill_fasync(&ctl->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_notify);
|
||||
|
||||
|
@ -717,22 +717,19 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
|
|||
}
|
||||
|
||||
static int snd_ctl_elem_list(struct snd_card *card,
|
||||
struct snd_ctl_elem_list __user *_list)
|
||||
struct snd_ctl_elem_list *list)
|
||||
{
|
||||
struct snd_ctl_elem_list list;
|
||||
struct snd_kcontrol *kctl;
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int offset, space, jidx;
|
||||
int err = 0;
|
||||
|
||||
if (copy_from_user(&list, _list, sizeof(list)))
|
||||
return -EFAULT;
|
||||
offset = list.offset;
|
||||
space = list.space;
|
||||
offset = list->offset;
|
||||
space = list->space;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
list.count = card->controls_count;
|
||||
list.used = 0;
|
||||
list->count = card->controls_count;
|
||||
list->used = 0;
|
||||
if (space > 0) {
|
||||
list_for_each_entry(kctl, &card->controls, list) {
|
||||
if (offset >= kctl->count) {
|
||||
|
@ -741,12 +738,12 @@ static int snd_ctl_elem_list(struct snd_card *card,
|
|||
}
|
||||
for (jidx = offset; jidx < kctl->count; jidx++) {
|
||||
snd_ctl_build_ioff(&id, kctl, jidx);
|
||||
if (copy_to_user(list.pids + list.used, &id,
|
||||
if (copy_to_user(list->pids + list->used, &id,
|
||||
sizeof(id))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
list.used++;
|
||||
list->used++;
|
||||
if (!--space)
|
||||
goto out;
|
||||
}
|
||||
|
@ -755,11 +752,26 @@ static int snd_ctl_elem_list(struct snd_card *card,
|
|||
}
|
||||
out:
|
||||
up_read(&card->controls_rwsem);
|
||||
if (!err && copy_to_user(_list, &list, sizeof(list)))
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_list_user(struct snd_card *card,
|
||||
struct snd_ctl_elem_list __user *_list)
|
||||
{
|
||||
struct snd_ctl_elem_list list;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&list, _list, sizeof(list)))
|
||||
return -EFAULT;
|
||||
err = snd_ctl_elem_list(card, &list);
|
||||
if (err)
|
||||
return err;
|
||||
if (copy_to_user(_list, &list, sizeof(list)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check whether the given kctl info is valid */
|
||||
static int snd_ctl_check_elem_info(struct snd_card *card,
|
||||
const struct snd_ctl_elem_info *info)
|
||||
|
@ -1703,7 +1715,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
|||
case SNDRV_CTL_IOCTL_CARD_INFO:
|
||||
return snd_ctl_card_info(card, ctl, cmd, argp);
|
||||
case SNDRV_CTL_IOCTL_ELEM_LIST:
|
||||
return snd_ctl_elem_list(card, argp);
|
||||
return snd_ctl_elem_list_user(card, argp);
|
||||
case SNDRV_CTL_IOCTL_ELEM_INFO:
|
||||
return snd_ctl_elem_info_user(ctl, argp);
|
||||
case SNDRV_CTL_IOCTL_ELEM_READ:
|
||||
|
@ -1939,8 +1951,9 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
|
|||
{
|
||||
struct snd_ctl_file *kctl;
|
||||
int subdevice = -1;
|
||||
unsigned long flags;
|
||||
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
read_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||
if (kctl->pid == task_pid(current)) {
|
||||
subdevice = kctl->preferred_subdevice[type];
|
||||
|
@ -1948,7 +1961,7 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
|
|||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
||||
return subdevice;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
|
||||
|
@ -1997,13 +2010,14 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
|
|||
{
|
||||
struct snd_card *card = device->device_data;
|
||||
struct snd_ctl_file *ctl;
|
||||
unsigned long flags;
|
||||
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
read_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||||
list_for_each_entry(ctl, &card->ctl_files, list) {
|
||||
wake_up(&ctl->change_sleep);
|
||||
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
|
||||
}
|
||||
read_unlock(&card->ctl_files_rwlock);
|
||||
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
||||
|
||||
return snd_unregister_device(&card->ctl_dev);
|
||||
}
|
||||
|
|
|
@ -22,24 +22,22 @@ struct snd_ctl_elem_list32 {
|
|||
static int snd_ctl_elem_list_compat(struct snd_card *card,
|
||||
struct snd_ctl_elem_list32 __user *data32)
|
||||
{
|
||||
struct snd_ctl_elem_list __user *data;
|
||||
struct snd_ctl_elem_list data = {};
|
||||
compat_caddr_t ptr;
|
||||
int err;
|
||||
|
||||
data = compat_alloc_user_space(sizeof(*data));
|
||||
|
||||
/* offset, space, used, count */
|
||||
if (copy_in_user(data, data32, 4 * sizeof(u32)))
|
||||
if (copy_from_user(&data, data32, 4 * sizeof(u32)))
|
||||
return -EFAULT;
|
||||
/* pids */
|
||||
if (get_user(ptr, &data32->pids) ||
|
||||
put_user(compat_ptr(ptr), &data->pids))
|
||||
if (get_user(ptr, &data32->pids))
|
||||
return -EFAULT;
|
||||
err = snd_ctl_elem_list(card, data);
|
||||
data.pids = compat_ptr(ptr);
|
||||
err = snd_ctl_elem_list(card, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/* copy the result */
|
||||
if (copy_in_user(data32, data, 4 * sizeof(u32)))
|
||||
if (copy_to_user(data32, &data, 4 * sizeof(u32)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ static int snd_hrtimer_stop(struct snd_timer *t)
|
|||
}
|
||||
|
||||
static const struct snd_timer_hardware hrtimer_hw __initconst = {
|
||||
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET,
|
||||
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
|
||||
.open = snd_hrtimer_open,
|
||||
.close = snd_hrtimer_close,
|
||||
.start = snd_hrtimer_start,
|
||||
|
|
|
@ -203,28 +203,35 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw,
|
|||
}
|
||||
|
||||
static int snd_hwdep_dsp_load(struct snd_hwdep *hw,
|
||||
struct snd_hwdep_dsp_image __user *_info)
|
||||
struct snd_hwdep_dsp_image *info)
|
||||
{
|
||||
struct snd_hwdep_dsp_image info;
|
||||
int err;
|
||||
|
||||
if (! hw->ops.dsp_load)
|
||||
return -ENXIO;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (copy_from_user(&info, _info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
if (info.index >= 32)
|
||||
if (info->index >= 32)
|
||||
return -EINVAL;
|
||||
/* check whether the dsp was already loaded */
|
||||
if (hw->dsp_loaded & (1u << info.index))
|
||||
if (hw->dsp_loaded & (1u << info->index))
|
||||
return -EBUSY;
|
||||
err = hw->ops.dsp_load(hw, &info);
|
||||
err = hw->ops.dsp_load(hw, info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
hw->dsp_loaded |= (1u << info.index);
|
||||
hw->dsp_loaded |= (1u << info->index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_hwdep_dsp_load_user(struct snd_hwdep *hw,
|
||||
struct snd_hwdep_dsp_image __user *_info)
|
||||
{
|
||||
struct snd_hwdep_dsp_image info = {};
|
||||
|
||||
if (copy_from_user(&info, _info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
return snd_hwdep_dsp_load(hw, &info);
|
||||
}
|
||||
|
||||
|
||||
static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
|
@ -238,7 +245,7 @@ static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
|
|||
case SNDRV_HWDEP_IOCTL_DSP_STATUS:
|
||||
return snd_hwdep_dsp_status(hw, argp);
|
||||
case SNDRV_HWDEP_IOCTL_DSP_LOAD:
|
||||
return snd_hwdep_dsp_load(hw, argp);
|
||||
return snd_hwdep_dsp_load_user(hw, argp);
|
||||
}
|
||||
if (hw->ops.ioctl)
|
||||
return hw->ops.ioctl(hw, file, cmd, arg);
|
||||
|
|
|
@ -19,26 +19,17 @@ struct snd_hwdep_dsp_image32 {
|
|||
static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw,
|
||||
struct snd_hwdep_dsp_image32 __user *src)
|
||||
{
|
||||
struct snd_hwdep_dsp_image __user *dst;
|
||||
struct snd_hwdep_dsp_image info = {};
|
||||
compat_caddr_t ptr;
|
||||
u32 val;
|
||||
|
||||
dst = compat_alloc_user_space(sizeof(*dst));
|
||||
if (copy_from_user(&info, src, 4 + 64) ||
|
||||
get_user(ptr, &src->image) ||
|
||||
get_user(info.length, &src->length) ||
|
||||
get_user(info.driver_data, &src->driver_data))
|
||||
return -EFAULT;
|
||||
info.image = compat_ptr(ptr);
|
||||
|
||||
/* index and name */
|
||||
if (copy_in_user(dst, src, 4 + 64))
|
||||
return -EFAULT;
|
||||
if (get_user(ptr, &src->image) ||
|
||||
put_user(compat_ptr(ptr), &dst->image))
|
||||
return -EFAULT;
|
||||
if (get_user(val, &src->length) ||
|
||||
put_user(val, &dst->length))
|
||||
return -EFAULT;
|
||||
if (get_user(val, &src->driver_data) ||
|
||||
put_user(val, &dst->driver_data))
|
||||
return -EFAULT;
|
||||
|
||||
return snd_hwdep_dsp_load(hw, dst);
|
||||
return snd_hwdep_dsp_load(hw, &info);
|
||||
}
|
||||
|
||||
enum {
|
||||
|
|
|
@ -519,10 +519,9 @@ EXPORT_SYMBOL(snd_card_free_when_closed);
|
|||
*/
|
||||
int snd_card_free(struct snd_card *card)
|
||||
{
|
||||
struct completion released;
|
||||
DECLARE_COMPLETION_ONSTACK(released);
|
||||
int ret;
|
||||
|
||||
init_completion(&released);
|
||||
card->release_completion = &released;
|
||||
ret = snd_card_free_when_closed(card);
|
||||
if (ret)
|
||||
|
|
|
@ -157,8 +157,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
|
|||
* so if we fail to malloc, try to fetch memory traditionally.
|
||||
*/
|
||||
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
||||
fallthrough;
|
||||
#endif /* CONFIG_GENERIC_ALLOCATOR */
|
||||
case SNDRV_DMA_TYPE_DEV:
|
||||
case SNDRV_DMA_TYPE_DEV_UC:
|
||||
snd_malloc_dev_pages(dmab, size);
|
||||
|
|
|
@ -991,11 +991,13 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
|||
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
|
||||
kfree(runtime->hw_constraints.rules);
|
||||
/* Avoid concurrent access to runtime via PCM timer interface */
|
||||
if (substream->timer)
|
||||
if (substream->timer) {
|
||||
spin_lock_irq(&substream->timer->lock);
|
||||
substream->runtime = NULL;
|
||||
if (substream->timer)
|
||||
substream->runtime = NULL;
|
||||
spin_unlock_irq(&substream->timer->lock);
|
||||
} else {
|
||||
substream->runtime = NULL;
|
||||
}
|
||||
kfree(runtime);
|
||||
put_pid(substream->pid);
|
||||
substream->pid = NULL;
|
||||
|
|
|
@ -377,7 +377,7 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
|
|||
*/
|
||||
int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
|
||||
{
|
||||
struct snd_card *card = substream->pcm->card;
|
||||
struct snd_card *card;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct snd_dma_buffer *dmab = NULL;
|
||||
|
||||
|
@ -387,6 +387,7 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
|
|||
SNDRV_DMA_TYPE_UNKNOWN))
|
||||
return -EINVAL;
|
||||
runtime = substream->runtime;
|
||||
card = substream->pcm->card;
|
||||
|
||||
if (runtime->dma_buffer_p) {
|
||||
/* perphaps, we might free the large DMA memory region
|
||||
|
|
|
@ -35,7 +35,7 @@ module_param_array(amidi_map, int, NULL, 0444);
|
|||
MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
|
||||
#endif /* CONFIG_SND_OSSEMUL */
|
||||
|
||||
static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
|
||||
static int snd_rawmidi_free(struct snd_rawmidi *rmidi);
|
||||
static int snd_rawmidi_dev_free(struct snd_device *device);
|
||||
static int snd_rawmidi_dev_register(struct snd_device *device);
|
||||
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
|
||||
|
|
|
@ -174,9 +174,12 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (snd_BUG_ON(!dp))
|
||||
return -ENXIO;
|
||||
|
||||
mutex_lock(®ister_mutex);
|
||||
if (cmd != SNDCTL_SEQ_SYNC &&
|
||||
mutex_lock_interruptible(®ister_mutex))
|
||||
return -ERESTARTSYS;
|
||||
rc = snd_seq_oss_ioctl(dp, cmd, arg);
|
||||
mutex_unlock(®ister_mutex);
|
||||
if (cmd != SNDCTL_SEQ_SYNC)
|
||||
mutex_unlock(®ister_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ EXPORT_SYMBOL(snd_timer_instance_free);
|
|||
*/
|
||||
static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
|
||||
{
|
||||
struct snd_timer *timer = NULL;
|
||||
struct snd_timer *timer;
|
||||
|
||||
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
||||
if (timer->tmr_class != tid->dev_class)
|
||||
|
@ -813,12 +813,12 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
|
|||
}
|
||||
|
||||
/*
|
||||
* timer tasklet
|
||||
* timer work
|
||||
*
|
||||
*/
|
||||
static void snd_timer_tasklet(struct tasklet_struct *t)
|
||||
static void snd_timer_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_timer *timer = from_tasklet(timer, t, task_queue);
|
||||
struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
|
||||
unsigned long flags;
|
||||
|
||||
if (timer->card && timer->card->shutdown) {
|
||||
|
@ -843,7 +843,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
unsigned long resolution;
|
||||
struct list_head *ack_list_head;
|
||||
unsigned long flags;
|
||||
int use_tasklet = 0;
|
||||
bool use_work = false;
|
||||
|
||||
if (timer == NULL)
|
||||
return;
|
||||
|
@ -884,7 +884,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
--timer->running;
|
||||
list_del_init(&ti->active_list);
|
||||
}
|
||||
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
|
||||
if ((timer->hw.flags & SNDRV_TIMER_HW_WORK) ||
|
||||
(ti->flags & SNDRV_TIMER_IFLG_FAST))
|
||||
ack_list_head = &timer->ack_list_head;
|
||||
else
|
||||
|
@ -919,11 +919,11 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
snd_timer_process_callbacks(timer, &timer->ack_list_head);
|
||||
|
||||
/* do we have any slow callbacks? */
|
||||
use_tasklet = !list_empty(&timer->sack_list_head);
|
||||
use_work = !list_empty(&timer->sack_list_head);
|
||||
spin_unlock_irqrestore(&timer->lock, flags);
|
||||
|
||||
if (use_tasklet)
|
||||
tasklet_schedule(&timer->task_queue);
|
||||
if (use_work)
|
||||
queue_work(system_highpri_wq, &timer->task_work);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_timer_interrupt);
|
||||
|
||||
|
@ -967,7 +967,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
|
|||
INIT_LIST_HEAD(&timer->ack_list_head);
|
||||
INIT_LIST_HEAD(&timer->sack_list_head);
|
||||
spin_lock_init(&timer->lock);
|
||||
tasklet_setup(&timer->task_queue, snd_timer_tasklet);
|
||||
INIT_WORK(&timer->task_work, snd_timer_work);
|
||||
timer->max_instances = 1000; /* default limit per timer */
|
||||
if (card != NULL) {
|
||||
timer->module = card->module;
|
||||
|
@ -1200,7 +1200,7 @@ static int snd_timer_s_close(struct snd_timer *timer)
|
|||
|
||||
static const struct snd_timer_hardware snd_timer_system =
|
||||
{
|
||||
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
|
||||
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK,
|
||||
.resolution = 1000000000L / HZ,
|
||||
.ticks = 10000000L,
|
||||
.close = snd_timer_s_close,
|
||||
|
@ -1280,8 +1280,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
|
|||
list_for_each_entry(ti, &timer->open_list_head, open_list)
|
||||
snd_iprintf(buffer, " Client %s : %s\n",
|
||||
ti->owner ? ti->owner : "unknown",
|
||||
ti->flags & (SNDRV_TIMER_IFLG_START |
|
||||
SNDRV_TIMER_IFLG_RUNNING)
|
||||
(ti->flags & (SNDRV_TIMER_IFLG_START |
|
||||
SNDRV_TIMER_IFLG_RUNNING))
|
||||
? "running" : "stopped");
|
||||
}
|
||||
mutex_unlock(®ister_mutex);
|
||||
|
|
|
@ -110,7 +110,7 @@ struct loopback_cable {
|
|||
struct {
|
||||
int stream;
|
||||
struct snd_timer_id id;
|
||||
struct tasklet_struct event_tasklet;
|
||||
struct work_struct event_work;
|
||||
struct snd_timer_instance *instance;
|
||||
} snd_timer;
|
||||
};
|
||||
|
@ -309,8 +309,8 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
|
|||
*/
|
||||
snd_timer_close(cable->snd_timer.instance);
|
||||
|
||||
/* wait till drain tasklet has finished if requested */
|
||||
tasklet_kill(&cable->snd_timer.event_tasklet);
|
||||
/* wait till drain work has finished if requested */
|
||||
cancel_work_sync(&cable->snd_timer.event_work);
|
||||
|
||||
snd_timer_instance_free(cable->snd_timer.instance);
|
||||
memset(&cable->snd_timer, 0, sizeof(cable->snd_timer));
|
||||
|
@ -794,11 +794,11 @@ static void loopback_snd_timer_function(struct snd_timer_instance *timeri,
|
|||
resolution);
|
||||
}
|
||||
|
||||
static void loopback_snd_timer_tasklet(unsigned long arg)
|
||||
static void loopback_snd_timer_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_timer_instance *timeri = (struct snd_timer_instance *)arg;
|
||||
struct loopback_cable *cable = timeri->callback_data;
|
||||
struct loopback_cable *cable;
|
||||
|
||||
cable = container_of(work, struct loopback_cable, snd_timer.event_work);
|
||||
loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0);
|
||||
}
|
||||
|
||||
|
@ -828,9 +828,9 @@ static void loopback_snd_timer_event(struct snd_timer_instance *timeri,
|
|||
* state the streaming will be aborted by the usual timeout. It
|
||||
* should not be aborted here because may be the timer sound
|
||||
* card does only a recovery and the timer is back soon.
|
||||
* This tasklet triggers loopback_snd_timer_tasklet()
|
||||
* This work triggers loopback_snd_timer_work()
|
||||
*/
|
||||
tasklet_schedule(&cable->snd_timer.event_tasklet);
|
||||
schedule_work(&cable->snd_timer.event_work);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1124,7 +1124,7 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
|
|||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
/* The callback has to be called from another tasklet. If
|
||||
/* The callback has to be called from another work. If
|
||||
* SNDRV_TIMER_IFLG_FAST is specified it will be called from the
|
||||
* snd_pcm_period_elapsed() call of the selected sound card.
|
||||
* snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave().
|
||||
|
@ -1137,9 +1137,8 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
|
|||
timeri->callback_data = (void *)cable;
|
||||
timeri->ccallback = loopback_snd_timer_event;
|
||||
|
||||
/* initialise a tasklet used for draining */
|
||||
tasklet_init(&cable->snd_timer.event_tasklet,
|
||||
loopback_snd_timer_tasklet, (unsigned long)timeri);
|
||||
/* initialise a work used for draining */
|
||||
INIT_WORK(&cable->snd_timer.event_work, loopback_snd_timer_work);
|
||||
|
||||
/* The mutex loopback->cable_lock is kept locked.
|
||||
* Therefore snd_timer_open() cannot be called a second time
|
||||
|
|
|
@ -23,10 +23,10 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
|
|||
#define DMIX_WANTS_S16 1
|
||||
|
||||
/*
|
||||
* Call snd_pcm_period_elapsed in a tasklet
|
||||
* Call snd_pcm_period_elapsed in a work
|
||||
* This avoids spinlock messes and long-running irq contexts
|
||||
*/
|
||||
static void pcsp_call_pcm_elapsed(unsigned long priv)
|
||||
static void pcsp_call_pcm_elapsed(struct work_struct *work)
|
||||
{
|
||||
if (atomic_read(&pcsp_chip.timer_active)) {
|
||||
struct snd_pcm_substream *substream;
|
||||
|
@ -36,7 +36,7 @@ static void pcsp_call_pcm_elapsed(unsigned long priv)
|
|||
}
|
||||
}
|
||||
|
||||
static DECLARE_TASKLET_OLD(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed);
|
||||
static DECLARE_WORK(pcsp_pcm_work, pcsp_call_pcm_elapsed);
|
||||
|
||||
/* write the port and returns the next expire time in ns;
|
||||
* called at the trigger-start and in hrtimer callback
|
||||
|
@ -119,11 +119,9 @@ static void pcsp_pointer_update(struct snd_pcsp *chip)
|
|||
if (periods_elapsed) {
|
||||
chip->period_ptr += periods_elapsed * period_bytes;
|
||||
chip->period_ptr %= buffer_bytes;
|
||||
queue_work(system_highpri_wq, &pcsp_pcm_work);
|
||||
}
|
||||
spin_unlock_irqrestore(&chip->substream_lock, flags);
|
||||
|
||||
if (periods_elapsed)
|
||||
tasklet_schedule(&pcsp_pcm_tasklet);
|
||||
}
|
||||
|
||||
enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
|
||||
|
@ -196,7 +194,7 @@ void pcsp_sync_stop(struct snd_pcsp *chip)
|
|||
pcsp_stop_playing(chip);
|
||||
local_irq_enable();
|
||||
hrtimer_cancel(&chip->timer);
|
||||
tasklet_kill(&pcsp_pcm_tasklet);
|
||||
cancel_work_sync(&pcsp_pcm_work);
|
||||
}
|
||||
|
||||
static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
|
||||
|
|
|
@ -467,7 +467,7 @@ static int portman_probe(struct parport *p)
|
|||
parport_write_control(p, 0); /* Reset Strobe=0. */
|
||||
|
||||
/* Check if Tx circuitry is functioning properly. If initialized
|
||||
* unit TxEmpty is false, send out char and see if if goes true.
|
||||
* unit TxEmpty is false, send out char and see if it goes true.
|
||||
*/
|
||||
/* 8 */
|
||||
parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */
|
||||
|
|
|
@ -597,9 +597,9 @@ static void vx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *b
|
|||
|
||||
snd_iprintf(buffer, "%s\n", chip->card->longname);
|
||||
snd_iprintf(buffer, "Xilinx Firmware: %s\n",
|
||||
chip->chip_status & VX_STAT_XILINX_LOADED ? "Loaded" : "No");
|
||||
(chip->chip_status & VX_STAT_XILINX_LOADED) ? "Loaded" : "No");
|
||||
snd_iprintf(buffer, "Device Initialized: %s\n",
|
||||
chip->chip_status & VX_STAT_DEVICE_INIT ? "Yes" : "No");
|
||||
(chip->chip_status & VX_STAT_DEVICE_INIT) ? "Yes" : "No");
|
||||
snd_iprintf(buffer, "DSP audio info:");
|
||||
if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME)
|
||||
snd_iprintf(buffer, " realtime");
|
||||
|
|
|
@ -60,7 +60,6 @@ static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *
|
|||
*buf++ = vx_inb(chip, RXL);
|
||||
if (++offset >= pipe->buffer_bytes) {
|
||||
offset = 0;
|
||||
buf = (unsigned char *)runtime->dma_area;
|
||||
}
|
||||
pipe->hw_ptr = offset;
|
||||
}
|
||||
|
@ -530,7 +529,6 @@ static int vx_pcm_playback_open(struct snd_pcm_substream *subs)
|
|||
err = vx_alloc_pipe(chip, 0, audio, 2, &pipe); /* stereo playback */
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->playback_pipes[audio] = pipe;
|
||||
}
|
||||
/* open for playback */
|
||||
pipe->references++;
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
#define IT_PKT_HEADER_SIZE_CIP 8 // For 2 CIP header.
|
||||
#define IT_PKT_HEADER_SIZE_NO_CIP 0 // Nothing.
|
||||
|
||||
static void pcm_period_tasklet(struct tasklet_struct *t);
|
||||
static void pcm_period_work(struct work_struct *work);
|
||||
|
||||
/**
|
||||
* amdtp_stream_init - initialize an AMDTP stream structure
|
||||
|
@ -94,7 +94,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
|
|||
s->flags = flags;
|
||||
s->context = ERR_PTR(-1);
|
||||
mutex_init(&s->mutex);
|
||||
tasklet_setup(&s->period_tasklet, pcm_period_tasklet);
|
||||
INIT_WORK(&s->period_work, pcm_period_work);
|
||||
s->packet_index = 0;
|
||||
|
||||
init_waitqueue_head(&s->callback_wait);
|
||||
|
@ -203,7 +203,7 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
|
|||
|
||||
// Linux driver for 1394 OHCI controller voluntarily flushes isoc
|
||||
// context when total size of accumulated context header reaches
|
||||
// PAGE_SIZE. This kicks tasklet for the isoc context and brings
|
||||
// PAGE_SIZE. This kicks work for the isoc context and brings
|
||||
// callback in the middle of scheduled interrupts.
|
||||
// Although AMDTP streams in the same domain use the same events per
|
||||
// IRQ, use the largest size of context header between IT/IR contexts.
|
||||
|
@ -333,7 +333,7 @@ EXPORT_SYMBOL(amdtp_stream_get_max_payload);
|
|||
*/
|
||||
void amdtp_stream_pcm_prepare(struct amdtp_stream *s)
|
||||
{
|
||||
tasklet_kill(&s->period_tasklet);
|
||||
cancel_work_sync(&s->period_work);
|
||||
s->pcm_buffer_pointer = 0;
|
||||
s->pcm_period_pointer = 0;
|
||||
}
|
||||
|
@ -437,13 +437,14 @@ static void update_pcm_pointers(struct amdtp_stream *s,
|
|||
s->pcm_period_pointer += frames;
|
||||
if (s->pcm_period_pointer >= pcm->runtime->period_size) {
|
||||
s->pcm_period_pointer -= pcm->runtime->period_size;
|
||||
tasklet_hi_schedule(&s->period_tasklet);
|
||||
queue_work(system_highpri_wq, &s->period_work);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcm_period_tasklet(struct tasklet_struct *t)
|
||||
static void pcm_period_work(struct work_struct *work)
|
||||
{
|
||||
struct amdtp_stream *s = from_tasklet(s, t, period_tasklet);
|
||||
struct amdtp_stream *s = container_of(work, struct amdtp_stream,
|
||||
period_work);
|
||||
struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
|
||||
|
||||
if (pcm)
|
||||
|
@ -794,7 +795,7 @@ static void generate_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs,
|
|||
static inline void cancel_stream(struct amdtp_stream *s)
|
||||
{
|
||||
s->packet_index = -1;
|
||||
if (in_interrupt())
|
||||
if (current_work() == &s->period_work)
|
||||
amdtp_stream_pcm_abort(s);
|
||||
WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
|
||||
}
|
||||
|
@ -1184,7 +1185,7 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
|
|||
|
||||
if (irq_target && amdtp_stream_running(irq_target)) {
|
||||
// This function is called in software IRQ context of
|
||||
// period_tasklet or process context.
|
||||
// period_work or process context.
|
||||
//
|
||||
// When the software IRQ context was scheduled by software IRQ
|
||||
// context of IT contexts, queued packets were already handled.
|
||||
|
@ -1195,9 +1196,9 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
|
|||
// immediately to keep better granularity of PCM pointer.
|
||||
//
|
||||
// Later, the process context will sometimes schedules software
|
||||
// IRQ context of the period_tasklet. Then, no need to flush the
|
||||
// IRQ context of the period_work. Then, no need to flush the
|
||||
// queue by the same reason as described in the above
|
||||
if (!in_interrupt()) {
|
||||
if (current_work() != &s->period_work) {
|
||||
// Queued packet should be processed without any kernel
|
||||
// preemption to keep latency against bus cycle.
|
||||
preempt_disable();
|
||||
|
@ -1263,7 +1264,7 @@ static void amdtp_stream_stop(struct amdtp_stream *s)
|
|||
return;
|
||||
}
|
||||
|
||||
tasklet_kill(&s->period_tasklet);
|
||||
cancel_work_sync(&s->period_work);
|
||||
fw_iso_context_stop(s->context);
|
||||
fw_iso_context_destroy(s->context);
|
||||
s->context = ERR_PTR(-1);
|
||||
|
|
|
@ -163,7 +163,7 @@ struct amdtp_stream {
|
|||
|
||||
/* For a PCM substream processing. */
|
||||
struct snd_pcm_substream *pcm;
|
||||
struct tasklet_struct period_tasklet;
|
||||
struct work_struct period_work;
|
||||
snd_pcm_uframes_t pcm_buffer_pointer;
|
||||
unsigned int pcm_period_pointer;
|
||||
|
||||
|
|
|
@ -210,12 +210,14 @@ static int hdac_component_master_bind(struct device *dev)
|
|||
goto module_put;
|
||||
}
|
||||
|
||||
complete_all(&acomp->master_bind_complete);
|
||||
return 0;
|
||||
|
||||
module_put:
|
||||
module_put(acomp->ops->owner);
|
||||
out_unbind:
|
||||
component_unbind_all(dev, acomp);
|
||||
complete_all(&acomp->master_bind_complete);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -296,6 +298,7 @@ int snd_hdac_acomp_init(struct hdac_bus *bus,
|
|||
if (!acomp)
|
||||
return -ENOMEM;
|
||||
acomp->audio_ops = aops;
|
||||
init_completion(&acomp->master_bind_complete);
|
||||
bus->audio_component = acomp;
|
||||
devres_add(dev, acomp);
|
||||
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
#include <sound/hda_i915.h>
|
||||
#include <sound/hda_register.h>
|
||||
|
||||
static struct completion bind_complete;
|
||||
|
||||
#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
|
||||
#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \
|
||||
((pci)->device == 0x0c0c) || \
|
||||
((pci)->device == 0x0d0c) || \
|
||||
((pci)->device == 0x160c))
|
||||
|
@ -41,7 +39,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
|
|||
|
||||
if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq)
|
||||
return; /* only for i915 binding */
|
||||
if (!CONTROLLER_IN_GPU(pci))
|
||||
if (!IS_HSW_CONTROLLER(pci))
|
||||
return; /* only HSW/BDW */
|
||||
|
||||
cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
|
||||
|
@ -73,11 +71,49 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk);
|
||||
|
||||
/* returns true if the devices can be connected for audio */
|
||||
static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac)
|
||||
{
|
||||
struct pci_bus *bus_a = i915->bus, *bus_b = hdac->bus;
|
||||
|
||||
/* directly connected on the same bus */
|
||||
if (bus_a == bus_b)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* on i915 discrete GPUs with embedded HDA audio, the two
|
||||
* devices are connected via 2nd level PCI bridge
|
||||
*/
|
||||
bus_a = bus_a->parent;
|
||||
bus_b = bus_b->parent;
|
||||
if (!bus_a || !bus_b)
|
||||
return false;
|
||||
bus_a = bus_a->parent;
|
||||
bus_b = bus_b->parent;
|
||||
if (bus_a && bus_a == bus_b)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int i915_component_master_match(struct device *dev, int subcomponent,
|
||||
void *data)
|
||||
{
|
||||
return !strcmp(dev->driver->name, "i915") &&
|
||||
subcomponent == I915_COMPONENT_AUDIO;
|
||||
struct pci_dev *hdac_pci, *i915_pci;
|
||||
struct hdac_bus *bus = data;
|
||||
|
||||
if (!dev_is_pci(dev))
|
||||
return 0;
|
||||
|
||||
hdac_pci = to_pci_dev(bus->dev);
|
||||
i915_pci = to_pci_dev(dev);
|
||||
|
||||
if (!strcmp(dev->driver->name, "i915") &&
|
||||
subcomponent == I915_COMPONENT_AUDIO &&
|
||||
connectivity_check(i915_pci, hdac_pci))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check whether intel graphics is present */
|
||||
|
@ -92,19 +128,6 @@ static bool i915_gfx_present(void)
|
|||
return pci_dev_present(ids);
|
||||
}
|
||||
|
||||
static int i915_master_bind(struct device *dev,
|
||||
struct drm_audio_component *acomp)
|
||||
{
|
||||
complete_all(&bind_complete);
|
||||
/* clear audio_ops here as it was needed only for completion call */
|
||||
acomp->audio_ops = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_audio_component_audio_ops i915_init_ops = {
|
||||
.master_bind = i915_master_bind
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_hdac_i915_init - Initialize i915 audio component
|
||||
* @bus: HDA core bus
|
||||
|
@ -125,9 +148,7 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
|
|||
if (!i915_gfx_present())
|
||||
return -ENODEV;
|
||||
|
||||
init_completion(&bind_complete);
|
||||
|
||||
err = snd_hdac_acomp_init(bus, &i915_init_ops,
|
||||
err = snd_hdac_acomp_init(bus, NULL,
|
||||
i915_component_master_match,
|
||||
sizeof(struct i915_audio_component) - sizeof(*acomp));
|
||||
if (err < 0)
|
||||
|
@ -139,8 +160,8 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
|
|||
if (!IS_ENABLED(CONFIG_MODULES) ||
|
||||
!request_module("i915")) {
|
||||
/* 60s timeout */
|
||||
wait_for_completion_timeout(&bind_complete,
|
||||
msecs_to_jiffies(60 * 1000));
|
||||
wait_for_completion_timeout(&acomp->master_bind_complete,
|
||||
msecs_to_jiffies(60 * 1000));
|
||||
}
|
||||
}
|
||||
if (!acomp->ops) {
|
||||
|
|
|
@ -117,7 +117,6 @@ struct snd_card_asihpi {
|
|||
* snd_card_asihpi_timer_function().
|
||||
*/
|
||||
struct snd_card_asihpi_pcm *llmode_streampriv;
|
||||
struct tasklet_struct t;
|
||||
void (*pcm_start)(struct snd_pcm_substream *substream);
|
||||
void (*pcm_stop)(struct snd_pcm_substream *substream);
|
||||
|
||||
|
@ -258,15 +257,6 @@ static inline u16 hpi_stream_group_reset(u32 h_stream)
|
|||
return hpi_instream_group_reset(h_stream);
|
||||
}
|
||||
|
||||
static inline u16 hpi_stream_group_get_map(
|
||||
u32 h_stream, u32 *mo, u32 *mi)
|
||||
{
|
||||
if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
|
||||
return hpi_outstream_group_get_map(h_stream, mo, mi);
|
||||
else
|
||||
return hpi_instream_group_get_map(h_stream, mo, mi);
|
||||
}
|
||||
|
||||
static u16 handle_error(u16 err, int line, char *filename)
|
||||
{
|
||||
if (err)
|
||||
|
@ -547,9 +537,7 @@ static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream)
|
|||
card = snd_pcm_substream_chip(substream);
|
||||
|
||||
WARN_ON(in_interrupt());
|
||||
tasklet_disable(&card->t);
|
||||
card->llmode_streampriv = dpcm;
|
||||
tasklet_enable(&card->t);
|
||||
|
||||
hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
|
||||
HPI_ADAPTER_PROPERTY_IRQ_RATE,
|
||||
|
@ -565,13 +553,7 @@ static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream)
|
|||
hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
|
||||
HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
|
||||
|
||||
if (in_interrupt())
|
||||
card->llmode_streampriv = NULL;
|
||||
else {
|
||||
tasklet_disable(&card->t);
|
||||
card->llmode_streampriv = NULL;
|
||||
tasklet_enable(&card->t);
|
||||
}
|
||||
card->llmode_streampriv = NULL;
|
||||
}
|
||||
|
||||
static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
|
||||
|
@ -921,25 +903,15 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
|
|||
add_timer(&dpcm->timer);
|
||||
}
|
||||
|
||||
static void snd_card_asihpi_int_task(struct tasklet_struct *t)
|
||||
{
|
||||
struct snd_card_asihpi *asihpi = from_tasklet(asihpi, t, t);
|
||||
struct hpi_adapter *a = asihpi->hpi;
|
||||
|
||||
WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
|
||||
asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
|
||||
if (asihpi->llmode_streampriv)
|
||||
snd_card_asihpi_timer_function(
|
||||
&asihpi->llmode_streampriv->timer);
|
||||
}
|
||||
|
||||
static void snd_card_asihpi_isr(struct hpi_adapter *a)
|
||||
{
|
||||
struct snd_card_asihpi *asihpi;
|
||||
|
||||
WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
|
||||
asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
|
||||
tasklet_schedule(&asihpi->t);
|
||||
if (asihpi->llmode_streampriv)
|
||||
snd_card_asihpi_timer_function(
|
||||
&asihpi->llmode_streampriv->timer);
|
||||
}
|
||||
|
||||
/***************************** PLAYBACK OPS ****************/
|
||||
|
@ -2871,7 +2843,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
|
|||
if (hpi->interrupt_mode) {
|
||||
asihpi->pcm_start = snd_card_asihpi_pcm_int_start;
|
||||
asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop;
|
||||
tasklet_setup(&asihpi->t, snd_card_asihpi_int_task);
|
||||
hpi->interrupt_callback = snd_card_asihpi_isr;
|
||||
} else {
|
||||
asihpi->pcm_start = snd_card_asihpi_pcm_timer_start;
|
||||
|
@ -2960,14 +2931,12 @@ __nodev:
|
|||
static void snd_asihpi_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct hpi_adapter *hpi = pci_get_drvdata(pci_dev);
|
||||
struct snd_card_asihpi *asihpi = hpi->snd_card->private_data;
|
||||
|
||||
/* Stop interrupts */
|
||||
if (hpi->interrupt_mode) {
|
||||
hpi->interrupt_callback = NULL;
|
||||
hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index,
|
||||
HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
|
||||
tasklet_kill(&asihpi->t);
|
||||
}
|
||||
|
||||
snd_card_free(hpi->snd_card);
|
||||
|
|
|
@ -329,11 +329,20 @@ static irqreturn_t asihpi_isr(int irq, void *dev_id)
|
|||
asihpi_irq_count, a->adapter->type, a->adapter->index); */
|
||||
|
||||
if (a->interrupt_callback)
|
||||
a->interrupt_callback(a);
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t asihpi_isr_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct hpi_adapter *a = dev_id;
|
||||
|
||||
if (a->interrupt_callback)
|
||||
a->interrupt_callback(a);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int asihpi_adapter_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
|
@ -478,8 +487,9 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
|
|||
}
|
||||
|
||||
/* Note: request_irq calls asihpi_isr here */
|
||||
if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED,
|
||||
"asihpi", &adapters[adapter_index])) {
|
||||
if (request_threaded_irq(pci_dev->irq, asihpi_isr,
|
||||
asihpi_isr_thread, IRQF_SHARED,
|
||||
"asihpi", &adapters[adapter_index])) {
|
||||
dev_err(&pci_dev->dev, "request_irq(%d) failed\n",
|
||||
pci_dev->irq);
|
||||
goto err;
|
||||
|
|
|
@ -67,7 +67,7 @@ struct hpi_ioctl_linux {
|
|||
};
|
||||
|
||||
/* Conflict?: H is already used by a number of drivers hid, bluetooth hci,
|
||||
and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is ununsed command
|
||||
and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is unused command
|
||||
*/
|
||||
#define HPI_IOCTL_LINUX _IOWR('H', 0xFC, struct hpi_ioctl_linux)
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
|||
*/
|
||||
if (!cfg->line_outs && cfg->hp_outs > 1 &&
|
||||
!(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
|
||||
int i = 0;
|
||||
i = 0;
|
||||
while (i < cfg->hp_outs) {
|
||||
/* The real HPs should have the sequence 0x0f */
|
||||
if ((hp_out[i].seq & 0x0f) == 0x0f) {
|
||||
|
|
|
@ -368,7 +368,8 @@ enum {
|
|||
#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
|
||||
((pci)->device == 0x0c0c) || \
|
||||
((pci)->device == 0x0d0c) || \
|
||||
((pci)->device == 0x160c))
|
||||
((pci)->device == 0x160c) || \
|
||||
((pci)->device == 0x490d))
|
||||
|
||||
#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
|
||||
|
||||
|
@ -2493,6 +2494,9 @@ static const struct pci_device_id azx_ids[] = {
|
|||
/* Tigerlake-H */
|
||||
{ PCI_DEVICE(0x8086, 0x43c8),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
/* DG1 */
|
||||
{ PCI_DEVICE(0x8086, 0x490d),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
/* Elkhart Lake */
|
||||
{ PCI_DEVICE(0x8086, 0x4b55),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
|
|
|
@ -77,7 +77,7 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
|
|||
|
||||
struct hda_jack_callback *
|
||||
snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid,
|
||||
int dev_id, hda_jack_callback_fn cb);
|
||||
int dev_id, hda_jack_callback_fn func);
|
||||
|
||||
/**
|
||||
* snd_hda_jack_detect_enable - enable the jack-detection
|
||||
|
|
|
@ -100,7 +100,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
|||
int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
||||
unsigned int size, unsigned int __user *tlv);
|
||||
unsigned int size, unsigned int __user *_tlv);
|
||||
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
|
||||
|
@ -119,7 +119,7 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
|
|||
int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid,
|
||||
int ch, int dir, int idx, int mask, int val);
|
||||
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
|
||||
int dir, int idx, int mask, int val);
|
||||
int direction, int idx, int mask, int val);
|
||||
int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
|
||||
int direction, int idx, int mask, int val);
|
||||
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
|
||||
|
@ -198,7 +198,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
|
|||
unsigned int *cur_val);
|
||||
int snd_hda_add_imux_item(struct hda_codec *codec,
|
||||
struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_index_ret);
|
||||
int index, int *type_idx);
|
||||
|
||||
/*
|
||||
* Multi-channel / digital-out PCM helper
|
||||
|
@ -642,7 +642,7 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
|
|||
*/
|
||||
int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo,
|
||||
int num_entries, const char * const *texts);
|
||||
int num_items, const char * const *texts);
|
||||
#define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \
|
||||
snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4269,6 +4269,7 @@ HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi),
|
|||
HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
|
||||
HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi),
|
||||
HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
|
||||
HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi),
|
||||
HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
|
||||
HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
|
||||
HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
|
||||
|
|
|
@ -69,7 +69,7 @@ struct mixart_mgr {
|
|||
u32 msg_fifo[MSG_FIFO_SIZE];
|
||||
int msg_fifo_readptr;
|
||||
int msg_fifo_writeptr;
|
||||
atomic_t msg_processed; /* number of messages to be processed in tasklet */
|
||||
atomic_t msg_processed; /* number of messages to be processed in irq thread */
|
||||
|
||||
struct mutex lock; /* interrupt lock */
|
||||
struct mutex msg_lock; /* mailbox lock */
|
||||
|
|
|
@ -445,7 +445,6 @@ struct snd_riptide {
|
|||
union firmware_version firmware;
|
||||
|
||||
spinlock_t lock;
|
||||
struct tasklet_struct riptide_tq;
|
||||
struct snd_info_entry *proc_entry;
|
||||
|
||||
unsigned long received_irqs;
|
||||
|
@ -1070,9 +1069,9 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void riptide_handleirq(struct tasklet_struct *t)
|
||||
static irqreturn_t riptide_handleirq(int irq, void *dev_id)
|
||||
{
|
||||
struct snd_riptide *chip = from_tasklet(chip, t, riptide_tq);
|
||||
struct snd_riptide *chip = dev_id;
|
||||
struct cmdif *cif = chip->cif;
|
||||
struct snd_pcm_substream *substream[PLAYBACK_SUBSTREAMS + 1];
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
@ -1083,7 +1082,7 @@ static void riptide_handleirq(struct tasklet_struct *t)
|
|||
unsigned int flag;
|
||||
|
||||
if (!cif)
|
||||
return;
|
||||
return IRQ_HANDLED;
|
||||
|
||||
for (i = 0; i < PLAYBACK_SUBSTREAMS; i++)
|
||||
substream[i] = chip->playback_substream[i];
|
||||
|
@ -1134,6 +1133,8 @@ static void riptide_handleirq(struct tasklet_struct *t)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -1699,13 +1700,14 @@ snd_riptide_interrupt(int irq, void *dev_id)
|
|||
{
|
||||
struct snd_riptide *chip = dev_id;
|
||||
struct cmdif *cif = chip->cif;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
|
||||
if (cif) {
|
||||
chip->received_irqs++;
|
||||
if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) ||
|
||||
IS_EOCIRQ(cif->hwport)) {
|
||||
chip->handled_irqs++;
|
||||
tasklet_schedule(&chip->riptide_tq);
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
if (chip->rmidi && IS_MPUIRQ(cif->hwport)) {
|
||||
chip->handled_irqs++;
|
||||
|
@ -1714,7 +1716,7 @@ snd_riptide_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
SET_AIACK(cif->hwport);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1843,7 +1845,6 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
|
|||
chip->received_irqs = 0;
|
||||
chip->handled_irqs = 0;
|
||||
chip->cif = NULL;
|
||||
tasklet_setup(&chip->riptide_tq, riptide_handleirq);
|
||||
|
||||
if ((chip->res_port =
|
||||
request_region(chip->port, 64, "RIPTIDE")) == NULL) {
|
||||
|
@ -1856,8 +1857,9 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
|
|||
hwport = (struct riptideport *)chip->port;
|
||||
UNSET_AIE(hwport);
|
||||
|
||||
if (request_irq(pci->irq, snd_riptide_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, chip)) {
|
||||
if (request_threaded_irq(pci->irq, snd_riptide_interrupt,
|
||||
riptide_handleirq, IRQF_SHARED,
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n",
|
||||
pci->irq);
|
||||
snd_riptide_free(chip);
|
||||
|
|
|
@ -447,8 +447,8 @@ struct hdsp {
|
|||
struct snd_pcm_substream *capture_substream;
|
||||
struct snd_pcm_substream *playback_substream;
|
||||
struct hdsp_midi midi[2];
|
||||
struct tasklet_struct midi_tasklet;
|
||||
int use_midi_tasklet;
|
||||
struct work_struct midi_work;
|
||||
int use_midi_work;
|
||||
int precise_ptr;
|
||||
u32 control_register; /* cached value */
|
||||
u32 control2_register; /* cached value */
|
||||
|
@ -1385,7 +1385,6 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream,
|
|||
}
|
||||
} else {
|
||||
hdsp->control_register &= ~ie;
|
||||
tasklet_kill(&hdsp->midi_tasklet);
|
||||
}
|
||||
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
|
@ -2542,37 +2541,37 @@ static int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct sn
|
|||
return change;
|
||||
}
|
||||
|
||||
#define HDSP_USE_MIDI_TASKLET(xname, xindex) \
|
||||
#define HDSP_USE_MIDI_WORK(xname, xindex) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
|
||||
.name = xname, \
|
||||
.index = xindex, \
|
||||
.info = snd_hdsp_info_use_midi_tasklet, \
|
||||
.get = snd_hdsp_get_use_midi_tasklet, \
|
||||
.put = snd_hdsp_put_use_midi_tasklet \
|
||||
.info = snd_hdsp_info_use_midi_work, \
|
||||
.get = snd_hdsp_get_use_midi_work, \
|
||||
.put = snd_hdsp_put_use_midi_work \
|
||||
}
|
||||
|
||||
static int hdsp_set_use_midi_tasklet(struct hdsp *hdsp, int use_tasklet)
|
||||
static int hdsp_set_use_midi_work(struct hdsp *hdsp, int use_work)
|
||||
{
|
||||
if (use_tasklet)
|
||||
hdsp->use_midi_tasklet = 1;
|
||||
if (use_work)
|
||||
hdsp->use_midi_work = 1;
|
||||
else
|
||||
hdsp->use_midi_tasklet = 0;
|
||||
hdsp->use_midi_work = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define snd_hdsp_info_use_midi_tasklet snd_ctl_boolean_mono_info
|
||||
#define snd_hdsp_info_use_midi_work snd_ctl_boolean_mono_info
|
||||
|
||||
static int snd_hdsp_get_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
static int snd_hdsp_get_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
spin_lock_irq(&hdsp->lock);
|
||||
ucontrol->value.integer.value[0] = hdsp->use_midi_tasklet;
|
||||
ucontrol->value.integer.value[0] = hdsp->use_midi_work;
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_hdsp_put_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
static int snd_hdsp_put_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
|
||||
int change;
|
||||
|
@ -2582,8 +2581,8 @@ static int snd_hdsp_put_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct s
|
|||
return -EBUSY;
|
||||
val = ucontrol->value.integer.value[0] & 1;
|
||||
spin_lock_irq(&hdsp->lock);
|
||||
change = (int)val != hdsp->use_midi_tasklet;
|
||||
hdsp_set_use_midi_tasklet(hdsp, val);
|
||||
change = (int)val != hdsp->use_midi_work;
|
||||
hdsp_set_use_midi_work(hdsp, val);
|
||||
spin_unlock_irq(&hdsp->lock);
|
||||
return change;
|
||||
}
|
||||
|
@ -2950,7 +2949,7 @@ HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
|
|||
HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
|
||||
HDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut),
|
||||
HDSP_PRECISE_POINTER("Precise Pointer", 0),
|
||||
HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
|
||||
HDSP_USE_MIDI_WORK("Use Midi Tasklet", 0),
|
||||
};
|
||||
|
||||
|
||||
|
@ -3370,7 +3369,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
|||
snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0));
|
||||
snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1));
|
||||
snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1));
|
||||
snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_tasklet ? "on" : "off");
|
||||
snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_work ? "on" : "off");
|
||||
|
||||
snd_iprintf(buffer, "\n");
|
||||
|
||||
|
@ -3791,9 +3790,9 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hdsp_midi_tasklet(struct tasklet_struct *t)
|
||||
static void hdsp_midi_work(struct work_struct *work)
|
||||
{
|
||||
struct hdsp *hdsp = from_tasklet(hdsp, t, midi_tasklet);
|
||||
struct hdsp *hdsp = container_of(work, struct hdsp, midi_work);
|
||||
|
||||
if (hdsp->midi[0].pending)
|
||||
snd_hdsp_midi_input_read (&hdsp->midi[0]);
|
||||
|
@ -3838,7 +3837,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
if (midi0 && midi0status) {
|
||||
if (hdsp->use_midi_tasklet) {
|
||||
if (hdsp->use_midi_work) {
|
||||
/* we disable interrupts for this input until processing is done */
|
||||
hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
|
@ -3849,7 +3848,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
}
|
||||
if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
|
||||
if (hdsp->use_midi_tasklet) {
|
||||
if (hdsp->use_midi_work) {
|
||||
/* we disable interrupts for this input until processing is done */
|
||||
hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
|
||||
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
|
@ -3859,8 +3858,8 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
|
|||
snd_hdsp_midi_input_read (&hdsp->midi[1]);
|
||||
}
|
||||
}
|
||||
if (hdsp->use_midi_tasklet && schedule)
|
||||
tasklet_schedule(&hdsp->midi_tasklet);
|
||||
if (hdsp->use_midi_work && schedule)
|
||||
queue_work(system_highpri_wq, &hdsp->midi_work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -5182,7 +5181,7 @@ static int snd_hdsp_create(struct snd_card *card,
|
|||
|
||||
spin_lock_init(&hdsp->lock);
|
||||
|
||||
tasklet_setup(&hdsp->midi_tasklet, hdsp_midi_tasklet);
|
||||
INIT_WORK(&hdsp->midi_work, hdsp_midi_work);
|
||||
|
||||
pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
|
||||
hdsp->firmware_rev &= 0xff;
|
||||
|
@ -5235,7 +5234,7 @@ static int snd_hdsp_create(struct snd_card *card,
|
|||
hdsp->irq = pci->irq;
|
||||
card->sync_irq = hdsp->irq;
|
||||
hdsp->precise_ptr = 0;
|
||||
hdsp->use_midi_tasklet = 1;
|
||||
hdsp->use_midi_work = 1;
|
||||
hdsp->dds_value = 0;
|
||||
|
||||
if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
|
||||
|
@ -5305,7 +5304,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
|
|||
{
|
||||
if (hdsp->port) {
|
||||
/* stop the audio, and cancel all interrupts */
|
||||
tasklet_kill(&hdsp->midi_tasklet);
|
||||
cancel_work_sync(&hdsp->midi_work);
|
||||
hdsp->control_register &= ~(HDSP_Start|HDSP_AudioInterruptEnable|HDSP_Midi0InterruptEnable|HDSP_Midi1InterruptEnable);
|
||||
hdsp_write (hdsp, HDSP_controlRegister, hdsp->control_register);
|
||||
}
|
||||
|
|
|
@ -997,7 +997,7 @@ struct hdspm {
|
|||
u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */
|
||||
|
||||
struct hdspm_midi midi[4];
|
||||
struct tasklet_struct midi_tasklet;
|
||||
struct work_struct midi_work;
|
||||
|
||||
size_t period_bytes;
|
||||
unsigned char ss_in_channels;
|
||||
|
@ -1217,7 +1217,7 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* round arbitary sample rates to commonly known rates */
|
||||
/* round arbitrary sample rates to commonly known rates */
|
||||
static int hdspm_round_frequency(int rate)
|
||||
{
|
||||
if (rate < 38050)
|
||||
|
@ -2169,9 +2169,9 @@ static int snd_hdspm_create_midi(struct snd_card *card,
|
|||
}
|
||||
|
||||
|
||||
static void hdspm_midi_tasklet(struct tasklet_struct *t)
|
||||
static void hdspm_midi_work(struct work_struct *work)
|
||||
{
|
||||
struct hdspm *hdspm = from_tasklet(hdspm, t, midi_tasklet);
|
||||
struct hdspm *hdspm = container_of(work, struct hdspm, midi_work);
|
||||
int i = 0;
|
||||
|
||||
while (i < hdspm->midiPorts) {
|
||||
|
@ -5449,7 +5449,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
if (schedule)
|
||||
tasklet_hi_schedule(&hdspm->midi_tasklet);
|
||||
queue_work(system_highpri_wq, &hdspm->midi_work);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -6538,6 +6538,7 @@ static int snd_hdspm_create(struct snd_card *card,
|
|||
hdspm->card = card;
|
||||
|
||||
spin_lock_init(&hdspm->lock);
|
||||
INIT_WORK(&hdspm->midi_work, hdspm_midi_work);
|
||||
|
||||
pci_read_config_word(hdspm->pci,
|
||||
PCI_CLASS_REVISION, &hdspm->firmware_rev);
|
||||
|
@ -6836,9 +6837,6 @@ static int snd_hdspm_create(struct snd_card *card,
|
|||
|
||||
}
|
||||
|
||||
tasklet_setup(&hdspm->midi_tasklet, hdspm_midi_tasklet);
|
||||
|
||||
|
||||
if (hdspm->io_type != MADIface) {
|
||||
hdspm->serial = (hdspm_read(hdspm,
|
||||
HDSPM_midiStatusIn0)>>8) & 0xFFFFFF;
|
||||
|
@ -6873,6 +6871,7 @@ static int snd_hdspm_free(struct hdspm * hdspm)
|
|||
{
|
||||
|
||||
if (hdspm->port) {
|
||||
cancel_work_sync(&hdspm->midi_work);
|
||||
|
||||
/* stop th audio, and cancel all interrupts */
|
||||
hdspm->control_register &=
|
||||
|
|
131
sound/usb/card.c
131
sound/usb/card.c
|
@ -332,6 +332,106 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Profile name preset table
|
||||
*/
|
||||
struct usb_audio_device_name {
|
||||
u32 id;
|
||||
const char *vendor_name;
|
||||
const char *product_name;
|
||||
const char *profile_name; /* override card->longname */
|
||||
};
|
||||
|
||||
#define PROFILE_NAME(vid, pid, vendor, product, profile) \
|
||||
{ .id = USB_ID(vid, pid), .vendor_name = (vendor), \
|
||||
.product_name = (product), .profile_name = (profile) }
|
||||
#define DEVICE_NAME(vid, pid, vendor, product) \
|
||||
PROFILE_NAME(vid, pid, vendor, product, NULL)
|
||||
|
||||
/* vendor/product and profile name presets, sorted in device id order */
|
||||
static const struct usb_audio_device_name usb_audio_names[] = {
|
||||
/* HP Thunderbolt Dock Audio Headset */
|
||||
PROFILE_NAME(0x03f0, 0x0269, "HP", "Thunderbolt Dock Audio Headset",
|
||||
"HP-Thunderbolt-Dock-Audio-Headset"),
|
||||
/* HP Thunderbolt Dock Audio Module */
|
||||
PROFILE_NAME(0x03f0, 0x0567, "HP", "Thunderbolt Dock Audio Module",
|
||||
"HP-Thunderbolt-Dock-Audio-Module"),
|
||||
|
||||
/* Two entries for Gigabyte TRX40 Aorus Master:
|
||||
* TRX40 Aorus Master has two USB-audio devices, one for the front
|
||||
* headphone with ESS SABRE9218 DAC chip, while another for the rest
|
||||
* I/O (the rear panel and the front mic) with Realtek ALC1220-VB.
|
||||
* Here we provide two distinct names for making UCM profiles easier.
|
||||
*/
|
||||
PROFILE_NAME(0x0414, 0xa000, "Gigabyte", "Aorus Master Front Headphone",
|
||||
"Gigabyte-Aorus-Master-Front-Headphone"),
|
||||
PROFILE_NAME(0x0414, 0xa001, "Gigabyte", "Aorus Master Main Audio",
|
||||
"Gigabyte-Aorus-Master-Main-Audio"),
|
||||
|
||||
/* Gigabyte TRX40 Aorus Pro WiFi */
|
||||
PROFILE_NAME(0x0414, 0xa002,
|
||||
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
|
||||
|
||||
/* Creative/E-Mu devices */
|
||||
DEVICE_NAME(0x041e, 0x3010, "Creative Labs", "Sound Blaster MP3+"),
|
||||
/* Creative/Toshiba Multimedia Center SB-0500 */
|
||||
DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
|
||||
|
||||
DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
|
||||
|
||||
/* Dell WD15 Dock */
|
||||
PROFILE_NAME(0x0bda, 0x4014, "Dell", "WD15 Dock", "Dell-WD15-Dock"),
|
||||
/* Dell WD19 Dock */
|
||||
PROFILE_NAME(0x0bda, 0x402e, "Dell", "WD19 Dock", "Dell-WD15-Dock"),
|
||||
|
||||
DEVICE_NAME(0x0ccd, 0x0028, "TerraTec", "Aureon5.1MkII"),
|
||||
|
||||
/*
|
||||
* The original product_name is "USB Sound Device", however this name
|
||||
* is also used by the CM106 based cards, so make it unique.
|
||||
*/
|
||||
DEVICE_NAME(0x0d8c, 0x0102, NULL, "ICUSBAUDIO7D"),
|
||||
DEVICE_NAME(0x0d8c, 0x0103, NULL, "Audio Advantage MicroII"),
|
||||
|
||||
/* MSI TRX40 Creator */
|
||||
PROFILE_NAME(0x0db0, 0x0d64,
|
||||
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
|
||||
/* MSI TRX40 */
|
||||
PROFILE_NAME(0x0db0, 0x543d,
|
||||
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
|
||||
|
||||
/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */
|
||||
DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"),
|
||||
DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"),
|
||||
|
||||
/* aka. Serato Scratch Live DJ Box */
|
||||
DEVICE_NAME(0x13e5, 0x0001, "Rane", "SL-1"),
|
||||
|
||||
/* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
|
||||
PROFILE_NAME(0x17aa, 0x1046, "Lenovo", "ThinkStation P620 Rear",
|
||||
"Lenovo-ThinkStation-P620-Rear"),
|
||||
/* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
|
||||
PROFILE_NAME(0x17aa, 0x104d, "Lenovo", "ThinkStation P620 Main",
|
||||
"Lenovo-ThinkStation-P620-Main"),
|
||||
|
||||
/* Asrock TRX40 Creator */
|
||||
PROFILE_NAME(0x26ce, 0x0a01,
|
||||
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
|
||||
|
||||
{ } /* terminator */
|
||||
};
|
||||
|
||||
static const struct usb_audio_device_name *
|
||||
lookup_device_name(u32 id)
|
||||
{
|
||||
static const struct usb_audio_device_name *p;
|
||||
|
||||
for (p = usb_audio_names; p->id; p++)
|
||||
if (p->id == id)
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* free the chip instance
|
||||
*
|
||||
|
@ -357,10 +457,16 @@ static void usb_audio_make_shortname(struct usb_device *dev,
|
|||
const struct snd_usb_audio_quirk *quirk)
|
||||
{
|
||||
struct snd_card *card = chip->card;
|
||||
const struct usb_audio_device_name *preset;
|
||||
const char *s = NULL;
|
||||
|
||||
if (quirk && quirk->product_name && *quirk->product_name) {
|
||||
strlcpy(card->shortname, quirk->product_name,
|
||||
sizeof(card->shortname));
|
||||
preset = lookup_device_name(chip->usb_id);
|
||||
if (preset && preset->product_name)
|
||||
s = preset->product_name;
|
||||
else if (quirk && quirk->product_name)
|
||||
s = quirk->product_name;
|
||||
if (s && *s) {
|
||||
strlcpy(card->shortname, s, sizeof(card->shortname));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -382,17 +488,26 @@ static void usb_audio_make_longname(struct usb_device *dev,
|
|||
const struct snd_usb_audio_quirk *quirk)
|
||||
{
|
||||
struct snd_card *card = chip->card;
|
||||
const struct usb_audio_device_name *preset;
|
||||
const char *s = NULL;
|
||||
int len;
|
||||
|
||||
preset = lookup_device_name(chip->usb_id);
|
||||
|
||||
/* shortcut - if any pre-defined string is given, use it */
|
||||
if (quirk && quirk->profile_name && *quirk->profile_name) {
|
||||
strlcpy(card->longname, quirk->profile_name,
|
||||
sizeof(card->longname));
|
||||
if (preset && preset->profile_name)
|
||||
s = preset->profile_name;
|
||||
if (s && *s) {
|
||||
strlcpy(card->longname, s, sizeof(card->longname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (quirk && quirk->vendor_name && *quirk->vendor_name) {
|
||||
len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname));
|
||||
if (preset && preset->vendor_name)
|
||||
s = preset->vendor_name;
|
||||
else if (quirk && quirk->vendor_name)
|
||||
s = quirk->vendor_name;
|
||||
if (s && *s) {
|
||||
len = strlcpy(card->longname, s, sizeof(card->longname));
|
||||
} else {
|
||||
/* retrieve the vendor and device strings as longname */
|
||||
if (dev->descriptor.iManufacturer)
|
||||
|
|
|
@ -318,7 +318,7 @@ static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
|
|||
|
||||
/*
|
||||
* Send output urbs that have been prepared previously. URBs are dequeued
|
||||
* from ep->ready_playback_urbs and in case there there aren't any available
|
||||
* from ep->ready_playback_urbs and in case there aren't any available
|
||||
* or there are no packets that have been prepared, this function does
|
||||
* nothing.
|
||||
*
|
||||
|
|
|
@ -142,7 +142,7 @@ struct snd_usb_midi_out_endpoint {
|
|||
unsigned int active_urbs;
|
||||
unsigned int drain_urbs;
|
||||
int max_transfer; /* size of urb buffer */
|
||||
struct tasklet_struct tasklet;
|
||||
struct work_struct work;
|
||||
unsigned int next_urb;
|
||||
spinlock_t buffer_lock;
|
||||
|
||||
|
@ -344,9 +344,10 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep)
|
|||
spin_unlock_irqrestore(&ep->buffer_lock, flags);
|
||||
}
|
||||
|
||||
static void snd_usbmidi_out_tasklet(struct tasklet_struct *t)
|
||||
static void snd_usbmidi_out_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_usb_midi_out_endpoint *ep = from_tasklet(ep, t, tasklet);
|
||||
struct snd_usb_midi_out_endpoint *ep =
|
||||
container_of(work, struct snd_usb_midi_out_endpoint, work);
|
||||
|
||||
snd_usbmidi_do_output(ep);
|
||||
}
|
||||
|
@ -1177,7 +1178,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
|
|||
snd_rawmidi_proceed(substream);
|
||||
return;
|
||||
}
|
||||
tasklet_schedule(&port->ep->tasklet);
|
||||
queue_work(system_highpri_wq, &port->ep->work);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1440,7 +1441,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi,
|
|||
}
|
||||
|
||||
spin_lock_init(&ep->buffer_lock);
|
||||
tasklet_setup(&ep->tasklet, snd_usbmidi_out_tasklet);
|
||||
INIT_WORK(&ep->work, snd_usbmidi_out_work);
|
||||
init_waitqueue_head(&ep->drain_wait);
|
||||
|
||||
for (i = 0; i < 0x10; ++i)
|
||||
|
@ -1503,7 +1504,7 @@ void snd_usbmidi_disconnect(struct list_head *p)
|
|||
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
|
||||
struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i];
|
||||
if (ep->out)
|
||||
tasklet_kill(&ep->out->tasklet);
|
||||
cancel_work_sync(&ep->out->work);
|
||||
if (ep->out) {
|
||||
for (j = 0; j < OUTPUT_URBS; ++j)
|
||||
usb_kill_urb(ep->out->urbs[j].urb);
|
||||
|
|
|
@ -96,7 +96,7 @@ struct ua101 {
|
|||
u8 rate_feedback[MAX_QUEUE_LENGTH];
|
||||
|
||||
struct list_head ready_playback_urbs;
|
||||
struct tasklet_struct playback_tasklet;
|
||||
struct work_struct playback_work;
|
||||
wait_queue_head_t alsa_capture_wait;
|
||||
wait_queue_head_t rate_feedback_wait;
|
||||
wait_queue_head_t alsa_playback_wait;
|
||||
|
@ -188,7 +188,7 @@ static void playback_urb_complete(struct urb *usb_urb)
|
|||
spin_lock_irqsave(&ua->lock, flags);
|
||||
list_add_tail(&urb->ready_list, &ua->ready_playback_urbs);
|
||||
if (ua->rate_feedback_count > 0)
|
||||
tasklet_schedule(&ua->playback_tasklet);
|
||||
queue_work(system_highpri_wq, &ua->playback_work);
|
||||
ua->playback.substream->runtime->delay -=
|
||||
urb->urb.iso_frame_desc[0].length /
|
||||
ua->playback.frame_bytes;
|
||||
|
@ -247,9 +247,9 @@ static inline void add_with_wraparound(struct ua101 *ua,
|
|||
*value -= ua->playback.queue_length;
|
||||
}
|
||||
|
||||
static void playback_tasklet(struct tasklet_struct *t)
|
||||
static void playback_work(struct work_struct *work)
|
||||
{
|
||||
struct ua101 *ua = from_tasklet(ua, t, playback_tasklet);
|
||||
struct ua101 *ua = container_of(work, struct ua101, playback_work);
|
||||
unsigned long flags;
|
||||
unsigned int frames;
|
||||
struct ua101_urb *urb;
|
||||
|
@ -401,7 +401,7 @@ static void capture_urb_complete(struct urb *urb)
|
|||
}
|
||||
if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) &&
|
||||
!list_empty(&ua->ready_playback_urbs))
|
||||
tasklet_schedule(&ua->playback_tasklet);
|
||||
queue_work(system_highpri_wq, &ua->playback_work);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ua->lock, flags);
|
||||
|
@ -532,7 +532,7 @@ static void stop_usb_playback(struct ua101 *ua)
|
|||
|
||||
kill_stream_urbs(&ua->playback);
|
||||
|
||||
tasklet_kill(&ua->playback_tasklet);
|
||||
cancel_work_sync(&ua->playback_work);
|
||||
|
||||
disable_iso_interface(ua, INTF_PLAYBACK);
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ static int start_usb_playback(struct ua101 *ua)
|
|||
return 0;
|
||||
|
||||
kill_stream_urbs(&ua->playback);
|
||||
tasklet_kill(&ua->playback_tasklet);
|
||||
cancel_work_sync(&ua->playback_work);
|
||||
|
||||
err = enable_iso_interface(ua, INTF_PLAYBACK);
|
||||
if (err < 0)
|
||||
|
@ -1218,7 +1218,7 @@ static int ua101_probe(struct usb_interface *interface,
|
|||
spin_lock_init(&ua->lock);
|
||||
mutex_init(&ua->mutex);
|
||||
INIT_LIST_HEAD(&ua->ready_playback_urbs);
|
||||
tasklet_setup(&ua->playback_tasklet, playback_tasklet);
|
||||
INIT_WORK(&ua->playback_work, playback_work);
|
||||
init_waitqueue_head(&ua->alsa_capture_wait);
|
||||
init_waitqueue_head(&ua->rate_feedback_wait);
|
||||
init_waitqueue_head(&ua->alsa_playback_wait);
|
||||
|
|
|
@ -2602,6 +2602,216 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pioneer DJ DJM-250MK2 and maybe other DJM models
|
||||
*
|
||||
* For playback, no duplicate mapping should be set.
|
||||
* There are three mixer stereo channels (CH1, CH2, AUX)
|
||||
* and three stereo sources (Playback 1-2, Playback 3-4, Playback 5-6).
|
||||
* Each channel should be mapped just once to one source.
|
||||
* If mapped multiple times, only one source will play on given channel
|
||||
* (sources are not mixed together).
|
||||
*
|
||||
* For recording, duplicate mapping is OK. We will get the same signal multiple times.
|
||||
*
|
||||
* Channels 7-8 are in both directions fixed to FX SEND / FX RETURN.
|
||||
*
|
||||
* See also notes in the quirks-table.h file.
|
||||
*/
|
||||
|
||||
struct snd_pioneer_djm_option {
|
||||
const u16 wIndex;
|
||||
const u16 wValue;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_level[] = {
|
||||
{ .name = "-5 dB", .wValue = 0x0300, .wIndex = 0x8003 },
|
||||
{ .name = "-10 dB", .wValue = 0x0200, .wIndex = 0x8003 },
|
||||
{ .name = "-15 dB", .wValue = 0x0100, .wIndex = 0x8003 },
|
||||
{ .name = "-19 dB", .wValue = 0x0000, .wIndex = 0x8003 }
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch12[] = {
|
||||
{ .name = "CH1 Control Tone PHONO", .wValue = 0x0103, .wIndex = 0x8002 },
|
||||
{ .name = "CH1 Control Tone LINE", .wValue = 0x0100, .wIndex = 0x8002 },
|
||||
{ .name = "Post CH1 Fader", .wValue = 0x0106, .wIndex = 0x8002 },
|
||||
{ .name = "Cross Fader A", .wValue = 0x0107, .wIndex = 0x8002 },
|
||||
{ .name = "Cross Fader B", .wValue = 0x0108, .wIndex = 0x8002 },
|
||||
{ .name = "MIC", .wValue = 0x0109, .wIndex = 0x8002 },
|
||||
{ .name = "AUX", .wValue = 0x010d, .wIndex = 0x8002 },
|
||||
{ .name = "REC OUT", .wValue = 0x010a, .wIndex = 0x8002 }
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch34[] = {
|
||||
{ .name = "CH2 Control Tone PHONO", .wValue = 0x0203, .wIndex = 0x8002 },
|
||||
{ .name = "CH2 Control Tone LINE", .wValue = 0x0200, .wIndex = 0x8002 },
|
||||
{ .name = "Post CH2 Fader", .wValue = 0x0206, .wIndex = 0x8002 },
|
||||
{ .name = "Cross Fader A", .wValue = 0x0207, .wIndex = 0x8002 },
|
||||
{ .name = "Cross Fader B", .wValue = 0x0208, .wIndex = 0x8002 },
|
||||
{ .name = "MIC", .wValue = 0x0209, .wIndex = 0x8002 },
|
||||
{ .name = "AUX", .wValue = 0x020d, .wIndex = 0x8002 },
|
||||
{ .name = "REC OUT", .wValue = 0x020a, .wIndex = 0x8002 }
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch56[] = {
|
||||
{ .name = "REC OUT", .wValue = 0x030a, .wIndex = 0x8002 },
|
||||
{ .name = "Post CH1 Fader", .wValue = 0x0311, .wIndex = 0x8002 },
|
||||
{ .name = "Post CH2 Fader", .wValue = 0x0312, .wIndex = 0x8002 },
|
||||
{ .name = "Cross Fader A", .wValue = 0x0307, .wIndex = 0x8002 },
|
||||
{ .name = "Cross Fader B", .wValue = 0x0308, .wIndex = 0x8002 },
|
||||
{ .name = "MIC", .wValue = 0x0309, .wIndex = 0x8002 },
|
||||
{ .name = "AUX", .wValue = 0x030d, .wIndex = 0x8002 }
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_12[] = {
|
||||
{ .name = "CH1", .wValue = 0x0100, .wIndex = 0x8016 },
|
||||
{ .name = "CH2", .wValue = 0x0101, .wIndex = 0x8016 },
|
||||
{ .name = "AUX", .wValue = 0x0104, .wIndex = 0x8016 }
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_34[] = {
|
||||
{ .name = "CH1", .wValue = 0x0200, .wIndex = 0x8016 },
|
||||
{ .name = "CH2", .wValue = 0x0201, .wIndex = 0x8016 },
|
||||
{ .name = "AUX", .wValue = 0x0204, .wIndex = 0x8016 }
|
||||
};
|
||||
|
||||
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_56[] = {
|
||||
{ .name = "CH1", .wValue = 0x0300, .wIndex = 0x8016 },
|
||||
{ .name = "CH2", .wValue = 0x0301, .wIndex = 0x8016 },
|
||||
{ .name = "AUX", .wValue = 0x0304, .wIndex = 0x8016 }
|
||||
};
|
||||
|
||||
struct snd_pioneer_djm_option_group {
|
||||
const char *name;
|
||||
const struct snd_pioneer_djm_option *options;
|
||||
const size_t count;
|
||||
const u16 default_value;
|
||||
};
|
||||
|
||||
#define snd_pioneer_djm_option_group_item(_name, suffix, _default_value) { \
|
||||
.name = _name, \
|
||||
.options = snd_pioneer_djm_options_##suffix, \
|
||||
.count = ARRAY_SIZE(snd_pioneer_djm_options_##suffix), \
|
||||
.default_value = _default_value }
|
||||
|
||||
static const struct snd_pioneer_djm_option_group snd_pioneer_djm_option_groups[] = {
|
||||
snd_pioneer_djm_option_group_item("Master Capture Level Capture Switch", capture_level, 0),
|
||||
snd_pioneer_djm_option_group_item("Capture 1-2 Capture Switch", capture_ch12, 2),
|
||||
snd_pioneer_djm_option_group_item("Capture 3-4 Capture Switch", capture_ch34, 2),
|
||||
snd_pioneer_djm_option_group_item("Capture 5-6 Capture Switch", capture_ch56, 0),
|
||||
snd_pioneer_djm_option_group_item("Playback 1-2 Playback Switch", playback_12, 0),
|
||||
snd_pioneer_djm_option_group_item("Playback 3-4 Playback Switch", playback_34, 1),
|
||||
snd_pioneer_djm_option_group_item("Playback 5-6 Playback Switch", playback_56, 2)
|
||||
};
|
||||
|
||||
// layout of the kcontrol->private_value:
|
||||
#define SND_PIONEER_DJM_VALUE_MASK 0x0000ffff
|
||||
#define SND_PIONEER_DJM_GROUP_MASK 0xffff0000
|
||||
#define SND_PIONEER_DJM_GROUP_SHIFT 16
|
||||
|
||||
static int snd_pioneer_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info)
|
||||
{
|
||||
u16 group_index = kctl->private_value >> SND_PIONEER_DJM_GROUP_SHIFT;
|
||||
size_t count;
|
||||
const char *name;
|
||||
const struct snd_pioneer_djm_option_group *group;
|
||||
|
||||
if (group_index >= ARRAY_SIZE(snd_pioneer_djm_option_groups))
|
||||
return -EINVAL;
|
||||
|
||||
group = &snd_pioneer_djm_option_groups[group_index];
|
||||
count = group->count;
|
||||
if (info->value.enumerated.item >= count)
|
||||
info->value.enumerated.item = count - 1;
|
||||
name = group->options[info->value.enumerated.item].name;
|
||||
strlcpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u16 group, u16 value)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (group >= ARRAY_SIZE(snd_pioneer_djm_option_groups)
|
||||
|| value >= snd_pioneer_djm_option_groups[group].count)
|
||||
return -EINVAL;
|
||||
|
||||
err = snd_usb_lock_shutdown(mixer->chip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = snd_usb_ctl_msg(
|
||||
mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0),
|
||||
USB_REQ_SET_FEATURE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
snd_pioneer_djm_option_groups[group].options[value].wValue,
|
||||
snd_pioneer_djm_option_groups[group].options[value].wIndex,
|
||||
NULL, 0);
|
||||
|
||||
snd_usb_unlock_shutdown(mixer->chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pioneer_djm_controls_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
|
||||
{
|
||||
elem->value.enumerated.item[0] = kctl->private_value & SND_PIONEER_DJM_VALUE_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pioneer_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
|
||||
{
|
||||
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
|
||||
struct usb_mixer_interface *mixer = list->mixer;
|
||||
unsigned long private_value = kctl->private_value;
|
||||
u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
|
||||
u16 value = elem->value.enumerated.item[0];
|
||||
|
||||
kctl->private_value = (group << SND_PIONEER_DJM_GROUP_SHIFT) | value;
|
||||
|
||||
return snd_pioneer_djm_controls_update(mixer, group, value);
|
||||
}
|
||||
|
||||
static int snd_pioneer_djm_controls_resume(struct usb_mixer_elem_list *list)
|
||||
{
|
||||
unsigned long private_value = list->kctl->private_value;
|
||||
u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
|
||||
u16 value = (private_value & SND_PIONEER_DJM_VALUE_MASK);
|
||||
|
||||
return snd_pioneer_djm_controls_update(list->mixer, group, value);
|
||||
}
|
||||
|
||||
static int snd_pioneer_djm_controls_create(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
int err, i;
|
||||
const struct snd_pioneer_djm_option_group *group;
|
||||
struct snd_kcontrol_new knew = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.index = 0,
|
||||
.info = snd_pioneer_djm_controls_info,
|
||||
.get = snd_pioneer_djm_controls_get,
|
||||
.put = snd_pioneer_djm_controls_put
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(snd_pioneer_djm_option_groups); i++) {
|
||||
group = &snd_pioneer_djm_option_groups[i];
|
||||
knew.name = group->name;
|
||||
knew.private_value = (i << SND_PIONEER_DJM_GROUP_SHIFT) | group->default_value;
|
||||
err = snd_pioneer_djm_controls_update(mixer, i, group->default_value);
|
||||
if (err)
|
||||
return err;
|
||||
err = add_single_ctl_with_resume(mixer, 0, snd_pioneer_djm_controls_resume,
|
||||
&knew, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -2706,6 +2916,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
|
|||
case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
|
||||
err = snd_bbfpro_controls_create(mixer);
|
||||
break;
|
||||
case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
|
||||
err = snd_pioneer_djm_controls_create(mixer);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -1946,7 +1946,7 @@ static void scarlett2_mixer_interrupt(struct urb *urb)
|
|||
goto requeue;
|
||||
|
||||
if (len == 8) {
|
||||
data = le32_to_cpu(*(u32 *)urb->transfer_buffer);
|
||||
data = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
|
||||
if (data & SCARLETT2_USB_INTERRUPT_VOL_CHANGE)
|
||||
scarlett2_mixer_interrupt_vol_change(mixer);
|
||||
if (data & SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE)
|
||||
|
|
|
@ -1109,7 +1109,7 @@ static const struct snd_us16x08_control_params eq_controls[] = {
|
|||
.control_id = SND_US16X08_ID_EQLOWFREQ,
|
||||
.type = USB_MIXER_U8,
|
||||
.num_channels = 16,
|
||||
.name = "EQ Low Frequence",
|
||||
.name = "EQ Low Frequency",
|
||||
},
|
||||
{ /* EQ mid low gain */
|
||||
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
|
||||
|
@ -1123,7 +1123,7 @@ static const struct snd_us16x08_control_params eq_controls[] = {
|
|||
.control_id = SND_US16X08_ID_EQLOWMIDFREQ,
|
||||
.type = USB_MIXER_U8,
|
||||
.num_channels = 16,
|
||||
.name = "EQ MidLow Frequence",
|
||||
.name = "EQ MidLow Frequency",
|
||||
},
|
||||
{ /* EQ mid low Q */
|
||||
.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
|
||||
|
@ -1144,7 +1144,7 @@ static const struct snd_us16x08_control_params eq_controls[] = {
|
|||
.control_id = SND_US16X08_ID_EQHIGHMIDFREQ,
|
||||
.type = USB_MIXER_U8,
|
||||
.num_channels = 16,
|
||||
.name = "EQ MidHigh Frequence",
|
||||
.name = "EQ MidHigh Frequency",
|
||||
},
|
||||
{ /* EQ mid high Q */
|
||||
.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
|
||||
|
@ -1165,7 +1165,7 @@ static const struct snd_us16x08_control_params eq_controls[] = {
|
|||
.control_id = SND_US16X08_ID_EQHIGHFREQ,
|
||||
.type = USB_MIXER_U8,
|
||||
.num_channels = 16,
|
||||
.name = "EQ High Frequence",
|
||||
.name = "EQ High Frequency",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -25,33 +25,16 @@
|
|||
.idProduct = prod, \
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC
|
||||
|
||||
#define QUIRK_RENAME_DEVICE(_vendor, _device) \
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
|
||||
.vendor_name = _vendor, \
|
||||
.product_name = _device, \
|
||||
.ifnum = QUIRK_NO_INTERFACE \
|
||||
}
|
||||
/* A standard entry matching with vid/pid and the audio class/subclass */
|
||||
#define USB_AUDIO_DEVICE(vend, prod) \
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS | \
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
|
||||
.idVendor = vend, \
|
||||
.idProduct = prod, \
|
||||
.bInterfaceClass = USB_CLASS_AUDIO, \
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
|
||||
#define QUIRK_DEVICE_PROFILE(_vendor, _device, _profile) \
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
|
||||
.vendor_name = _vendor, \
|
||||
.product_name = _device, \
|
||||
.profile_name = _profile, \
|
||||
.ifnum = QUIRK_NO_INTERFACE \
|
||||
}
|
||||
|
||||
/* HP Thunderbolt Dock Audio Headset */
|
||||
{
|
||||
USB_DEVICE(0x03f0, 0x0269),
|
||||
QUIRK_DEVICE_PROFILE("HP", "Thunderbolt Dock Audio Headset",
|
||||
"HP-Thunderbolt-Dock-Audio-Headset"),
|
||||
},
|
||||
/* HP Thunderbolt Dock Audio Module */
|
||||
{
|
||||
USB_DEVICE(0x03f0, 0x0567),
|
||||
QUIRK_DEVICE_PROFILE("HP", "Thunderbolt Dock Audio Module",
|
||||
"HP-Thunderbolt-Dock-Audio-Module"),
|
||||
},
|
||||
/* FTDI devices */
|
||||
{
|
||||
USB_DEVICE(0x0403, 0xb8d8),
|
||||
|
@ -85,44 +68,14 @@
|
|||
}
|
||||
},
|
||||
|
||||
/* Creative/E-Mu devices */
|
||||
{
|
||||
USB_DEVICE(0x041e, 0x3010),
|
||||
QUIRK_RENAME_DEVICE("Creative Labs", "Sound Blaster MP3+")
|
||||
},
|
||||
/* Creative/Toshiba Multimedia Center SB-0500 */
|
||||
{
|
||||
USB_DEVICE(0x041e, 0x3048),
|
||||
QUIRK_RENAME_DEVICE("Toshiba", "SB-0500")
|
||||
},
|
||||
{
|
||||
/* E-Mu 0202 USB */
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
|
||||
.idVendor = 0x041e,
|
||||
.idProduct = 0x3f02,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
},
|
||||
{
|
||||
/* E-Mu 0404 USB */
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
|
||||
.idVendor = 0x041e,
|
||||
.idProduct = 0x3f04,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
},
|
||||
{
|
||||
/* E-Mu Tracker Pre */
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
|
||||
.idVendor = 0x041e,
|
||||
.idProduct = 0x3f0a,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
},
|
||||
{
|
||||
/* E-Mu 0204 USB */
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
|
||||
.idVendor = 0x041e,
|
||||
.idProduct = 0x3f19,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
},
|
||||
/* E-Mu 0202 USB */
|
||||
{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f02) },
|
||||
/* E-Mu 0404 USB */
|
||||
{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f04) },
|
||||
/* E-Mu Tracker Pre */
|
||||
{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f0a) },
|
||||
/* E-Mu 0204 USB */
|
||||
{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f19) },
|
||||
|
||||
/*
|
||||
* HP Wireless Audio
|
||||
|
@ -164,70 +117,13 @@
|
|||
* Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
|
||||
* class matches do not take effect without an explicit ID match.
|
||||
*/
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x0850,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
},
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x08ae,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
},
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x08c6,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
},
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x08f0,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
},
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x08f5,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
},
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x08f6,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
|
||||
},
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x0990,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
|
||||
QUIRK_RENAME_DEVICE("Logitech, Inc.", "QuickCam Pro 9000")
|
||||
},
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x0850) },
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x08ae) },
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x08c6) },
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x08f0) },
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x08f5) },
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x08f6) },
|
||||
{ USB_AUDIO_DEVICE(0x046d, 0x0990) },
|
||||
|
||||
/*
|
||||
* Yamaha devices
|
||||
|
@ -2609,10 +2505,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
.type = QUIRK_MIDI_STANDARD_INTERFACE
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0ccd, 0x0028),
|
||||
QUIRK_RENAME_DEVICE("TerraTec", "Aureon5.1MkII")
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0ccd, 0x0035),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
|
@ -2623,16 +2515,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
}
|
||||
},
|
||||
|
||||
/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */
|
||||
{
|
||||
USB_DEVICE(0x103d, 0x0100),
|
||||
QUIRK_RENAME_DEVICE("Stanton", "ScratchAmp")
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x103d, 0x0101),
|
||||
QUIRK_RENAME_DEVICE("Stanton", "ScratchAmp")
|
||||
},
|
||||
|
||||
/* Novation EMS devices */
|
||||
{
|
||||
USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001),
|
||||
|
@ -2817,20 +2699,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
}
|
||||
},
|
||||
|
||||
/* */
|
||||
{
|
||||
/* aka. Serato Scratch Live DJ Box */
|
||||
USB_DEVICE(0x13e5, 0x0001),
|
||||
QUIRK_RENAME_DEVICE("Rane", "SL-1")
|
||||
},
|
||||
|
||||
/* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
|
||||
{
|
||||
USB_DEVICE(0x17aa, 0x1046),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Lenovo",
|
||||
.product_name = "ThinkStation P620 Rear",
|
||||
.profile_name = "Lenovo-ThinkStation-P620-Rear",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_SETUP_DISABLE_AUTOSUSPEND
|
||||
}
|
||||
|
@ -2839,9 +2711,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
{
|
||||
USB_DEVICE(0x17aa, 0x104d),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Lenovo",
|
||||
.product_name = "ThinkStation P620 Main",
|
||||
.profile_name = "Lenovo-ThinkStation-P620-Main",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_SETUP_DISABLE_AUTOSUSPEND
|
||||
}
|
||||
|
@ -2879,10 +2748,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
},
|
||||
|
||||
/* KeithMcMillen Stringport */
|
||||
{
|
||||
USB_DEVICE(0x1f38, 0x0001),
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
},
|
||||
{ USB_DEVICE(0x1f38, 0x0001) }, /* FIXME: should be more restrictive matching */
|
||||
|
||||
/* Miditech devices */
|
||||
{
|
||||
|
@ -2913,13 +2779,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
*/
|
||||
|
||||
#define AU0828_DEVICE(vid, pid, vname, pname) { \
|
||||
.idVendor = vid, \
|
||||
.idProduct = pid, \
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS | \
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
|
||||
.bInterfaceClass = USB_CLASS_AUDIO, \
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, \
|
||||
USB_AUDIO_DEVICE(vid, pid), \
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { \
|
||||
.vendor_name = vname, \
|
||||
.product_name = pname, \
|
||||
|
@ -2949,13 +2809,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
|
||||
/* Syntek STK1160 */
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x05e1,
|
||||
.idProduct = 0x0408,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
|
||||
USB_AUDIO_DEVICE(0x05e1, 0x0408),
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Syntek",
|
||||
.product_name = "STK1160",
|
||||
|
@ -3117,10 +2971,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
},
|
||||
{
|
||||
/* Tascam US122 MKII - playback-only support */
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
|
||||
.idVendor = 0x0644,
|
||||
.idProduct = 0x8021,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021),
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "TASCAM",
|
||||
.product_name = "US122 MKII",
|
||||
|
@ -3305,19 +3156,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* The original product_name is "USB Sound Device", however this name
|
||||
* is also used by the CM106 based cards, so make it unique.
|
||||
*/
|
||||
{
|
||||
USB_DEVICE(0x0d8c, 0x0102),
|
||||
QUIRK_RENAME_DEVICE(NULL, "ICUSBAUDIO7D")
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0d8c, 0x0103),
|
||||
QUIRK_RENAME_DEVICE(NULL, "Audio Advantage MicroII")
|
||||
},
|
||||
|
||||
/* disabled due to regression for other devices;
|
||||
* see https://bugzilla.kernel.org/show_bug.cgi?id=199905
|
||||
*/
|
||||
|
@ -3418,18 +3256,10 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
}
|
||||
}
|
||||
},
|
||||
/* Dell WD15 Dock */
|
||||
{
|
||||
USB_DEVICE(0x0bda, 0x4014),
|
||||
QUIRK_DEVICE_PROFILE("Dell", "WD15 Dock", "Dell-WD15-Dock")
|
||||
},
|
||||
/* Dell WD19 Dock */
|
||||
{
|
||||
USB_DEVICE(0x0bda, 0x402e),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Dell",
|
||||
.product_name = "WD19 Dock",
|
||||
.profile_name = "Dell-WD15-Dock",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_SETUP_FMT_AFTER_RESUME
|
||||
}
|
||||
|
@ -3701,33 +3531,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
}
|
||||
},
|
||||
|
||||
#define ALC1220_VB_DESKTOP(vend, prod) { \
|
||||
USB_DEVICE(vend, prod), \
|
||||
QUIRK_DEVICE_PROFILE("Realtek", "ALC1220-VB-DT", \
|
||||
"Realtek-ALC1220-VB-Desktop") \
|
||||
}
|
||||
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 */
|
||||
ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */
|
||||
#undef ALC1220_VB_DESKTOP
|
||||
|
||||
/* Two entries for Gigabyte TRX40 Aorus Master:
|
||||
* TRX40 Aorus Master has two USB-audio devices, one for the front headphone
|
||||
* with ESS SABRE9218 DAC chip, while another for the rest I/O (the rear
|
||||
* panel and the front mic) with Realtek ALC1220-VB.
|
||||
* Here we provide two distinct names for making UCM profiles easier.
|
||||
*/
|
||||
{
|
||||
USB_DEVICE(0x0414, 0xa000),
|
||||
QUIRK_DEVICE_PROFILE("Gigabyte", "Aorus Master Front Headphone",
|
||||
"Gigabyte-Aorus-Master-Front-Headphone")
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0414, 0xa001),
|
||||
QUIRK_DEVICE_PROFILE("Gigabyte", "Aorus Master Main Audio",
|
||||
"Gigabyte-Aorus-Master-Main-Audio")
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Pioneer DJ DJM-900NXS2
|
||||
|
@ -3804,13 +3607,7 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */
|
|||
* channels to be swapped and out of phase, which is dealt with in quirks.c.
|
||||
*/
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
|
||||
.idVendor = 0x534d,
|
||||
.idProduct = 0x2109,
|
||||
.bInterfaceClass = USB_CLASS_AUDIO,
|
||||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
|
||||
USB_AUDIO_DEVICE(0x534d, 0x2109),
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "MacroSilicon",
|
||||
.product_name = "MS2109",
|
||||
|
@ -3851,3 +3648,4 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */
|
|||
},
|
||||
|
||||
#undef USB_DEVICE_VENDOR_SPEC
|
||||
#undef USB_AUDIO_DEVICE
|
||||
|
|
|
@ -110,7 +110,6 @@ enum quirk_type {
|
|||
struct snd_usb_audio_quirk {
|
||||
const char *vendor_name;
|
||||
const char *product_name;
|
||||
const char *profile_name; /* override the card->longname */
|
||||
int16_t ifnum;
|
||||
uint16_t type;
|
||||
bool shares_media_device;
|
||||
|
|
Loading…
Reference in New Issue