mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge branch 'topic/usb-uac2-effect-unit' into for-next
Merging the UAC2 effect unit parser improvement. As it's based on the previous usb-audio driver fix, it was deviated from for-next branch. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
@@ -156,6 +156,18 @@ struct uac2_feature_unit_descriptor {
|
|||||||
__u8 bmaControls[0]; /* variable length */
|
__u8 bmaControls[0]; /* variable length */
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* 4.7.2.10 Effect Unit Descriptor */
|
||||||
|
|
||||||
|
struct uac2_effect_unit_descriptor {
|
||||||
|
__u8 bLength;
|
||||||
|
__u8 bDescriptorType;
|
||||||
|
__u8 bDescriptorSubtype;
|
||||||
|
__u8 bUnitID;
|
||||||
|
__le16 wEffectType;
|
||||||
|
__u8 bSourceID;
|
||||||
|
__u8 bmaControls[]; /* variable length */
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
/* 4.9.2 Class-Specific AS Interface Descriptor */
|
/* 4.9.2 Class-Specific AS Interface Descriptor */
|
||||||
|
|
||||||
struct uac2_as_header_descriptor {
|
struct uac2_as_header_descriptor {
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ struct snd_rawmidi_substream {
|
|||||||
struct list_head list; /* list of all substream for given stream */
|
struct list_head list; /* list of all substream for given stream */
|
||||||
int stream; /* direction */
|
int stream; /* direction */
|
||||||
int number; /* substream number */
|
int number; /* substream number */
|
||||||
unsigned int opened: 1, /* open flag */
|
bool opened; /* open flag */
|
||||||
append: 1, /* append flag (merge more streams) */
|
bool append; /* append flag (merge more streams) */
|
||||||
active_sensing: 1; /* send active sensing when close */
|
bool active_sensing; /* send active sensing when close */
|
||||||
int use_count; /* use counter (for output) */
|
int use_count; /* use counter (for output) */
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
struct snd_rawmidi *rmidi;
|
struct snd_rawmidi *rmidi;
|
||||||
|
|||||||
@@ -2599,6 +2599,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
|
|||||||
|
|
||||||
snd_pcm_drop(substream);
|
snd_pcm_drop(substream);
|
||||||
if (substream->hw_opened) {
|
if (substream->hw_opened) {
|
||||||
|
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
|
||||||
do_hw_free(substream);
|
do_hw_free(substream);
|
||||||
substream->ops->close(substream);
|
substream->ops->close(substream);
|
||||||
substream->hw_opened = 0;
|
substream->hw_opened = 0;
|
||||||
|
|||||||
@@ -580,7 +580,7 @@ static int update_timestamp_of_queue(struct snd_seq_event *event,
|
|||||||
event->queue = queue;
|
event->queue = queue;
|
||||||
event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
|
event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
|
||||||
if (real_time) {
|
if (real_time) {
|
||||||
event->time.time = snd_seq_timer_get_cur_time(q->timer);
|
event->time.time = snd_seq_timer_get_cur_time(q->timer, true);
|
||||||
event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
|
event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
|
||||||
} else {
|
} else {
|
||||||
event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
|
event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
|
||||||
@@ -1659,7 +1659,7 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client,
|
|||||||
tmr = queue->timer;
|
tmr = queue->timer;
|
||||||
status->events = queue->tickq->cells + queue->timeq->cells;
|
status->events = queue->tickq->cells + queue->timeq->cells;
|
||||||
|
|
||||||
status->time = snd_seq_timer_get_cur_time(tmr);
|
status->time = snd_seq_timer_get_cur_time(tmr, true);
|
||||||
status->tick = snd_seq_timer_get_cur_tick(tmr);
|
status->tick = snd_seq_timer_get_cur_tick(tmr);
|
||||||
|
|
||||||
status->running = tmr->running;
|
status->running = tmr->running;
|
||||||
|
|||||||
@@ -238,6 +238,8 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct snd_seq_event_cell *cell;
|
struct snd_seq_event_cell *cell;
|
||||||
|
snd_seq_tick_time_t cur_tick;
|
||||||
|
snd_seq_real_time_t cur_time;
|
||||||
|
|
||||||
if (q == NULL)
|
if (q == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -254,17 +256,18 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
|||||||
|
|
||||||
__again:
|
__again:
|
||||||
/* Process tick queue... */
|
/* Process tick queue... */
|
||||||
|
cur_tick = snd_seq_timer_get_cur_tick(q->timer);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cell = snd_seq_prioq_cell_out(q->tickq,
|
cell = snd_seq_prioq_cell_out(q->tickq, &cur_tick);
|
||||||
&q->timer->tick.cur_tick);
|
|
||||||
if (!cell)
|
if (!cell)
|
||||||
break;
|
break;
|
||||||
snd_seq_dispatch_event(cell, atomic, hop);
|
snd_seq_dispatch_event(cell, atomic, hop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process time queue... */
|
/* Process time queue... */
|
||||||
|
cur_time = snd_seq_timer_get_cur_time(q->timer, false);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time);
|
cell = snd_seq_prioq_cell_out(q->timeq, &cur_time);
|
||||||
if (!cell)
|
if (!cell)
|
||||||
break;
|
break;
|
||||||
snd_seq_dispatch_event(cell, atomic, hop);
|
snd_seq_dispatch_event(cell, atomic, hop);
|
||||||
@@ -392,6 +395,7 @@ int snd_seq_queue_check_access(int queueid, int client)
|
|||||||
int snd_seq_queue_set_owner(int queueid, int client, int locked)
|
int snd_seq_queue_set_owner(int queueid, int client, int locked)
|
||||||
{
|
{
|
||||||
struct snd_seq_queue *q = queueptr(queueid);
|
struct snd_seq_queue *q = queueptr(queueid);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (q == NULL)
|
if (q == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -401,8 +405,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked)
|
|||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&q->owner_lock, flags);
|
||||||
q->locked = locked ? 1 : 0;
|
q->locked = locked ? 1 : 0;
|
||||||
q->owner = client;
|
q->owner = client;
|
||||||
|
spin_unlock_irqrestore(&q->owner_lock, flags);
|
||||||
queue_access_unlock(q);
|
queue_access_unlock(q);
|
||||||
queuefree(q);
|
queuefree(q);
|
||||||
|
|
||||||
@@ -539,15 +545,17 @@ void snd_seq_queue_client_termination(int client)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
struct snd_seq_queue *q;
|
struct snd_seq_queue *q;
|
||||||
|
bool matched;
|
||||||
|
|
||||||
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
|
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
|
||||||
if ((q = queueptr(i)) == NULL)
|
if ((q = queueptr(i)) == NULL)
|
||||||
continue;
|
continue;
|
||||||
spin_lock_irqsave(&q->owner_lock, flags);
|
spin_lock_irqsave(&q->owner_lock, flags);
|
||||||
if (q->owner == client)
|
matched = (q->owner == client);
|
||||||
|
if (matched)
|
||||||
q->klocked = 1;
|
q->klocked = 1;
|
||||||
spin_unlock_irqrestore(&q->owner_lock, flags);
|
spin_unlock_irqrestore(&q->owner_lock, flags);
|
||||||
if (q->owner == client) {
|
if (matched) {
|
||||||
if (q->timer->running)
|
if (q->timer->running)
|
||||||
snd_seq_timer_stop(q->timer);
|
snd_seq_timer_stop(q->timer);
|
||||||
snd_seq_timer_reset(q->timer);
|
snd_seq_timer_reset(q->timer);
|
||||||
@@ -739,6 +747,8 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
|
|||||||
int i, bpm;
|
int i, bpm;
|
||||||
struct snd_seq_queue *q;
|
struct snd_seq_queue *q;
|
||||||
struct snd_seq_timer *tmr;
|
struct snd_seq_timer *tmr;
|
||||||
|
bool locked;
|
||||||
|
int owner;
|
||||||
|
|
||||||
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
|
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
|
||||||
if ((q = queueptr(i)) == NULL)
|
if ((q = queueptr(i)) == NULL)
|
||||||
@@ -750,9 +760,14 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
|
|||||||
else
|
else
|
||||||
bpm = 0;
|
bpm = 0;
|
||||||
|
|
||||||
|
spin_lock_irq(&q->owner_lock);
|
||||||
|
locked = q->locked;
|
||||||
|
owner = q->owner;
|
||||||
|
spin_unlock_irq(&q->owner_lock);
|
||||||
|
|
||||||
snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
|
snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
|
||||||
snd_iprintf(buffer, "owned by client : %d\n", q->owner);
|
snd_iprintf(buffer, "owned by client : %d\n", owner);
|
||||||
snd_iprintf(buffer, "lock status : %s\n", q->locked ? "Locked" : "Free");
|
snd_iprintf(buffer, "lock status : %s\n", locked ? "Locked" : "Free");
|
||||||
snd_iprintf(buffer, "queued time events : %d\n", snd_seq_prioq_avail(q->timeq));
|
snd_iprintf(buffer, "queued time events : %d\n", snd_seq_prioq_avail(q->timeq));
|
||||||
snd_iprintf(buffer, "queued tick events : %d\n", snd_seq_prioq_avail(q->tickq));
|
snd_iprintf(buffer, "queued tick events : %d\n", snd_seq_prioq_avail(q->tickq));
|
||||||
snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped");
|
snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped");
|
||||||
|
|||||||
@@ -428,14 +428,15 @@ int snd_seq_timer_continue(struct snd_seq_timer *tmr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return current 'real' time. use timeofday() to get better granularity. */
|
/* return current 'real' time. use timeofday() to get better granularity. */
|
||||||
snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
|
snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
|
||||||
|
bool adjust_ktime)
|
||||||
{
|
{
|
||||||
snd_seq_real_time_t cur_time;
|
snd_seq_real_time_t cur_time;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&tmr->lock, flags);
|
spin_lock_irqsave(&tmr->lock, flags);
|
||||||
cur_time = tmr->cur_time;
|
cur_time = tmr->cur_time;
|
||||||
if (tmr->running) {
|
if (adjust_ktime && tmr->running) {
|
||||||
struct timespec64 tm;
|
struct timespec64 tm;
|
||||||
|
|
||||||
ktime_get_ts64(&tm);
|
ktime_get_ts64(&tm);
|
||||||
@@ -452,7 +453,13 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
|
|||||||
high PPQ values) */
|
high PPQ values) */
|
||||||
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
|
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
|
||||||
{
|
{
|
||||||
return tmr->tick.cur_tick;
|
snd_seq_tick_time_t cur_tick;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&tmr->lock, flags);
|
||||||
|
cur_tick = tmr->tick.cur_tick;
|
||||||
|
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||||
|
return cur_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,8 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq);
|
|||||||
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
|
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
|
||||||
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
|
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
|
||||||
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);
|
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);
|
||||||
snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr);
|
snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
|
||||||
|
bool adjust_ktime);
|
||||||
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr);
|
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr);
|
||||||
|
|
||||||
extern int seq_default_timer_class;
|
extern int seq_default_timer_class;
|
||||||
|
|||||||
@@ -2447,6 +2447,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
|
|||||||
SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
|
SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
|
||||||
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
|
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
|
||||||
SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
|
SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
|
||||||
|
SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
|
||||||
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
|
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
|
||||||
SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
|
SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
|
||||||
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
|
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
|
||||||
@@ -5701,8 +5702,11 @@ static void alc_fixup_headset_jack(struct hda_codec *codec,
|
|||||||
break;
|
break;
|
||||||
case HDA_FIXUP_ACT_INIT:
|
case HDA_FIXUP_ACT_INIT:
|
||||||
switch (codec->core.vendor_id) {
|
switch (codec->core.vendor_id) {
|
||||||
|
case 0x10ec0215:
|
||||||
case 0x10ec0225:
|
case 0x10ec0225:
|
||||||
|
case 0x10ec0285:
|
||||||
case 0x10ec0295:
|
case 0x10ec0295:
|
||||||
|
case 0x10ec0289:
|
||||||
case 0x10ec0299:
|
case 0x10ec0299:
|
||||||
alc_write_coef_idx(codec, 0x48, 0xd011);
|
alc_write_coef_idx(codec, 0x48, 0xd011);
|
||||||
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
|
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
|
||||||
|
|||||||
+58
-23
@@ -151,8 +151,34 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume the clock is valid if clock source supports only one single sample
|
||||||
|
* rate, the terminal is connected directly to it (there is no clock selector)
|
||||||
|
* and clock type is internal. This is to deal with some Denon DJ controllers
|
||||||
|
* that always reports that clock is invalid.
|
||||||
|
*/
|
||||||
|
static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
|
||||||
|
struct audioformat *fmt,
|
||||||
|
int source_id)
|
||||||
|
{
|
||||||
|
if (fmt->protocol == UAC_VERSION_2) {
|
||||||
|
struct uac_clock_source_descriptor *cs_desc =
|
||||||
|
snd_usb_find_clock_source(chip->ctrl_intf, source_id);
|
||||||
|
|
||||||
|
if (!cs_desc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (fmt->nr_rates == 1 &&
|
||||||
|
(fmt->clock & 0xff) == cs_desc->bClockID &&
|
||||||
|
(cs_desc->bmAttributes & 0x3) !=
|
||||||
|
UAC_CLOCK_SOURCE_TYPE_EXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
|
static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
|
||||||
int protocol,
|
struct audioformat *fmt,
|
||||||
int source_id)
|
int source_id)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -160,7 +186,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
|
|||||||
struct usb_device *dev = chip->dev;
|
struct usb_device *dev = chip->dev;
|
||||||
u32 bmControls;
|
u32 bmControls;
|
||||||
|
|
||||||
if (protocol == UAC_VERSION_3) {
|
if (fmt->protocol == UAC_VERSION_3) {
|
||||||
struct uac3_clock_source_descriptor *cs_desc =
|
struct uac3_clock_source_descriptor *cs_desc =
|
||||||
snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id);
|
snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id);
|
||||||
|
|
||||||
@@ -194,10 +220,14 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data ? true : false;
|
if (data)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return uac_clock_source_is_valid_quirk(chip, fmt, source_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
static int __uac_clock_find_source(struct snd_usb_audio *chip,
|
||||||
|
struct audioformat *fmt, int entity_id,
|
||||||
unsigned long *visited, bool validate)
|
unsigned long *visited, bool validate)
|
||||||
{
|
{
|
||||||
struct uac_clock_source_descriptor *source;
|
struct uac_clock_source_descriptor *source;
|
||||||
@@ -217,7 +247,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
|
source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
|
||||||
if (source) {
|
if (source) {
|
||||||
entity_id = source->bClockID;
|
entity_id = source->bClockID;
|
||||||
if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2,
|
if (validate && !uac_clock_source_is_valid(chip, fmt,
|
||||||
entity_id)) {
|
entity_id)) {
|
||||||
usb_audio_err(chip,
|
usb_audio_err(chip,
|
||||||
"clock source %d is not valid, cannot use\n",
|
"clock source %d is not valid, cannot use\n",
|
||||||
@@ -248,7 +278,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur = ret;
|
cur = ret;
|
||||||
ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
|
ret = __uac_clock_find_source(chip, fmt,
|
||||||
|
selector->baCSourceID[ret - 1],
|
||||||
visited, validate);
|
visited, validate);
|
||||||
if (!validate || ret > 0 || !chip->autoclock)
|
if (!validate || ret > 0 || !chip->autoclock)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -260,7 +291,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
if (i == cur)
|
if (i == cur)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
|
ret = __uac_clock_find_source(chip, fmt,
|
||||||
|
selector->baCSourceID[i - 1],
|
||||||
visited, true);
|
visited, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -281,13 +313,15 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
/* FIXME: multipliers only act as pass-thru element for now */
|
/* FIXME: multipliers only act as pass-thru element for now */
|
||||||
multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
|
multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
|
||||||
if (multiplier)
|
if (multiplier)
|
||||||
return __uac_clock_find_source(chip, multiplier->bCSourceID,
|
return __uac_clock_find_source(chip, fmt,
|
||||||
|
multiplier->bCSourceID,
|
||||||
visited, validate);
|
visited, validate);
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
static int __uac3_clock_find_source(struct snd_usb_audio *chip,
|
||||||
|
struct audioformat *fmt, int entity_id,
|
||||||
unsigned long *visited, bool validate)
|
unsigned long *visited, bool validate)
|
||||||
{
|
{
|
||||||
struct uac3_clock_source_descriptor *source;
|
struct uac3_clock_source_descriptor *source;
|
||||||
@@ -307,7 +341,7 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id);
|
source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id);
|
||||||
if (source) {
|
if (source) {
|
||||||
entity_id = source->bClockID;
|
entity_id = source->bClockID;
|
||||||
if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3,
|
if (validate && !uac_clock_source_is_valid(chip, fmt,
|
||||||
entity_id)) {
|
entity_id)) {
|
||||||
usb_audio_err(chip,
|
usb_audio_err(chip,
|
||||||
"clock source %d is not valid, cannot use\n",
|
"clock source %d is not valid, cannot use\n",
|
||||||
@@ -338,7 +372,8 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur = ret;
|
cur = ret;
|
||||||
ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1],
|
ret = __uac3_clock_find_source(chip, fmt,
|
||||||
|
selector->baCSourceID[ret - 1],
|
||||||
visited, validate);
|
visited, validate);
|
||||||
if (!validate || ret > 0 || !chip->autoclock)
|
if (!validate || ret > 0 || !chip->autoclock)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -350,7 +385,8 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
if (i == cur)
|
if (i == cur)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1],
|
ret = __uac3_clock_find_source(chip, fmt,
|
||||||
|
selector->baCSourceID[i - 1],
|
||||||
visited, true);
|
visited, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -372,7 +408,8 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf,
|
multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf,
|
||||||
entity_id);
|
entity_id);
|
||||||
if (multiplier)
|
if (multiplier)
|
||||||
return __uac3_clock_find_source(chip, multiplier->bCSourceID,
|
return __uac3_clock_find_source(chip, fmt,
|
||||||
|
multiplier->bCSourceID,
|
||||||
visited, validate);
|
visited, validate);
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -389,18 +426,18 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
|
|||||||
*
|
*
|
||||||
* Returns the clock source UnitID (>=0) on success, or an error.
|
* Returns the clock source UnitID (>=0) on success, or an error.
|
||||||
*/
|
*/
|
||||||
int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol,
|
int snd_usb_clock_find_source(struct snd_usb_audio *chip,
|
||||||
int entity_id, bool validate)
|
struct audioformat *fmt, bool validate)
|
||||||
{
|
{
|
||||||
DECLARE_BITMAP(visited, 256);
|
DECLARE_BITMAP(visited, 256);
|
||||||
memset(visited, 0, sizeof(visited));
|
memset(visited, 0, sizeof(visited));
|
||||||
|
|
||||||
switch (protocol) {
|
switch (fmt->protocol) {
|
||||||
case UAC_VERSION_2:
|
case UAC_VERSION_2:
|
||||||
return __uac_clock_find_source(chip, entity_id, visited,
|
return __uac_clock_find_source(chip, fmt, fmt->clock, visited,
|
||||||
validate);
|
validate);
|
||||||
case UAC_VERSION_3:
|
case UAC_VERSION_3:
|
||||||
return __uac3_clock_find_source(chip, entity_id, visited,
|
return __uac3_clock_find_source(chip, fmt, fmt->clock, visited,
|
||||||
validate);
|
validate);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -501,8 +538,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
|
|||||||
* automatic clock selection if the current clock is not
|
* automatic clock selection if the current clock is not
|
||||||
* valid.
|
* valid.
|
||||||
*/
|
*/
|
||||||
clock = snd_usb_clock_find_source(chip, fmt->protocol,
|
clock = snd_usb_clock_find_source(chip, fmt, true);
|
||||||
fmt->clock, true);
|
|
||||||
if (clock < 0) {
|
if (clock < 0) {
|
||||||
/* We did not find a valid clock, but that might be
|
/* We did not find a valid clock, but that might be
|
||||||
* because the current sample rate does not match an
|
* because the current sample rate does not match an
|
||||||
@@ -510,8 +546,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
|
|||||||
* and we will do another validation after setting the
|
* and we will do another validation after setting the
|
||||||
* rate.
|
* rate.
|
||||||
*/
|
*/
|
||||||
clock = snd_usb_clock_find_source(chip, fmt->protocol,
|
clock = snd_usb_clock_find_source(chip, fmt, false);
|
||||||
fmt->clock, false);
|
|
||||||
if (clock < 0)
|
if (clock < 0)
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
@@ -577,7 +612,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
|
|||||||
|
|
||||||
validation:
|
validation:
|
||||||
/* validate clock after rate change */
|
/* validate clock after rate change */
|
||||||
if (!uac_clock_source_is_valid(chip, fmt->protocol, clock))
|
if (!uac_clock_source_is_valid(chip, fmt, clock))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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 protocol,
|
int snd_usb_clock_find_source(struct snd_usb_audio *chip,
|
||||||
int entity_id, bool validate);
|
struct audioformat *fmt, bool validate);
|
||||||
|
|
||||||
#endif /* __USBAUDIO_CLOCK_H */
|
#endif /* __USBAUDIO_CLOCK_H */
|
||||||
|
|||||||
+23
-13
@@ -151,6 +151,19 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
|
|||||||
return pcm_formats;
|
return pcm_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_fixed_rate(struct audioformat *fp, int rate, int rate_bits)
|
||||||
|
{
|
||||||
|
kfree(fp->rate_table);
|
||||||
|
fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL);
|
||||||
|
if (!fp->rate_table)
|
||||||
|
return -ENOMEM;
|
||||||
|
fp->nr_rates = 1;
|
||||||
|
fp->rate_min = rate;
|
||||||
|
fp->rate_max = rate;
|
||||||
|
fp->rates = rate_bits;
|
||||||
|
fp->rate_table[0] = rate;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse the format descriptor and stores the possible sample rates
|
* parse the format descriptor and stores the possible sample rates
|
||||||
@@ -223,6 +236,14 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
|
|||||||
fp->rate_min = combine_triple(&fmt[offset + 1]);
|
fp->rate_min = combine_triple(&fmt[offset + 1]);
|
||||||
fp->rate_max = combine_triple(&fmt[offset + 4]);
|
fp->rate_max = combine_triple(&fmt[offset + 4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Jabra Evolve 65 headset */
|
||||||
|
if (chip->usb_id == USB_ID(0x0b0e, 0x030b)) {
|
||||||
|
/* only 48kHz for playback while keeping 16kHz for capture */
|
||||||
|
if (fp->nr_rates != 1)
|
||||||
|
return set_fixed_rate(fp, 48000, SNDRV_PCM_RATE_48000);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,17 +357,7 @@ static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip,
|
|||||||
case USB_ID(0x0e41, 0x4248): /* Line6 Helix >= fw 2.82 */
|
case USB_ID(0x0e41, 0x4248): /* Line6 Helix >= fw 2.82 */
|
||||||
case USB_ID(0x0e41, 0x4249): /* Line6 Helix Rack >= fw 2.82 */
|
case USB_ID(0x0e41, 0x4249): /* Line6 Helix Rack >= fw 2.82 */
|
||||||
case USB_ID(0x0e41, 0x424a): /* Line6 Helix LT >= fw 2.82 */
|
case USB_ID(0x0e41, 0x424a): /* Line6 Helix LT >= fw 2.82 */
|
||||||
/* supported rates: 48Khz */
|
return set_fixed_rate(fp, 48000, SNDRV_PCM_RATE_48000);
|
||||||
kfree(fp->rate_table);
|
|
||||||
fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL);
|
|
||||||
if (!fp->rate_table)
|
|
||||||
return -ENOMEM;
|
|
||||||
fp->nr_rates = 1;
|
|
||||||
fp->rate_min = 48000;
|
|
||||||
fp->rate_max = 48000;
|
|
||||||
fp->rates = SNDRV_PCM_RATE_48000;
|
|
||||||
fp->rate_table[0] = 48000;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -362,8 +373,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
|
|||||||
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, ret_l6;
|
int nr_triplets, data_size, ret = 0, ret_l6;
|
||||||
int clock = snd_usb_clock_find_source(chip, fp->protocol,
|
int clock = snd_usb_clock_find_source(chip, fp, false);
|
||||||
fp->clock, false);
|
|
||||||
|
|
||||||
if (clock < 0) {
|
if (clock < 0) {
|
||||||
dev_err(&dev->dev,
|
dev_err(&dev->dev,
|
||||||
|
|||||||
+16
-2
@@ -897,6 +897,21 @@ static int parse_term_proc_unit(struct mixer_build *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_term_effect_unit(struct mixer_build *state,
|
||||||
|
struct usb_audio_term *term,
|
||||||
|
void *p1, int id)
|
||||||
|
{
|
||||||
|
struct uac2_effect_unit_descriptor *d = p1;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = __check_input_term(state, d->bSourceID, term);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */
|
||||||
|
term->id = id;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_term_uac2_clock_source(struct mixer_build *state,
|
static int parse_term_uac2_clock_source(struct mixer_build *state,
|
||||||
struct usb_audio_term *term,
|
struct usb_audio_term *term,
|
||||||
void *p1, int id)
|
void *p1, int id)
|
||||||
@@ -981,8 +996,7 @@ static int __check_input_term(struct mixer_build *state, int id,
|
|||||||
UAC3_PROCESSING_UNIT);
|
UAC3_PROCESSING_UNIT);
|
||||||
case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT):
|
case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT):
|
||||||
case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT):
|
case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT):
|
||||||
return parse_term_proc_unit(state, term, p1, id,
|
return parse_term_effect_unit(state, term, p1, id);
|
||||||
UAC3_EFFECT_UNIT);
|
|
||||||
case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT):
|
case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT):
|
||||||
case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2):
|
case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2):
|
||||||
case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT):
|
case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT):
|
||||||
|
|||||||
@@ -1476,6 +1476,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
|
|||||||
case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
|
case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
|
||||||
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
|
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
|
||||||
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
|
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
|
||||||
|
case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user