Commit bc334cb6 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'for-next' into for-linus

Preparation for 4.17 merge.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents 5607dddb b44d419b
......@@ -34,14 +34,14 @@
*
*/
static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control)
{
return (bmControls >> (control * 2)) & 0x1;
return (bmControls >> ((control - 1) * 2)) & 0x1;
}
static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control)
{
return (bmControls >> (control * 2)) & 0x2;
return (bmControls >> ((control - 1) * 2)) & 0x2;
}
/* 4.7.2 Class-Specific AC Interface Descriptor */
......
This diff is collapsed.
......@@ -1710,6 +1710,7 @@ struct snd_emu10k1 {
unsigned int ecard_ctrl; /* ecard control bits */
unsigned int address_mode; /* address mode */
unsigned long dma_mask; /* PCI DMA mask */
bool iommu_workaround; /* IOMMU workaround needed */
unsigned int delay_pcm_irq; /* in samples */
int max_cache_pages; /* max memory size / PAGE_SIZE */
struct snd_dma_buffer silent_page; /* silent page */
......@@ -1718,7 +1719,6 @@ struct snd_emu10k1 {
struct snd_dma_buffer p16v_buffer;
struct snd_util_memhdr *memhdr; /* page allocation list */
struct snd_emu10k1_memblk *reserved_page; /* reserved page */
struct list_head mapped_link_head;
struct list_head mapped_order_link_head;
......@@ -1878,6 +1878,8 @@ void snd_p16v_resume(struct snd_emu10k1 *emu);
/* memory allocation */
struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream);
int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
struct snd_dma_buffer *dmab);
struct snd_util_memblk *snd_emu10k1_synth_alloc(struct snd_emu10k1 *emu, unsigned int size);
int snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, int size);
......
......@@ -146,6 +146,8 @@ int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid,
int flags, unsigned int verb, unsigned int parm);
bool snd_hdac_check_power_state(struct hdac_device *hdac,
hda_nid_t nid, unsigned int target_state);
unsigned int snd_hdac_sync_power_state(struct hdac_device *hdac,
hda_nid_t nid, unsigned int target_state);
/**
* snd_hdac_read_parm - read a codec parameter
* @codec: the codec object
......
......@@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime {
char *buffer; /* vmallocated period */
size_t buffer_used; /* used length from period buffer */
struct mutex params_lock;
atomic_t rw_ref; /* concurrent read/write accesses */
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
struct snd_pcm_plugin *plugin_first;
struct snd_pcm_plugin *plugin_last;
......
......@@ -27,6 +27,7 @@
/* bInterfaceProtocol values to denote the version of the standard used */
#define UAC_VERSION_1 0x00
#define UAC_VERSION_2 0x20
#define UAC_VERSION_3 0x30
/* A.2 Audio Interface Subclass Codes */
#define USB_SUBCLASS_AUDIOCONTROL 0x01
......
......@@ -105,7 +105,7 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
{
unsigned long flags;
struct snd_kctl_event *cread;
spin_lock_irqsave(&ctl->read_lock, flags);
while (!list_empty(&ctl->events)) {
cread = snd_kctl_event(ctl->events.next);
......@@ -159,7 +159,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
unsigned long flags;
struct snd_ctl_file *ctl;
struct snd_kctl_event *ev;
if (snd_BUG_ON(!card || !id))
return;
if (card->shutdown)
......@@ -213,7 +213,7 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
{
unsigned int size;
unsigned int idx;
if (count == 0 || count > MAX_CONTROL_COUNT)
return -EINVAL;
......@@ -238,7 +238,7 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
* @ncontrol: the initialization record
* @private_data: the private data to set
*
* Allocates a new struct snd_kcontrol instance and initialize from the given
* Allocates a new struct snd_kcontrol instance and initialize from the given
* template. When the access field of ncontrol is 0, it's assumed as
* READWRITE access. When the count field is 0, it's assumes as one.
*
......@@ -251,7 +251,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
unsigned int count;
unsigned int access;
int err;
if (snd_BUG_ON(!ncontrol || !ncontrol->info))
return NULL;
......@@ -753,7 +753,7 @@ static int snd_ctl_elem_list(struct snd_card *card,
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;
......@@ -827,7 +827,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
int result;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &info->id);
if (kctl == NULL) {
......@@ -992,7 +992,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
int result;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
down_write(&card->controls_rwsem);
......@@ -1020,7 +1020,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
int result;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
down_write(&card->controls_rwsem);
......
......@@ -670,7 +670,7 @@ card_id_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
return snprintf(buf, PAGE_SIZE, "%s\n", card->id);
return scnprintf(buf, PAGE_SIZE, "%s\n", card->id);
}
static ssize_t
......@@ -710,7 +710,7 @@ card_number_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
return snprintf(buf, PAGE_SIZE, "%i\n", card->number);
return scnprintf(buf, PAGE_SIZE, "%i\n", card->number);
}
static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL);
......
This diff is collapsed.
......@@ -1129,16 +1129,12 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
if (constrs->rules_num >= constrs->rules_all) {
struct snd_pcm_hw_rule *new;
unsigned int new_rules = constrs->rules_all + 16;
new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
new = krealloc(constrs->rules, new_rules * sizeof(*c),
GFP_KERNEL);
if (!new) {
va_end(args);
return -ENOMEM;
}
if (constrs->rules) {
memcpy(new, constrs->rules,
constrs->rules_num * sizeof(*c));
kfree(constrs->rules);
}
constrs->rules = new;
constrs->rules_all = new_rules;
}
......
......@@ -323,7 +323,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_pcm_hw_constraints *constrs =
&substream->runtime->hw_constraints;
unsigned int k;
unsigned int rstamps[constrs->rules_num];
unsigned int *rstamps;
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp;
struct snd_pcm_hw_rule *r;
......@@ -331,7 +331,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_mask old_mask;
struct snd_interval old_interval;
bool again;
int changed;
int changed, err = 0;
/*
* Each application of rule has own sequence number.
......@@ -339,8 +339,9 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
* Each member of 'rstamps' array represents the sequence number of
* recent application of corresponding rule.
*/
for (k = 0; k < constrs->rules_num; k++)
rstamps[k] = 0;
rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL);
if (!rstamps)
return -ENOMEM;
/*
* Each member of 'vstamps' array represents the sequence number of
......@@ -398,8 +399,10 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
}
changed = r->func(params, r);
if (changed < 0)
return changed;
if (changed < 0) {
err = changed;
goto out;
}
/*
* When the parameter is changed, notify it to the caller
......@@ -430,7 +433,9 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
if (again)
goto retry;
return 0;
out:
kfree(rstamps);
return err;
}
static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
......
......@@ -63,15 +63,18 @@ static int slave_update(struct link_slave *slave)
struct snd_ctl_elem_value *uctl;
int err, ch;
uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (!uctl)
return -ENOMEM;
uctl->id = slave->slave.id;
err = slave->slave.get(&slave->slave, uctl);
if (err < 0)
goto error;
for (ch = 0; ch < slave->info.count; ch++)
slave->vals[ch] = uctl->value.integer.value[ch];
error:
kfree(uctl);
return 0;
return err < 0 ? err : 0;
}
/* get the slave ctl info and save the initial values */
......
......@@ -296,6 +296,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
cable->pause |= stream;
loopback_timer_stop(dpcm);
spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
......@@ -304,6 +306,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
cable->pause &= ~stream;
loopback_timer_start(dpcm);
spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break;
default:
return -EINVAL;
......@@ -892,9 +896,11 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol,
[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
unsigned int val = 0;
if (cable != NULL)
val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
1 : 0;
if (cable != NULL) {
unsigned int running = cable->running ^ cable->pause;
val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0;
}
ucontrol->value.integer.value[0] = val;
return 0;
}
......
......@@ -3,6 +3,7 @@
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/module.h>
......@@ -1064,3 +1065,37 @@ bool snd_hdac_check_power_state(struct hdac_device *hdac,
return (state == target_state);
}
EXPORT_SYMBOL_GPL(snd_hdac_check_power_state);
/**
* snd_hdac_sync_power_state - wait until actual power state matches
* with the target state
*
* @hdac: the HDAC device
* @nid: NID to send the command
* @target_state: target state to check for
*
* Return power state or PS_ERROR if codec rejects GET verb.
*/
unsigned int snd_hdac_sync_power_state(struct hdac_device *codec,
hda_nid_t nid, unsigned int power_state)
{
unsigned long end_time = jiffies + msecs_to_jiffies(500);
unsigned int state, actual_state, count;
for (count = 0; count < 500; count++) {
state = snd_hdac_codec_read(codec, nid, 0,
AC_VERB_GET_POWER_STATE, 0);
if (state & AC_PWRST_ERROR) {
msleep(20);
break;
}
actual_state = (state >> 4) & 0x0f;
if (actual_state == power_state)
break;
if (time_after_eq(jiffies, end_time))
break;
/* wait until the codec reachs to the target state */
msleep(1);
}
return state;
}
EXPORT_SYMBOL_GPL(snd_hdac_sync_power_state);
......@@ -736,8 +736,7 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct echoaudio *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct audiopipe *pipe = runtime->private_data;
struct audiopipe *pipe;
int i, err;
u32 channelmask = 0;
struct snd_pcm_substream *s;
......
......@@ -36,6 +36,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
......@@ -1272,12 +1273,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
release_firmware(emu->dock_fw);
if (emu->irq >= 0)
free_irq(emu->irq, emu);
/* remove reserved page */
if (emu->reserved_page) {
snd_emu10k1_synth_free(emu,
(struct snd_util_memblk *)emu->reserved_page);
emu->reserved_page = NULL;
}
snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area)
snd_dma_free_pages(&emu->silent_page);
......@@ -1764,6 +1759,38 @@ static struct snd_emu_chip_details emu_chip_details[] = {
{ } /* terminator */
};
/*
* The chip (at least the Audigy 2 CA0102 chip, but most likely others, too)
* has a problem that from time to time it likes to do few DMA reads a bit
* beyond its normal allocation and gets very confused if these reads get
* blocked by a IOMMU.
*
* This behaviour has been observed for the first (reserved) page
* (for which it happens multiple times at every playback), often for various
* synth pages and sometimes for PCM playback buffers and the page table
* memory itself.
*
* As a workaround let's widen these DMA allocations by an extra page if we
* detect that the device is behind a non-passthrough IOMMU.
*/
static void snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu)
{
struct iommu_domain *domain;
emu->iommu_workaround = false;
if (!iommu_present(emu->card->dev->bus))
return;
domain = iommu_get_domain_for_dev(emu->card->dev);
if (domain && domain->type == IOMMU_DOMAIN_IDENTITY)
return;
dev_notice(emu->card->dev,
"non-passthrough IOMMU detected, widening DMA allocations");
emu->iommu_workaround = true;
}
int snd_emu10k1_create(struct snd_card *card,
struct pci_dev *pci,
unsigned short extin_mask,
......@@ -1776,6 +1803,7 @@ int snd_emu10k1_create(struct snd_card *card,
struct snd_emu10k1 *emu;
int idx, err;
int is_audigy;
size_t page_table_size;
unsigned int silent_page;
const struct snd_emu_chip_details *c;
static struct snd_device_ops ops = {
......@@ -1873,12 +1901,13 @@ int snd_emu10k1_create(struct snd_card *card,
is_audigy = emu->audigy = c->emu10k2_chip;
snd_emu10k1_detect_iommu(emu);
/* set addressing mode */
emu->address_mode = is_audigy ? 0 : 1;
/* set the DMA transfer mask */
emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
if (dma_set_mask(&pci->dev, emu->dma_mask) < 0 ||
dma_set_coherent_mask(&pci->dev, emu->dma_mask) < 0) {
if (dma_set_mask_and_coherent(&pci->dev, emu->dma_mask) < 0) {
dev_err(card->dev,
"architecture does not support PCI busmaster DMA with mask 0x%lx\n",
emu->dma_mask);
......@@ -1900,11 +1929,17 @@ int snd_emu10k1_create(struct snd_card *card,
emu->port = pci_resource_start(pci, 0);
emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
(emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) {
page_table_size = sizeof(u32) * (emu->address_mode ? MAXPAGES1 :
MAXPAGES0);
if (snd_emu10k1_alloc_pages_maybe_wider(emu, page_table_size,
&emu->ptb_pages) < 0) {
err = -ENOMEM;
goto error;
}
dev_dbg(card->dev, "page table address range is %.8lx:%.8lx\n",
(unsigned long)emu->ptb_pages.addr,
(unsigned long)(emu->ptb_pages.addr + emu->ptb_pages.bytes));
emu->page_ptr_table = vmalloc(emu->max_cache_pages * sizeof(void *));
emu->page_addr_table = vmalloc(emu->max_cache_pages *
......@@ -1914,11 +1949,16 @@ int snd_emu10k1_create(struct snd_card *card,
goto error;
}
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
EMUPAGESIZE, &emu->silent_page) < 0) {
if (snd_emu10k1_alloc_pages_maybe_wider(emu, EMUPAGESIZE,
&emu->silent_page) < 0) {
err = -ENOMEM;
goto error;
}
dev_dbg(card->dev, "silent page range is %.8lx:%.8lx\n",
(unsigned long)emu->silent_page.addr,
(unsigned long)(emu->silent_page.addr +
emu->silent_page.bytes));
emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
if (emu->memhdr == NULL) {
err = -ENOMEM;
......@@ -1993,13 +2033,8 @@ int snd_emu10k1_create(struct snd_card *card,
SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
emu->reserved_page = (struct snd_emu10k1_memblk *)
snd_emu10k1_synth_alloc(emu, 4096);
if (emu->reserved_page)
emu->reserved_page->map_locked = 1;
/* Clear silent pages and set up pointers */
memset(emu->silent_page.area, 0, PAGE_SIZE);
memset(emu->silent_page.area, 0, emu->silent_page.bytes);
silent_page = emu->silent_page.addr << emu->address_mode;
for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
......
......@@ -411,12 +411,20 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
size_t alloc_size;
int err;
if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
return err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
alloc_size = params_buffer_bytes(hw_params);
if (emu->iommu_workaround)
alloc_size += EMUPAGESIZE;
err = snd_pcm_lib_malloc_pages(substream, alloc_size);
if (err < 0)
return err;
if (emu->iommu_workaround && runtime->dma_bytes >= EMUPAGESIZE)
runtime->dma_bytes -= EMUPAGESIZE;
if (err > 0) { /* change */
int mapped;
if (epcm->memblk != NULL)
......
......@@ -34,7 +34,10 @@
* aligned pages in others
*/
#define __set_ptb_entry(emu,page,addr) \
(((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
(((__le32 *)(emu)->ptb_pages.area)[page] = \
cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
#define __get_ptb_entry(emu, page) \
(le32_to_cpu(((__le32 *)(emu)->ptb_pages.area)[page]))
#define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE)
#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES)
......@@ -44,8 +47,7 @@
/* get offset address from aligned page */
#define aligned_page_offset(page) ((page) << PAGE_SHIFT)
#if PAGE_SIZE == 4096
/* page size == EMUPAGESIZE */
#if PAGE_SIZE == EMUPAGESIZE && !IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
/* fill PTB entrie(s) corresponding to page with addr */
#define set_ptb_entry(emu,page,addr) __set_ptb_entry(emu,page,addr)
/* fill PTB entrie(s) corresponding to page with silence pointer */
......@@ -58,6 +60,8 @@ static inline void set_ptb_entry(struct snd_emu10k1 *emu, int page, dma_addr_t a
page *= UNIT_PAGES;
for (i = 0; i < UNIT_PAGES; i++, page++) {
__set_ptb_entry(emu, page, addr);
dev_dbg(emu->card->dev, "mapped page %d to entry %.8x\n", page,
(unsigned int)__get_ptb_entry(emu, page));
addr += EMUPAGESIZE;
}
}
......@@ -65,9 +69,12 @@ static inline void set_silent_ptb(struct snd_emu10k1 *emu, int page)
{
int i;
page *= UNIT_PAGES;
for (i = 0; i < UNIT_PAGES; i++, page++)
for (i = 0; i < UNIT_PAGES; i++, page++) {
/* do not increment ptr */
__set_ptb_entry(emu, page, emu->silent_page.addr);
dev_dbg(emu->card->dev, "mapped silent page %d to entry %.8x\n",
page, (unsigned int)__get_ptb_entry(emu, page));
}
}
#endif /* PAGE_SIZE */
......@@ -102,7 +109,7 @@ static void emu10k1_memblk_init(struct snd_emu10k1_memblk *blk)
*/
static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct list_head **nextp)
{
int page = 0, found_page = -ENOMEM;
int page = 1, found_page = -ENOMEM;
int max_size = npages;
int size;
struct list_head *candidate = &emu->mapped_link_head;
......@@ -147,6 +154,10 @@ static int map_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
page = search_empty_map_area(emu, blk->pages, &next);
if (page < 0) /* not found */
return page;
if (page == 0) {
dev_err(emu->card->dev, "trying to map zero (reserved) page\n");
return -EINVAL;
}
/* insert this block in the proper position of mapped list */
list_add_tail(&blk->mapped_link, next);
/* append this as a newest block in order list */
......@@ -177,7 +188,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
q = get_emu10k1_memblk(p, mapped_link);
start_page = q->mapped_page + q->pages;
} else
start_page = 0;
start_page = 1;
if ((p = blk->mapped_link.next) != &emu->mapped_link_head) {
q = get_emu10k1_memblk(p, mapped_link);
end_page = q->mapped_page;
......@@ -366,6 +377,33 @@ int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk)
return snd_emu10k1_synth_free(emu, blk);
}
/*
* allocate DMA pages, widening the allocation if necessary
*
* See the comment above snd_emu10k1_detect_iommu() in emu10k1_main.c why
* this might be needed.
*
* If you modify this function check whether __synth_free_pages() also needs
* changes.
*/
int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
struct snd_dma_buffer *dmab)
{
if (emu->iommu_workaround) {
size_t npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
size_t size_real = npages * PAGE_SIZE;
/*
* The device has been observed to accesses up to 256 extra
* bytes, but use 1k to be safe.
*/
if (size_real < size + 1024)
size += PAGE_SIZE;
}
return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci), size, dmab);
}
/*
* memory allocation using multiple pages (for synth)
......@@ -450,10 +488,27 @@ static void get_single_page_range(struct snd_util_memhdr *hdr,
static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
int last_page)
{
struct snd_dma_buffer dmab;
int page;
dmab.dev.type = SNDRV_DMA_TYPE_DEV;
dmab.dev.dev = snd_dma_pci_data(emu->pci);
for (page = first_page; page <= last_page; page++) {
free_page((unsigned long)emu->page_ptr_table[page]);
if (emu->page_ptr_table[page] == NULL)
continue;
dmab.area = emu->page_ptr_table[page];
dmab.addr = emu->page_addr_table[page];
/*
* please keep me in sync with logic in
* snd_emu10k1_alloc_pages_maybe_wider()
*/
dmab.bytes = PAGE_SIZE;
if (emu->iommu_workaround)
dmab.bytes *= 2;
snd_dma_free_pages(&dmab);
emu->page_addr_table[page] = 0;
emu->page_ptr_table[page] = NULL;
}
......@@ -465,30 +520,30 @@ static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
{
int page, first_page, last_page;
struct snd_dma_buffer dmab;
emu10k1_memblk_init(blk);
get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
/* allocate kernel pages */
for (page = first_page; page <= last_page; page++) {
/* first try to allocate from <4GB zone */
struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 |
__GFP_NOWARN);
if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) {
if (p)
__free_page(p);
/* try to allocate from <16MB zone */
p = alloc_page(GFP_ATOMIC | GFP_DMA |
__GFP_NORETRY | /* no OOM-killer */
__GFP_NOWARN);
if (snd_emu10k1_alloc_pages_maybe_wider(emu, PAGE_SIZE,
&dmab) < 0)
goto __fail;
if (!is_valid_page(emu, dmab.addr)) {
snd_dma_free_pages(&dmab);
goto __fail;
}
if (!p) {
__synth_free_pages(emu, first_page, page - 1);
return -ENOMEM;
}
emu->page_addr_table[page] = page_to_phys(p);
emu->page_ptr_table[page] = page_address(p);
emu->page_addr_table[page] = dmab.addr;
emu->page_ptr_table[page] = dmab.area;
}
return 0;
__fail:
/* release allocated pages */
last_page = page - 1;
__synth_free_pages(emu, first_page, last_page);
return -ENOMEM;
}
/*
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Digital Beep Input Interface for HD-audio codec
*
* Author: Matt Ranostay <mranostay@gmail.com>
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
* Copyright (c) 2008 Embedded Alley Solutions Inc
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/input.h>
......
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Digital Beep Input Interface for HD-audio codec
*
* Author: Matt Ranostay <mranostay@gmail.com>
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
* Copyright (c) 2008 Embedded Alley Solutions Inc
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SOUND_HDA_BEEP_H
......
......@@ -2702,32 +2702,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all);
/*
* wait until the state is reached, returns the current state
*/
static unsigned int hda_sync_power_state(struct hda_codec *codec,
hda_nid_t fg,
unsigned int power_state)
{
unsigned long end_time = jiffies + msecs_to_jiffies(500);
unsigned int state, actual_state;
for (;;) {
state = snd_hda_codec_read(codec, fg, 0,
AC_VERB_GET_POWER_STATE, 0);
if (state & AC_PWRST_ERROR)
break;
actual_state = (state >> 4) & 0x0f;
if (actual_state == power_state)
break;
if (time_after_eq(jiffies, end_time))
break;
/* wait until the codec reachs to the target state */
msleep(1);
}
return state;
}
/**
* snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
* @codec: the HDA codec
......@@ -2790,7 +2764,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
state);
snd_hda_codec_set_power_to_all(codec, fg, power_state);
}
state = hda_sync_power_state(codec, fg, power_state);
state = snd_hda_sync_power_state(codec, fg, power_state);
if (!(state & AC_PWRST_ERROR))
break;
}
......
......@@ -2434,6 +2434,9 @@ static const struct pci_device_id azx_ids[] = {
/* Cannonlake */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
/* Icelake */
{ PCI_DEVICE(0x8086, 0x34c8),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
/* Broxton-P(Apollolake) */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
......
......@@ -622,7 +622,11 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
{
return snd_hdac_check_power_state(&codec->core, nid, target_state);
}
static inline bool snd_hda_sync_power_state(struct hda_codec *codec,
hda_nid_t nid, unsigned int target_state)
{
return snd_hdac_sync_power_state(&codec->core, nid, target_state);
}
unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state);
......
......@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <sound/core.h>
#include <sound/tlv.h>
......@@ -425,10 +426,9 @@ DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1);
static struct snd_kcontrol *ctl_find(struct snd_card *card,
const char *name)
{
struct snd_ctl_elem_id sid;
memset(&sid, 0, sizeof(sid));
/* FIXME: strcpy is bad. */
strcpy(sid.name, name);
struct snd_ctl_elem_id sid = {0};
strlcpy(sid.name, name, sizeof(sid.name));
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(card, &sid);
}
......
......@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/info.h>
......@@ -785,10 +786,9 @@ DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
static struct snd_kcontrol *ctl_find(struct snd_card *card,
const char *name)
{
struct snd_ctl_elem_id sid;
memset(&sid, 0, sizeof(sid));
/* FIXME: strcpy is bad. */
strcpy(sid.name, name);
struct snd_ctl_elem_id sid = {0};
strlcpy(sid.name, name, sizeof(sid.name));
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(card, &sid);
}
......
......@@ -7,6 +7,7 @@
* Alan Cox (alan@lxorguk.ukuu.org.uk)
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* Audio Class 3.0 support by Ruslan Bilovol <ruslan.bilovol@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -44,6 +45,7 @@
#include <linux/mutex.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <linux/usb/audio-v3.h>
#include <linux/module.h>
#include <sound/control.h>
......@@ -281,7 +283,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
break;
}
case UAC_VERSION_2: {
case UAC_VERSION_2:
case UAC_VERSION_3: {
struct usb_interface_assoc_descriptor *assoc =
usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
......@@ -301,7 +304,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
}
if (!assoc) {
dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n");
dev_err(&dev->dev, "Audio class v2/v3 interfaces need an interface association\n");
return -EINVAL;
}
......
......@@ -22,7 +22,7 @@ struct audioformat {
unsigned char endpoint; /* endpoint */
unsigned char ep_attr; /* endpoint attributes */
unsigned char datainterval; /* log_2 of data packet interval */
unsigned char protocol; /* UAC_VERSION_1/2 */
unsigned char protocol; /* UAC_VERSION_1/2/3 */
unsigned int maxpacksize; /* max. packet size */
unsigned int rates; /* rate bitmasks */
unsigned int rate_min, rate_max; /* min/max rates */
......
This diff is collapsed.
......@@ -6,7 +6,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate);
int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id,
bool validate);
int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol,
int entity_id, bool validate);
#endif /* __USBAUDIO_CLOCK_H */
......@@ -20,6 +20,7 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <linux/usb/audio-v3.h>
#include <sound/core.h>
#include <sound/pcm.h>
......@@ -39,11 +40,11 @@
* @dev: usb device
* @fp: audioformat record
* @format: the format tag (wFormatTag)
* @fmt: the format type descriptor
* @fmt: the format type descriptor (v1/v2) or AudioStreaming descriptor (v3)
*/
static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int format, void *_fmt)
u64 format, void *_fmt)
{
int sample_width, sample_bytes;
u64 pcm_formats = 0;
......@@ -54,7 +55,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
sample_width = fmt->bBitResolution;
sample_bytes = fmt->bSubframeSize;
format = 1 << format;
format = 1ULL << format;
break;
}
......@@ -69,6 +70,18 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
format <<= 1;
break;
}
case UAC_VERSION_3: {
struct uac3_as_header_descriptor *as = _fmt;
sample_width = as->bBitResolution;
sample_bytes = as->bSubslotSize;
if (format & UAC3_FORMAT_TYPE_I_RAW_DATA)
pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL;
format <<= 1;
break;
}
}
if ((pcm_formats == 0) &&
......@@ -137,7 +150,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
}
if (format & ~0x3f) {
usb_audio_info(chip,
"%u:%d : unsupported format bits %#x\n",
"%u:%d : unsupported format bits %#llx\n",
fp->iface, fp->altsetting, format);
}
......@@ -281,15 +294,16 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
/*
* parse the format descriptor and stores the possible sample rates
* on the audioformat table (audio class v2).
* on the audioformat table (audio class v2 and v3).
*/
static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
struct audioformat *fp)
{
struct usb_device *dev = chip->dev;
unsigned char tmp[2], *data;
int nr_triplets, data_size, ret = 0;
int clock = snd_usb_clock_find_source(chip, fp->clock, false);
int clock = snd_usb_clock_find_source(chip, fp->protocol,
fp->clock, false);
if (clock < 0) {
dev_err(&dev->dev,
......@@ -368,13 +382,30 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
* parse the format type I and III descriptors
*/
static int parse_audio_format_i(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format,
struct uac_format_type_i_continuous_descriptor *fmt)
struct audioformat *fp, u64 format,
void *_fmt)
{
snd_pcm_format_t pcm_format;
unsigned int fmt_type;
int ret;
if (fmt->bFormatType == UAC_FORMAT_TYPE_III) {
switch (fp->protocol) {
default:
case UAC_VERSION_1:
case UAC_VERSION_2: {
struct uac_format_type_i_continuous_descriptor *fmt = _fmt;
fmt_type = fmt->bFormatType;
break;
}
case UAC_VERSION_3: {
/* fp->fmt_type is already set in this case */
fmt_type = fp->fmt_type;
break;
}
}
if (fmt_type == UAC_FORMAT_TYPE_III) {
/* FIXME: the format type is really IECxxx
* but we give normal PCM format to get the existing
* apps working...
......@@ -393,7 +424,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
}
fp->formats = pcm_format_to_bits(pcm_format);
} else {
fp->formats = parse_audio_format_i_type(chip, fp, format, fmt);
fp->formats = parse_audio_format_i_type(chip, fp, format, _fmt);
if (!fp->formats)
return -EINVAL;
}
......@@ -405,15 +436,20 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
*/
switch (fp->protocol) {
default:
case UAC_VERSION_1:
case UAC_VERSION_1: {
struct uac_format_type_i_continuous_descriptor *fmt = _fmt;
fp->channels = fmt->bNrChannels;
ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
break;
}
case UAC_VERSION_2:
case UAC_VERSION_3: {
/* fp->channels is already set in this case */
ret = parse_audio_format_rates_v2(chip, fp);
ret = parse_audio_format_rates_v2v3(chip, fp);
break;
}
}
if (fp->channels < 1) {
usb_audio_err(chip,
......@@ -430,7 +466,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
*/
static int parse_audio_format_ii(struct snd_usb_audio *chip,
struct audioformat *fp,
int format, void *_fmt)
u64 format, void *_fmt)
{
int brate, framesize, ret;
......@@ -445,7 +481,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
break;
default:
usb_audio_info(chip,
"%u:%d : unknown format tag %#x is detected. processed as MPEG.\n",
"%u:%d : unknown format tag %#llx is detected. processed as MPEG.\n",
fp->iface, fp->altsetting, format);
fp->formats = SNDRV_PCM_FMTBIT_MPEG;
break;
......@@ -470,7 +506,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
framesize = le16_to_cpu(fmt->wSamplesPerFrame);
usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
fp->frame_size = framesize;
ret = parse_audio_format_rates_v2(chip, fp);
ret = parse_audio_format_rates_v2v3(chip, fp);
break;
}
}
......@@ -479,7 +515,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
}
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format,
struct audioformat *fp, u64 format,
struct uac_format_type_i_continuous_descriptor *fmt,
int stream)
{
......@@ -520,3 +556,26 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
return 0;
}
int snd_usb_parse_audio_format_v3(struct snd_usb_audio *chip,
struct audioformat *fp,
struct uac3_as_header_descriptor *as,
int stream)
{
u64 format = le64_to_cpu(as->bmFormats);
int err;
/*
* Type I format bits are D0..D6
* This test works because type IV is not supported
*/
if (format & 0x7f)
fp->fmt_type = UAC_FORMAT_TYPE_I;
else
fp->fmt_type = UAC_FORMAT_TYPE_III;
err = parse_audio_format_i(chip, fp, format, as);
if (err < 0)
return err;
return 0;
}
......@@ -3,8 +3,12 @@
#define __USBAUDIO_FORMAT_H
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format,
struct audioformat *fp, u64 format,
struct uac_format_type_i_continuous_descriptor *fmt,
int stream);
int snd_usb_parse_audio_format_v3(struct snd_usb_audio *chip,
struct audioformat *fp,
struct uac3_as_header_descriptor *as,
int stream);
#endif /* __USBAUDIO_FORMAT_H */
This diff is collapsed.
......@@ -1149,27 +1149,17 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
return false;
}
/* Marantz/Denon USB DACs need a vendor cmd to switch
/* ITF-USB DSD based DACs need a vendor cmd to switch
* between PCM and native DSD mode
*/
static bool is_marantz_denon_dac(unsigned int id)
static bool is_itf_usb_dsd_dac(unsigned int id)
{
switch (id) {
case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
return true;
}
return false;
}
/* TEAC UD-501/UD-503/NT-503 USB DACs need a vendor cmd to switch
* between PCM/DOP and native DSD mode
*/
static bool is_teac_dsd_dac(unsigned int id)
{
switch (id) {
case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */
case USB_ID(0x1852, 0x5065): /* Luxman DA-06 */
case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
return true;
......@@ -1183,7 +1173,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
struct usb_device *dev = subs->dev;
int err;
if (is_marantz_denon_dac(subs->stream->chip->usb_id)) {
if (is_itf_usb_dsd_dac(subs->stream->chip->usb_id)) {
/* First switch to alt set 0, otherwise the mode switch cmd
* will not be accepted by the DAC
*/
......@@ -1193,37 +1183,26 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
mdelay(20); /* Delay needed after setting the interface */
switch (fmt->altsetting) {
case 2: /* DSD mode requested */
case 1: /* PCM mode requested */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
fmt->altsetting - 1, 1, NULL, 0);
if (err < 0)
return err;
break;
}
mdelay(20);
} else if (is_teac_dsd_dac(subs->stream->chip->usb_id)) {
/* Vendor mode switch cmd is required. */
switch (fmt->altsetting) {
case 3: /* DSD mode (DSD_U32) requested */
if (fmt->formats & SNDRV_PCM_FMTBIT_DSD_U32_BE) {
/* DSD mode (DSD_U32) requested */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
1, 1, NULL, 0);
if (err < 0)
return err;
break;
case 2: /* PCM or DOP mode (S32) requested */
case 1: /* PCM mode (S16) requested */
} else {
/* PCM or DOP mode (S32) requested */
/* PCM mode (S16) requested */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
0, 1, NULL, 0);
if (err < 0)
return err;
break;
}
mdelay(20);
}
return 0;
}
......@@ -1300,10 +1279,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20);
/* Marantz/Denon devices with USB DAC functionality need a delay
/* ITF-USB DSD based DACs functionality need a delay
* after each class compliant request
*/
if (is_marantz_denon_dac(chip->usb_id)
if (is_itf_usb_dsd_dac(chip->usb_id)
&& (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20);
......@@ -1329,6 +1308,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int sample_bytes)
{
struct usb_interface *iface;
/* Playback Designs */
if (USB_ID_VENDOR(chip->usb_id) == 0x23ba) {
switch (fp->altsetting) {
......@@ -1390,17 +1371,52 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
break;
}
/* Denon/Marantz devices with USB DAC functionality */
if (is_marantz_denon_dac(chip->usb_id)) {
if (fp->altsetting == 2)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
}
/* ITF-USB DSD based DACs */
if (is_itf_usb_dsd_dac(chip->usb_id)) {
iface = usb_ifnum_to_if(chip->dev, fp->iface);
/* TEAC devices with USB DAC functionality */
if (is_teac_dsd_dac(chip->usb_id)) {
if (fp->altsetting == 3)
/* Altsetting 2 support native DSD if the num of altsets is
* three (0-2),
* Altsetting 3 support native DSD if the num of altsets is
* four (0-3).
*/
if (fp->altsetting == iface->num_altsetting - 1)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
}
return 0;
}
void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
struct audioformat *fp,
int stream)
{
switch (chip->usb_id) {
case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
/* Optoplay sets the sample rate attribute although
* it seems not supporting it in fact.
*/
fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
break;
case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
/* doesn't set the sample rate attribute, but supports it */
fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
break;
case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */
case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */
case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
an older model 77d:223) */
/*
* plantronics headset and Griffin iMic have set adaptive-in
* although it's really not...
*/
fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
else
fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
break;
}
}
......@@ -42,4 +42,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int sample_bytes);
void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
struct audioformat *fp,
int stream);
#endif /* __USBAUDIO_QUIRKS_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment