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 @@ ...@@ -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 */ /* 4.7.2 Class-Specific AC Interface Descriptor */
......
This diff is collapsed.
...@@ -1710,6 +1710,7 @@ struct snd_emu10k1 { ...@@ -1710,6 +1710,7 @@ struct snd_emu10k1 {
unsigned int ecard_ctrl; /* ecard control bits */ unsigned int ecard_ctrl; /* ecard control bits */
unsigned int address_mode; /* address mode */ unsigned int address_mode; /* address mode */
unsigned long dma_mask; /* PCI DMA mask */ unsigned long dma_mask; /* PCI DMA mask */
bool iommu_workaround; /* IOMMU workaround needed */
unsigned int delay_pcm_irq; /* in samples */ unsigned int delay_pcm_irq; /* in samples */
int max_cache_pages; /* max memory size / PAGE_SIZE */ int max_cache_pages; /* max memory size / PAGE_SIZE */
struct snd_dma_buffer silent_page; /* silent page */ struct snd_dma_buffer silent_page; /* silent page */
...@@ -1718,7 +1719,6 @@ struct snd_emu10k1 { ...@@ -1718,7 +1719,6 @@ struct snd_emu10k1 {
struct snd_dma_buffer p16v_buffer; struct snd_dma_buffer p16v_buffer;
struct snd_util_memhdr *memhdr; /* page allocation list */ 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_link_head;
struct list_head mapped_order_link_head; struct list_head mapped_order_link_head;
...@@ -1878,6 +1878,8 @@ void snd_p16v_resume(struct snd_emu10k1 *emu); ...@@ -1878,6 +1878,8 @@ void snd_p16v_resume(struct snd_emu10k1 *emu);
/* memory allocation */ /* memory allocation */
struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream); 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_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); 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_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); 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, ...@@ -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); int flags, unsigned int verb, unsigned int parm);
bool snd_hdac_check_power_state(struct hdac_device *hdac, bool snd_hdac_check_power_state(struct hdac_device *hdac,
hda_nid_t nid, unsigned int target_state); 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 * snd_hdac_read_parm - read a codec parameter
* @codec: the codec object * @codec: the codec object
......
...@@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime { ...@@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime {
char *buffer; /* vmallocated period */ char *buffer; /* vmallocated period */
size_t buffer_used; /* used length from period buffer */ size_t buffer_used; /* used length from period buffer */
struct mutex params_lock; struct mutex params_lock;
atomic_t rw_ref; /* concurrent read/write accesses */
#ifdef CONFIG_SND_PCM_OSS_PLUGINS #ifdef CONFIG_SND_PCM_OSS_PLUGINS
struct snd_pcm_plugin *plugin_first; struct snd_pcm_plugin *plugin_first;
struct snd_pcm_plugin *plugin_last; struct snd_pcm_plugin *plugin_last;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
/* bInterfaceProtocol values to denote the version of the standard used */ /* bInterfaceProtocol values to denote the version of the standard used */
#define UAC_VERSION_1 0x00 #define UAC_VERSION_1 0x00
#define UAC_VERSION_2 0x20 #define UAC_VERSION_2 0x20
#define UAC_VERSION_3 0x30
/* A.2 Audio Interface Subclass Codes */ /* A.2 Audio Interface Subclass Codes */
#define USB_SUBCLASS_AUDIOCONTROL 0x01 #define USB_SUBCLASS_AUDIOCONTROL 0x01
......
...@@ -670,7 +670,7 @@ card_id_show_attr(struct device *dev, ...@@ -670,7 +670,7 @@ card_id_show_attr(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct snd_card *card = container_of(dev, struct snd_card, card_dev); 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 static ssize_t
...@@ -710,7 +710,7 @@ card_number_show_attr(struct device *dev, ...@@ -710,7 +710,7 @@ card_number_show_attr(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct snd_card *card = container_of(dev, struct snd_card, card_dev); 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); 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, ...@@ -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) { if (constrs->rules_num >= constrs->rules_all) {
struct snd_pcm_hw_rule *new; struct snd_pcm_hw_rule *new;
unsigned int new_rules = constrs->rules_all + 16; 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) { if (!new) {
va_end(args); va_end(args);
return -ENOMEM; return -ENOMEM;
} }
if (constrs->rules) {
memcpy(new, constrs->rules,
constrs->rules_num * sizeof(*c));
kfree(constrs->rules);
}
constrs->rules = new; constrs->rules = new;
constrs->rules_all = new_rules; constrs->rules_all = new_rules;
} }
......
...@@ -323,7 +323,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, ...@@ -323,7 +323,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_pcm_hw_constraints *constrs = struct snd_pcm_hw_constraints *constrs =
&substream->runtime->hw_constraints; &substream->runtime->hw_constraints;
unsigned int k; unsigned int k;
unsigned int rstamps[constrs->rules_num]; unsigned int *rstamps;
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp; unsigned int stamp;
struct snd_pcm_hw_rule *r; struct snd_pcm_hw_rule *r;
...@@ -331,7 +331,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, ...@@ -331,7 +331,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_mask old_mask; struct snd_mask old_mask;
struct snd_interval old_interval; struct snd_interval old_interval;
bool again; bool again;
int changed; int changed, err = 0;
/* /*
* Each application of rule has own sequence number. * Each application of rule has own sequence number.
...@@ -339,8 +339,9 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, ...@@ -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 * Each member of 'rstamps' array represents the sequence number of
* recent application of corresponding rule. * recent application of corresponding rule.
*/ */
for (k = 0; k < constrs->rules_num; k++) rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL);
rstamps[k] = 0; if (!rstamps)
return -ENOMEM;
/* /*
* Each member of 'vstamps' array represents the sequence number of * 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, ...@@ -398,8 +399,10 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
} }
changed = r->func(params, r); changed = r->func(params, r);
if (changed < 0) if (changed < 0) {
return changed; err = changed;
goto out;
}
/* /*
* When the parameter is changed, notify it to the caller * 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, ...@@ -430,7 +433,9 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
if (again) if (again)
goto retry; goto retry;
return 0; out:
kfree(rstamps);
return err;
} }
static int fixup_unreferenced_params(struct snd_pcm_substream *substream, static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
......
...@@ -63,15 +63,18 @@ static int slave_update(struct link_slave *slave) ...@@ -63,15 +63,18 @@ static int slave_update(struct link_slave *slave)
struct snd_ctl_elem_value *uctl; struct snd_ctl_elem_value *uctl;
int err, ch; int err, ch;
uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (!uctl) if (!uctl)
return -ENOMEM; return -ENOMEM;
uctl->id = slave->slave.id; uctl->id = slave->slave.id;
err = slave->slave.get(&slave->slave, uctl); err = slave->slave.get(&slave->slave, uctl);
if (err < 0)
goto error;
for (ch = 0; ch < slave->info.count; ch++) for (ch = 0; ch < slave->info.count; ch++)
slave->vals[ch] = uctl->value.integer.value[ch]; slave->vals[ch] = uctl->value.integer.value[ch];
error:
kfree(uctl); kfree(uctl);
return 0; return err < 0 ? err : 0;
} }
/* get the slave ctl info and save the initial values */ /* 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) ...@@ -296,6 +296,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
cable->pause |= stream; cable->pause |= stream;
loopback_timer_stop(dpcm); loopback_timer_stop(dpcm);
spin_unlock(&cable->lock); spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
...@@ -304,6 +306,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -304,6 +306,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
cable->pause &= ~stream; cable->pause &= ~stream;
loopback_timer_start(dpcm); loopback_timer_start(dpcm);
spin_unlock(&cable->lock); spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -892,9 +896,11 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, ...@@ -892,9 +896,11 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol,
[kcontrol->id.subdevice][kcontrol->id.device ^ 1]; [kcontrol->id.subdevice][kcontrol->id.device ^ 1];
unsigned int val = 0; unsigned int val = 0;
if (cable != NULL) if (cable != NULL) {
val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? unsigned int running = cable->running ^ cable->pause;
1 : 0;
val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0;
}
ucontrol->value.integer.value[0] = val; ucontrol->value.integer.value[0] = val;
return 0; return 0;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -1064,3 +1065,37 @@ bool snd_hdac_check_power_state(struct hdac_device *hdac, ...@@ -1064,3 +1065,37 @@ bool snd_hdac_check_power_state(struct hdac_device *hdac,
return (state == target_state); return (state == target_state);
} }
EXPORT_SYMBOL_GPL(snd_hdac_check_power_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) ...@@ -736,8 +736,7 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{ {
struct echoaudio *chip = snd_pcm_substream_chip(substream); struct echoaudio *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct audiopipe *pipe;
struct audiopipe *pipe = runtime->private_data;
int i, err; int i, err;
u32 channelmask = 0; u32 channelmask = 0;
struct snd_pcm_substream *s; struct snd_pcm_substream *s;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/iommu.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
...@@ -1272,12 +1273,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) ...@@ -1272,12 +1273,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
release_firmware(emu->dock_fw); release_firmware(emu->dock_fw);
if (emu->irq >= 0) if (emu->irq >= 0)
free_irq(emu->irq, emu); 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); snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area) if (emu->silent_page.area)
snd_dma_free_pages(&emu->silent_page); snd_dma_free_pages(&emu->silent_page);
...@@ -1764,6 +1759,38 @@ static struct snd_emu_chip_details emu_chip_details[] = { ...@@ -1764,6 +1759,38 @@ static struct snd_emu_chip_details emu_chip_details[] = {
{ } /* terminator */ { } /* 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, int snd_emu10k1_create(struct snd_card *card,
struct pci_dev *pci, struct pci_dev *pci,
unsigned short extin_mask, unsigned short extin_mask,
...@@ -1776,6 +1803,7 @@ int snd_emu10k1_create(struct snd_card *card, ...@@ -1776,6 +1803,7 @@ int snd_emu10k1_create(struct snd_card *card,
struct snd_emu10k1 *emu; struct snd_emu10k1 *emu;
int idx, err; int idx, err;
int is_audigy; int is_audigy;
size_t page_table_size;
unsigned int silent_page; unsigned int silent_page;
const struct snd_emu_chip_details *c; const struct snd_emu_chip_details *c;
static struct snd_device_ops ops = { static struct snd_device_ops ops = {
...@@ -1873,12 +1901,13 @@ int snd_emu10k1_create(struct snd_card *card, ...@@ -1873,12 +1901,13 @@ int snd_emu10k1_create(struct snd_card *card,
is_audigy = emu->audigy = c->emu10k2_chip; is_audigy = emu->audigy = c->emu10k2_chip;
snd_emu10k1_detect_iommu(emu);
/* set addressing mode */ /* set addressing mode */
emu->address_mode = is_audigy ? 0 : 1; emu->address_mode = is_audigy ? 0 : 1;
/* set the DMA transfer mask */ /* set the DMA transfer mask */
emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK; emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
if (dma_set_mask(&pci->dev, emu->dma_mask) < 0 || if (dma_set_mask_and_coherent(&pci->dev, emu->dma_mask) < 0) {
dma_set_coherent_mask(&pci->dev, emu->dma_mask) < 0) {
dev_err(card->dev, dev_err(card->dev,
"architecture does not support PCI busmaster DMA with mask 0x%lx\n", "architecture does not support PCI busmaster DMA with mask 0x%lx\n",
emu->dma_mask); emu->dma_mask);
...@@ -1900,11 +1929,17 @@ int snd_emu10k1_create(struct snd_card *card, ...@@ -1900,11 +1929,17 @@ int snd_emu10k1_create(struct snd_card *card,
emu->port = pci_resource_start(pci, 0); emu->port = pci_resource_start(pci, 0);
emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; 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; err = -ENOMEM;
goto error; 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_ptr_table = vmalloc(emu->max_cache_pages * sizeof(void *));
emu->page_addr_table = vmalloc(emu->max_cache_pages * emu->page_addr_table = vmalloc(emu->max_cache_pages *
...@@ -1914,11 +1949,16 @@ int snd_emu10k1_create(struct snd_card *card, ...@@ -1914,11 +1949,16 @@ int snd_emu10k1_create(struct snd_card *card,
goto error; goto error;
} }
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), if (snd_emu10k1_alloc_pages_maybe_wider(emu, EMUPAGESIZE,
EMUPAGESIZE, &emu->silent_page) < 0) { &emu->silent_page) < 0) {
err = -ENOMEM; err = -ENOMEM;
goto error; 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); emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
if (emu->memhdr == NULL) { if (emu->memhdr == NULL) {
err = -ENOMEM; err = -ENOMEM;
...@@ -1993,13 +2033,8 @@ int snd_emu10k1_create(struct snd_card *card, ...@@ -1993,13 +2033,8 @@ int snd_emu10k1_create(struct snd_card *card,
SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; 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 */ /* 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; silent_page = emu->silent_page.addr << emu->address_mode;
for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++) for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | 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, ...@@ -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_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data; struct snd_emu10k1_pcm *epcm = runtime->private_data;
size_t alloc_size;
int err; int err;
if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
return err; 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; return err;
if (emu->iommu_workaround && runtime->dma_bytes >= EMUPAGESIZE)
runtime->dma_bytes -= EMUPAGESIZE;
if (err > 0) { /* change */ if (err > 0) { /* change */
int mapped; int mapped;
if (epcm->memblk != NULL) if (epcm->memblk != NULL)
......
...@@ -34,7 +34,10 @@ ...@@ -34,7 +34,10 @@
* aligned pages in others * aligned pages in others
*/ */
#define __set_ptb_entry(emu,page,addr) \ #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 UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE)
#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES) #define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES)
...@@ -44,8 +47,7 @@ ...@@ -44,8 +47,7 @@
/* get offset address from aligned page */ /* get offset address from aligned page */
#define aligned_page_offset(page) ((page) << PAGE_SHIFT) #define aligned_page_offset(page) ((page) << PAGE_SHIFT)
#if PAGE_SIZE == 4096 #if PAGE_SIZE == EMUPAGESIZE && !IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
/* page size == EMUPAGESIZE */
/* fill PTB entrie(s) corresponding to page with addr */ /* fill PTB entrie(s) corresponding to page with addr */
#define set_ptb_entry(emu,page,addr) __set_ptb_entry(emu,page,addr) #define set_ptb_entry(emu,page,addr) __set_ptb_entry(emu,page,addr)
/* fill PTB entrie(s) corresponding to page with silence pointer */ /* 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 ...@@ -58,6 +60,8 @@ static inline void set_ptb_entry(struct snd_emu10k1 *emu, int page, dma_addr_t a
page *= UNIT_PAGES; page *= UNIT_PAGES;
for (i = 0; i < UNIT_PAGES; i++, page++) { for (i = 0; i < UNIT_PAGES; i++, page++) {
__set_ptb_entry(emu, page, addr); __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; addr += EMUPAGESIZE;
} }
} }
...@@ -65,9 +69,12 @@ static inline void set_silent_ptb(struct snd_emu10k1 *emu, int page) ...@@ -65,9 +69,12 @@ static inline void set_silent_ptb(struct snd_emu10k1 *emu, int page)
{ {
int i; int i;
page *= UNIT_PAGES; page *= UNIT_PAGES;
for (i = 0; i < UNIT_PAGES; i++, page++) for (i = 0; i < UNIT_PAGES; i++, page++) {
/* do not increment ptr */ /* do not increment ptr */
__set_ptb_entry(emu, page, emu->silent_page.addr); __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 */ #endif /* PAGE_SIZE */
...@@ -102,7 +109,7 @@ static void emu10k1_memblk_init(struct snd_emu10k1_memblk *blk) ...@@ -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) 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 max_size = npages;
int size; int size;
struct list_head *candidate = &emu->mapped_link_head; 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) ...@@ -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); page = search_empty_map_area(emu, blk->pages, &next);
if (page < 0) /* not found */ if (page < 0) /* not found */
return page; 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 */ /* insert this block in the proper position of mapped list */
list_add_tail(&blk->mapped_link, next); list_add_tail(&blk->mapped_link, next);
/* append this as a newest block in order list */ /* 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) ...@@ -177,7 +188,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
q = get_emu10k1_memblk(p, mapped_link); q = get_emu10k1_memblk(p, mapped_link);
start_page = q->mapped_page + q->pages; start_page = q->mapped_page + q->pages;
} else } else
start_page = 0; start_page = 1;
if ((p = blk->mapped_link.next) != &emu->mapped_link_head) { if ((p = blk->mapped_link.next) != &emu->mapped_link_head) {
q = get_emu10k1_memblk(p, mapped_link); q = get_emu10k1_memblk(p, mapped_link);
end_page = q->mapped_page; end_page = q->mapped_page;
...@@ -366,6 +377,33 @@ int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk) ...@@ -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); 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) * memory allocation using multiple pages (for synth)
...@@ -450,10 +488,27 @@ static void get_single_page_range(struct snd_util_memhdr *hdr, ...@@ -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, static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
int last_page) int last_page)
{ {
struct snd_dma_buffer dmab;
int page; 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++) { 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_addr_table[page] = 0;
emu->page_ptr_table[page] = NULL; emu->page_ptr_table[page] = NULL;
} }
...@@ -465,30 +520,30 @@ static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page, ...@@ -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) static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
{ {
int page, first_page, last_page; int page, first_page, last_page;
struct snd_dma_buffer dmab;
emu10k1_memblk_init(blk); emu10k1_memblk_init(blk);
get_single_page_range(emu->memhdr, blk, &first_page, &last_page); get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
/* allocate kernel pages */ /* allocate kernel pages */
for (page = first_page; page <= last_page; page++) { for (page = first_page; page <= last_page; page++) {
/* first try to allocate from <4GB zone */ if (snd_emu10k1_alloc_pages_maybe_wider(emu, PAGE_SIZE,
struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 | &dmab) < 0)
__GFP_NOWARN); goto __fail;
if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) { if (!is_valid_page(emu, dmab.addr)) {
if (p) snd_dma_free_pages(&dmab);
__free_page(p); goto __fail;
/* try to allocate from <16MB zone */
p = alloc_page(GFP_ATOMIC | GFP_DMA |
__GFP_NORETRY | /* no OOM-killer */
__GFP_NOWARN);
} }
if (!p) { emu->page_addr_table[page] = dmab.addr;
__synth_free_pages(emu, first_page, page - 1); emu->page_ptr_table[page] = dmab.area;
return -ENOMEM;
}
emu->page_addr_table[page] = page_to_phys(p);
emu->page_ptr_table[page] = page_address(p);
} }
return 0; 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 * 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 * 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> #include <linux/input.h>
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* /*
* Digital Beep Input Interface for HD-audio codec * 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 * 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 #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, ...@@ -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); 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 * snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
* @codec: the HDA codec * @codec: the HDA codec
...@@ -2790,7 +2764,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, ...@@ -2790,7 +2764,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
state); state);
snd_hda_codec_set_power_to_all(codec, fg, power_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)) if (!(state & AC_PWRST_ERROR))
break; break;
} }
......
...@@ -2434,6 +2434,9 @@ static const struct pci_device_id azx_ids[] = { ...@@ -2434,6 +2434,9 @@ static const struct pci_device_id azx_ids[] = {
/* Cannonlake */ /* Cannonlake */
{ PCI_DEVICE(0x8086, 0x9dc8), { PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, .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) */ /* Broxton-P(Apollolake) */
{ PCI_DEVICE(0x8086, 0x5a98), { PCI_DEVICE(0x8086, 0x5a98),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, .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, ...@@ -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); 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, unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
hda_nid_t nid, hda_nid_t nid,
unsigned int power_state); unsigned int power_state);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/tlv.h> #include <sound/tlv.h>
...@@ -425,10 +426,9 @@ DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1); ...@@ -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, static struct snd_kcontrol *ctl_find(struct snd_card *card,
const char *name) const char *name)
{ {
struct snd_ctl_elem_id sid; struct snd_ctl_elem_id sid = {0};
memset(&sid, 0, sizeof(sid));
/* FIXME: strcpy is bad. */ strlcpy(sid.name, name, sizeof(sid.name));
strcpy(sid.name, name);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(card, &sid); return snd_ctl_find_id(card, &sid);
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/tlv.h> #include <sound/tlv.h>
#include <sound/info.h> #include <sound/info.h>
...@@ -785,10 +786,9 @@ DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); ...@@ -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, static struct snd_kcontrol *ctl_find(struct snd_card *card,
const char *name) const char *name)
{ {
struct snd_ctl_elem_id sid; struct snd_ctl_elem_id sid = {0};
memset(&sid, 0, sizeof(sid));
/* FIXME: strcpy is bad. */ strlcpy(sid.name, name, sizeof(sid.name));
strcpy(sid.name, name);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(card, &sid); return snd_ctl_find_id(card, &sid);
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Alan Cox (alan@lxorguk.ukuu.org.uk) * Alan Cox (alan@lxorguk.ukuu.org.uk)
* Thomas Sailer (sailer@ife.ee.ethz.ch) * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/usb/audio.h> #include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h> #include <linux/usb/audio-v2.h>
#include <linux/usb/audio-v3.h>
#include <linux/module.h> #include <linux/module.h>
#include <sound/control.h> #include <sound/control.h>
...@@ -281,7 +283,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -281,7 +283,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
break; break;
} }
case UAC_VERSION_2: { case UAC_VERSION_2:
case UAC_VERSION_3: {
struct usb_interface_assoc_descriptor *assoc = struct usb_interface_assoc_descriptor *assoc =
usb_ifnum_to_if(dev, ctrlif)->intf_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) ...@@ -301,7 +304,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
} }
if (!assoc) { 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; return -EINVAL;
} }
......
...@@ -22,7 +22,7 @@ struct audioformat { ...@@ -22,7 +22,7 @@ struct audioformat {
unsigned char endpoint; /* endpoint */ unsigned char endpoint; /* endpoint */
unsigned char ep_attr; /* endpoint attributes */ unsigned char ep_attr; /* endpoint attributes */
unsigned char datainterval; /* log_2 of data packet interval */ 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 maxpacksize; /* max. packet size */
unsigned int rates; /* rate bitmasks */ unsigned int rates; /* rate bitmasks */
unsigned int rate_min, rate_max; /* min/max rates */ 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, ...@@ -6,7 +6,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts, struct usb_host_interface *alts,
struct audioformat *fmt, int rate); struct audioformat *fmt, int rate);
int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol,
bool validate); int entity_id, bool validate);
#endif /* __USBAUDIO_CLOCK_H */ #endif /* __USBAUDIO_CLOCK_H */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/audio.h> #include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h> #include <linux/usb/audio-v2.h>
#include <linux/usb/audio-v3.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -39,11 +40,11 @@ ...@@ -39,11 +40,11 @@
* @dev: usb device * @dev: usb device
* @fp: audioformat record * @fp: audioformat record
* @format: the format tag (wFormatTag) * @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, static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
struct audioformat *fp, struct audioformat *fp,
unsigned int format, void *_fmt) u64 format, void *_fmt)
{ {
int sample_width, sample_bytes; int sample_width, sample_bytes;
u64 pcm_formats = 0; u64 pcm_formats = 0;
...@@ -54,7 +55,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, ...@@ -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; struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
sample_width = fmt->bBitResolution; sample_width = fmt->bBitResolution;
sample_bytes = fmt->bSubframeSize; sample_bytes = fmt->bSubframeSize;
format = 1 << format; format = 1ULL << format;
break; break;
} }
...@@ -69,6 +70,18 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, ...@@ -69,6 +70,18 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
format <<= 1; format <<= 1;
break; 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) && if ((pcm_formats == 0) &&
...@@ -137,7 +150,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, ...@@ -137,7 +150,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
} }
if (format & ~0x3f) { if (format & ~0x3f) {
usb_audio_info(chip, usb_audio_info(chip,
"%u:%d : unsupported format bits %#x\n", "%u:%d : unsupported format bits %#llx\n",
fp->iface, fp->altsetting, format); fp->iface, fp->altsetting, format);
} }
...@@ -281,15 +294,16 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, ...@@ -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 * 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 audioformat *fp)
{ {
struct usb_device *dev = chip->dev; struct usb_device *dev = chip->dev;
unsigned char tmp[2], *data; unsigned char tmp[2], *data;
int nr_triplets, data_size, ret = 0; 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) { if (clock < 0) {
dev_err(&dev->dev, dev_err(&dev->dev,
...@@ -368,13 +382,30 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, ...@@ -368,13 +382,30 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
* parse the format type I and III descriptors * parse the format type I and III descriptors
*/ */
static int parse_audio_format_i(struct snd_usb_audio *chip, static int parse_audio_format_i(struct snd_usb_audio *chip,
struct audioformat *fp, unsigned int format, struct audioformat *fp, u64 format,
struct uac_format_type_i_continuous_descriptor *fmt) void *_fmt)
{ {
snd_pcm_format_t pcm_format; snd_pcm_format_t pcm_format;
unsigned int fmt_type;
int ret; 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 /* FIXME: the format type is really IECxxx
* but we give normal PCM format to get the existing * but we give normal PCM format to get the existing
* apps working... * apps working...
...@@ -393,7 +424,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, ...@@ -393,7 +424,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
} }
fp->formats = pcm_format_to_bits(pcm_format); fp->formats = pcm_format_to_bits(pcm_format);
} else { } 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) if (!fp->formats)
return -EINVAL; return -EINVAL;
} }
...@@ -405,15 +436,20 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, ...@@ -405,15 +436,20 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
*/ */
switch (fp->protocol) { switch (fp->protocol) {
default: default:
case UAC_VERSION_1: case UAC_VERSION_1: {
struct uac_format_type_i_continuous_descriptor *fmt = _fmt;
fp->channels = fmt->bNrChannels; fp->channels = fmt->bNrChannels;
ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
break; break;
}
case UAC_VERSION_2: case UAC_VERSION_2:
case UAC_VERSION_3: {
/* fp->channels is already set in this case */ /* 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; break;
} }
}
if (fp->channels < 1) { if (fp->channels < 1) {
usb_audio_err(chip, usb_audio_err(chip,
...@@ -430,7 +466,7 @@ static int parse_audio_format_i(struct snd_usb_audio *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, static int parse_audio_format_ii(struct snd_usb_audio *chip,
struct audioformat *fp, struct audioformat *fp,
int format, void *_fmt) u64 format, void *_fmt)
{ {
int brate, framesize, ret; int brate, framesize, ret;
...@@ -445,7 +481,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, ...@@ -445,7 +481,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
break; break;
default: default:
usb_audio_info(chip, 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->iface, fp->altsetting, format);
fp->formats = SNDRV_PCM_FMTBIT_MPEG; fp->formats = SNDRV_PCM_FMTBIT_MPEG;
break; break;
...@@ -470,7 +506,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, ...@@ -470,7 +506,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
framesize = le16_to_cpu(fmt->wSamplesPerFrame); framesize = le16_to_cpu(fmt->wSamplesPerFrame);
usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
fp->frame_size = framesize; fp->frame_size = framesize;
ret = parse_audio_format_rates_v2(chip, fp); ret = parse_audio_format_rates_v2v3(chip, fp);
break; break;
} }
} }
...@@ -479,7 +515,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, ...@@ -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, 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, struct uac_format_type_i_continuous_descriptor *fmt,
int stream) int stream)
{ {
...@@ -520,3 +556,26 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, ...@@ -520,3 +556,26 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
return 0; 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 @@ ...@@ -3,8 +3,12 @@
#define __USBAUDIO_FORMAT_H #define __USBAUDIO_FORMAT_H
int snd_usb_parse_audio_format(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, struct uac_format_type_i_continuous_descriptor *fmt,
int stream); 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 */ #endif /* __USBAUDIO_FORMAT_H */
This diff is collapsed.
...@@ -1149,27 +1149,17 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) ...@@ -1149,27 +1149,17 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
return false; 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 * 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) { switch (id) {
case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */ case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
return true; case USB_ID(0x1852, 0x5065): /* Luxman DA-06 */
} case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
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(0x0644, 0x8044): /* Esoteric D-05X */ case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */ case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
return true; return true;
...@@ -1183,7 +1173,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, ...@@ -1183,7 +1173,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
struct usb_device *dev = subs->dev; struct usb_device *dev = subs->dev;
int err; 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 /* First switch to alt set 0, otherwise the mode switch cmd
* will not be accepted by the DAC * will not be accepted by the DAC
*/ */
...@@ -1193,37 +1183,26 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, ...@@ -1193,37 +1183,26 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
mdelay(20); /* Delay needed after setting the interface */ 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. */ /* Vendor mode switch cmd is required. */
switch (fmt->altsetting) { if (fmt->formats & SNDRV_PCM_FMTBIT_DSD_U32_BE) {
case 3: /* DSD mode (DSD_U32) requested */ /* DSD mode (DSD_U32) requested */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0, err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
1, 1, NULL, 0); 1, 1, NULL, 0);
if (err < 0) if (err < 0)
return err; return err;
break;
case 2: /* PCM or DOP mode (S32) requested */ } else {
case 1: /* PCM mode (S16) requested */ /* PCM or DOP mode (S32) requested */
/* PCM mode (S16) requested */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0, err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
0, 1, NULL, 0); 0, 1, NULL, 0);
if (err < 0) if (err < 0)
return err; return err;
break;
} }
mdelay(20);
} }
return 0; return 0;
} }
...@@ -1300,10 +1279,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, ...@@ -1300,10 +1279,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20); 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 * 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) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20); mdelay(20);
...@@ -1329,6 +1308,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, ...@@ -1329,6 +1308,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp, struct audioformat *fp,
unsigned int sample_bytes) unsigned int sample_bytes)
{ {
struct usb_interface *iface;
/* Playback Designs */ /* Playback Designs */
if (USB_ID_VENDOR(chip->usb_id) == 0x23ba) { if (USB_ID_VENDOR(chip->usb_id) == 0x23ba) {
switch (fp->altsetting) { switch (fp->altsetting) {
...@@ -1390,17 +1371,52 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, ...@@ -1390,17 +1371,52 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
break; break;
} }
/* Denon/Marantz devices with USB DAC functionality */ /* ITF-USB DSD based DACs */
if (is_marantz_denon_dac(chip->usb_id)) { if (is_itf_usb_dsd_dac(chip->usb_id)) {
if (fp->altsetting == 2) iface = usb_ifnum_to_if(chip->dev, fp->iface);
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
}
/* TEAC devices with USB DAC functionality */ /* Altsetting 2 support native DSD if the num of altsets is
if (is_teac_dsd_dac(chip->usb_id)) { * three (0-2),
if (fp->altsetting == 3) * 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 SNDRV_PCM_FMTBIT_DSD_U32_BE;
} }
return 0; 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, ...@@ -42,4 +42,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp, struct audioformat *fp,
unsigned int sample_bytes); unsigned int sample_bytes);
void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
struct audioformat *fp,
int stream);
#endif /* __USBAUDIO_QUIRKS_H */ #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