diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 23:21:35 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 23:21:35 +0100 |
commit | 10e2ec8edece2566b40f69bae035a555ece71ab4 (patch) | |
tree | 27eed009a4817948623bbc31a83911c5ace7a4b0 /sound/usb | |
parent | Merge tag 'media/v5.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mc... (diff) | |
parent | ALSA: hda: intel-dsp-config: add Alder Lake support (diff) | |
download | linux-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.c | 2 | ||||
-rw-r--r-- | sound/usb/caiaq/audio.c | 2 | ||||
-rw-r--r-- | sound/usb/caiaq/device.c | 6 | ||||
-rw-r--r-- | sound/usb/caiaq/midi.c | 2 | ||||
-rw-r--r-- | sound/usb/card.c | 15 | ||||
-rw-r--r-- | sound/usb/card.h | 2 | ||||
-rw-r--r-- | sound/usb/clock.c | 6 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 87 | ||||
-rw-r--r-- | sound/usb/hiface/chip.c | 6 | ||||
-rw-r--r-- | sound/usb/hiface/pcm.c | 2 | ||||
-rw-r--r-- | sound/usb/implicit.c | 5 | ||||
-rw-r--r-- | sound/usb/mixer.c | 30 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 369 | ||||
-rw-r--r-- | sound/usb/mixer_scarlett.c | 2 | ||||
-rw-r--r-- | sound/usb/mixer_scarlett_gen2.c | 2 | ||||
-rw-r--r-- | sound/usb/mixer_us16x08.c | 2 | ||||
-rw-r--r-- | sound/usb/pcm.c | 7 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 117 | ||||
-rw-r--r-- | sound/usb/quirks.c | 20 |
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; } } |