summaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-02-21 23:21:35 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2021-02-21 23:21:35 +0100
commit10e2ec8edece2566b40f69bae035a555ece71ab4 (patch)
tree27eed009a4817948623bbc31a83911c5ace7a4b0 /sound/usb
parentMerge tag 'media/v5.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mc... (diff)
parentALSA: hda: intel-dsp-config: add Alder Lake support (diff)
downloadlinux-10e2ec8edece2566b40f69bae035a555ece71ab4.tar.xz
linux-10e2ec8edece2566b40f69bae035a555ece71ab4.zip
Merge tag 'sound-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "A relatively calm release at this time, and no massive code changes are found in the stats, while a wide range of code refactoring and cleanup have been done. Note that this update includes the tree-wide trivial changes for dropping the return value from ISA remove callbacks, too. Below lists up some highlight: ALSA Core: - Support for the software jack injection via debugfs - Fixes for sync_stop PCM operations HD-audio and USB-audio: - A few usual HD-audio device quirks - Updates for Tegra HD-audio - More quirks for Pioneer and other USB-audio devices - Stricter state checks at USB-audio disconnection ASoC: - Continued code refactoring, cleanup and fixes in ASoC core API - A KUnit testsuite for the topology code - Lots of ASoC Intel driver Realtek codec updates, quirk additions and fixes - Support for Ingenic JZ4760(B), Intel AlderLake-P, DT configured nVidia cards, Qualcomm lpass-rx-macro and lpass-tx-macro - Removal of obsolete SIRF prima/atlas, Txx9 and ZTE zx drivers Others: - Drop return value from ISA driver remove callback - Cleanup with DIV_ROUND_UP() macro - FireWire updates, HDSP output loopback support" * tag 'sound-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (322 commits) ALSA: hda: intel-dsp-config: add Alder Lake support ASoC: soc-pcm: fix hw param limits calculation for multi-DAI ASoC: Intel: bytcr_rt5640: Add quirk for the Acer One S1002 tablet ASoC: Intel: bytcr_rt5651: Add quirk for the Jumper EZpad 7 tablet ASoC: Intel: bytcr_rt5640: Add quirk for the Voyo Winpad A15 tablet ASoC: Intel: bytcr_rt5640: Add quirk for the Estar Beauty HD MID 7316R tablet ASoC: soc-pcm: fix hwparams min/max init for dpcm ALSA: hda/realtek: Quirk for HP Spectre x360 14 amp setup ALSA: usb-audio: Add implicit fb quirk for BOSS GP-10 ALSA: hda: Add another CometLake-H PCI ID ASoC: soc-pcm: add soc_pcm_hw_update_format() ASoC: soc-pcm: add soc_pcm_hw_update_chan() ASoC: soc-pcm: add soc_pcm_hw_update_rate() ASoC: wm_adsp: Remove unused control callback structure ASoC: SOF: relax ABI checks and avoid unnecessary warnings ASoC: codecs: lpass-tx-macro: add dapm widgets and route ASoC: codecs: lpass-tx-macro: add support for lpass tx macro ASoC: qcom: dt-bindings: add bindings for lpass tx macro codec ASoC: codecs: lpass-rx-macro: add iir widgets ASoC: codecs: lpass-rx-macro: add dapm widgets and route ...
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/bcd2000/bcd2000.c2
-rw-r--r--sound/usb/caiaq/audio.c2
-rw-r--r--sound/usb/caiaq/device.c6
-rw-r--r--sound/usb/caiaq/midi.c2
-rw-r--r--sound/usb/card.c15
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/clock.c6
-rw-r--r--sound/usb/endpoint.c87
-rw-r--r--sound/usb/hiface/chip.c6
-rw-r--r--sound/usb/hiface/pcm.c2
-rw-r--r--sound/usb/implicit.c5
-rw-r--r--sound/usb/mixer.c30
-rw-r--r--sound/usb/mixer_quirks.c369
-rw-r--r--sound/usb/mixer_scarlett.c2
-rw-r--r--sound/usb/mixer_scarlett_gen2.c2
-rw-r--r--sound/usb/mixer_us16x08.c2
-rw-r--r--sound/usb/pcm.c7
-rw-r--r--sound/usb/quirks-table.h117
-rw-r--r--sound/usb/quirks.c20
19 files changed, 487 insertions, 197 deletions
diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c
index 010976d9ceb2..cd4a0bc6d278 100644
--- a/sound/usb/bcd2000/bcd2000.c
+++ b/sound/usb/bcd2000/bcd2000.c
@@ -300,7 +300,7 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k)
if (ret < 0)
return ret;
- strlcpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
+ strscpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = bcd2k;
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 3b6bb2cbe886..4981753652a7 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -804,7 +804,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
}
cdev->pcm->private_data = cdev;
- strlcpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
+ strscpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 2af3b7eb0a88..e03481caf7f6 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -477,9 +477,9 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
usb_string(usb_dev, usb_dev->descriptor.iProduct,
cdev->product_name, CAIAQ_USB_STR_LEN);
- strlcpy(card->driver, MODNAME, sizeof(card->driver));
- strlcpy(card->shortname, cdev->product_name, sizeof(card->shortname));
- strlcpy(card->mixername, cdev->product_name, sizeof(card->mixername));
+ strscpy(card->driver, MODNAME, sizeof(card->driver));
+ strscpy(card->shortname, cdev->product_name, sizeof(card->shortname));
+ strscpy(card->mixername, cdev->product_name, sizeof(card->mixername));
/* if the id was not passed as module option, fill it with a shortened
* version of the product string which does not contain any
diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c
index 512fbb3ee604..c656d0162432 100644
--- a/sound/usb/caiaq/midi.c
+++ b/sound/usb/caiaq/midi.c
@@ -125,7 +125,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
if (ret < 0)
return ret;
- strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name));
+ strscpy(rmidi->name, device->product_name, sizeof(rmidi->name));
rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = device;
diff --git a/sound/usb/card.c b/sound/usb/card.c
index e08fbf8e3ee0..85ed8507e41a 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -472,7 +472,7 @@ static void usb_audio_make_shortname(struct usb_device *dev,
else if (quirk && quirk->product_name)
s = quirk->product_name;
if (s && *s) {
- strlcpy(card->shortname, s, sizeof(card->shortname));
+ strscpy(card->shortname, s, sizeof(card->shortname));
return;
}
@@ -504,7 +504,7 @@ static void usb_audio_make_longname(struct usb_device *dev,
if (preset && preset->profile_name)
s = preset->profile_name;
if (s && *s) {
- strlcpy(card->longname, s, sizeof(card->longname));
+ strscpy(card->longname, s, sizeof(card->longname));
return;
}
@@ -512,18 +512,17 @@ static void usb_audio_make_longname(struct usb_device *dev,
s = preset->vendor_name;
else if (quirk && quirk->vendor_name)
s = quirk->vendor_name;
+ *card->longname = 0;
if (s && *s) {
- len = strlcpy(card->longname, s, sizeof(card->longname));
+ strscpy(card->longname, s, sizeof(card->longname));
} else {
/* retrieve the vendor and device strings as longname */
if (dev->descriptor.iManufacturer)
- len = usb_string(dev, dev->descriptor.iManufacturer,
- card->longname, sizeof(card->longname));
- else
- len = 0;
+ usb_string(dev, dev->descriptor.iManufacturer,
+ card->longname, sizeof(card->longname));
/* we don't really care if there isn't any vendor string */
}
- if (len > 0) {
+ if (*card->longname) {
strim(card->longname);
if (*card->longname)
strlcat(card->longname, " ", sizeof(card->longname));
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 37091b117614..a741e7da83a2 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -71,7 +71,7 @@ struct snd_usb_endpoint {
unsigned char altsetting; /* corresponding alternate setting */
unsigned char ep_idx; /* endpoint array index */
- unsigned long flags; /* running bit flags */
+ atomic_t state; /* running state */
void (*prepare_data_urb) (struct snd_usb_substream *subs,
struct urb *urb);
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index dc68ed65e478..8243652d5604 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -298,6 +298,11 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
if (selector) {
int ret, i, cur;
+ if (selector->bNrInPins == 1) {
+ ret = 1;
+ goto find_source;
+ }
+
/* the entity ID we are looking for is a selector.
* find out what it currently selects */
ret = uac_clock_selector_get_val(chip, selector->bClockID);
@@ -314,6 +319,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
return -EINVAL;
}
+ find_source:
cur = ret;
ret = __uac_clock_find_source(chip, fmt,
selector->baCSourceID[ret - 1],
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 8e568823c992..102d53515a76 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -21,8 +21,11 @@
#include "clock.h"
#include "quirks.h"
-#define EP_FLAG_RUNNING 1
-#define EP_FLAG_STOPPING 2
+enum {
+ EP_STATE_STOPPED,
+ EP_STATE_RUNNING,
+ EP_STATE_STOPPING,
+};
/* interface refcounting */
struct snd_usb_iface_ref {
@@ -115,6 +118,16 @@ static const char *usb_error_string(int err)
}
}
+static inline bool ep_state_running(struct snd_usb_endpoint *ep)
+{
+ return atomic_read(&ep->state) == EP_STATE_RUNNING;
+}
+
+static inline bool ep_state_update(struct snd_usb_endpoint *ep, int old, int new)
+{
+ return atomic_cmpxchg(&ep->state, old, new) == old;
+}
+
/**
* snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type
*
@@ -393,7 +406,7 @@ next_packet_fifo_dequeue(struct snd_usb_endpoint *ep)
*/
static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
{
- while (test_bit(EP_FLAG_RUNNING, &ep->flags)) {
+ while (ep_state_running(ep)) {
unsigned long flags;
struct snd_usb_packet_info *packet;
@@ -454,13 +467,13 @@ static void snd_complete_urb(struct urb *urb)
if (unlikely(atomic_read(&ep->chip->shutdown)))
goto exit_clear;
- if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+ if (unlikely(!ep_state_running(ep)))
goto exit_clear;
if (usb_pipeout(ep->pipe)) {
retire_outbound_urb(ep, ctx);
/* can be stopped during retire callback */
- if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+ if (unlikely(!ep_state_running(ep)))
goto exit_clear;
if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
@@ -474,12 +487,12 @@ static void snd_complete_urb(struct urb *urb)
prepare_outbound_urb(ep, ctx);
/* can be stopped during prepare callback */
- if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+ if (unlikely(!ep_state_running(ep)))
goto exit_clear;
} else {
retire_inbound_urb(ep, ctx);
/* can be stopped during retire callback */
- if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+ if (unlikely(!ep_state_running(ep)))
goto exit_clear;
prepare_inbound_urb(ep, ctx);
@@ -835,7 +848,7 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
int alive;
- if (!test_bit(EP_FLAG_STOPPING, &ep->flags))
+ if (atomic_read(&ep->state) != EP_STATE_STOPPING)
return 0;
do {
@@ -850,10 +863,11 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
usb_audio_err(ep->chip,
"timeout: still %d active urbs on EP #%x\n",
alive, ep->ep_num);
- clear_bit(EP_FLAG_STOPPING, &ep->flags);
- ep->sync_sink = NULL;
- snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
+ if (ep_state_update(ep, EP_STATE_STOPPING, EP_STATE_STOPPED)) {
+ ep->sync_sink = NULL;
+ snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
+ }
return 0;
}
@@ -868,26 +882,20 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
}
/*
- * Stop and unlink active urbs.
+ * Stop active urbs
*
- * This function checks and clears EP_FLAG_RUNNING state.
- * When @wait_sync is set, it waits until all pending URBs are killed.
+ * This function moves the EP to STOPPING state if it's being RUNNING.
*/
-static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
- bool wait_sync)
+static int stop_urbs(struct snd_usb_endpoint *ep, bool force)
{
unsigned int i;
- if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */
- return -EBADFD;
-
- if (atomic_read(&ep->running))
+ if (!force && atomic_read(&ep->running))
return -EBUSY;
- if (!test_and_clear_bit(EP_FLAG_RUNNING, &ep->flags))
- goto out;
+ if (!ep_state_update(ep, EP_STATE_RUNNING, EP_STATE_STOPPING))
+ return 0;
- set_bit(EP_FLAG_STOPPING, &ep->flags);
INIT_LIST_HEAD(&ep->ready_playback_urbs);
ep->next_packet_head = 0;
ep->next_packet_queued = 0;
@@ -901,24 +909,25 @@ static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
}
}
- out:
- if (wait_sync)
- return wait_clear_urbs(ep);
return 0;
}
/*
* release an endpoint's urbs
*/
-static void release_urbs(struct snd_usb_endpoint *ep, int force)
+static int release_urbs(struct snd_usb_endpoint *ep, bool force)
{
- int i;
+ int i, err;
/* route incoming urbs to nirvana */
snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
- /* stop urbs */
- stop_and_unlink_urbs(ep, force, true);
+ /* stop and unlink urbs */
+ err = stop_urbs(ep, force);
+ if (err)
+ return err;
+
+ wait_clear_urbs(ep);
for (i = 0; i < ep->nurbs; i++)
release_urb_ctx(&ep->urb[i]);
@@ -928,6 +937,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)
ep->syncbuf = NULL;
ep->nurbs = 0;
+ return 0;
}
/*
@@ -1118,7 +1128,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
return 0;
out_of_memory:
- release_urbs(ep, 0);
+ release_urbs(ep, false);
return -ENOMEM;
}
@@ -1162,7 +1172,7 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep)
return 0;
out_of_memory:
- release_urbs(ep, 0);
+ release_urbs(ep, false);
return -ENOMEM;
}
@@ -1180,7 +1190,9 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
int err;
/* release old buffers, if any */
- release_urbs(ep, 0);
+ err = release_urbs(ep, false);
+ if (err < 0)
+ return err;
ep->datainterval = fmt->datainterval;
ep->maxpacksize = fmt->maxpacksize;
@@ -1360,7 +1372,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
* from that context.
*/
- set_bit(EP_FLAG_RUNNING, &ep->flags);
+ if (!ep_state_update(ep, EP_STATE_STOPPED, EP_STATE_RUNNING))
+ goto __error;
if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
for (i = 0; i < ep->nurbs; i++) {
@@ -1433,7 +1446,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
WRITE_ONCE(ep->sync_source->sync_sink, NULL);
if (!atomic_dec_return(&ep->running))
- stop_and_unlink_urbs(ep, false, false);
+ stop_urbs(ep, false);
}
/**
@@ -1446,12 +1459,12 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
*/
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
{
- release_urbs(ep, 1);
+ release_urbs(ep, true);
}
/**
* snd_usb_endpoint_free_all: Free the resources of an snd_usb_endpoint
- * @card: The chip
+ * @chip: The chip
*
* This free all endpoints and those resources
*/
diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c
index b2d9623e9934..c2824188d142 100644
--- a/sound/usb/hiface/chip.c
+++ b/sound/usb/hiface/chip.c
@@ -80,12 +80,12 @@ static int hiface_chip_create(struct usb_interface *intf,
return ret;
}
- strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+ strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
if (quirk && quirk->device_name)
- strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname));
+ strscpy(card->shortname, quirk->device_name, sizeof(card->shortname));
else
- strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
+ strscpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
strlcat(card->longname, card->shortname, sizeof(card->longname));
len = strlcat(card->longname, " at ", sizeof(card->longname));
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
index d942179ca095..71f17f02f341 100644
--- a/sound/usb/hiface/pcm.c
+++ b/sound/usb/hiface/pcm.c
@@ -594,7 +594,7 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
pcm->private_data = rt;
pcm->private_free = hiface_pcm_free;
- strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
+ strscpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
NULL, 0, 0);
diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
index 521cc846d9d9..11a85e66aa96 100644
--- a/sound/usb/implicit.c
+++ b/sound/usb/implicit.c
@@ -73,6 +73,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
/* No quirk for playback but with capture quirk (see below) */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130), /* BOSS BR-80 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x0171), /* BOSS RC-505 */
+ IMPLICIT_FB_SKIP_DEV(0x0582, 0x0185), /* BOSS GP-10 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189), /* BOSS GT-100v2 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d6), /* BOSS GT-1 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */
@@ -86,6 +87,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */
+ IMPLICIT_FB_FIXED_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */
@@ -302,7 +304,8 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
/* Pioneer devices with vendor spec class */
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
- USB_ID_VENDOR(chip->usb_id) == 0x2b73 /* Pioneer */) {
+ (USB_ID_VENDOR(chip->usb_id) == 0x2b73 || /* Pioneer */
+ USB_ID_VENDOR(chip->usb_id) == 0x08e4 /* Pioneer */)) {
if (skip_pioneer_sync_ep(chip, fmt, alts))
return 1;
}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 12b15ed59eaa..b1c78db0d470 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -115,11 +115,14 @@ find_map(const struct usbmix_name_map *p, int unitid, int control)
static int
check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
{
+ int len;
+
if (!p || !p->name)
return 0;
buflen--;
- return strlcpy(buf, p->name, buflen);
+ len = strscpy(buf, p->name, buflen);
+ return len < 0 ? buflen : len;
}
/* ignore the error value if ignore_ctl_error flag is set */
@@ -151,12 +154,15 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,
int index, char *buf, int buflen)
{
const struct usbmix_selector_map *p;
+ int len;
if (!state->selector_map)
return 0;
for (p = state->selector_map; p->id; p++) {
- if (p->id == unitid && index < p->count)
- return strlcpy(buf, p->names[index], buflen);
+ if (p->id == unitid && index < p->count) {
+ len = strscpy(buf, p->names[index], buflen);
+ return len < 0 ? buflen : len;
+ }
}
return 0;
}
@@ -254,7 +260,7 @@ static int get_relative_value(struct usb_mixer_elem_info *cval, int val)
if (val < cval->min)
return 0;
else if (val >= cval->max)
- return (cval->max - cval->min + cval->res - 1) / cval->res;
+ return DIV_ROUND_UP(cval->max - cval->min, cval->res);
else
return (val - cval->min) / cval->res;
}
@@ -1232,7 +1238,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
(cval->control << 8) | minchn,
&cval->res) < 0) {
cval->res = 1;
- } else {
+ } else if (cval->head.mixer->protocol == UAC_VERSION_1) {
int last_valid_res = cval->res;
while (cval->res > 1) {
@@ -1338,7 +1344,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
}
uinfo->value.integer.min = 0;
uinfo->value.integer.max =
- (cval->max - cval->min + cval->res - 1) / cval->res;
+ DIV_ROUND_UP(cval->max - cval->min, cval->res);
}
return 0;
}
@@ -1556,7 +1562,7 @@ static void check_no_speaker_on_headset(struct snd_kcontrol *kctl,
if (!found)
return;
- strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name));
+ strscpy(kctl->id.name, "Headphone", sizeof(kctl->id.name));
}
static const struct usb_feature_control_info *get_feature_control_info(int control)
@@ -1691,7 +1697,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
break;
default:
if (!len)
- strlcpy(kctl->id.name, audio_feature_info[control-1].name,
+ strscpy(kctl->id.name, audio_feature_info[control-1].name,
sizeof(kctl->id.name));
break;
}
@@ -1770,7 +1776,7 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer,
int name_len = get_term_name(mixer->chip, term, name, name_size, 0);
if (name_len == 0)
- strlcpy(name, "Unknown", name_size);
+ strscpy(name, "Unknown", name_size);
/*
* sound/core/ctljack.c has a convention of naming jack controls
@@ -2490,7 +2496,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {
/* nothing */ ;
} else if (info->name) {
- strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
+ strscpy(kctl->id.name, info->name, sizeof(kctl->id.name));
} else {
if (extension_unit)
nameid = uac_extension_unit_iExtension(desc, state->mixer->protocol);
@@ -2503,7 +2509,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
kctl->id.name,
sizeof(kctl->id.name));
if (!len)
- strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+ strscpy(kctl->id.name, name, sizeof(kctl->id.name));
}
append_ctl_name(kctl, " ");
append_ctl_name(kctl, valinfo->suffix);
@@ -2743,7 +2749,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
kctl->id.name, sizeof(kctl->id.name), 0);
/* ... or use the fixed string "USB" as the last resort */
if (!len)
- strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
+ strscpy(kctl->id.name, "USB", sizeof(kctl->id.name));
/* and add the proper suffix */
if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index df036a359f2f..08873d2afe4d 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -2603,141 +2603,251 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
}
/*
- * Pioneer DJ DJM-250MK2 and maybe other DJM models
+ * Pioneer DJ DJM Mixers
*
- * For playback, no duplicate mapping should be set.
- * There are three mixer stereo channels (CH1, CH2, AUX)
- * and three stereo sources (Playback 1-2, Playback 3-4, Playback 5-6).
- * Each channel should be mapped just once to one source.
- * If mapped multiple times, only one source will play on given channel
- * (sources are not mixed together).
+ * These devices generally have options for soft-switching the playback and
+ * capture sources in addition to the recording level. Although different
+ * devices have different configurations, there seems to be canonical values
+ * for specific capture/playback types: See the definitions of these below.
*
- * For recording, duplicate mapping is OK. We will get the same signal multiple times.
- *
- * Channels 7-8 are in both directions fixed to FX SEND / FX RETURN.
- *
- * See also notes in the quirks-table.h file.
+ * The wValue is masked with the stereo channel number. e.g. Setting Ch2 to
+ * capture phono would be 0x0203. Capture, playback and capture level have
+ * different wIndexes.
*/
-struct snd_pioneer_djm_option {
- const u16 wIndex;
- const u16 wValue;
+// Capture types
+#define SND_DJM_CAP_LINE 0x00
+#define SND_DJM_CAP_CDLINE 0x01
+#define SND_DJM_CAP_DIGITAL 0x02
+#define SND_DJM_CAP_PHONO 0x03
+#define SND_DJM_CAP_PFADER 0x06
+#define SND_DJM_CAP_XFADERA 0x07
+#define SND_DJM_CAP_XFADERB 0x08
+#define SND_DJM_CAP_MIC 0x09
+#define SND_DJM_CAP_AUX 0x0d
+#define SND_DJM_CAP_RECOUT 0x0a
+#define SND_DJM_CAP_NONE 0x0f
+#define SND_DJM_CAP_CH1PFADER 0x11
+#define SND_DJM_CAP_CH2PFADER 0x12
+#define SND_DJM_CAP_CH3PFADER 0x13
+#define SND_DJM_CAP_CH4PFADER 0x14
+
+// Playback types
+#define SND_DJM_PB_CH1 0x00
+#define SND_DJM_PB_CH2 0x01
+#define SND_DJM_PB_AUX 0x04
+
+#define SND_DJM_WINDEX_CAP 0x8002
+#define SND_DJM_WINDEX_CAPLVL 0x8003
+#define SND_DJM_WINDEX_PB 0x8016
+
+// kcontrol->private_value layout
+#define SND_DJM_VALUE_MASK 0x0000ffff
+#define SND_DJM_GROUP_MASK 0x00ff0000
+#define SND_DJM_DEVICE_MASK 0xff000000
+#define SND_DJM_GROUP_SHIFT 16
+#define SND_DJM_DEVICE_SHIFT 24
+
+// device table index
+#define SND_DJM_250MK2_IDX 0x0
+#define SND_DJM_750_IDX 0x1
+#define SND_DJM_900NXS2_IDX 0x2
+
+
+#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
+ .name = _name, \
+ .options = snd_djm_opts_##suffix, \
+ .noptions = ARRAY_SIZE(snd_djm_opts_##suffix), \
+ .default_value = _default_value, \
+ .wIndex = _windex }
+
+#define SND_DJM_DEVICE(suffix) { \
+ .controls = snd_djm_ctls_##suffix, \
+ .ncontrols = ARRAY_SIZE(snd_djm_ctls_##suffix) }
+
+
+struct snd_djm_device {
const char *name;
+ const struct snd_djm_ctl *controls;
+ size_t ncontrols;
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_level[] = {
- { .name = "-5 dB", .wValue = 0x0300, .wIndex = 0x8003 },
- { .name = "-10 dB", .wValue = 0x0200, .wIndex = 0x8003 },
- { .name = "-15 dB", .wValue = 0x0100, .wIndex = 0x8003 },
- { .name = "-19 dB", .wValue = 0x0000, .wIndex = 0x8003 }
+struct snd_djm_ctl {
+ const char *name;
+ const u16 *options;
+ size_t noptions;
+ u16 default_value;
+ u16 wIndex;
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch12[] = {
- { .name = "CH1 Control Tone PHONO", .wValue = 0x0103, .wIndex = 0x8002 },
- { .name = "CH1 Control Tone LINE", .wValue = 0x0100, .wIndex = 0x8002 },
- { .name = "Post CH1 Fader", .wValue = 0x0106, .wIndex = 0x8002 },
- { .name = "Cross Fader A", .wValue = 0x0107, .wIndex = 0x8002 },
- { .name = "Cross Fader B", .wValue = 0x0108, .wIndex = 0x8002 },
- { .name = "MIC", .wValue = 0x0109, .wIndex = 0x8002 },
- { .name = "AUX", .wValue = 0x010d, .wIndex = 0x8002 },
- { .name = "REC OUT", .wValue = 0x010a, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_caplevel(u16 wvalue)
+{
+ switch (wvalue) {
+ case 0x0000: return "-19dB";
+ case 0x0100: return "-15dB";
+ case 0x0200: return "-10dB";
+ case 0x0300: return "-5dB";
+ default: return NULL;
+ }
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch34[] = {
- { .name = "CH2 Control Tone PHONO", .wValue = 0x0203, .wIndex = 0x8002 },
- { .name = "CH2 Control Tone LINE", .wValue = 0x0200, .wIndex = 0x8002 },
- { .name = "Post CH2 Fader", .wValue = 0x0206, .wIndex = 0x8002 },
- { .name = "Cross Fader A", .wValue = 0x0207, .wIndex = 0x8002 },
- { .name = "Cross Fader B", .wValue = 0x0208, .wIndex = 0x8002 },
- { .name = "MIC", .wValue = 0x0209, .wIndex = 0x8002 },
- { .name = "AUX", .wValue = 0x020d, .wIndex = 0x8002 },
- { .name = "REC OUT", .wValue = 0x020a, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_cap(u16 wvalue)
+{
+ switch (wvalue & 0x00ff) {
+ case SND_DJM_CAP_LINE: return "Control Tone LINE";
+ case SND_DJM_CAP_CDLINE: return "Control Tone CD/LINE";
+ case SND_DJM_CAP_DIGITAL: return "Control Tone DIGITAL";
+ case SND_DJM_CAP_PHONO: return "Control Tone PHONO";
+ case SND_DJM_CAP_PFADER: return "Post Fader";
+ case SND_DJM_CAP_XFADERA: return "Cross Fader A";
+ case SND_DJM_CAP_XFADERB: return "Cross Fader B";
+ case SND_DJM_CAP_MIC: return "Mic";
+ case SND_DJM_CAP_RECOUT: return "Rec Out";
+ case SND_DJM_CAP_AUX: return "Aux";
+ case SND_DJM_CAP_NONE: return "None";
+ case SND_DJM_CAP_CH1PFADER: return "Post Fader Ch1";
+ case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2";
+ case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3";
+ case SND_DJM_CAP_CH4PFADER: return "Post Fader Ch4";
+ default: return NULL;
+ }
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch56[] = {
- { .name = "REC OUT", .wValue = 0x030a, .wIndex = 0x8002 },
- { .name = "Post CH1 Fader", .wValue = 0x0311, .wIndex = 0x8002 },
- { .name = "Post CH2 Fader", .wValue = 0x0312, .wIndex = 0x8002 },
- { .name = "Cross Fader A", .wValue = 0x0307, .wIndex = 0x8002 },
- { .name = "Cross Fader B", .wValue = 0x0308, .wIndex = 0x8002 },
- { .name = "MIC", .wValue = 0x0309, .wIndex = 0x8002 },
- { .name = "AUX", .wValue = 0x030d, .wIndex = 0x8002 }
+static const char *snd_djm_get_label_pb(u16 wvalue)
+{
+ switch (wvalue & 0x00ff) {
+ case SND_DJM_PB_CH1: return "Ch1";
+ case SND_DJM_PB_CH2: return "Ch2";
+ case SND_DJM_PB_AUX: return "Aux";
+ default: return NULL;
+ }
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_12[] = {
- { .name = "CH1", .wValue = 0x0100, .wIndex = 0x8016 },
- { .name = "CH2", .wValue = 0x0101, .wIndex = 0x8016 },
- { .name = "AUX", .wValue = 0x0104, .wIndex = 0x8016 }
+static const char *snd_djm_get_label(u16 wvalue, u16 windex)
+{
+ switch (windex) {
+ case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue);
+ case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(wvalue);
+ case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue);
+ default: return NULL;
+ }
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_34[] = {
- { .name = "CH1", .wValue = 0x0200, .wIndex = 0x8016 },
- { .name = "CH2", .wValue = 0x0201, .wIndex = 0x8016 },
- { .name = "AUX", .wValue = 0x0204, .wIndex = 0x8016 }
+
+// DJM-250MK2
+static const u16 snd_djm_opts_cap_level[] = {
+ 0x0000, 0x0100, 0x0200, 0x0300 };
+
+static const u16 snd_djm_opts_250mk2_cap1[] = {
+ 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a };
+
+static const u16 snd_djm_opts_250mk2_cap2[] = {
+ 0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a };
+
+static const u16 snd_djm_opts_250mk2_cap3[] = {
+ 0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d };
+
+static const u16 snd_djm_opts_250mk2_pb1[] = { 0x0100, 0x0101, 0x0104 };
+static const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 };
+static const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 };
+
+static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = {
+ SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+ SND_DJM_CTL("Ch1 Input", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch2 Input", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch3 Input", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch1 Output", 250mk2_pb1, 0, SND_DJM_WINDEX_PB),
+ SND_DJM_CTL("Ch2 Output", 250mk2_pb2, 1, SND_DJM_WINDEX_PB),
+ SND_DJM_CTL("Ch3 Output", 250mk2_pb3, 2, SND_DJM_WINDEX_PB)
};
-static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_56[] = {
- { .name = "CH1", .wValue = 0x0300, .wIndex = 0x8016 },
- { .name = "CH2", .wValue = 0x0301, .wIndex = 0x8016 },
- { .name = "AUX", .wValue = 0x0304, .wIndex = 0x8016 }
+
+// DJM-750
+static const u16 snd_djm_opts_750_cap1[] = {
+ 0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f };
+static const u16 snd_djm_opts_750_cap2[] = {
+ 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f };
+static const u16 snd_djm_opts_750_cap3[] = {
+ 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f };
+static const u16 snd_djm_opts_750_cap4[] = {
+ 0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f };
+
+static const struct snd_djm_ctl snd_djm_ctls_750[] = {
+ SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+ SND_DJM_CTL("Ch1 Input", 750_cap1, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch2 Input", 750_cap2, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch3 Input", 750_cap3, 0, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch4 Input", 750_cap4, 0, SND_DJM_WINDEX_CAP)
};
-struct snd_pioneer_djm_option_group {
- const char *name;
- const struct snd_pioneer_djm_option *options;
- const size_t count;
- const u16 default_value;
+
+// DJM-900NXS2
+static const u16 snd_djm_opts_900nxs2_cap1[] = {
+ 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a };
+static const u16 snd_djm_opts_900nxs2_cap2[] = {
+ 0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a };
+static const u16 snd_djm_opts_900nxs2_cap3[] = {
+ 0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a };
+static const u16 snd_djm_opts_900nxs2_cap4[] = {
+ 0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a };
+static const u16 snd_djm_opts_900nxs2_cap5[] = {
+ 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 };
+
+static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = {
+ SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+ SND_DJM_CTL("Ch1 Input", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch2 Input", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch3 Input", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch4 Input", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Ch5 Input", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP)
};
-#define snd_pioneer_djm_option_group_item(_name, suffix, _default_value) { \
- .name = _name, \
- .options = snd_pioneer_djm_options_##suffix, \
- .count = ARRAY_SIZE(snd_pioneer_djm_options_##suffix), \
- .default_value = _default_value }
-
-static const struct snd_pioneer_djm_option_group snd_pioneer_djm_option_groups[] = {
- snd_pioneer_djm_option_group_item("Master Capture Level Capture Switch", capture_level, 0),
- snd_pioneer_djm_option_group_item("Capture 1-2 Capture Switch", capture_ch12, 2),
- snd_pioneer_djm_option_group_item("Capture 3-4 Capture Switch", capture_ch34, 2),
- snd_pioneer_djm_option_group_item("Capture 5-6 Capture Switch", capture_ch56, 0),
- snd_pioneer_djm_option_group_item("Playback 1-2 Playback Switch", playback_12, 0),
- snd_pioneer_djm_option_group_item("Playback 3-4 Playback Switch", playback_34, 1),
- snd_pioneer_djm_option_group_item("Playback 5-6 Playback Switch", playback_56, 2)
+
+static const struct snd_djm_device snd_djm_devices[] = {
+ SND_DJM_DEVICE(250mk2),
+ SND_DJM_DEVICE(750),
+ SND_DJM_DEVICE(900nxs2)
};
-// layout of the kcontrol->private_value:
-#define SND_PIONEER_DJM_VALUE_MASK 0x0000ffff
-#define SND_PIONEER_DJM_GROUP_MASK 0xffff0000
-#define SND_PIONEER_DJM_GROUP_SHIFT 16
-static int snd_pioneer_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info)
+static int snd_djm_controls_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *info)
{
- u16 group_index = kctl->private_value >> SND_PIONEER_DJM_GROUP_SHIFT;
- size_t count;
+ unsigned long private_value = kctl->private_value;
+ u8 device_idx = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+ u8 ctl_idx = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
+ const struct snd_djm_device *device = &snd_djm_devices[device_idx];
const char *name;
- const struct snd_pioneer_djm_option_group *group;
+ const struct snd_djm_ctl *ctl;
+ size_t noptions;
- if (group_index >= ARRAY_SIZE(snd_pioneer_djm_option_groups))
+ if (ctl_idx >= device->ncontrols)
return -EINVAL;
- group = &snd_pioneer_djm_option_groups[group_index];
- count = group->count;
- if (info->value.enumerated.item >= count)
- info->value.enumerated.item = count - 1;
- name = group->options[info->value.enumerated.item].name;
- strlcpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
+ ctl = &device->controls[ctl_idx];
+ noptions = ctl->noptions;
+ if (info->value.enumerated.item >= noptions)
+ info->value.enumerated.item = noptions - 1;
+
+ name = snd_djm_get_label(ctl->options[info->value.enumerated.item],
+ ctl->wIndex);
+ if (!name)
+ return -EINVAL;
+
+ strscpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = 1;
- info->value.enumerated.items = count;
+ info->value.enumerated.items = noptions;
return 0;
}
-static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u16 group, u16 value)
+static int snd_djm_controls_update(struct usb_mixer_interface *mixer,
+ u8 device_idx, u8 group, u16 value)
{
int err;
+ const struct snd_djm_device *device = &snd_djm_devices[device_idx];
- if (group >= ARRAY_SIZE(snd_pioneer_djm_option_groups)
- || value >= snd_pioneer_djm_option_groups[group].count)
+ if ((group >= device->ncontrols) || value >= device->controls[group].noptions)
return -EINVAL;
err = snd_usb_lock_shutdown(mixer->chip);
@@ -2748,63 +2858,76 @@ static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u1
mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0),
USB_REQ_SET_FEATURE,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- snd_pioneer_djm_option_groups[group].options[value].wValue,
- snd_pioneer_djm_option_groups[group].options[value].wIndex,
+ device->controls[group].options[value],
+ device->controls[group].wIndex,
NULL, 0);
snd_usb_unlock_shutdown(mixer->chip);
return err;
}
-static int snd_pioneer_djm_controls_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
+static int snd_djm_controls_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *elem)
{
- elem->value.enumerated.item[0] = kctl->private_value & SND_PIONEER_DJM_VALUE_MASK;
+ elem->value.enumerated.item[0] = kctl->private_value & SND_DJM_VALUE_MASK;
return 0;
}
-static int snd_pioneer_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
+static int snd_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
{
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
struct usb_mixer_interface *mixer = list->mixer;
unsigned long private_value = kctl->private_value;
- u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
+
+ u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+ u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
u16 value = elem->value.enumerated.item[0];
- kctl->private_value = (group << SND_PIONEER_DJM_GROUP_SHIFT) | value;
+ kctl->private_value = ((device << SND_DJM_DEVICE_SHIFT) |
+ (group << SND_DJM_GROUP_SHIFT) |
+ value);
- return snd_pioneer_djm_controls_update(mixer, group, value);
+ return snd_djm_controls_update(mixer, device, group, value);
}
-static int snd_pioneer_djm_controls_resume(struct usb_mixer_elem_list *list)
+static int snd_djm_controls_resume(struct usb_mixer_elem_list *list)
{
unsigned long private_value = list->kctl->private_value;
- u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
- u16 value = (private_value & SND_PIONEER_DJM_VALUE_MASK);
+ u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT;
+ u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
+ u16 value = (private_value & SND_DJM_VALUE_MASK);
- return snd_pioneer_djm_controls_update(list->mixer, group, value);
+ return snd_djm_controls_update(list->mixer, device, group, value);
}
-static int snd_pioneer_djm_controls_create(struct usb_mixer_interface *mixer)
+static int snd_djm_controls_create(struct usb_mixer_interface *mixer,
+ const u8 device_idx)
{
int err, i;
- const struct snd_pioneer_djm_option_group *group;
+ u16 value;
+
+ const struct snd_djm_device *device = &snd_djm_devices[device_idx];
+
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.index = 0,
- .info = snd_pioneer_djm_controls_info,
- .get = snd_pioneer_djm_controls_get,
- .put = snd_pioneer_djm_controls_put
+ .info = snd_djm_controls_info,
+ .get = snd_djm_controls_get,
+ .put = snd_djm_controls_put
};
- for (i = 0; i < ARRAY_SIZE(snd_pioneer_djm_option_groups); i++) {
- group = &snd_pioneer_djm_option_groups[i];
- knew.name = group->name;
- knew.private_value = (i << SND_PIONEER_DJM_GROUP_SHIFT) | group->default_value;
- err = snd_pioneer_djm_controls_update(mixer, i, group->default_value);
+ for (i = 0; i < device->ncontrols; i++) {
+ value = device->controls[i].default_value;
+ knew.name = device->controls[i].name;
+ knew.private_value = (
+ (device_idx << SND_DJM_DEVICE_SHIFT) |
+ (i << SND_DJM_GROUP_SHIFT) |
+ value);
+ err = snd_djm_controls_update(mixer, device_idx, i, value);
if (err)
return err;
- err = add_single_ctl_with_resume(mixer, 0, snd_pioneer_djm_controls_resume,
+ err = add_single_ctl_with_resume(mixer, 0, snd_djm_controls_resume,
&knew, NULL);
if (err)
return err;
@@ -2917,7 +3040,13 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
err = snd_bbfpro_controls_create(mixer);
break;
case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
- err = snd_pioneer_djm_controls_create(mixer);
+ err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
+ break;
+ case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */
+ err = snd_djm_controls_create(mixer, SND_DJM_750_IDX);
+ break;
+ case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
+ err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX);
break;
}
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
index 49fcd2505443..691b95466d0f 100644
--- a/sound/usb/mixer_scarlett.c
+++ b/sound/usb/mixer_scarlett.c
@@ -569,7 +569,7 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
}
kctl->private_free = snd_usb_mixer_elem_free;
- strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+ strscpy(kctl->id.name, name, sizeof(kctl->id.name));
err = snd_usb_mixer_add_control(&elem->head, kctl);
if (err < 0)
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 4bbec56c7df3..560c2ade829d 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -961,7 +961,7 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer,
}
kctl->private_free = snd_usb_mixer_elem_free;
- strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+ strscpy(kctl->id.name, name, sizeof(kctl->id.name));
err = snd_usb_mixer_add_control(&elem->head, kctl);
if (err < 0)
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
index bd63a9ce6a70..b7b6f3834ed5 100644
--- a/sound/usb/mixer_us16x08.c
+++ b/sound/usb/mixer_us16x08.c
@@ -1076,7 +1076,7 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
else
kctl->private_free = snd_usb_mixer_elem_free;
- strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+ strscpy(kctl->id.name, name, sizeof(kctl->id.name));
err = snd_usb_mixer_add_control(&elem->head, kctl);
if (err < 0)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 078bb4c94033..bf5a0f3c1fad 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -270,10 +270,7 @@ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream)
{
struct snd_usb_substream *subs = substream->runtime->private_data;
- if (!snd_usb_lock_shutdown(subs->stream->chip)) {
- sync_pending_stops(subs);
- snd_usb_unlock_shutdown(subs->stream->chip);
- }
+ sync_pending_stops(subs);
return 0;
}
@@ -1558,7 +1555,7 @@ void snd_usb_preallocate_buffer(struct snd_usb_substream *subs)
{
struct snd_pcm *pcm = subs->stream->pcm;
struct snd_pcm_substream *s = pcm->streams[subs->direction].substream;
- struct device *dev = subs->dev->bus->controller;
+ struct device *dev = subs->dev->bus->sysdev;
if (snd_usb_use_vmalloc)
snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_VMALLOC,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c8a4bdf18207..1165a5ac60f2 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3757,6 +3757,123 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
}
}
},
+{
+ /*
+ * Pioneer DJ DJM-750
+ * 8 channels playback & 8 channels capture @ 44.1/48/96kHz S24LE
+ */
+ USB_DEVICE_VENDOR_SPEC(0x08e4, 0x017f),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x05,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC|
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rates = SNDRV_PCM_RATE_44100|
+ SNDRV_PCM_RATE_48000|
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 3,
+ .rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+ }
+ },
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x86,
+ .ep_idx = 1,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC|
+ USB_ENDPOINT_SYNC_ASYNC|
+ USB_ENDPOINT_USAGE_IMPLICIT_FB,
+ .rates = SNDRV_PCM_RATE_44100|
+ SNDRV_PCM_RATE_48000|
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 3,
+ .rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+{
+ /*
+ * Pioneer DJ DJM-450
+ * PCM is 8 channels out @ 48 fixed (endpoint 0x01)
+ * and 8 channels in @ 48 fixed (endpoint 0x82).
+ */
+ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0013),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8, // outputs
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC|
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 48000 }
+ }
+ },
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8, // inputs
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x82,
+ .ep_idx = 1,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC|
+ USB_ENDPOINT_SYNC_ASYNC|
+ USB_ENDPOINT_USAGE_IMPLICIT_FB,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 48000 }
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
#undef USB_DEVICE_VENDOR_SPEC
#undef USB_AUDIO_DEVICE
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e196e364cef1..9ba4682ebc48 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1470,6 +1470,23 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,
subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
}
+static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs,
+ u16 windex)
+{
+ unsigned int cur_rate = subs->data_endpoint->cur_rate;
+ u8 sr[3];
+ // Convert to little endian
+ sr[0] = cur_rate & 0xff;
+ sr[1] = (cur_rate >> 8) & 0xff;
+ sr[2] = (cur_rate >> 16) & 0xff;
+ usb_set_interface(subs->dev, 0, 1);
+ // we should derive windex from fmt-sync_ep but it's not set
+ snd_usb_ctl_msg(subs->stream->chip->dev,
+ usb_rcvctrlpipe(subs->stream->chip->dev, 0),
+ 0x01, 0x22, 0x0100, windex, &sr, 0x0003);
+ return 0;
+}
+
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
const struct audioformat *fmt)
{
@@ -1483,6 +1500,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
subs->stream_offset_adj = 2;
break;
+ case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */
+ pioneer_djm_set_format_quirk(subs, 0x0082);
+ break;
}
}